[PATCH 1/9] libnvdimm, label: add v1.2 nvdimm label definitions

2017-06-08 Thread Dan Williams
In support of improved interoperability between operating systems and pre-boot
environments the Intel proposed NVDIMM Namespace Specification [1], has been
adopted and modified to the the UEFI 2.7 NVDIMM Label Protocol [2].

Update the definitions of the namespace label data structures so that the new
format can be supported alongside the existing label format.

The new specification changes the default label size to 256 bytes, so
everywhere that relied on sizeof(struct nd_namespace_label) must now use the
sizeof_namespace_label() helper.

There should be no functional differences from these changes as the
default is still the v1.1 128-byte format. Future patches will move the
default to the v1.2 definition.

[1]: http://pmem.io/documents/NVDIMM_Namespace_Spec.pdf
[2]: http://www.uefi.org/sites/default/files/resources/UEFI_Spec_2_7.pdf

Signed-off-by: Dan Williams 
---
 drivers/nvdimm/label.c |   95 +++-
 drivers/nvdimm/label.h |   15 +++-
 drivers/nvdimm/nd.h|8 
 3 files changed, 97 insertions(+), 21 deletions(-)

diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c
index dd615345699f..d6233d220bfd 100644
--- a/drivers/nvdimm/label.c
+++ b/drivers/nvdimm/label.c
@@ -34,6 +34,11 @@ static u32 best_seq(u32 a, u32 b)
return a;
 }
 
