Bug#854568: grub2: Add support for modern sparc64 hardware

John Paul Adrian Glaubitz glaubitz at physik.fu-berlin.de
Wed Feb 8 11:36:26 UTC 2017


Source: grub2
Version: 2.02~beta3-4
Severity: normal
Tags: patch
User: debian-sparc at lists.debian.org
Usertags: sparc64

Hi!

The attached patch adds support for modern sparc64 hardware to grub2.

This patch was generated out of a patch set [1] by Eric Snowberg (CC'ed)
from Oracle and is pending to be merged upstream. We have already tested
the patch set on Debian sparc64 and it seems to work fine so far.

According to Eric, it's also advised to tune the default grub2 configu-
ration for sparc64 to disable video mode and use a text console by
default. The current recommended settings for grub2 on sparc64
are:

GRUB_TERMINAL_OUTPUT="console"
GRUB_DISABLE_RECOVERY="true"
GRUB_PRELOAD_MODULES=“iso9660"

We have also verified that with the patch added, the grub2 package
still builds fine on non-sparc64 targets. This wasn't true for the
first revision of the patch.

I'm fully aware that this patch comes way too late due to the freeze,
but it might be an idea to add the patch to the experimental version
of the grub2 package to give it some testing on all targets.

Thanks,
Adrian

> [1] https://github.com/esnowberg/grub2-sparc/tree/sparc-next-v2

--
 .''`.  John Paul Adrian Glaubitz
: :' :  Debian Developer - glaubitz at debian.org
`. `'   Freie Universitaet Berlin - glaubitz at physik.fu-berlin.de
  `-    GPG: 62FF 8A75 84E0 2956 9546  0006 7426 3B37 F5B5 F913
-------------- next part --------------
Description: Add support for sparc64
Author: Eric Snowberg <eric.snowberg at oracle.com>
Last-Update: 2017-02-08
Source: https://github.com/esnowberg/grub2-sparc/tree/sparc-next-v2

Index: grub2-2.02~beta3/grub-core/commands/ls.c
===================================================================
--- grub2-2.02~beta3.orig/grub-core/commands/ls.c
+++ grub2-2.02~beta3/grub-core/commands/ls.c
@@ -201,6 +201,8 @@ grub_ls_list_files (char *dirname, int l
       if (grub_errno == GRUB_ERR_UNKNOWN_FS)
 	grub_errno = GRUB_ERR_NONE;
 
+      grub_device_close (dev);
+      dev = NULL;
       grub_normal_print_device_info (device_name);
     }
   else if (fs)
Index: grub2-2.02~beta3/grub-core/disk/ieee1275/ofdisk.c
===================================================================
--- grub2-2.02~beta3.orig/grub-core/disk/ieee1275/ofdisk.c
+++ grub2-2.02~beta3/grub-core/disk/ieee1275/ofdisk.c
@@ -22,8 +22,10 @@
 #include <grub/mm.h>
 #include <grub/ieee1275/ieee1275.h>
 #include <grub/ieee1275/ofdisk.h>
+#include <grub/scsicmd.h>
 #include <grub/i18n.h>
 #include <grub/time.h>
+#include <grub/list.h>
 
 static char *last_devpath;
 static grub_ieee1275_ihandle_t last_ihandle;
@@ -35,7 +37,9 @@ struct ofdisk_hash_ent
   char *grub_devpath;
   int is_boot;
   int is_removable;
-  int block_size_fails;
+  int block_size_retries;
+  grub_uint32_t block_size;
+  grub_ieee1275_ihandle_t ihandle;
   /* Pointer to shortest available name on nodes representing canonical names,
      otherwise NULL.  */
   const char *shortest;
@@ -43,13 +47,53 @@ struct ofdisk_hash_ent
   struct ofdisk_hash_ent *next;
 };
 
+struct ofdisk_hba_ent
+{
+  struct ofdisk_hba_ent *next;
+  struct ofdisk_hba_ent **prev;
+  grub_ieee1275_ihandle_t ihandle;
+  char *path;
+};
+
 static grub_err_t
-grub_ofdisk_get_block_size (const char *device, grub_uint32_t *block_size,
-			    struct ofdisk_hash_ent *op);
+grub_ofdisk_get_block_size (grub_uint32_t *block_size,
+                            struct ofdisk_hash_ent *op);
+
+static grub_err_t
+grub_ofdisk_open_real (grub_disk_t disk);
 
 #define OFDISK_HASH_SZ	8
 static struct ofdisk_hash_ent *ofdisk_hash[OFDISK_HASH_SZ];
 
+#ifdef __sparc__
+static grub_err_t
+sparc_disk_present (const char *path);
+
+static char *
+get_hbaname_from_path (const char *path);
+
+static char *
+get_diskname_from_path (const char *path);
+
+static struct ofdisk_hba_ent *
+ofdisk_hba_find (const char *devpath);
+
+static grub_ieee1275_ihandle_t
+ofdisk_hba_open (const char *hba_name);
+
+static struct ofdisk_hba_ent *ofdisk_hba_ents = NULL;
+
+static struct grub_scsi_test_unit_ready ofdisk_tur =
+{
+  .opcode = grub_scsi_cmd_test_unit_ready,
+  .lun = 0,
+  .reserved1 = 0,
+  .reserved2 = 0,
+  .reserved3 = 0,
+  .control = 0,
+};
+#endif
+
 static int
 ofdisk_hash_fn (const char *devpath)
 {
@@ -74,7 +118,7 @@ ofdisk_hash_find (const char *devpath)
 }
 
 static struct ofdisk_hash_ent *
