aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVishal Verma <vishal.l.verma@intel.com>2017-06-28 16:25:00 -0400
committerDan Williams <dan.j.williams@intel.com>2017-06-29 16:50:38 -0400
commit14e494542636b7a685c5bf27e695e3bb9ec3fe7d (patch)
treeab04daf7eacbc7237c127c3052628c5cac729755
parent5e93746f065c49445cf8115007fc887789438ec0 (diff)
libnvdimm, btt: BTT updates for UEFI 2.7 format
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 <toshi.kani@hpe.com> Cc: Linda Knippers <linda.knippers@hpe.com> Cc: Dan Williams <dan.j.williams@intel.com> Signed-off-by: Vishal Verma <vishal.l.verma@intel.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
-rw-r--r--drivers/nvdimm/btt.c28
-rw-r--r--drivers/nvdimm/btt.h2
-rw-r--r--drivers/nvdimm/btt_devs.c46
-rw-r--r--drivers/nvdimm/claim.c1
-rw-r--r--drivers/nvdimm/label.c6
-rw-r--r--drivers/nvdimm/label.h1
-rw-r--r--drivers/nvdimm/namespace_devs.c61
-rw-r--r--drivers/nvdimm/nd.h3
-rw-r--r--include/linux/nd.h1
9 files changed, 134 insertions, 15 deletions
diff --git a/drivers/nvdimm/btt.c b/drivers/nvdimm/btt.c
index 983718b8fd9b..7ca11df80ae8 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,
37 struct nd_btt *nd_btt = arena->nd_btt; 37 struct nd_btt *nd_btt = arena->nd_btt;
38 struct nd_namespace_common *ndns = nd_btt->ndns; 38 struct nd_namespace_common *ndns = nd_btt->ndns;
39 39
40 /* arena offsets are 4K from the base of the device */ 40 /* arena offsets may be shifted from the base of the device */
41 offset += SZ_4K; 41 offset += arena->nd_btt->initial_offset;
42 return nvdimm_read_bytes(ndns, offset, buf, n, flags); 42 return nvdimm_read_bytes(ndns, offset, buf, n, flags);
43} 43}
44 44
@@ -48,8 +48,8 @@ static int arena_write_bytes(struct arena_info *arena, resource_size_t offset,
48 struct nd_btt *nd_btt = arena->nd_btt; 48 struct nd_btt *nd_btt = arena->nd_btt;
49 struct nd_namespace_common *ndns = nd_btt->ndns; 49 struct nd_namespace_common *ndns = nd_btt->ndns;
50 50
51 /* arena offsets are 4K from the base of the device */ 51 /* arena offsets may be shifted from the base of the device */
52 offset += SZ_4K; 52 offset += arena->nd_btt->initial_offset;
53 return nvdimm_write_bytes(ndns, offset, buf, n, flags); 53 return nvdimm_write_bytes(ndns, offset, buf, n, flags);
54} 54}
55 55
@@ -576,8 +576,8 @@ static struct arena_info *alloc_arena(struct btt *btt, size_t size,
576 arena->internal_lbasize = roundup(arena->external_lbasize, 576 arena->internal_lbasize = roundup(arena->external_lbasize,
577 INT_LBASIZE_ALIGNMENT); 577 INT_LBASIZE_ALIGNMENT);
578 arena->nfree = BTT_DEFAULT_NFREE; 578 arena->nfree = BTT_DEFAULT_NFREE;
579 arena->version_major = 1; 579 arena->version_major = btt->nd_btt->version_major;
580 arena->version_minor = 1; 580 arena->version_minor = btt->nd_btt->version_minor;
581 581
582 if (available % BTT_PG_SIZE) 582 if (available % BTT_PG_SIZE)
583 available -= (available % BTT_PG_SIZE); 583 available -= (available % BTT_PG_SIZE);
@@ -1425,6 +1425,7 @@ int nvdimm_namespace_attach_btt(struct nd_namespace_common *ndns)
1425{ 1425{
1426 struct nd_btt *nd_btt = to_nd_btt(ndns->claim); 1426 struct nd_btt *nd_btt = to_nd_btt(ndns->claim);
1427 struct nd_region *nd_region; 1427 struct nd_region *nd_region;
1428 struct btt_sb *btt_sb;
1428 struct btt *btt; 1429 struct btt *btt;
1429 size_t rawsize; 1430 size_t rawsize;
1430 1431
@@ -1433,10 +1434,21 @@ int nvdimm_namespace_attach_btt(struct nd_namespace_common *ndns)
1433 return -ENODEV; 1434 return -ENODEV;
1434 } 1435 }
1435 1436
1436 rawsize = nvdimm_namespace_capacity(ndns) - SZ_4K; 1437 btt_sb = devm_kzalloc(&nd_btt->dev, sizeof(*btt_sb), GFP_KERNEL);
1438
1439 /*
1440 * If this returns < 0, that is ok as it just means there wasn't
1441 * an existing BTT, and we're creating a new one. We still need to
1442 * call this as we need the version dependent fields in nd_btt to be
1443 * set correctly based on the holder class
1444 */
1445 nd_btt_version(nd_btt, ndns, btt_sb);
1446
1447 rawsize = nvdimm_namespace_capacity(ndns) - nd_btt->initial_offset;
1437 if (rawsize < ARENA_MIN_SIZE) { 1448 if (rawsize < ARENA_MIN_SIZE) {
1438 dev_dbg(&nd_btt->dev, "%s must be at least %ld bytes\n", 1449 dev_dbg(&nd_btt->dev, "%s must be at least %ld bytes\n",
1439 dev_name(&ndns->dev), ARENA_MIN_SIZE + SZ_4K); 1450 dev_name(&ndns->dev),
1451 ARENA_MIN_SIZE + nd_btt->initial_offset);
1440 return -ENXIO; 1452 return -ENXIO;
1441 } 1453 }
1442 nd_region = to_nd_region(nd_btt->dev.parent); 1454 nd_region = to_nd_region(nd_btt->dev.parent);
diff --git a/drivers/nvdimm/btt.h b/drivers/nvdimm/btt.h
index b2f8651e5395..888e862907a0 100644
--- a/drivers/nvdimm/btt.h
+++ b/drivers/nvdimm/btt.h
@@ -184,5 +184,7 @@ struct btt {
184}; 184};
185 185
186bool nd_btt_arena_is_valid(struct nd_btt *nd_btt, struct btt_sb *super); 186bool nd_btt_arena_is_valid(struct nd_btt *nd_btt, struct btt_sb *super);
187int nd_btt_version(struct nd_btt *nd_btt, struct nd_namespace_common *ndns,
188 struct btt_sb *btt_sb);
187 189
188#endif 190#endif
diff --git a/drivers/nvdimm/btt_devs.c b/drivers/nvdimm/btt_devs.c
index 31d875a91569..3e359d282f8e 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)
260} 260}
261EXPORT_SYMBOL(nd_btt_arena_is_valid); 261EXPORT_SYMBOL(nd_btt_arena_is_valid);
262 262
263int nd_btt_version(struct nd_btt *nd_btt, struct nd_namespace_common *ndns,
264 struct btt_sb *btt_sb)
265{
266 if (ndns->claim_class == NVDIMM_CCLASS_BTT2) {
267 /* Probe/setup for BTT v2.0 */
268 nd_btt->initial_offset = 0;
269 nd_btt->version_major = 2;
270 nd_btt->version_minor = 0;
271 if (nvdimm_read_bytes(ndns, 0, btt_sb, sizeof(*btt_sb), 0))
272 return -ENXIO;
273 if (!nd_btt_arena_is_valid(nd_btt, btt_sb))
274 return -ENODEV;
275 if ((le16_to_cpu(btt_sb->version_major) != 2) ||
276 (le16_to_cpu(btt_sb->version_minor) != 0))
277 return -ENODEV;
278 } else {
279 /*
280 * Probe/setup for BTT v1.1 (NVDIMM_CCLASS_NONE or
281 * NVDIMM_CCLASS_BTT)
282 */
283 nd_btt->initial_offset = SZ_4K;
284 nd_btt->version_major = 1;
285 nd_btt->version_minor = 1;
286 if (nvdimm_read_bytes(ndns, SZ_4K, btt_sb, sizeof(*btt_sb), 0))
287 return -ENXIO;
288 if (!nd_btt_arena_is_valid(nd_btt, btt_sb))
289 return -ENODEV;
290 if ((le16_to_cpu(btt_sb->version_major) != 1) ||
291 (le16_to_cpu(btt_sb->version_minor) != 1))
292 return -ENODEV;
293 }
294 return 0;
295}
296EXPORT_SYMBOL(nd_btt_version);
297
263static int __nd_btt_probe(struct nd_btt *nd_btt, 298static int __nd_btt_probe(struct nd_btt *nd_btt,
264 struct nd_namespace_common *ndns, struct btt_sb *btt_sb) 299 struct nd_namespace_common *ndns, struct btt_sb *btt_sb)
265{ 300{
301 int rc;
302
266 if (!btt_sb || !ndns || !nd_btt) 303 if (!btt_sb || !ndns || !nd_btt)
267 return -ENODEV; 304 return -ENODEV;
268 305
269 if (nvdimm_read_bytes(ndns, SZ_4K, btt_sb, sizeof(*btt_sb), 0))
270 return -ENXIO;
271
272 if (nvdimm_namespace_capacity(ndns) < SZ_16M) 306 if (nvdimm_namespace_capacity(ndns) < SZ_16M)
273 return -ENXIO; 307 return -ENXIO;
274 308
275 if (!nd_btt_arena_is_valid(nd_btt, btt_sb)) 309 rc = nd_btt_version(nd_btt, ndns, btt_sb);
276 return -ENODEV; 310 if (rc < 0)
311 return rc;
277 312
278 nd_btt->lbasize = le32_to_cpu(btt_sb->external_lbasize); 313 nd_btt->lbasize = le32_to_cpu(btt_sb->external_lbasize);
279 nd_btt->uuid = kmemdup(btt_sb->uuid, 16, GFP_KERNEL); 314 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)
298 switch (ndns->claim_class) { 333 switch (ndns->claim_class) {
299 case NVDIMM_CCLASS_NONE: 334 case NVDIMM_CCLASS_NONE:
300 case NVDIMM_CCLASS_BTT: 335 case NVDIMM_CCLASS_BTT:
336 case NVDIMM_CCLASS_BTT2:
301 break; 337 break;
302 default: 338 default:
303 return -ENODEV; 339 return -ENODEV;
diff --git a/drivers/nvdimm/claim.c b/drivers/nvdimm/claim.c
index de9b1cce242e..8d23f68737d9 100644
--- a/drivers/nvdimm/claim.c
+++ b/drivers/nvdimm/claim.c
@@ -189,6 +189,7 @@ ssize_t nd_namespace_store(struct device *dev,
189 case NVDIMM_CCLASS_NONE: 189 case NVDIMM_CCLASS_NONE:
190 break; 190 break;
191 case NVDIMM_CCLASS_BTT: 191 case NVDIMM_CCLASS_BTT:
192 case NVDIMM_CCLASS_BTT2:
192 if (!is_nd_btt(dev)) { 193 if (!is_nd_btt(dev)) {
193 len = -EBUSY; 194 len = -EBUSY;
194 goto out_attach; 195 goto out_attach;
diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c
index 235f2089fab2..922b68718a1a 100644
--- a/drivers/nvdimm/label.c
+++ b/drivers/nvdimm/label.c
@@ -21,6 +21,7 @@
21#include "nd.h" 21#include "nd.h"
22 22
23static guid_t nvdimm_btt_guid; 23static guid_t nvdimm_btt_guid;
24static guid_t nvdimm_btt2_guid;
24static guid_t nvdimm_pfn_guid; 25static guid_t nvdimm_pfn_guid;
25static guid_t nvdimm_dax_guid; 26static guid_t nvdimm_dax_guid;
26 27
@@ -578,6 +579,8 @@ enum nvdimm_claim_class to_nvdimm_cclass(guid_t *guid)
578{ 579{
579 if (guid_equal(guid, &nvdimm_btt_guid)) 580 if (guid_equal(guid, &nvdimm_btt_guid))
580 return NVDIMM_CCLASS_BTT; 581 return NVDIMM_CCLASS_BTT;
582 else if (guid_equal(guid, &nvdimm_btt2_guid))
583 return NVDIMM_CCLASS_BTT2;
581 else if (guid_equal(guid, &nvdimm_pfn_guid)) 584 else if (guid_equal(guid, &nvdimm_pfn_guid))
582 return NVDIMM_CCLASS_PFN; 585 return NVDIMM_CCLASS_PFN;
583 else if (guid_equal(guid, &nvdimm_dax_guid)) 586 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,
593{ 596{
594 if (claim_class == NVDIMM_CCLASS_BTT) 597 if (claim_class == NVDIMM_CCLASS_BTT)
595 return &nvdimm_btt_guid; 598 return &nvdimm_btt_guid;
599 else if (claim_class == NVDIMM_CCLASS_BTT2)
600 return &nvdimm_btt2_guid;
596 else if (claim_class == NVDIMM_CCLASS_PFN) 601 else if (claim_class == NVDIMM_CCLASS_PFN)
597 return &nvdimm_pfn_guid; 602 return &nvdimm_pfn_guid;
598 else if (claim_class == NVDIMM_CCLASS_DAX) 603 else if (claim_class == NVDIMM_CCLASS_DAX)
@@ -1158,6 +1163,7 @@ int nd_blk_namespace_label_update(struct nd_region *nd_region,
1158int __init nd_label_init(void) 1163int __init nd_label_init(void)
1159{ 1164{
1160 WARN_ON(guid_parse(NVDIMM_BTT_GUID, &nvdimm_btt_guid)); 1165 WARN_ON(guid_parse(NVDIMM_BTT_GUID, &nvdimm_btt_guid));
1166 WARN_ON(guid_parse(NVDIMM_BTT2_GUID, &nvdimm_btt2_guid));
1161 WARN_ON(guid_parse(NVDIMM_PFN_GUID, &nvdimm_pfn_guid)); 1167 WARN_ON(guid_parse(NVDIMM_PFN_GUID, &nvdimm_pfn_guid));
1162 WARN_ON(guid_parse(NVDIMM_DAX_GUID, &nvdimm_dax_guid)); 1168 WARN_ON(guid_parse(NVDIMM_DAX_GUID, &nvdimm_dax_guid));
1163 1169
diff --git a/drivers/nvdimm/label.h b/drivers/nvdimm/label.h
index 7c8e2cc9e73e..1ebf4d3d01ba 100644
--- a/drivers/nvdimm/label.h
+++ b/drivers/nvdimm/label.h
@@ -113,6 +113,7 @@ struct nd_namespace_label {
113}; 113};
114 114
115#define NVDIMM_BTT_GUID "8aed63a2-29a2-4c66-8b12-f05d15d3922a" 115#define NVDIMM_BTT_GUID "8aed63a2-29a2-4c66-8b12-f05d15d3922a"
116#define NVDIMM_BTT2_GUID "18633bfc-1735-4217-8ac9-17239282d3f8"
116#define NVDIMM_PFN_GUID "266400ba-fb9f-4677-bcb0-968f11d0d225" 117#define NVDIMM_PFN_GUID "266400ba-fb9f-4677-bcb0-968f11d0d225"
117#define NVDIMM_DAX_GUID "97a86d9c-3cdd-4eda-986f-5068b4f80088" 118#define NVDIMM_DAX_GUID "97a86d9c-3cdd-4eda-986f-5068b4f80088"
118 119
diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c
index f05d9b0672bf..c96e31330213 100644
--- a/drivers/nvdimm/namespace_devs.c
+++ b/drivers/nvdimm/namespace_devs.c
@@ -1411,6 +1411,58 @@ static ssize_t dpa_extents_show(struct device *dev,
1411} 1411}
1412static DEVICE_ATTR_RO(dpa_extents); 1412static DEVICE_ATTR_RO(dpa_extents);
1413 1413
1414static int btt_claim_class(struct device *dev)
1415{
1416 struct nd_region *nd_region = to_nd_region(dev->parent);
1417 int i, loop_bitmask = 0;
1418
1419 for (i = 0; i < nd_region->ndr_mappings; i++) {
1420 struct nd_mapping *nd_mapping = &nd_region->mapping[i];
1421 struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
1422 struct nd_namespace_index *nsindex;
1423
1424 nsindex = to_namespace_index(ndd, ndd->ns_current);
1425 if (nsindex == NULL)
1426 loop_bitmask |= 1;
1427 else {
1428 /* check whether existing labels are v1.1 or v1.2 */
1429 if (__le16_to_cpu(nsindex->major) == 1
1430 && __le16_to_cpu(nsindex->minor) == 1)
1431 loop_bitmask |= 2;
1432 else
1433 loop_bitmask |= 4;
1434 }
1435 }
1436 /*
1437 * If nsindex is null loop_bitmask's bit 0 will be set, and if an index
1438 * block is found, a v1.1 label for any mapping will set bit 1, and a
1439 * v1.2 label will set bit 2.
1440 *
1441 * At the end of the loop, at most one of the three bits must be set.
1442 * If multiple bits were set, it means the different mappings disagree
1443 * about their labels, and this must be cleaned up first.
1444 *
1445 * If all the label index blocks are found to agree, nsindex of NULL
1446 * implies labels haven't been initialized yet, and when they will,
1447 * they will be of the 1.2 format, so we can assume BTT2.0
1448 *
1449 * If 1.1 labels are found, we enforce BTT1.1, and if 1.2 labels are
1450 * found, we enforce BTT2.0
1451 *
1452 * If the loop was never entered, default to BTT1.1 (legacy namespaces)
1453 */
1454 switch (loop_bitmask) {
1455 case 0:
1456 case 2:
1457 return NVDIMM_CCLASS_BTT;
1458 case 1:
1459 case 4:
1460 return NVDIMM_CCLASS_BTT2;
1461 default:
1462 return -ENXIO;
1463 }
1464}
1465
1414static ssize_t holder_show(struct device *dev, 1466static ssize_t holder_show(struct device *dev,
1415 struct device_attribute *attr, char *buf) 1467 struct device_attribute *attr, char *buf)
1416{ 1468{
@@ -1433,7 +1485,7 @@ static ssize_t __holder_class_store(struct device *dev, const char *buf)
1433 return -EBUSY; 1485 return -EBUSY;
1434 1486
1435 if (strcmp(buf, "btt") == 0 || strcmp(buf, "btt\n") == 0) 1487 if (strcmp(buf, "btt") == 0 || strcmp(buf, "btt\n") == 0)
1436 ndns->claim_class = NVDIMM_CCLASS_BTT; 1488 ndns->claim_class = btt_claim_class(dev);
1437 else if (strcmp(buf, "pfn") == 0 || strcmp(buf, "pfn\n") == 0) 1489 else if (strcmp(buf, "pfn") == 0 || strcmp(buf, "pfn\n") == 0)
1438 ndns->claim_class = NVDIMM_CCLASS_PFN; 1490 ndns->claim_class = NVDIMM_CCLASS_PFN;
1439 else if (strcmp(buf, "dax") == 0 || strcmp(buf, "dax\n") == 0) 1491 else if (strcmp(buf, "dax") == 0 || strcmp(buf, "dax\n") == 0)
@@ -1443,6 +1495,10 @@ static ssize_t __holder_class_store(struct device *dev, const char *buf)
1443 else 1495 else
1444 return -EINVAL; 1496 return -EINVAL;
1445 1497
1498 /* btt_claim_class() could've returned an error */
1499 if (ndns->claim_class < 0)
1500 return ndns->claim_class;
1501
1446 return 0; 1502 return 0;
1447} 1503}
1448 1504
@@ -1474,7 +1530,8 @@ static ssize_t holder_class_show(struct device *dev,
1474 device_lock(dev); 1530 device_lock(dev);
1475 if (ndns->claim_class == NVDIMM_CCLASS_NONE) 1531 if (ndns->claim_class == NVDIMM_CCLASS_NONE)
1476 rc = sprintf(buf, "\n"); 1532 rc = sprintf(buf, "\n");
1477 else if (ndns->claim_class == NVDIMM_CCLASS_BTT) 1533 else if ((ndns->claim_class == NVDIMM_CCLASS_BTT) ||
1534 (ndns->claim_class == NVDIMM_CCLASS_BTT2))
1478 rc = sprintf(buf, "btt\n"); 1535 rc = sprintf(buf, "btt\n");
1479 else if (ndns->claim_class == NVDIMM_CCLASS_PFN) 1536 else if (ndns->claim_class == NVDIMM_CCLASS_PFN)
1480 rc = sprintf(buf, "pfn\n"); 1537 rc = sprintf(buf, "pfn\n");
diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
index e802c877d783..e1b5715bd91f 100644
--- a/drivers/nvdimm/nd.h
+++ b/drivers/nvdimm/nd.h
@@ -195,6 +195,9 @@ struct nd_btt {
195 u64 size; 195 u64 size;
196 u8 *uuid; 196 u8 *uuid;
197 int id; 197 int id;
198 int initial_offset;
199 u16 version_major;
200 u16 version_minor;
198}; 201};
199 202
200enum nd_pfn_mode { 203enum nd_pfn_mode {
diff --git a/include/linux/nd.h b/include/linux/nd.h
index 96069c543890..5dc6b695437d 100644
--- a/include/linux/nd.h
+++ b/include/linux/nd.h
@@ -24,6 +24,7 @@ enum nvdimm_event {
24enum nvdimm_claim_class { 24enum nvdimm_claim_class {
25 NVDIMM_CCLASS_NONE, 25 NVDIMM_CCLASS_NONE,
26 NVDIMM_CCLASS_BTT, 26 NVDIMM_CCLASS_BTT,
27 NVDIMM_CCLASS_BTT2,
27 NVDIMM_CCLASS_PFN, 28 NVDIMM_CCLASS_PFN,
28 NVDIMM_CCLASS_DAX, 29 NVDIMM_CCLASS_DAX,
29 NVDIMM_CCLASS_UNKNOWN, 30 NVDIMM_CCLASS_UNKNOWN,