+unsigned sizeof_namespace_label(struct nvdimm_drvdata *ndd)
+{
+   return ndd->nslabel_size;
+}
+
 size_t sizeof_namespace_index(struct nvdimm_drvdata *ndd)
 {
u32 index_span;
@@ -49,7 +54,7 @@ size_t sizeof_namespace_index(struct nvdimm_drvdata *ndd)
 * starts to waste space at larger config_sizes, but it's
 * unlikely we'll ever see anything but 128K.
 */
-   index_span = ndd->nsarea.config_size / 129;
+   index_span = ndd->nsarea.config_size / (sizeof_namespace_label(ndd) + 
1);
index_span /= NSINDEX_ALIGN * 2;
ndd->nsindex_size = index_span * NSINDEX_ALIGN;
 
@@ -58,10 +63,10 @@ size_t sizeof_namespace_index(struct nvdimm_drvdata *ndd)
 
 int nvdimm_num_label_slots(struct nvdimm_drvdata *ndd)
 {
-   return ndd->nsarea.config_size / 129;
+   return ndd->nsarea.config_size / (sizeof_namespace_label(ndd) + 1);
 }
 
-int nd_label_validate(struct nvdimm_drvdata *ndd)
+static int __nd_label_validate(struct nvdimm_drvdata *ndd)
 {
/*
 * On media label format consists of two index blocks followed
@@ -104,6 +109,7 @@ int nd_label_validate(struct nvdimm_drvdata *ndd)
u32 nslot;
u8 sig[NSINDEX_SIG_LEN];
u64 sum_save, sum, size;
+   unsigned int version, labelsize;
 
memcpy(sig, nsindex[i]->sig, NSINDEX_SIG_LEN);
if (memcmp(sig, NSINDEX_SIGNATURE, NSINDEX_SIG_LEN) != 0) {
@@ -111,6 +117,21 @@ int nd_label_validate(struct nvdimm_drvdata *ndd)
__func__, i);
continue;
}
+
+   /* label sizes larger than 128 arrived with v1.2 */
+   version = __le16_to_cpu(nsindex[i]->major) * 100
+   + __le16_to_cpu(nsindex[i]->minor);
+   if (version >= 102)
+   labelsize = 1 << (7 + nsindex[i]->labelsize);
+   else
+   labelsize = 128;
+
+   if (labelsize != sizeof_namespace_label(ndd)) {
+   dev_dbg(dev, "%s: nsindex%d labelsize %d invalid\n",
+   __func__, i, nsindex[i]->labelsize);
+   continue;
+   }
+
sum_save = __le64_to_cpu(nsindex[i]->checksum);
nsindex[i]->checksum = __cpu_to_le64(0);
sum = nd_fletcher64(nsindex[i], sizeof_namespace_index(ndd), 1);
@@ -153,7 +174,7 @@ int nd_label_validate(struct nvdimm_drvdata *ndd)
}
 
nslot = __le32_to_cpu(nsindex[i]->nslot);
-   if (nslot * sizeof(struct nd_namespace_label)
+   if (nslot * sizeof_namespace_label(ndd)
+ 2 * sizeof_namespace_index(ndd)
> ndd->nsarea.config_size) {
dev_dbg(dev, "%s: nsindex%d nslot: %u invalid, 
config_size: %#x\n",
@@ -189,6 +210,28 @@ int nd_label_validate(struct nvdimm_drvdata *ndd)
return -1;
 }
 
+int nd_label_validate(struct nvdimm_drvdata *ndd)
+{
+   /*
+* In order to probe for and validate namespace index blocks we
+* need to know the size of the labels, and we can't trust the
+* size of the labels until we validate the index blocks.
+* Resolve this dependency loop by probing for known label
+* sizes.
+*/
+   int label_size[] = { 256, 128 };
+   int i, rc;
+
+   for (i = 0; i < ARRAY_SIZE(label_size); i++) {
+   ndd->nslabel_size = label_size[i];
+   rc = 

[PATCH 1/9] libnvdimm, label: add v1.2 nvdimm label definitions

2017-06-08 Thread Dan Williams
In support of improved interoperability between operating systems and pre-boot
environments the Intel proposed NVDIMM Namespace Specification [1], has been
adopted and modified to the the UEFI 2.7 NVDIMM Label Protocol [2].

Update the definitions of the namespace label data structures so that the new
format can be supported alongside the existing label format.

The new specification changes the default label size to 256 bytes, so
everywhere that relied on sizeof(struct nd_namespace_label) must now use the
sizeof_namespace_label() helper.

There should be no functional differences from these changes as the
default is still the v1.1 128-byte format. Future patches will move the
default to the v1.2 definition.

[1]: http://pmem.io/documents/NVDIMM_Namespace_Spec.pdf
[2]: http://www.uefi.org/sites/default/files/resources/UEFI_Spec_2_7.pdf

Signed-off-by: Dan Williams 
---
 drivers/nvdimm/label.c |   95 +++-
 drivers/nvdimm/label.h |   15 +++-
 drivers/nvdimm/nd.h|8 
 3 files changed, 97 insertions(+), 21 deletions(-)

diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c
index dd615345699f..d6233d220bfd 100644
--- a/drivers/nvdimm/label.c
+++ b/drivers/nvdimm/label.c
@@ -34,6 +34,11 @@ static u32 best_seq(u32 a, u32 b)
return a;
 }
 
+unsigned sizeof_namespace_label(struct nvdimm_drvdata *ndd)
+{
+   return ndd->nslabel_size;
+}
+
 size_t sizeof_namespace_index(struct nvdimm_drvdata *ndd)
 {
u32 index_span;
@@ -49,7 +54,7 @@ size_t sizeof_namespace_index(struct nvdimm_drvdata *ndd)
 * starts to waste space at larger config_sizes, but it's
 * unlikely we'll ever see anything but 128K.
 */
-   index_span = ndd->nsarea.config_size / 129;
+   index_span = ndd->nsarea.config_size / (sizeof_namespace_label(ndd) + 
1);
index_span /= NSINDEX_ALIGN * 2;
ndd->nsindex_size = index_span * NSINDEX_ALIGN;
 
@@ -58,10 +63,10 @@ size_t sizeof_namespace_index(struct nvdimm_drvdata *ndd)
 
 int nvdimm_num_label_slots(struct nvdimm_drvdata *ndd)
 {
-   return ndd->nsarea.config_size / 129;
+   return ndd->nsarea.config_size / (sizeof_namespace_label(ndd) + 1);
 }
 
-int nd_label_validate(struct nvdimm_drvdata *ndd)
+static int __nd_label_validate(struct nvdimm_drvdata *ndd)
 {
/*
 * On media label format consists of two index blocks followed
@@ -104,6 +109,7 @@ int nd_label_validate(struct nvdimm_drvdata *ndd)
u32 nslot;
u8 sig[NSINDEX_SIG_LEN];
u64 sum_save, sum, size;
+   unsigned int version, labelsize;
 
memcpy(sig, nsindex[i]->sig, NSINDEX_SIG_LEN);
if (memcmp(sig, NSINDEX_SIGNATURE, NSINDEX_SIG_LEN) != 0) {
@@ -111,6 +117,21 @@ int nd_label_validate(struct nvdimm_drvdata *ndd)
__func__, i);
continue;
}
+
+   /* label sizes larger than 128 arrived with v1.2 */
+   version = __le16_to_cpu(nsindex[i]->major) * 100
+   + __le16_to_cpu(nsindex[i]->minor);
+   if (version >= 102)
+   labelsize = 1 << (7 + nsindex[i]->labelsize);
+   else
+   labelsize = 128;
+
+   if (labelsize != sizeof_namespace_label(ndd)) {
+   dev_dbg(dev, "%s: nsindex%d labelsize %d invalid\n",
+   __func__, i, nsindex[i]->labelsize);
+   continue;
+   }
+
sum_save = __le64_to_cpu(nsindex[i]->checksum);
nsindex[i]->checksum = __cpu_to_le64(0);
sum = nd_fletcher64(nsindex[i], sizeof_namespace_index(ndd), 1);
@@ -153,7 +174,7 @@ int nd_label_validate(struct nvdimm_drvdata *ndd)
}
 
nslot = __le32_to_cpu(nsindex[i]->nslot);
-   if (nslot * sizeof(struct nd_namespace_label)
+   if (nslot * sizeof_namespace_label(ndd)
+ 2 * sizeof_namespace_index(ndd)
> ndd->nsarea.config_size) {
dev_dbg(dev, "%s: nsindex%d nslot: %u invalid, 
config_size: %#x\n",
@@ -189,6 +210,28 @@ int nd_label_validate(struct nvdimm_drvdata *ndd)
return -1;
 }
 
+int nd_label_validate(struct nvdimm_drvdata *ndd)
+{
+   /*
+* In order to probe for and validate namespace index blocks we
+* need to know the size of the labels, and we can't trust the
+* size of the labels until we validate the index blocks.
+* Resolve this dependency loop by probing for known label
+* sizes.
+*/
+   int label_size[] = { 256, 128 };
+   int i, rc;
+
+   for (i = 0; i < ARRAY_SIZE(label_size); i++) {
+   ndd->nslabel_size = label_size[i];
+   rc = __nd_label_validate(ndd);
+   if