-ofdisk_hash_add_real (char *devpath)
+ofdisk_hash_add_real (const char *devpath)
 {
   struct ofdisk_hash_ent *p;
   struct ofdisk_hash_ent **head = &ofdisk_hash[ofdisk_hash_fn(devpath)];
@@ -85,13 +129,20 @@ ofdisk_hash_add_real (char *devpath)
   if (!p)
     return NULL;
 
-  p->devpath = devpath;
+  p->devpath = grub_strdup (devpath);
+
+  if (!p->devpath)
+    {
+      grub_free (p);
+      return NULL;
+    }
 
   p->grub_devpath = grub_malloc (sizeof ("ieee1275/")
 				 + 2 * grub_strlen (p->devpath));
 
   if (!p->grub_devpath)
     {
+      grub_free (p->devpath);
       grub_free (p);
       return NULL;
     }
@@ -101,6 +152,7 @@ ofdisk_hash_add_real (char *devpath)
       p->open_path = grub_malloc (grub_strlen (p->devpath) + 3);
       if (!p->open_path)
 	{
+          grub_free (p->devpath);
 	  grub_free (p->grub_devpath);
 	  grub_free (p);
 	  return NULL;
@@ -140,7 +192,7 @@ check_string_removable (const char *str)
 }
 
 static struct ofdisk_hash_ent *
-ofdisk_hash_add (char *devpath, char *curcan)
+ofdisk_hash_add (const char *devpath, const char *curcan)
 {
   struct ofdisk_hash_ent *p, *pcan;
 
@@ -160,8 +212,6 @@ ofdisk_hash_add (char *devpath, char *cu
   pcan = ofdisk_hash_find (curcan);
   if (!pcan)
     pcan = ofdisk_hash_add_real (curcan);
-  else
-    grub_free (curcan);
 
   if (check_string_removable (devpath) || check_string_removable (curcan))
     pcan->is_removable = 1;
@@ -191,18 +241,7 @@ dev_iterate_real (const char *name, cons
 
   op = ofdisk_hash_find (path);
   if (!op)
-    {
-      char *name_dup = grub_strdup (name);
-      char *can = grub_strdup (path);
-      if (!name_dup || !can)
-	{
-	  grub_errno = GRUB_ERR_NONE;
-	  grub_free (name_dup);
-	  grub_free (can);
-	  return;
-	}
-      op = ofdisk_hash_add (name_dup, can);
-    }
+    op = ofdisk_hash_add (name, path);
   return;
 }
 
@@ -339,10 +378,159 @@ dev_iterate (const struct grub_ieee1275_
       grub_free (table);
       grub_free (buf);
     }
+#ifdef __sparc__
+  else if (grub_strcmp (alias->type, "scsi-2") == 0)
+    {
+      grub_ieee1275_ihandle_t ihandle;
+      grub_ssize_t result;
+      char *buf, *bufptr;
+      grub_uint8_t tgt;
+
+      buf = grub_malloc (grub_strlen (alias->path) +
+                         sizeof ("/disk at 00"));
+      if (!buf)
+        return;
+
+      bufptr = grub_stpcpy (buf, alias->path);
+      ihandle = ofdisk_hba_open (alias->path);
+
+      if (ihandle == 0)
+        {
+          grub_free (buf);
+          return;
+        }
+
+      for (tgt = 0; tgt <= 0xf; tgt++)
+        {
+          if (grub_ieee1275_set_address(ihandle, tgt, 0) == 0)
+            if (grub_ieee1275_no_data_command (ihandle, &ofdisk_tur,
+                                               &result) == 0)
+              if (result == 0)
+                {
+                  grub_snprintf (bufptr, sizeof ("/disk at 00"),
+                                 "/disk@%" PRIxGRUB_UINT32_T, tgt);
+                  dev_iterate_real (buf, buf);
+                }
+        }
+
+      grub_free (buf);
+      return;
+    }
+  else if (grub_strcmp (alias->type, "scsi-sas") == 0)
+    {
+      grub_ieee1275_ihandle_t ihandle;
+      grub_uint32_t address_cells = 2;
+      grub_ieee1275_phandle_t root;
+      grub_ssize_t result;
+      char *buf, *bufptr;
+
+      buf = grub_malloc (grub_strlen (alias->path) +
+                         sizeof ("/disk at p1100"));
+
+      if (!buf)
+        return;
+
+      bufptr = grub_stpcpy (buf, alias->path);
+      bufptr = grub_stpcpy (bufptr, "/disk@");
+      ihandle = ofdisk_hba_open (alias->path);
+
+      if (ihandle == 0)
+        {
+          grub_free (buf);
+          return;
+        }
+
+      grub_ieee1275_finddevice (alias->path, &root);
+      grub_ieee1275_get_integer_property (root, "#address-cells", &address_cells,
+                                          sizeof address_cells, 0);
+      if (address_cells == 2)
+        {
+          grub_uint8_t tgt;
+
+          for (tgt = 0; tgt < 0xf; tgt++)
+            {
+              if (grub_ieee1275_set_address(ihandle, tgt, 0) == 0)
+                if (grub_ieee1275_no_data_command (ihandle, &ofdisk_tur,
+                                                   &result) == 0)
+                  if (result == 0)
+                    {
+                      grub_snprintf (bufptr, sizeof ("p1100"),
+                                     "%" PRIxGRUB_UINT32_T, tgt);
+                      dev_iterate_real (buf, buf);
+                    }
+            }
+        }
+      else if (address_cells == 4)
+        {
+          grub_uint16_t exp;
+          grub_uint8_t phy;
+
+          for (exp = 0; exp <= 0x100; exp+=0x100)
+            for (phy = 0; phy < 0xff; phy++)
+              {
+                grub_snprintf (bufptr, sizeof ("p1100"),
+                               "p%" PRIxGRUB_UINT32_T, exp | phy);
+                if (grub_ieee1275_set_sas_address (ihandle, bufptr, 0) == 0)
+                  if (grub_ieee1275_no_data_command (ihandle, &ofdisk_tur,
+                                                     &result) == 0)
+                    if (result == 0)
+                      dev_iterate_real (buf, buf);
+              }
+        }
+      grub_free (buf);
+      return;
+    }
+  else if (grub_strcmp (alias->type, "nvme") == 0)
+    {
+      char *buf;
+
+      buf = grub_malloc (IEEE1275_MAX_PATH_LEN);
+
+      if (!buf)
+        return;
+
+      grub_snprintf (buf, IEEE1275_MAX_PATH_LEN, "%s/disk at 1", alias->path);
+      dev_iterate_real (buf, buf);
+      grub_free (buf);
+      return;
+    }
+  else if (grub_strcmp (alias->type, "scsi-usb") == 0)
+    {
+      grub_ieee1275_ihandle_t ihandle;
+      grub_ssize_t result;
+
+      ihandle = ofdisk_hba_open (alias->path);
+
+      if (ihandle == 0)
+        return;
+
+      if (grub_ieee1275_set_address (ihandle, 0, 0) == 0)
+        if (grub_ieee1275_no_data_command (ihandle, &ofdisk_tur, &result) == 0)
+          if (result == 0)
+            {
+              char *buf, *bufptr;
+
+              buf = grub_malloc (grub_strlen (alias->path) +
+                                 sizeof ("/disk at 0"));
+
+              if (!buf)
+                return;
+
+              bufptr = grub_stpcpy (buf, alias->path);
+              grub_snprintf (bufptr, sizeof ("/disk at 0"), "/disk at 0");
+              dev_iterate_real (buf, buf);
+              grub_free (buf);
+            }
+      return;
+    }
+#endif
 
   if (!grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_NO_TREE_SCANNING_FOR_DISKS)
       && grub_strcmp (alias->type, "block") == 0)
     {
+      if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_IGNORE_REBOOT_DEV)
+          && grub_strstr (alias->path, "reboot-memory"))
+        return;
       dev_iterate_real (alias->path, alias->path);
       return;
     }
@@ -363,6 +551,11 @@ scan (void)
     {
       if (grub_strcmp (alias.type, "block") != 0)
 	continue;
+#ifdef __sparc__
+      if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_VALIDATE_DEV_ALIASES) &&
+          sparc_disk_present (alias.path) == 0)
+        continue;
+#endif
       dev_iterate_real (alias.name, alias.path);
     }
 
@@ -451,6 +644,48 @@ compute_dev_path (const char *name)
   return devpath;
 }
 
