The UEFI 2.7 specification defines an updated BTT metadata format,
bumping the revision to 2.0. Add support for the new format, while
retaining compatibility for the old 1.1 format.

Cc: Toshi Kani <[email protected]>
Cc: Linda Knippers <[email protected]>
Cc: Dan Williams <[email protected]>
Signed-off-by: Vishal Verma <[email protected]>
---

v3:
 - Add athe actual BTT2 guid from the UEFI spec, and plumb a new
   claim class for it (Dan)
v2:
 - Don't enforce new BTTs being v2, base that decision on the holder class (Dan)
 - Refactor nd_btt_version slightly, and get rid of the version enum.

 drivers/nvdimm/btt.c            | 28 ++++++++++++++++++-------
 drivers/nvdimm/btt.h            |  2 ++
 drivers/nvdimm/btt_devs.c       | 46 ++++++++++++++++++++++++++++++++++++-----
 drivers/nvdimm/claim.c          |  1 +
 drivers/nvdimm/label.c          |  6 ++++++
 drivers/nvdimm/label.h          |  1 +
 drivers/nvdimm/namespace_devs.c | 38 ++++++++++++++++++++++++++++++----
 drivers/nvdimm/nd.h             |  3 +++
 include/linux/nd.h              |  1 +
 9 files changed, 109 insertions(+), 17 deletions(-)

diff --git a/drivers/nvdimm/btt.c b/drivers/nvdimm/btt.c
index 983718b..7ca11df 100644
--- a/drivers/nvdimm/btt.c
+++ b/drivers/nvdimm/btt.c
@@ -37,8 +37,8 @@ static int arena_read_bytes(struct arena_info *arena, 
resource_size_t offset,
        struct nd_btt *nd_btt = arena->nd_btt;
        struct nd_namespace_common *ndns = nd_btt->ndns;
 
-       /* arena offsets are 4K from the base of the device */
-       offset += SZ_4K;
+       /* arena offsets may be shifted from the base of the device */
+       offset += arena->nd_btt->initial_offset;
        return nvdimm_read_bytes(ndns, offset, buf, n, flags);
 }
 
@@ -48,8 +48,8 @@ static int arena_write_bytes(struct arena_info *arena, 
resource_size_t offset,
        struct nd_btt *nd_btt = arena->nd_btt;
        struct nd_namespace_common *ndns = nd_btt->ndns;
 
-       /* arena offsets are 4K from the base of the device */
-       offset += SZ_4K;
+       /* arena offsets may be shifted from the base of the device */
+       offset += arena->nd_btt->initial_offset;
        return nvdimm_write_bytes(ndns, offset, buf, n, flags);
 }
 
@@ -576,8 +576,8 @@ static struct arena_info *alloc_arena(struct btt *btt, 
size_t size,
        arena->internal_lbasize = roundup(arena->external_lbasize,
                                        INT_LBASIZE_ALIGNMENT);
        arena->nfree = BTT_DEFAULT_NFREE;
-       arena->version_major = 1;
-       arena->version_minor = 1;
+       arena->version_major = btt->nd_btt->version_major;
+       arena->version_minor = btt->nd_btt->version_minor;
 
        if (available % BTT_PG_SIZE)
                available -= (available % BTT_PG_SIZE);
@@ -1425,6 +1425,7 @@ int nvdimm_namespace_attach_btt(struct 
nd_namespace_common *ndns)
 {
        struct nd_btt *nd_btt = to_nd_btt(ndns->claim);
        struct nd_region *nd_region;
+       struct btt_sb *btt_sb;
        struct btt *btt;
        size_t rawsize;
 
@@ -1433,10 +1434,21 @@ int nvdimm_namespace_attach_btt(struct 
nd_namespace_common *ndns)
                return -ENODEV;
        }
 
-       rawsize = nvdimm_namespace_capacity(ndns) - SZ_4K;
+       btt_sb = devm_kzalloc(&nd_btt->dev, sizeof(*btt_sb), GFP_KERNEL);
+
+       /*
+        * If this returns < 0, that is ok as it just means there wasn't
+        * an existing BTT, and we're creating a new one. We still need to
+        * call this as we need the version dependent fields in nd_btt to be
+        * set correctly based on the holder class
+        */
+       nd_btt_version(nd_btt, ndns, btt_sb);
+
+       rawsize = nvdimm_namespace_capacity(ndns) - nd_btt->initial_offset;
        if (rawsize < ARENA_MIN_SIZE) {
                dev_dbg(&nd_btt->dev, "%s must be at least %ld bytes\n",
-                               dev_name(&ndns->dev), ARENA_MIN_SIZE + SZ_4K);
+                               dev_name(&ndns->dev),
+                               ARENA_MIN_SIZE + nd_btt->initial_offset);
                return -ENXIO;
        }
        nd_region = to_nd_region(nd_btt->dev.parent);