+#ifdef __sparc__
+static char *
+get_hbaname_from_path (const char *path)
+{
+  char *sptr, *hba_name;
+
+  hba_name = grub_strdup (path);
+
+  if (!hba_name)
+    return NULL;
+
+  sptr = grub_strstr (hba_name, "/disk@");
+
+  if (!sptr)
+    return NULL;
+
+  *sptr = '\0';
+
+  return hba_name;
+}
+
+static char *
+get_diskname_from_path (const char *path)
+{
+  const char *disk_dev = "/disk@";
+  char *sptr, *disk_name;
+
+  sptr = grub_strstr (path, disk_dev);
+
+  if (!sptr)
+    return NULL;
+
+  disk_name = grub_strdup (sptr + grub_strlen (disk_dev));
+  sptr = grub_strstr (disk_name, ":");
+
+  if (sptr)
+    *sptr = '\0';
+
+  return disk_name;
+}
+#endif
+
 static grub_err_t
 grub_ofdisk_open (const char *name, grub_disk_t disk)
 {
@@ -508,8 +743,14 @@ grub_ofdisk_open (const char *name, grub
       }
     disk->id = (unsigned long) op;
     disk->data = op->open_path;
+    err = grub_ofdisk_open_real (disk);
+    if (err)
+      {
+        grub_free (devpath);
+        return err;
+      }
 
-    err = grub_ofdisk_get_block_size (devpath, &block_size, op);
+    err = grub_ofdisk_get_block_size (&block_size, op);
     if (err)
       {
         grub_free (devpath);
@@ -534,7 +775,7 @@ grub_ofdisk_close (grub_disk_t disk)
 {
   if (disk->data == last_devpath)
     {
-      if (last_ihandle)
+      if (! (grub_ieee1275_test_flag(GRUB_IEEE1275_FLAG_CACHE_OPEN)) && last_ihandle)
 	grub_ieee1275_close (last_ihandle);
       last_ihandle = 0;
       last_devpath = NULL;
@@ -547,17 +788,13 @@ grub_ofdisk_prepare (grub_disk_t disk, g
 {
   grub_ssize_t status;
   unsigned long long pos;
+  grub_err_t err;
 
   if (disk->data != last_devpath)
     {
-      if (last_ihandle)
-	grub_ieee1275_close (last_ihandle);
-      last_ihandle = 0;
-      last_devpath = NULL;
-
-      grub_ieee1275_open (disk->data, &last_ihandle);
-      if (! last_ihandle)
-	return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device");
+      err = grub_ofdisk_open_real (disk);
+      if (err)
+        return err;
       last_devpath = disk->data;      
     }
 
@@ -658,6 +895,7 @@ insert_bootpath (void)
       char *device = grub_ieee1275_get_devname (bootpath);
       op = ofdisk_hash_add (device, NULL);
       op->is_boot = 1;
+      grub_free (device);
     }
   grub_free (type);
   grub_free (bootpath);
@@ -685,8 +923,7 @@ grub_ofdisk_init (void)
 }
 
 static grub_err_t
-grub_ofdisk_get_block_size (const char *device, grub_uint32_t *block_size,
-			    struct ofdisk_hash_ent *op)
+grub_ofdisk_get_block_size (grub_uint32_t *block_size, struct ofdisk_hash_ent *op)
 {
   struct size_args_ieee1275
     {
@@ -698,20 +935,15 @@ grub_ofdisk_get_block_size (const char *
       grub_ieee1275_cell_t size2;
     } args_ieee1275;
 
-  if (last_ihandle)
-    grub_ieee1275_close (last_ihandle);
-
-  last_ihandle = 0;
-  last_devpath = NULL;
-
-  grub_ieee1275_open (device, &last_ihandle);
-  if (! last_ihandle)
-    return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device");
+  if ((op->block_size_retries >= 2) || (op->block_size > 0))
+    {
+      *block_size = op->block_size;
+      return GRUB_ERR_NONE;
+    }
 
   *block_size = 0;
 
-  if (op->block_size_fails >= 2)
-    return GRUB_ERR_NONE;
+  op->block_size_retries++;
 
   INIT_IEEE1275_COMMON (&args_ieee1275.common, "call-method", 2, 2);
   args_ieee1275.method = (grub_ieee1275_cell_t) "block-size";
@@ -719,23 +951,194 @@ grub_ofdisk_get_block_size (const char *
   args_ieee1275.result = 1;
 
   if (IEEE1275_CALL_ENTRY_FN (&args_ieee1275) == -1)
-    {
-      grub_dprintf ("disk", "can't get block size: failed call-method\n");
-      op->block_size_fails++;
-    }
+    grub_dprintf ("disk", "can't get block size: failed call-method\n");
   else if (args_ieee1275.result)
-    {
-      grub_dprintf ("disk", "can't get block size: %lld\n",
-		    (long long) args_ieee1275.result);
-      op->block_size_fails++;
-    }
+    grub_dprintf ("disk", "can't get block size: %lld\n",
+		 (long long) args_ieee1275.result);
   else if (args_ieee1275.size1
 	   && !(args_ieee1275.size1 & (args_ieee1275.size1 - 1))
 	   && args_ieee1275.size1 >= 512 && args_ieee1275.size1 <= 16384)
     {
-      op->block_size_fails = 0;
+      op->block_size = args_ieee1275.size1;
       *block_size = args_ieee1275.size1;
     }
 
   return 0;
 }
+
+static grub_err_t
+grub_ofdisk_open_real (grub_disk_t disk)
+{
+  struct ofdisk_hash_ent *op = (struct ofdisk_hash_ent *)disk->id;
+
+  if (!op)
+    return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "BUG: can't open device ");
+
+  if (grub_ieee1275_test_flag(GRUB_IEEE1275_FLAG_CACHE_OPEN) && op->ihandle)
+    {
+      last_ihandle = op->ihandle;
+      last_devpath = disk->data;
+      return 0;
+    }
+
+  if (last_ihandle)
+    grub_ieee1275_close (last_ihandle);
+
+  last_ihandle = 0;
+  last_devpath = NULL;
+
+  grub_ieee1275_open (disk->data, &last_ihandle);
+  if (! last_ihandle)
+    return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device");
+
+  op->ihandle = last_ihandle;
+  last_devpath = disk->data;
+  return 0;
+}
+
+#ifdef __sparc__
+static struct ofdisk_hba_ent *
+ofdisk_hba_find (const char *devpath)
+{
+  struct ofdisk_hba_ent *dev = NULL;
+
+  FOR_LIST_ELEMENTS (dev, ofdisk_hba_ents)
+    if (grub_strcmp (dev->path, devpath) == 0)
+      break;
+
+  return dev;
+}
+
+static struct ofdisk_hba_ent *
+ofdisk_hba_add (const char *devpath, grub_ieee1275_ihandle_t ihandle)
+{
+  struct ofdisk_hba_ent *dev;
+
+  dev = grub_zalloc (sizeof (struct ofdisk_hba_ent));
+
+  if (!dev)
+    return NULL;
+
+  dev->path = grub_strdup (devpath);
+
+  if (!dev->path)
+    {
+      grub_free (dev);
+      return NULL;
+    }
+
+  dev->ihandle = ihandle;
+  grub_list_push (GRUB_AS_LIST_P (&ofdisk_hba_ents), GRUB_AS_LIST (dev));
+
+  return dev;
+}
+
+static grub_ieee1275_ihandle_t
+ofdisk_hba_open (const char *hba_name)
+{
+  grub_ieee1275_ihandle_t ihandle;
+  struct ofdisk_hba_ent *dev;
+
+  dev = ofdisk_hba_find (hba_name);
+
+  if (dev)
+    ihandle = dev->ihandle;
+  else if (grub_ieee1275_open (hba_name, &ihandle))
+    ihandle = 0;
+  else
+    {
+      dev = ofdisk_hba_add (hba_name, ihandle);
+
+      if (!dev)
+        ihandle = 0;
+    }
+
+  return ihandle;
+}
+
+static grub_err_t
+sparc_disk_present (const char *full_path)
+{
+  char *disk_name = get_diskname_from_path (full_path);
+  char *hba_name = get_hbaname_from_path (full_path);
+  char *lun_name = NULL, *sptr = NULL, *device_type = 0;
+  grub_ieee1275_ihandle_t ihandle;
+  /* Per SPARC SCSI binding spec, default to 2 for legacy devices that may
+     not have this property */
+  grub_uint32_t address_cells = 2;
+  grub_ieee1275_phandle_t root;
+  grub_uint64_t lun = 0;
+  grub_ssize_t result;
+  grub_err_t rval = GRUB_ERR_NONE;
+
+  if ((!hba_name) || (!disk_name))
+    {
+      grub_free (hba_name);
+      grub_free (disk_name);
+      return GRUB_ERR_NONE;
+    }
+
+  ihandle = ofdisk_hba_open (hba_name);
+
+  if (ihandle == 0)
+    {
+      grub_free (hba_name);
+      grub_free (disk_name);
+      return GRUB_ERR_NONE;
+    }
+
+  sptr = grub_strstr (disk_name, ",");
+
+  if (sptr)
+    {
+      lun_name = grub_strdup (sptr + 1);
+      *sptr = '\0';
+      lun = grub_strtoull (lun_name, 0, 16);
+    }
+
+  grub_ieee1275_finddevice (hba_name, &root);
+  grub_ieee1275_get_integer_property (root, "#address-cells", &address_cells,
+                                      sizeof address_cells, 0);
+  device_type = grub_ieee1275_get_device_type (hba_name);
+
+  if ((grub_strcmp (device_type, "scsi-2") == 0) ||
+      (grub_strcmp (device_type, "scsi-sas") == 0))
+    {
+      if (address_cells == 4)
+        {
+          if (grub_ieee1275_set_sas_address (ihandle, disk_name, lun) == 0)
+            if (grub_ieee1275_no_data_command (ihandle, &ofdisk_tur,
+                                               &result) == 0)
+              if (result == 0)
+                rval = GRUB_ERR_BAD_DEVICE;
+        }
+      else if ((address_cells == 2) && (grub_isxdigit (*disk_name)))
+        {
+          grub_uint32_t tgt;
+          tgt = grub_strtol (disk_name, 0, 16);
+          if (tgt <= 0xff)
+            if (grub_ieee1275_set_address (ihandle, tgt, lun) == 0)
+              if (grub_ieee1275_no_data_command (ihandle, &ofdisk_tur,
+                                                 &result) == 0)
+                if (result == 0)
+                  rval = GRUB_ERR_BAD_DEVICE;
+        }
+    }
+  else if (grub_strcmp (device_type, "scsi-usb") == 0)
+    {
+      if (grub_ieee1275_set_address (ihandle, 0, 0) == 0)
+        if (grub_ieee1275_no_data_command (ihandle, &ofdisk_tur, &result) == 0)
+          if (result == 0)
+            rval = GRUB_ERR_BAD_DEVICE;
+    }
+  else
+    {
+      /* ieee1275_finddevice would validate these already */
+      rval = GRUB_ERR_BAD_DEVICE;
+    }
+
+  grub_free (hba_name);
+  grub_free (disk_name);
+  return rval;
+}
+#endif
Index: grub2-2.02~beta3/grub-core/kern/ieee1275/cmain.c
===================================================================
--- grub2-2.02~beta3.orig/grub-core/kern/ieee1275/cmain.c
+++ grub2-2.02~beta3/grub-core/kern/ieee1275/cmain.c
@@ -108,6 +108,14 @@ grub_ieee1275_find_options (void)
   if (rc >= 0)
     {
       char *ptr;
+
+      if (grub_strncmp (tmp, "sun4v", 5) == 0)
+	{
+	  grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_CACHE_OPEN);
+	  grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_VALIDATE_DEV_ALIASES);
+	  grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_IGNORE_REBOOT_DEV);
+	}
+
       for (ptr = tmp; ptr - tmp < actual; ptr += grub_strlen (ptr) + 1)
 	{
 	  if (grub_memcmp (ptr, "MacRISC", sizeof ("MacRISC") - 1) == 0
Index: grub2-2.02~beta3/grub-core/kern/ieee1275/ieee1275.c
===================================================================
--- grub2-2.02~beta3.orig/grub-core/kern/ieee1275/ieee1275.c
+++ grub2-2.02~beta3/grub-core/kern/ieee1275/ieee1275.c
@@ -607,3 +607,91 @@ grub_ieee1275_milliseconds (grub_uint32_
   *msecs = args.msecs;
   return 0;
 }
+
+int
+grub_ieee1275_set_address (grub_ieee1275_ihandle_t ihandle,
+                           grub_uint32_t target, grub_uint32_t lun)
+{
+  struct set_address
+  {
+    struct grub_ieee1275_common_hdr common;
+    grub_ieee1275_cell_t method;
+    grub_ieee1275_cell_t ihandle;
+    grub_ieee1275_cell_t tgt;
+    grub_ieee1275_cell_t lun;
+    grub_ieee1275_cell_t catch_result;
+  }
+  args;
+
+  INIT_IEEE1275_COMMON (&args.common, "call-method", 4, 2);
+
+  /* IEEE Standard for Boot (Initialization Configuration)
+     Firmware: Core Requirements and Practices
+     E.3.2.2 Bus-specific methods for bus nodes
+
+     A package implementing the scsi-2 device type shall implement the
+     following bus-specific method:
+
+     set-address ( unit# target# -- )
+     Sets the SCSI target number (0x0..0xf) and unit number (0..7) to which
+     subsequent commands apply.
+  */
+  args.method = (grub_ieee1275_cell_t) "set-address";
+  args.ihandle = ihandle;
+  args.tgt = target;
+  args.lun = lun;
+
+  if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
+    return -1;
+
+  return args.catch_result;
+}
+
+int
+grub_ieee1275_no_data_command (grub_ieee1275_ihandle_t ihandle,
+                               const void *cmd_addr, grub_ssize_t *result)
+{
+  struct set_address
+  {
+    struct grub_ieee1275_common_hdr common;
+    grub_ieee1275_cell_t method;
+    grub_ieee1275_cell_t ihandle;
+    grub_ieee1275_cell_t cmd_addr;
+    grub_ieee1275_cell_t error;
+    grub_ieee1275_cell_t catch_result;
+  }
+  args;
+
+  INIT_IEEE1275_COMMON (&args.common, "call-method", 3, 2);
+  /* IEEE 1275-1994 Standard for Boot (Initialization Configuration)
+     Firmware: Core Requirements and Practices
+
+     E.3.2.2 Bus-specific methods for bus nodes
+
+     A package implementing the scsi-2 device type shall implement the
+     following bus-specific method:
+
+     no-data-command ( cmd-addr -- error? )
+     Executes a simple SCSI command, automatically retrying under
+     certain conditions.  cmd-addr is the address of a 6-byte command buffer
+     containing an SCSI command that does not have a data transfer phase.
+     Executes the command, retrying indefinitely with the same retry criteria
+     as retry-command.
+
+     error? is nonzero if an error occurred, zero otherwise.
+     NOTE no-data-command is a convenience function. It provides
+     no capabilities that are not present in retry-command, but for
+     those commands that meet its restrictions, it is easier to use.
+   */
+  args.method = (grub_ieee1275_cell_t) "no-data-command";
+  args.ihandle = ihandle;
+  args.cmd_addr = (grub_ieee1275_cell_t) cmd_addr;
+
+  if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
+    return -1;
+
+  if (result)
+    *result = args.error;
+
+  return args.catch_result;
+}
Index: grub2-2.02~beta3/grub-core/kern/ieee1275/openfw.c
===================================================================
--- grub2-2.02~beta3.orig/grub-core/kern/ieee1275/openfw.c
+++ grub2-2.02~beta3/grub-core/kern/ieee1275/openfw.c
@@ -561,3 +561,71 @@ grub_ieee1275_canonicalise_devname (cons
   return NULL;
 }
 
+/* Allocate memory with alloc-mem */
+void *
+grub_ieee1275_alloc_mem (grub_size_t len)
+{
+  struct alloc_args
+  {
+    struct grub_ieee1275_common_hdr common;
+    grub_ieee1275_cell_t method;
+    grub_ieee1275_cell_t len;
+    grub_ieee1275_cell_t catch;
+    grub_ieee1275_cell_t result;
+  }
+  args;
+
+  if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_CANNOT_INTERPRET))
+    {
+      grub_error (GRUB_ERR_UNKNOWN_COMMAND, N_("interpret is not supported"));
+      return NULL;
+    }
+
+  INIT_IEEE1275_COMMON (&args.common, "interpret", 2, 2);
+  args.len = len;
+  args.method = (grub_ieee1275_cell_t) "alloc-mem";
+
+  if (IEEE1275_CALL_ENTRY_FN (&args) == -1
+      || args.catch)
+    {
+      grub_error (GRUB_ERR_INVALID_COMMAND, N_("alloc-mem failed"));
+      return NULL;
+    }
+  else
+    return (void *)args.result;
+}
+
+/* Free memory allocated by alloc-mem */
+grub_err_t
+grub_ieee1275_free_mem (void *addr, grub_size_t len)
+{
+  struct free_args
+  {
+    struct grub_ieee1275_common_hdr common;
+    grub_ieee1275_cell_t method;
+    grub_ieee1275_cell_t len;
+    grub_ieee1275_cell_t addr;
+    grub_ieee1275_cell_t catch;
+  }
+  args;
+
+  if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_CANNOT_INTERPRET))
+    {
+      grub_error (GRUB_ERR_UNKNOWN_COMMAND, N_("interpret is not supported"));
+      return grub_errno;
+    }
+
+  INIT_IEEE1275_COMMON (&args.common, "interpret", 3, 1);
+  args.addr = (grub_ieee1275_cell_t)addr;
+  args.len = len;
+  args.method = (grub_ieee1275_cell_t) "free-mem";
+
+  if (IEEE1275_CALL_ENTRY_FN(&args) == -1
+      || args.catch)
+    {
+      grub_error (GRUB_ERR_INVALID_COMMAND, N_("free-mem failed"));
+      return grub_errno;
+    }
+
+  return GRUB_ERR_NONE;
+}
Index: grub2-2.02~beta3/grub-core/kern/parser.c
===================================================================
--- grub2-2.02~beta3.orig/grub-core/kern/parser.c
+++ grub2-2.02~beta3/grub-core/kern/parser.c
@@ -30,7 +30,6 @@ static struct grub_parser_state_transiti
   {GRUB_PARSER_STATE_TEXT, GRUB_PARSER_STATE_QUOTE, '\'', 0},
   {GRUB_PARSER_STATE_TEXT, GRUB_PARSER_STATE_DQUOTE, '\"', 0},
   {GRUB_PARSER_STATE_TEXT, GRUB_PARSER_STATE_VAR, '$', 0},
-  {GRUB_PARSER_STATE_TEXT, GRUB_PARSER_STATE_ESC, '\\', 0},
 
   {GRUB_PARSER_STATE_ESC, GRUB_PARSER_STATE_TEXT, 0, 1},
 
Index: grub2-2.02~beta3/grub-core/kern/sparc64/ieee1275/ieee1275.c
===================================================================
--- grub2-2.02~beta3.orig/grub-core/kern/sparc64/ieee1275/ieee1275.c
+++ grub2-2.02~beta3/grub-core/kern/sparc64/ieee1275/ieee1275.c
@@ -18,6 +18,7 @@
 
 #include <grub/ieee1275/ieee1275.h>
 #include <grub/types.h>
+#include <grub/misc.h>
 
 /* Sun specific ieee1275 interfaces used by GRUB.  */
 
@@ -89,3 +90,113 @@ grub_ieee1275_alloc_physmem (grub_addr_t
 
   return args.catch_result;
 }
+
+int
+grub_ieee1275_set_sas_address (grub_ieee1275_ihandle_t ihandle,
+                               const char *disk_name,
+                               grub_uint64_t lun)
+{
+  struct dev_set_address
+  {
+    struct grub_ieee1275_common_hdr common;
+    grub_ieee1275_cell_t method;
+    grub_ieee1275_cell_t ihandle;
+    grub_ieee1275_cell_t tgt_h;
+    grub_ieee1275_cell_t tgt_l;
+    grub_ieee1275_cell_t lun_h;
+    grub_ieee1275_cell_t lun_l;
+    grub_ieee1275_cell_t catch_result;
+  }
+  args;
+
+  grub_uint32_t sas_phy = 0, tgt = 0;
+  grub_uint64_t wwn = 0;
+
+  if (disk_name == 0)
+    return -1;
+
+  INIT_IEEE1275_COMMON (&args.common, "call-method", 6, 1);
+  args.method = (grub_ieee1275_cell_t) "set-address";
+  args.ihandle = ihandle;
+  args.lun_l = lun & 0xffffffff;
+  args.lun_h = lun >> 32;
+
+  /* PHY addressing */
+  if (*disk_name == 'p')
+    {
+      /*         Bit #   33222222 22221111 11111100 00000000
+                         10987654 32109876 54321098 76543210
+
+         sas.hi cell:    00000000 00000000 00000000 00000000
+         sas.lo cell:    00000000 00000001 jjjjjjjj iiiiiiii
+         lun.hi cell:    uuuuuuuu uuuuuuuu uuuuuuuu uuuuuuuu
+         lun.lo cell:    uuuuuuuu uuuuuuuu uuuuuuuu uuuuuuuu
+
+         00..00          Bits with the value zero
+         ii..ii          8-bit unsigned number phy identifier in the range
+                         of 0..FE .
+         jj..jj          Expander identifier. Either zero (indicating the PHY number
+                         iiiiiiii is on the SAS adapter itself) or identifies the PHY
+                         connecting to the expander, in which case iiiiiiii identifies
+                         a PHY on a SAS expander. In the non-zero case, jjjjjjjj is an
+                         8-bit unsigned number of the PHY plus one, in the range 1..FF
+         uu..uu          64-bit unsigned number logical unit number
+      */
+      sas_phy = grub_strtoul (disk_name + 1, 0, 16);
+      args.tgt_l = 0x10000 | sas_phy;
+      args.tgt_h = 0;
+    }
+  /* WWN addressing */
+  else if ((*disk_name =='w') && (*(disk_name + 1) == '5'))
+    {
+      /*          Bit #   33222222 22221111 11111100 00000000
+                          10987654 32109876 54321098 76543210
+
+          sas.hi cell:    0101vvvv vvvvvvvv vvvvvvvv vvvvssss
+          sas.lo cell:    ssssssss ssssssss ssssssss ssssssss
+          lun.hi cell:    uuuuuuuu uuuuuuuu uuuuuuuu uuuuuuuu
+          lun.lo cell:    uuuuuuuu uuuuuuuu uuuuuuuu uuuuuuuu
+
+          0101            The value "5" in the high-order NAA nibble
+          vv..vv          24-bit IEEE Organization ID
+          ss..ss          36-bit unsigned device serial number
+          uu..uu          64-bit unsigned number logical unit number
+      */
+      wwn = grub_strtoull (disk_name + 1, 0, 16);
+      args.tgt_l = wwn & 0xffffffff;
+      args.tgt_h = wwn >> 32;
+    }
+   /* Target LUN addressing */
+   else if (grub_isxdigit (*disk_name))
+    {
+      /* Deprecated
+                  Bit #   33222222 22221111 11111100 00000000
+                          10987654 32109876 54321098 76543210
+
+          sas.hi cell:    00000000 00000000 00000000 00000000
+          sas.lo cell:    00000000 00000000 00000000 tttttttt
+          lun.hi cell:    uuuuuuuu uuuuuuuu uuuuuuuu uuuuuuuu
+          lun.lo cell:    uuuuuuuu uuuuuuuu uuuuuuuu uuuuuuuu
+
+          00..00          Bits with the value zero
+          tt..tt          8-bit unsigned number target identifier in the range
+                          of 0..FF
+          uu..uu          64-bit unsigned number logical unit number
+      */
+      tgt = grub_strtol (disk_name, 0, 16);
+      if (tgt <= 0xff)
+        {
+          args.tgt_l = tgt;
+          args.tgt_h = 0;
+        }
+      else
+        return -1;
+    }
+  else
+    return -1;
+
+  if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
+    return -1;
+
+  return args.catch_result;
+}
Index: grub2-2.02~beta3/grub-core/net/drivers/ieee1275/ofnet.c
===================================================================
--- grub2-2.02~beta3.orig/grub-core/net/drivers/ieee1275/ofnet.c
+++ grub2-2.02~beta3/grub-core/net/drivers/ieee1275/ofnet.c
@@ -85,24 +85,35 @@ get_card_packet (struct grub_net_card *d
   grub_uint64_t start_time;
   struct grub_net_buff *nb;
 
-  nb = grub_netbuff_alloc (dev->mtu + 64 + 2);
+  start_time = grub_get_time_ms ();
+  do
+    rc = grub_ieee1275_read (data->handle, dev->rcvbuf, dev->rcvbufsize, &actual);
+  while ((actual <= 0 || rc < 0) && (grub_get_time_ms () - start_time < 200));
+
+  if (actual <= 0)
+    return NULL;
+
+  nb = grub_netbuff_alloc (actual + 2);
   if (!nb)
     return NULL;
+
   /* Reserve 2 bytes so that 2 + 14/18 bytes of ethernet header is divisible
      by 4. So that IP header is aligned on 4 bytes. */
-  grub_netbuff_reserve (nb, 2);
+  if (grub_netbuff_reserve (nb, 2))
+    {
+      grub_netbuff_free (nb);
+      return NULL;
+    }
 
-  start_time = grub_get_time_ms ();
-  do
-    rc = grub_ieee1275_read (data->handle, nb->data, dev->mtu + 64, &actual);
-  while ((actual <= 0 || rc < 0) && (grub_get_time_ms () - start_time < 200));
-  if (actual > 0)
+  grub_memcpy (nb->data, dev->rcvbuf, actual);
+
+  if (grub_netbuff_put (nb, actual))
     {
-      grub_netbuff_put (nb, actual);
-      return nb;
+      grub_netbuff_free (nb);
+      return NULL;
     }
-  grub_netbuff_free (nb);
-  return NULL;
+
+  return nb;
 }
 
 static struct grub_net_card_driver ofdriver =
@@ -294,6 +305,24 @@ grub_ieee1275_net_config_real (const cha
   }
 }
 
+static void *
+ofnet_alloc_netbuf (grub_size_t len)
+{
+  if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_VIRT_TO_REAL_BROKEN))
+    return grub_ieee1275_alloc_mem (len);
+  else
+    return grub_malloc (len);
+}
+
+static void
+ofnet_free_netbuf (void *addr, grub_size_t len)
+{
+  if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_VIRT_TO_REAL_BROKEN))
+    grub_ieee1275_free_mem (addr, len);
+  else
+    grub_free (addr);
+}
+
 static int
 search_net_devices (struct grub_ieee1275_devalias *alias)
 {
@@ -409,41 +438,21 @@ search_net_devices (struct grub_ieee1275
   card->default_address = lla;
 
   card->txbufsize = ALIGN_UP (card->mtu, 64) + 256;
+  card->rcvbufsize = ALIGN_UP (card->mtu, 64) + 256;
 
-  if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_VIRT_TO_REAL_BROKEN))
-    {
-      struct alloc_args
-      {
-	struct grub_ieee1275_common_hdr common;
-	grub_ieee1275_cell_t method;
-	grub_ieee1275_cell_t len;
-	grub_ieee1275_cell_t catch;
-	grub_ieee1275_cell_t result;
-      }
-      args;
-      INIT_IEEE1275_COMMON (&args.common, "interpret", 2, 2);
-      args.len = card->txbufsize;
-      args.method = (grub_ieee1275_cell_t) "alloc-mem";
-
-      if (IEEE1275_CALL_ENTRY_FN (&args) == -1
-	  || args.catch)
-	{
-	  card->txbuf = 0;
-	  grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
-	}
-      else
-	card->txbuf = (void *) args.result;
-    }
-  else
-    card->txbuf = grub_zalloc (card->txbufsize);
+  card->txbuf = ofnet_alloc_netbuf (card->txbufsize);
   if (!card->txbuf)