diff --git a/drivers/nvdimm/btt.h b/drivers/nvdimm/btt.h
index b2f8651..888e862 100644
--- a/drivers/nvdimm/btt.h
+++ b/drivers/nvdimm/btt.h
@@ -184,5 +184,7 @@ struct btt {
 };
 
 bool nd_btt_arena_is_valid(struct nd_btt *nd_btt, struct btt_sb *super);
+int nd_btt_version(struct nd_btt *nd_btt, struct nd_namespace_common *ndns,
+               struct btt_sb *btt_sb);
 
 #endif
diff --git a/drivers/nvdimm/btt_devs.c b/drivers/nvdimm/btt_devs.c
index 31d875a..3e359d2 100644
--- a/drivers/nvdimm/btt_devs.c
+++ b/drivers/nvdimm/btt_devs.c
@@ -260,20 +260,55 @@ bool nd_btt_arena_is_valid(struct nd_btt *nd_btt, struct 
btt_sb *super)
 }
 EXPORT_SYMBOL(nd_btt_arena_is_valid);
 
+int nd_btt_version(struct nd_btt *nd_btt, struct nd_namespace_common *ndns,
+               struct btt_sb *btt_sb)
+{
+       if (ndns->claim_class == NVDIMM_CCLASS_BTT2) {
+               /* Probe/setup for BTT v2.0 */
+               nd_btt->initial_offset = 0;
+               nd_btt->version_major = 2;
+               nd_btt->version_minor = 0;
+               if (nvdimm_read_bytes(ndns, 0, btt_sb, sizeof(*btt_sb), 0))
+                       return -ENXIO;
+               if (!nd_btt_arena_is_valid(nd_btt, btt_sb))
+                       return -ENODEV;
+               if ((le16_to_cpu(btt_sb->version_major) != 2) ||
+                               (le16_to_cpu(btt_sb->version_minor) != 0))
+                       return -ENODEV;
+       } else {
+               /*
+                * Probe/setup for BTT v1.1 (NVDIMM_CCLASS_NONE or
+                * NVDIMM_CCLASS_BTT)
+                */
+               nd_btt->initial_offset = SZ_4K;
+               nd_btt->version_major = 1;
+               nd_btt->version_minor = 1;
+               if (nvdimm_read_bytes(ndns, SZ_4K, btt_sb, sizeof(*btt_sb), 0))
+                       return -ENXIO;
+               if (!nd_btt_arena_is_valid(nd_btt, btt_sb))
+                       return -ENODEV;
+               if ((le16_to_cpu(btt_sb->version_major) != 1) ||
+                               (le16_to_cpu(btt_sb->version_minor) != 1))
+                       return -ENODEV;
+       }
+       return 0;
+}
+EXPORT_SYMBOL(nd_btt_version);
+
 static int __nd_btt_probe(struct nd_btt *nd_btt,
                struct nd_namespace_common *ndns, struct btt_sb *btt_sb)
 {
+       int rc;
+
        if (!btt_sb || !ndns || !nd_btt)
                return -ENODEV;
 
-       if (nvdimm_read_bytes(ndns, SZ_4K, btt_sb, sizeof(*btt_sb), 0))
-               return -ENXIO;
-
        if (nvdimm_namespace_capacity(ndns) < SZ_16M)
                return -ENXIO;
 
-       if (!nd_btt_arena_is_valid(nd_btt, btt_sb))
-               return -ENODEV;
+       rc = nd_btt_version(nd_btt, ndns, btt_sb);
+       if (rc < 0)
+               return rc;
 
        nd_btt->lbasize = le32_to_cpu(btt_sb->external_lbasize);
        nd_btt->uuid = kmemdup(btt_sb->uuid, 16, GFP_KERNEL);
@@ -298,6 +333,7 @@ int nd_btt_probe(struct device *dev, struct 
nd_namespace_common *ndns)
        switch (ndns->claim_class) {
        case NVDIMM_CCLASS_NONE:
        case NVDIMM_CCLASS_BTT:
+       case NVDIMM_CCLASS_BTT2:
                break;
        default:
                return -ENODEV;
diff --git a/drivers/nvdimm/claim.c b/drivers/nvdimm/claim.c
index de9b1cc..8d23f68 100644
--- a/drivers/nvdimm/claim.c
+++ b/drivers/nvdimm/claim.c
@@ -189,6 +189,7 @@ ssize_t nd_namespace_store(struct device *dev,
        case NVDIMM_CCLASS_NONE:
                break;
        case NVDIMM_CCLASS_BTT:
+       case NVDIMM_CCLASS_BTT2:
                if (!is_nd_btt(dev)) {
                        len = -EBUSY;
                        goto out_attach;
diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c
index 235f208..922b687 100644
--- a/drivers/nvdimm/label.c
+++ b/drivers/nvdimm/label.c
@@ -21,6 +21,7 @@
 #include "nd.h"
 
 static guid_t nvdimm_btt_guid;
+static guid_t nvdimm_btt2_guid;
 static guid_t nvdimm_pfn_guid;
 static guid_t nvdimm_dax_guid;
 
@@ -578,6 +579,8 @@ enum nvdimm_claim_class to_nvdimm_cclass(guid_t *guid)
 {
        if (guid_equal(guid, &nvdimm_btt_guid))
                return NVDIMM_CCLASS_BTT;
+       else if (guid_equal(guid, &nvdimm_btt2_guid))
+               return NVDIMM_CCLASS_BTT2;
        else if (guid_equal(guid, &nvdimm_pfn_guid))
                return NVDIMM_CCLASS_PFN;
        else if (guid_equal(guid, &nvdimm_dax_guid))
@@ -593,6 +596,8 @@ static const guid_t *to_abstraction_guid(enum 
nvdimm_claim_class claim_class,
 {
        if (claim_class == NVDIMM_CCLASS_BTT)
                return &nvdimm_btt_guid;
+       else if (claim_class == NVDIMM_CCLASS_BTT2)
+               return &nvdimm_btt2_guid;
        else if (claim_class == NVDIMM_CCLASS_PFN)
                return &nvdimm_pfn_guid;
        else if (claim_class == NVDIMM_CCLASS_DAX)
@@ -1158,6 +1163,7 @@ int nd_blk_namespace_label_update(struct nd_region 
*nd_region,
 int __init nd_label_init(void)
 {
        WARN_ON(guid_parse(NVDIMM_BTT_GUID, &nvdimm_btt_guid));
+       WARN_ON(guid_parse(NVDIMM_BTT2_GUID, &nvdimm_btt2_guid));
        WARN_ON(guid_parse(NVDIMM_PFN_GUID, &nvdimm_pfn_guid));
        WARN_ON(guid_parse(NVDIMM_DAX_GUID, &nvdimm_dax_guid));
 
diff --git a/drivers/nvdimm/label.h b/drivers/nvdimm/label.h
index 7c8e2cc..1ebf4d3 100644
--- a/drivers/nvdimm/label.h
+++ b/drivers/nvdimm/label.h
@@ -113,6 +113,7 @@ struct nd_namespace_label {
 };
 
 #define NVDIMM_BTT_GUID "8aed63a2-29a2-4c66-8b12-f05d15d3922a"
+#define NVDIMM_BTT2_GUID "18633bfc-1735-4217-8ac9-17239282d3f8"
 #define NVDIMM_PFN_GUID "266400ba-fb9f-4677-bcb0-968f11d0d225"
 #define NVDIMM_DAX_GUID "97a86d9c-3cdd-4eda-986f-5068b4f80088"
 
diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c
index f05d9b0..a11c189 100644
--- a/drivers/nvdimm/namespace_devs.c
+++ b/drivers/nvdimm/namespace_devs.c
@@ -1427,14 +1427,43 @@ static DEVICE_ATTR_RO(holder);
 
 static ssize_t __holder_class_store(struct device *dev, const char *buf)
 {
+       struct nd_region *nd_region = to_nd_region(dev->parent);
+       struct nd_mapping *nd_mapping = &nd_region->mapping[0];
        struct nd_namespace_common *ndns = to_ndns(dev);
+       int use_btt_legacy = 0;
+
+       /* for legacy/label-less namespaces, just use BTT1 */
+       if (nd_mapping != NULL && nd_mapping->nvdimm != NULL) {
+               struct nd_namespace_index *nsindex;
+               struct nvdimm_drvdata *ndd;
+
+               ndd = to_ndd(nd_mapping);
+               nsindex = to_namespace_index(ndd, ndd->ns_current);
+               if (nsindex == NULL) {
+                       ;
+                       /*
+                        * Labels haven't been initialized yet, and when they
+                        * will, they will be of the 1.2 format, so we can
+                        * assume BTT2.0
+                        */
+               } else {
+                       /* check if existing labels are v1.1 */
+                       if (__le16_to_cpu(nsindex->major) == 1
+                                       && __le16_to_cpu(nsindex->minor) == 1)
+                               use_btt_legacy = 1;
+               }
+       } else
+               use_btt_legacy = 1;
 
        if (dev->driver || ndns->claim)
                return -EBUSY;
 
-       if (strcmp(buf, "btt") == 0 || strcmp(buf, "btt\n") == 0)
-               ndns->claim_class = NVDIMM_CCLASS_BTT;
-       else if (strcmp(buf, "pfn") == 0 || strcmp(buf, "pfn\n") == 0)
+       if (strcmp(buf, "btt") == 0 || strcmp(buf, "btt\n") == 0) {
+               if (use_btt_legacy)
+                       ndns->claim_class = NVDIMM_CCLASS_BTT;
+               else
+                       ndns->claim_class = NVDIMM_CCLASS_BTT2;
+       } else if (strcmp(buf, "pfn") == 0 || strcmp(buf, "pfn\n") == 0)
                ndns->claim_class = NVDIMM_CCLASS_PFN;
        else if (strcmp(buf, "dax") == 0 || strcmp(buf, "dax\n") == 0)
                ndns->claim_class = NVDIMM_CCLASS_DAX;
@@ -1474,7 +1503,8 @@ static ssize_t holder_class_show(struct device *dev,
        device_lock(dev);
        if (ndns->claim_class == NVDIMM_CCLASS_NONE)
                rc = sprintf(buf, "\n");
-       else if (ndns->claim_class == NVDIMM_CCLASS_BTT)
+       else if ((ndns->claim_class == NVDIMM_CCLASS_BTT) ||
+                       (ndns->claim_class == NVDIMM_CCLASS_BTT2))
                rc = sprintf(buf, "btt\n");
        else if (ndns->claim_class == NVDIMM_CCLASS_PFN)
                rc = sprintf(buf, "pfn\n");
diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
index 8cabd83..1496ef9 100644
--- a/drivers/nvdimm/nd.h
+++ b/drivers/nvdimm/nd.h
@@ -194,6 +194,9 @@ struct nd_btt {
        u64 size;
        u8 *uuid;
        int id;
+       int initial_offset;
+       u16 version_major;
+       u16 version_minor;
 };
 
 enum nd_pfn_mode {
diff --git a/include/linux/nd.h b/include/linux/nd.h
index 96069c5..5dc6b69 100644
--- a/include/linux/nd.h
+++ b/include/linux/nd.h
@@ -24,6 +24,7 @@ enum nvdimm_event {
 enum nvdimm_claim_class {
        NVDIMM_CCLASS_NONE,
        NVDIMM_CCLASS_BTT,
+       NVDIMM_CCLASS_BTT2,
        NVDIMM_CCLASS_PFN,
        NVDIMM_CCLASS_DAX,
        NVDIMM_CCLASS_UNKNOWN,
-- 
2.9.3

_______________________________________________
Linux-nvdimm mailing list
[email protected]
https://lists.01.org/mailman/listinfo/linux-nvdimm

Reply via email to