+    goto fail;
+
+  card->rcvbuf = ofnet_alloc_netbuf (card->rcvbufsize);
+  if (!card->rcvbuf)
     {
-      grub_free (ofdata->path);
-      grub_free (ofdata);
-      grub_free (card);
-      grub_print_error ();
-      return 0;
+      grub_error_push ();
+      ofnet_free_netbuf(card->txbuf, card->txbufsize);
+      grub_error_pop ();
+      goto fail;
     }
+
   card->driver = NULL;
   card->data = ofdata;
   card->flags = 0;
@@ -455,6 +464,13 @@ search_net_devices (struct grub_ieee1275
   card->driver = &ofdriver;
   grub_net_card_register (card);
   return 0;
+
+ fail:
+  grub_free (ofdata->path);
+  grub_free (ofdata);
+  grub_free (card);
+  grub_print_error ();
+  return 1;
 }
 
 static void
Index: grub2-2.02~beta3/grub-core/osdep/linux/blocklist.c
===================================================================
--- grub2-2.02~beta3.orig/grub-core/osdep/linux/blocklist.c
+++ grub2-2.02~beta3/grub-core/osdep/linux/blocklist.c
@@ -58,6 +58,11 @@ grub_install_get_blocklist (grub_device_
   struct fiemap fie1;
   int fd;
 
+#ifdef __sparc__
+  if (grub_strstr (container->partmap->name, "gpt"))
+    container_start = 0;
+#endif
+
   /* Write the first two sectors of the core image onto the disk.  */
   grub_util_info ("opening the core image `%s'", core_path);
   fd = open (core_path, O_RDONLY);
Index: grub2-2.02~beta3/grub-core/osdep/linux/ofpath.c
===================================================================
--- grub2-2.02~beta3.orig/grub-core/osdep/linux/ofpath.c
+++ grub2-2.02~beta3/grub-core/osdep/linux/ofpath.c
@@ -38,6 +38,44 @@
 #include <errno.h>
 #include <ctype.h>
 
+#ifdef __sparc__
+typedef enum
+  {
+    GRUB_OFPATH_SPARC_PHY_ADDR = 1,
+    GRUB_OFPATH_SPARC_TGT_LUN,
+  } ofpath_sparc_addressing;
+
+struct ofpath_sparc_hba
+{
+  grub_uint32_t device_id;
+  ofpath_sparc_addressing addressing;
+};
+
+static struct ofpath_sparc_hba sparc_lsi_hba[] = {
+  /* Rhea, Jasper 320, LSI53C1020/1030 */
+  {0x30, GRUB_OFPATH_SPARC_TGT_LUN},
+  /* SAS-1068E */
+  {0x50, GRUB_OFPATH_SPARC_TGT_LUN},
+  /* SAS-1064E */
+  {0x56, GRUB_OFPATH_SPARC_TGT_LUN},
+  /* Pandora SAS-1068E */
+  {0x58, GRUB_OFPATH_SPARC_TGT_LUN},
+  /* Aspen, Invader, LSI SAS-3108 */
+  {0x5d, GRUB_OFPATH_SPARC_TGT_LUN},
+  /* Niwot, SAS 2108 */
+  {0x79, GRUB_OFPATH_SPARC_TGT_LUN},
+  /* Erie, Falcon, LSI SAS 2008 */
+  {0x72, GRUB_OFPATH_SPARC_PHY_ADDR},
+  /* LSI WarpDrive 6203 */
+  {0x7e, GRUB_OFPATH_SPARC_PHY_ADDR},
+  /* LSI SAS 2308 */
+  {0x87, GRUB_OFPATH_SPARC_PHY_ADDR},
+  /* LSI SAS 3008 */
+  {0x97, GRUB_OFPATH_SPARC_PHY_ADDR},
+  {0, 0}
+};
+#endif
+
 #ifdef OFPATH_STANDALONE
 #define xmalloc malloc
 void
@@ -120,6 +158,7 @@ find_obppath (const char *sysfs_path_ori
 #endif
 
       fd = open(path, O_RDONLY);
+#ifndef __sparc__
       if (fd < 0 || fstat (fd, &st) < 0)
 	{
 	  if (fd >= 0)
@@ -128,6 +167,7 @@ find_obppath (const char *sysfs_path_ori
 	  fd = open(path, O_RDONLY);
 	}
 
+#endif
       if (fd < 0 || fstat (fd, &st) < 0)
 	{
 	  if (fd >= 0)
@@ -307,6 +347,49 @@ of_path_of_ide(const char *sys_devname _
   return ret;
 }
 
+static char *
+of_path_of_nvme(const char *sys_devname __attribute__((unused)),
+	        const char *device,
+	        const char *devnode __attribute__((unused)),
+	        const char *devicenode)
+{
+  char *sysfs_path, *of_path, disk[MAX_DISK_CAT];
+  const char *digit_string, *part_end;
+
+  digit_string = trailing_digits (device);
+  part_end = devicenode + strlen (devicenode) - 1;
+
+  if ((digit_string != '\0') && (*part_end == 'p'))
+    {
+      /* We have a partition number, strip it off */
+      int part;
+      char *nvmedev, *end;
+
+      nvmedev = strdup (devicenode);
+
+      if (nvmedev == NULL)
+        return NULL;
+
+      end = nvmedev + strlen (nvmedev) - 1;
+      *end = '\0'; /* remove the p */
+      sscanf (digit_string, "%d", &part);
+      snprintf (disk, sizeof (disk), "/disk at 1:%c", 'a' + (part - 1));
+      sysfs_path = block_device_get_sysfs_path_and_link (nvmedev);
+      free (nvmedev);
+    }
+  else
+    {
+      /* We do not have the parition */
+      snprintf (disk, sizeof (disk), "/disk at 1");
+      sysfs_path = block_device_get_sysfs_path_and_link (device);
+    }
+
+  of_path = find_obppath (sysfs_path);
+  free (sysfs_path);
+  strcat (of_path, disk);
+  return of_path;
+}
+
 static int
 vendor_is_ATA(const char *path)
 {
@@ -335,6 +418,87 @@ vendor_is_ATA(const char *path)
   return (memcmp(bufcont, "ATA", 3) == 0);
 }
 
+#ifdef __sparc__
+static void
+check_hba_identifiers(const char *sysfs_path, int *vendor, int *device_id)
+{
+  char *ed = strstr (sysfs_path, "host");
+  size_t path_size;
+  char *p = NULL, *path = NULL;
+  char buf[8];
+  int fd;
+
+  if (!ed)
+    return;
+
+  p = xstrdup (sysfs_path);
+  ed = strstr (p, "host");
+
+  if (!ed)
+    {
+      free (p);
+      return;
+    }
+  *ed = '\0';
+
+  path_size = (strlen (p) + sizeof("vendor"));
+  path = xmalloc (path_size);
+
+  if (!path)
+    {
+      free (p);
+      return;
+    }
+
+  snprintf (path, path_size, "%svendor", p);
+  fd = open (path, O_RDONLY);
+
+  if (fd < 0)
+    {
+      free (p);
+      free (path);
+      return;
+    }
+
+  memset (buf, 0, sizeof (buf));
+
+  if (read (fd, buf, sizeof (buf) - 1) < 0)
+    {
+      close (fd);
+      free (p);
+      free (path);
+      return;
+    }
+
+  close (fd);
+  sscanf (buf, "%x", vendor);
+  snprintf (path, path_size, "%sdevice", p);
+  fd = open (path, O_RDONLY);
+
+  if (fd < 0)
+    {
+      free (p);
+      free (path);
+      return;
+    }
+
+  memset (buf, 0, sizeof (buf));
+
+  if (read (fd, buf, sizeof (buf) - 1) < 0)
+    {
+      close (fd);
+      free (p);
+      free (path);
+      return;
+    }
+
+  close (fd);
+  sscanf (buf, "%x", device_id);
+  free (path);
+  free (p);
+}
+#endif
+
 static void
 check_sas (const char *sysfs_path, int *tgt, unsigned long int *sas_address)
 {
@@ -413,9 +577,11 @@ of_path_of_scsi(const char *sys_devname
     }
 
   of_path = find_obppath(sysfs_path);
-  free (sysfs_path);
   if (!of_path)
-    return NULL;
+    {
+      free (sysfs_path);
+      return NULL;
+    }
 
   if (strstr (of_path, "qlc"))
     strcat (of_path, "/fp at 0,0");
@@ -444,6 +610,45 @@ of_path_of_scsi(const char *sys_devname
     }
   else
     {
+#ifdef __sparc__
+      ofpath_sparc_addressing addressing = GRUB_OFPATH_SPARC_TGT_LUN;
+      int vendor = 0, device_id = 0;
+      char *optr = disk;
+
+      check_hba_identifiers (sysfs_path, &vendor, &device_id);
+
+      /* Over time different OF addressing schemes have been supported */
+      /* There is no generic addressing scheme that works across */
+      /* every HBA */
+      if (vendor == 0x1000) /* LSI Logic Vendor ID */
+        {
+          struct ofpath_sparc_hba *lsi_hba;
+
+          for (lsi_hba = sparc_lsi_hba; lsi_hba->device_id; lsi_hba++)
+            if (lsi_hba->device_id == device_id)
+              {
+                addressing = lsi_hba->addressing;
+                break;
+              }
+        }
+
+      if (addressing == GRUB_OFPATH_SPARC_PHY_ADDR)
+        optr += snprintf (disk, sizeof (disk), "/%s at p%x", disk_name, tgt);
+      else
+        optr += snprintf (disk, sizeof (disk), "/%s@%x", disk_name, tgt);
+
+      if (lun)
+        optr += snprintf (optr, sizeof (disk) - (optr - disk - 1), ",%x", lun);
+
+      if (*digit_string != '\0')
+        {
+          int part;
+
+          sscanf (digit_string, "%d", &part);
+          snprintf (optr, sizeof (disk) - (optr - disk - 1), ":%c", 'a'
+                    + (part - 1));
+        }
+#else
       if (lun == 0)
         {
           int sas_id = 0;
@@ -491,7 +696,9 @@ of_path_of_scsi(const char *sys_devname
             }
 	  free (lunstr);
         }
+#endif
     }
+  free (sysfs_path);
   strcat(of_path, disk);
   return of_path;
 }
@@ -537,6 +744,9 @@ grub_util_devname_to_ofpath (const char
     /* All the models I've seen have a devalias "floppy".
        New models have no floppy at all. */
     ofpath = xstrdup ("floppy");
+  else if (device[0] == 'n' && device[1] == 'v' && device[2] == 'm'
+           && device[3] == 'e')
+    ofpath = of_path_of_nvme (name_buf, device, devnode, devicenode);
   else
     {
       grub_util_warn (_("unknown device type %s"), device);
Index: grub2-2.02~beta3/include/grub/emu/getroot.h
===================================================================
--- grub2-2.02~beta3.orig/include/grub/emu/getroot.h
+++ grub2-2.02~beta3/include/grub/emu/getroot.h
@@ -100,5 +100,7 @@ grub_util_guess_baremetal_drive (const c
 void
 grub_util_fprint_full_disk_name (FILE *f,
 				 const char *drive, grub_device_t dev);
+char *
+escape_of_path (const char *orig_path);
 
 #endif /* ! GRUB_UTIL_GETROOT_HEADER */
Index: grub2-2.02~beta3/include/grub/ieee1275/ieee1275.h
===================================================================
--- grub2-2.02~beta3.orig/include/grub/ieee1275/ieee1275.h
+++ grub2-2.02~beta3/include/grub/ieee1275/ieee1275.h
@@ -146,6 +146,12 @@ enum grub_ieee1275_flag
   GRUB_IEEE1275_FLAG_BROKEN_REPEAT,
 
   GRUB_IEEE1275_FLAG_CURSORONOFF_ANSI_BROKEN,
+
+  GRUB_IEEE1275_FLAG_CACHE_OPEN,
+
+  GRUB_IEEE1275_FLAG_VALIDATE_DEV_ALIASES,
+
+  GRUB_IEEE1275_FLAG_IGNORE_REBOOT_DEV,
 };
 
 extern int EXPORT_FUNC(grub_ieee1275_test_flag) (enum grub_ieee1275_flag flag);
@@ -211,6 +217,13 @@ int EXPORT_FUNC(grub_ieee1275_set_color)
 					  int index, int r, int g, int b);
 int EXPORT_FUNC(grub_ieee1275_milliseconds) (grub_uint32_t *msecs);
 
+int EXPORT_FUNC(grub_ieee1275_set_address) (grub_ieee1275_ihandle_t ihandle,
+                                            grub_uint32_t target,
+                                            grub_uint32_t lun);
+
+int EXPORT_FUNC(grub_ieee1275_no_data_command) (grub_ieee1275_ihandle_t ihandle,
+                                                const void *cmd_addr,
+                                                grub_ssize_t *result);
 
 grub_err_t EXPORT_FUNC(grub_claimmap) (grub_addr_t addr, grub_size_t size);
 
@@ -234,6 +247,8 @@ int EXPORT_FUNC(grub_ieee1275_devalias_n
 void EXPORT_FUNC(grub_ieee1275_children_peer) (struct grub_ieee1275_devalias *alias);
 void EXPORT_FUNC(grub_ieee1275_children_first) (const char *devpath,
 						struct grub_ieee1275_devalias *alias);
+void *EXPORT_FUNC(grub_ieee1275_alloc_mem) (grub_size_t len);
+grub_err_t EXPORT_FUNC(grub_ieee1275_free_mem) (void * addr, grub_size_t len);
 
 #define FOR_IEEE1275_DEVALIASES(alias) for (grub_ieee1275_devalias_init_iterator (&(alias)); grub_ieee1275_devalias_next (&(alias));)
 
Index: grub2-2.02~beta3/include/grub/sparc64/ieee1275/ieee1275.h
===================================================================
--- grub2-2.02~beta3.orig/include/grub/sparc64/ieee1275/ieee1275.h
+++ grub2-2.02~beta3/include/grub/sparc64/ieee1275/ieee1275.h
@@ -21,6 +21,7 @@
 #define GRUB_IEEE1275_MACHINE_HEADER	1
 
 #include <grub/types.h>
+#include <grub/ieee1275/ieee1275.h>
 
 #define GRUB_IEEE1275_CELL_SIZEOF 8
 typedef grub_uint64_t grub_ieee1275_cell_t;
@@ -42,6 +43,9 @@ extern int EXPORT_FUNC(grub_ieee1275_cla
 extern int EXPORT_FUNC(grub_ieee1275_alloc_physmem) (grub_addr_t *paddr,
 						     grub_size_t size,
 						     grub_uint32_t align);
+extern int EXPORT_FUNC(grub_ieee1275_set_sas_address) (grub_uint32_t ihandle,
+                                                       const char *disk_name,
+                                                       grub_uint64_t lun);
 
 extern grub_addr_t EXPORT_VAR (grub_ieee1275_original_stack);
 
Index: grub2-2.02~beta3/util/grub-install.c
===================================================================
--- grub2-2.02~beta3.orig/util/grub-install.c
+++ grub2-2.02~beta3/util/grub-install.c
@@ -1494,6 +1494,7 @@ main (int argc, char *argv[])
 	  || grub_drives[1]
 	  || (!install_drive
 	      && platform != GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275)
+	  || (platform == GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275)
 	  || (install_drive && !is_same_disk (grub_drives[0], install_drive))
 	  || !have_bootdev (platform)
 	  || uefi_secure_boot)
@@ -1586,6 +1587,18 @@ main (int argc, char *argv[])
 		    g = grub_util_guess_efi_drive (*curdev);
 		    break;
 		  case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275:
+		    {
+		      char *dname;
+		      const char *ofpath = grub_util_devname_to_ofpath (*curdev);
+		      g = xasprintf ("ieee1275/%s", ofpath);
+		      dname = escape_of_path (g);
+		      fprintf (load_cfg_f, "%s ", dname);
+		      free (dname);
+		      free (g);
+		      g = NULL;
+		      break;
+		    }
+
 		  case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275:
 		  case GRUB_INSTALL_PLATFORM_I386_IEEE1275:
 		    {
@@ -1616,6 +1629,7 @@ main (int argc, char *argv[])
 		{
 		  grub_util_fprint_full_disk_name (load_cfg_f, g, dev);
 		  fprintf (load_cfg_f, " ");
+		  free (g);
 		}
 	      if (dev != grub_dev)
 		grub_device_close (dev);
Index: grub2-2.02~beta3/util/ieee1275/grub-ofpathname.c
===================================================================
--- grub2-2.02~beta3.orig/util/ieee1275/grub-ofpathname.c
+++ grub2-2.02~beta3/util/ieee1275/grub-ofpathname.c
@@ -46,7 +46,9 @@ int main(int argc, char **argv)
     }
 
   of_path = grub_util_devname_to_ofpath (argv[1]);
-  printf("%s\n", of_path);
+
+  if (of_path)
+    printf ("%s\n", of_path);
 
   free (of_path);
 
Index: grub2-2.02~beta3/util/probe.c
===================================================================
--- grub2-2.02~beta3.orig/util/probe.c
+++ grub2-2.02~beta3/util/probe.c
@@ -44,7 +44,7 @@
 /* Since OF path names can have "," characters in them, and GRUB
    internally uses "," to indicate partitions (unlike OF which uses
    ":" for this purpose) we escape such commas.  */
-static char *
+char *
 escape_of_path (const char *orig_path)
 {
   char *new_path, *d, c;
Index: grub2-2.02~beta3/util/setup.c
===================================================================
--- grub2-2.02~beta3.orig/util/setup.c
+++ grub2-2.02~beta3/util/setup.c
@@ -200,7 +200,6 @@ save_blocklists (grub_disk_addr_t sector
 #endif
 }
 
-#ifdef GRUB_SETUP_BIOS
 /* Context for setup/identify_partmap.  */
 struct identify_partmap_ctx
 {
@@ -236,7 +235,6 @@ identify_partmap (grub_disk_t disk __att
   ctx->multiple_partmaps = 1;
   return 1;
 }
-#endif
 
 #ifdef GRUB_SETUP_BIOS
 #define SETUP grub_util_bios_setup
@@ -257,9 +255,7 @@ SETUP (const char *dir,
   char *boot_img, *core_img, *boot_path;
   char *root = 0;
   size_t boot_size, core_size;
-#ifdef GRUB_SETUP_BIOS
   grub_uint16_t core_sectors;
-#endif
   grub_device_t root_dev = 0, dest_dev, core_dev;
   grub_util_fd_t fp;
   struct blocklists bl;
@@ -283,10 +279,8 @@ SETUP (const char *dir,
 
   core_path = grub_util_get_path (dir, core_file);
   core_size = grub_util_get_image_size (core_path);
-#ifdef GRUB_SETUP_BIOS
   core_sectors = ((core_size + GRUB_DISK_SECTOR_SIZE - 1)
 		  >> GRUB_DISK_SECTOR_BITS);
-#endif
   if (core_size < GRUB_DISK_SECTOR_SIZE)
     grub_util_error (_("the size of `%s' is too small"), core_path);
 #ifdef GRUB_SETUP_BIOS
@@ -368,8 +362,8 @@ SETUP (const char *dir,
   if (grub_env_set ("root", root) != GRUB_ERR_NONE)
     grub_util_error ("%s", grub_errmsg);
 
-#ifdef GRUB_SETUP_BIOS
   {
+#ifdef GRUB_SETUP_BIOS
     char *tmp_img;
     grub_uint8_t *boot_drive_check;
 
@@ -394,6 +388,7 @@ SETUP (const char *dir,
 	boot_drive_check[0] = 0x90;
 	boot_drive_check[1] = 0x90;
       }
+#endif
 
     struct identify_partmap_ctx ctx = {
       .dest_partmap = NULL,
@@ -409,6 +404,7 @@ SETUP (const char *dir,
 
     grub_partition_iterate (dest_dev->disk, identify_partmap, &ctx);
 
+#ifdef GRUB_SETUP_BIOS
     /* Copy the partition table.  */
     if (ctx.dest_partmap ||
         (!allow_floppy && !grub_util_biosdisk_is_floppy (dest_dev->disk)))
@@ -417,6 +413,7 @@ SETUP (const char *dir,
 	      GRUB_BOOT_MACHINE_PART_END - GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC);
 
     free (tmp_img);
+#endif
 
     if (ctx.container
 	&& grub_strcmp (ctx.container->partmap->name, "msdos") == 0
@@ -504,10 +501,21 @@ SETUP (const char *dir,
     else
       maxsec = core_sectors;
 
+#ifdef GRUB_SETUP_BIOS
     if (maxsec > ((0x78000 - GRUB_KERNEL_I386_PC_LINK_ADDR)
 		>> GRUB_DISK_SECTOR_BITS))
       maxsec = ((0x78000 - GRUB_KERNEL_I386_PC_LINK_ADDR)
 		>> GRUB_DISK_SECTOR_BITS);
+#endif
+
+#ifdef GRUB_SETUP_SPARC64
+    /* On SPARC we need two extra.  One is because we are combining the
+     * core.img with the boot.img. The other is because the boot sector
+     * starts at 1.
+     */
+    nsec += 2;
+    maxsec += 2;
+#endif
 
     if (is_ldm)
       err = grub_util_ldm_embed (dest_dev->disk, &nsec, maxsec,
@@ -556,9 +564,35 @@ SETUP (const char *dir,
       bl.block--;
     bl.block->start = 0;
     bl.block->len = 0;
+#ifdef GRUB_SETUP_BIOS
     bl.block->segment = 0;
+#endif
+
+#ifdef GRUB_SETUP_SPARC64
+    {
+      /* On SPARC, the block-list entries need to be based off the beginning
+         of the parition, not the beginning of the disk. */
+      struct grub_boot_blocklist *block;
+      block = bl.first_block;
+
+      while (block->len)
+        {
+          block->start -= bl.first_sector;
+          block--;
+        }
+    }
 
+    /* Reserve space for the boot block since it can not be in the
+       Parition table on SPARC */
+    assert (bl.first_block->len > 2);
+    bl.first_block->start += 2;
+    bl.first_block->len -= 2;
+    write_rootdev (root_dev, boot_img, sectors[BOOT_SECTOR + 1] - bl.first_sector);
+#endif
+
+#ifdef GRUB_SETUP_BIOS
     write_rootdev (root_dev, boot_img, bl.first_sector);
+#endif
 
     /* Round up to the nearest sector boundary, and zero the extra memory */
     core_img = xrealloc (core_img, nsec * GRUB_DISK_SECTOR_SIZE);
@@ -568,7 +602,7 @@ SETUP (const char *dir,
     bl.first_block = (struct grub_boot_blocklist *) (core_img
 						     + GRUB_DISK_SECTOR_SIZE
 						     - sizeof (*bl.block));
-
+#if GRUB_SETUP_BIOS
     grub_size_t no_rs_length;
     no_rs_length = grub_target_to_host16 
       (grub_get_unaligned16 (core_img
@@ -599,7 +633,28 @@ SETUP (const char *dir,
       grub_disk_write (dest_dev->disk, sectors[i], 0,
 		       GRUB_DISK_SECTOR_SIZE,
 		       core_img + i * GRUB_DISK_SECTOR_SIZE);
+#endif
+
+#ifdef GRUB_SETUP_SPARC64
+    {
+      int isec = BOOT_SECTOR;
+
+      /* Write the boot image onto the disk. */
+      if (grub_disk_write (dest_dev->disk, sectors[isec++], 0,
+                           GRUB_DISK_SECTOR_SIZE, boot_img))
+        grub_util_error ("%s", grub_errmsg);
+
+      /* Write the core image onto the disk. */
+      for (i = 0 ; isec < nsec; i++, isec++)
+        {
+          if (grub_disk_write (dest_dev->disk, sectors[isec], 0,
+                               GRUB_DISK_SECTOR_SIZE,
+                               core_img  + i * GRUB_DISK_SECTOR_SIZE))
+            grub_util_error ("%s", grub_errmsg);
+        }
+    }
 
+#endif
     grub_free (sectors);
 
     unlink (DEFAULT_DIRECTORY "/" CORE_IMG_IN_FS);
@@ -608,7 +663,6 @@ SETUP (const char *dir,
   }
 
 unable_to_embed:
-#endif
 
   if (dest_dev->disk->dev->id != root_dev->disk->dev->id)
     grub_util_error ("%s", _("embedding is not possible, but this is required for "
@@ -729,15 +783,21 @@ unable_to_embed:
   {
     char *buf, *ptr = core_img;
     size_t len = core_size;
-    grub_uint64_t blk;
+    grub_uint64_t blk, offset = 0;
     grub_partition_t container = core_dev->disk->partition;
     grub_err_t err;
 
     core_dev->disk->partition = 0;
+#ifdef GRUB_SETUP_SPARC64
+    {
+      if (grub_strstr (container->partmap->name, "gpt"))
+        offset = grub_partition_get_start (container);
+    }
+#endif
 
     buf = xmalloc (core_size);
     blk = bl.first_sector;
-    err = grub_disk_read (core_dev->disk, blk, 0, GRUB_DISK_SECTOR_SIZE, buf);
+    err = grub_disk_read (core_dev->disk, blk + offset, 0, GRUB_DISK_SECTOR_SIZE, buf);
     if (err)
       grub_util_error (_("cannot read `%s': %s"), core_dev->disk->name,
 		       grub_errmsg);
@@ -756,7 +816,7 @@ unable_to_embed:
 	if (cur > len)
 	  cur = len;
 
-	err = grub_disk_read (core_dev->disk, blk, 0, cur, buf);
+	err = grub_disk_read (core_dev->disk, blk + offset, 0, cur, buf);
 	if (err)
 	  grub_util_error (_("cannot read `%s': %s"), core_dev->disk->name,
 			   grub_errmsg);
@@ -786,6 +846,10 @@ unable_to_embed:
 		       0, GRUB_DISK_SECTOR_SIZE, boot_img))
     grub_util_error ("%s", grub_errmsg);
 
+#ifdef GRUB_SETUP_SPARC64
+ finish:
+#endif
+
   grub_util_biosdisk_flush (root_dev->disk);
   grub_util_biosdisk_flush (dest_dev->disk);
 


More information about the Pkg-grub-devel mailing list