diff options
-rw-r--r-- | drivers/acpi/nfit.c | 31 | ||||
-rw-r--r-- | drivers/acpi/nfit.h | 3 | ||||
-rw-r--r-- | drivers/nvdimm/blk.c | 2 | ||||
-rw-r--r-- | drivers/nvdimm/btt.c | 10 | ||||
-rw-r--r-- | drivers/nvdimm/bus.c | 18 | ||||
-rw-r--r-- | drivers/nvdimm/nd.h | 3 | ||||
-rw-r--r-- | drivers/nvdimm/pmem.c | 2 | ||||
-rw-r--r-- | drivers/nvdimm/region_devs.c | 29 | ||||
-rw-r--r-- | include/linux/libnvdimm.h | 2 | ||||
-rw-r--r-- | tools/testing/nvdimm/test/nfit.c | 3 |
10 files changed, 100 insertions, 3 deletions
diff --git a/drivers/acpi/nfit.c b/drivers/acpi/nfit.c index 07d630e9f4ae..1f6f1b1a54f4 100644 --- a/drivers/acpi/nfit.c +++ b/drivers/acpi/nfit.c | |||
@@ -668,6 +668,20 @@ static ssize_t serial_show(struct device *dev, | |||
668 | } | 668 | } |
669 | static DEVICE_ATTR_RO(serial); | 669 | static DEVICE_ATTR_RO(serial); |
670 | 670 | ||
671 | static ssize_t flags_show(struct device *dev, | ||
672 | struct device_attribute *attr, char *buf) | ||
673 | { | ||
674 | u16 flags = to_nfit_memdev(dev)->flags; | ||
675 | |||
676 | return sprintf(buf, "%s%s%s%s%s\n", | ||
677 | flags & ACPI_NFIT_MEM_SAVE_FAILED ? "save " : "", | ||
678 | flags & ACPI_NFIT_MEM_RESTORE_FAILED ? "restore " : "", | ||
679 | flags & ACPI_NFIT_MEM_FLUSH_FAILED ? "flush " : "", | ||
680 | flags & ACPI_NFIT_MEM_ARMED ? "arm " : "", | ||
681 | flags & ACPI_NFIT_MEM_HEALTH_OBSERVED ? "smart " : ""); | ||
682 | } | ||
683 | static DEVICE_ATTR_RO(flags); | ||
684 | |||
671 | static struct attribute *acpi_nfit_dimm_attributes[] = { | 685 | static struct attribute *acpi_nfit_dimm_attributes[] = { |
672 | &dev_attr_handle.attr, | 686 | &dev_attr_handle.attr, |
673 | &dev_attr_phys_id.attr, | 687 | &dev_attr_phys_id.attr, |
@@ -676,6 +690,7 @@ static struct attribute *acpi_nfit_dimm_attributes[] = { | |||
676 | &dev_attr_format.attr, | 690 | &dev_attr_format.attr, |
677 | &dev_attr_serial.attr, | 691 | &dev_attr_serial.attr, |
678 | &dev_attr_rev_id.attr, | 692 | &dev_attr_rev_id.attr, |
693 | &dev_attr_flags.attr, | ||
679 | NULL, | 694 | NULL, |
680 | }; | 695 | }; |
681 | 696 | ||
@@ -768,6 +783,7 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc) | |||
768 | struct nvdimm *nvdimm; | 783 | struct nvdimm *nvdimm; |
769 | unsigned long flags = 0; | 784 | unsigned long flags = 0; |
770 | u32 device_handle; | 785 | u32 device_handle; |
786 | u16 mem_flags; | ||
771 | int rc; | 787 | int rc; |
772 | 788 | ||
773 | device_handle = __to_nfit_memdev(nfit_mem)->device_handle; | 789 | device_handle = __to_nfit_memdev(nfit_mem)->device_handle; |
@@ -785,6 +801,10 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc) | |||
785 | if (nfit_mem->bdw && nfit_mem->memdev_pmem) | 801 | if (nfit_mem->bdw && nfit_mem->memdev_pmem) |
786 | flags |= NDD_ALIASING; | 802 | flags |= NDD_ALIASING; |
787 | 803 | ||
804 | mem_flags = __to_nfit_memdev(nfit_mem)->flags; | ||
805 | if (mem_flags & ACPI_NFIT_MEM_ARMED) | ||
806 | flags |= NDD_UNARMED; | ||
807 | |||
788 | rc = acpi_nfit_add_dimm(acpi_desc, nfit_mem, device_handle); | 808 | rc = acpi_nfit_add_dimm(acpi_desc, nfit_mem, device_handle); |
789 | if (rc) | 809 | if (rc) |
790 | continue; | 810 | continue; |
@@ -797,6 +817,17 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc) | |||
797 | 817 | ||
798 | nfit_mem->nvdimm = nvdimm; | 818 | nfit_mem->nvdimm = nvdimm; |
799 | dimm_count++; | 819 | dimm_count++; |
820 | |||
821 | if ((mem_flags & ACPI_NFIT_MEM_FAILED_MASK) == 0) | ||
822 | continue; | ||
823 | |||
824 | dev_info(acpi_desc->dev, "%s: failed: %s%s%s%s\n", | ||
825 | nvdimm_name(nvdimm), | ||
826 | mem_flags & ACPI_NFIT_MEM_SAVE_FAILED ? "save " : "", | ||
827 | mem_flags & ACPI_NFIT_MEM_RESTORE_FAILED ? "restore " : "", | ||
828 | mem_flags & ACPI_NFIT_MEM_FLUSH_FAILED ? "flush " : "", | ||
829 | mem_flags & ACPI_NFIT_MEM_ARMED ? "arm " : ""); | ||
830 | |||
800 | } | 831 | } |
801 | 832 | ||
802 | return nvdimm_bus_check_dimm_count(acpi_desc->nvdimm_bus, dimm_count); | 833 | return nvdimm_bus_check_dimm_count(acpi_desc->nvdimm_bus, dimm_count); |
diff --git a/drivers/acpi/nfit.h b/drivers/acpi/nfit.h index c62fffea8423..81f2e8c5a79c 100644 --- a/drivers/acpi/nfit.h +++ b/drivers/acpi/nfit.h | |||
@@ -22,6 +22,9 @@ | |||
22 | 22 | ||
23 | #define UUID_NFIT_BUS "2f10e7a4-9e91-11e4-89d3-123b93f75cba" | 23 | #define UUID_NFIT_BUS "2f10e7a4-9e91-11e4-89d3-123b93f75cba" |
24 | #define UUID_NFIT_DIMM "4309ac30-0d11-11e4-9191-0800200c9a66" | 24 | #define UUID_NFIT_DIMM "4309ac30-0d11-11e4-9191-0800200c9a66" |
25 | #define ACPI_NFIT_MEM_FAILED_MASK (ACPI_NFIT_MEM_SAVE_FAILED \ | ||
26 | | ACPI_NFIT_MEM_RESTORE_FAILED | ACPI_NFIT_MEM_FLUSH_FAILED \ | ||
27 | | ACPI_NFIT_MEM_ARMED) | ||
25 | 28 | ||
26 | enum nfit_uuids { | 29 | enum nfit_uuids { |
27 | NFIT_SPA_VOLATILE, | 30 | NFIT_SPA_VOLATILE, |
diff --git a/drivers/nvdimm/blk.c b/drivers/nvdimm/blk.c index 96ef38ceeceb..4f97b248c236 100644 --- a/drivers/nvdimm/blk.c +++ b/drivers/nvdimm/blk.c | |||
@@ -232,6 +232,7 @@ static int nd_blk_rw_bytes(struct nd_namespace_common *ndns, | |||
232 | 232 | ||
233 | static const struct block_device_operations nd_blk_fops = { | 233 | static const struct block_device_operations nd_blk_fops = { |
234 | .owner = THIS_MODULE, | 234 | .owner = THIS_MODULE, |
235 | .revalidate_disk = nvdimm_revalidate_disk, | ||
235 | }; | 236 | }; |
236 | 237 | ||
237 | static int nd_blk_attach_disk(struct nd_namespace_common *ndns, | 238 | static int nd_blk_attach_disk(struct nd_namespace_common *ndns, |
@@ -283,6 +284,7 @@ static int nd_blk_attach_disk(struct nd_namespace_common *ndns, | |||
283 | } | 284 | } |
284 | 285 | ||
285 | set_capacity(disk, available_disk_size >> SECTOR_SHIFT); | 286 | set_capacity(disk, available_disk_size >> SECTOR_SHIFT); |
287 | revalidate_disk(disk); | ||
286 | return 0; | 288 | return 0; |
287 | } | 289 | } |
288 | 290 | ||
diff --git a/drivers/nvdimm/btt.c b/drivers/nvdimm/btt.c index c02065aed03d..411c7b2bb37a 100644 --- a/drivers/nvdimm/btt.c +++ b/drivers/nvdimm/btt.c | |||
@@ -1245,6 +1245,7 @@ static const struct block_device_operations btt_fops = { | |||
1245 | .owner = THIS_MODULE, | 1245 | .owner = THIS_MODULE, |
1246 | .rw_page = btt_rw_page, | 1246 | .rw_page = btt_rw_page, |
1247 | .getgeo = btt_getgeo, | 1247 | .getgeo = btt_getgeo, |
1248 | .revalidate_disk = nvdimm_revalidate_disk, | ||
1248 | }; | 1249 | }; |
1249 | 1250 | ||
1250 | static int btt_blk_init(struct btt *btt) | 1251 | static int btt_blk_init(struct btt *btt) |
@@ -1292,6 +1293,7 @@ static int btt_blk_init(struct btt *btt) | |||
1292 | } | 1293 | } |
1293 | } | 1294 | } |
1294 | set_capacity(btt->btt_disk, btt->nlba * btt->sector_size >> 9); | 1295 | set_capacity(btt->btt_disk, btt->nlba * btt->sector_size >> 9); |
1296 | revalidate_disk(btt->btt_disk); | ||
1295 | 1297 | ||
1296 | return 0; | 1298 | return 0; |
1297 | } | 1299 | } |
@@ -1346,7 +1348,11 @@ static struct btt *btt_init(struct nd_btt *nd_btt, unsigned long long rawsize, | |||
1346 | goto out_free; | 1348 | goto out_free; |
1347 | } | 1349 | } |
1348 | 1350 | ||
1349 | if (btt->init_state != INIT_READY) { | 1351 | if (btt->init_state != INIT_READY && nd_region->ro) { |
1352 | dev_info(dev, "%s is read-only, unable to init btt metadata\n", | ||
1353 | dev_name(&nd_region->dev)); | ||
1354 | goto out_free; | ||
1355 | } else if (btt->init_state != INIT_READY) { | ||
1350 | btt->num_arenas = (rawsize / ARENA_MAX_SIZE) + | 1356 | btt->num_arenas = (rawsize / ARENA_MAX_SIZE) + |
1351 | ((rawsize % ARENA_MAX_SIZE) ? 1 : 0); | 1357 | ((rawsize % ARENA_MAX_SIZE) ? 1 : 0); |
1352 | dev_dbg(dev, "init: %d arenas for %llu rawsize\n", | 1358 | dev_dbg(dev, "init: %d arenas for %llu rawsize\n", |
@@ -1361,7 +1367,7 @@ static struct btt *btt_init(struct nd_btt *nd_btt, unsigned long long rawsize, | |||
1361 | ret = btt_meta_init(btt); | 1367 | ret = btt_meta_init(btt); |
1362 | if (ret) { | 1368 | if (ret) { |
1363 | dev_err(dev, "init: error in meta_init: %d\n", ret); | 1369 | dev_err(dev, "init: error in meta_init: %d\n", ret); |
1364 | return NULL; | 1370 | goto out_free; |
1365 | } | 1371 | } |
1366 | } | 1372 | } |
1367 | 1373 | ||
diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c index dd12f38397db..ec59f1f26d95 100644 --- a/drivers/nvdimm/bus.c +++ b/drivers/nvdimm/bus.c | |||
@@ -227,6 +227,24 @@ int __nd_driver_register(struct nd_device_driver *nd_drv, struct module *owner, | |||
227 | } | 227 | } |
228 | EXPORT_SYMBOL(__nd_driver_register); | 228 | EXPORT_SYMBOL(__nd_driver_register); |
229 | 229 | ||
230 | int nvdimm_revalidate_disk(struct gendisk *disk) | ||
231 | { | ||
232 | struct device *dev = disk->driverfs_dev; | ||
233 | struct nd_region *nd_region = to_nd_region(dev->parent); | ||
234 | const char *pol = nd_region->ro ? "only" : "write"; | ||
235 | |||
236 | if (nd_region->ro == get_disk_ro(disk)) | ||
237 | return 0; | ||
238 | |||
239 | dev_info(dev, "%s read-%s, marking %s read-%s\n", | ||
240 | dev_name(&nd_region->dev), pol, disk->disk_name, pol); | ||
241 | set_disk_ro(disk, nd_region->ro); | ||
242 | |||
243 | return 0; | ||
244 | |||
245 | } | ||
246 | EXPORT_SYMBOL(nvdimm_revalidate_disk); | ||
247 | |||
230 | static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, | 248 | static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, |
231 | char *buf) | 249 | char *buf) |
232 | { | 250 | { |
diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h index 4614b00542d1..48b09a210689 100644 --- a/drivers/nvdimm/nd.h +++ b/drivers/nvdimm/nd.h | |||
@@ -97,7 +97,7 @@ struct nd_region { | |||
97 | u16 ndr_mappings; | 97 | u16 ndr_mappings; |
98 | u64 ndr_size; | 98 | u64 ndr_size; |
99 | u64 ndr_start; | 99 | u64 ndr_start; |
100 | int id, num_lanes; | 100 | int id, num_lanes, ro; |
101 | void *provider_data; | 101 | void *provider_data; |
102 | struct nd_interleave_set *nd_set; | 102 | struct nd_interleave_set *nd_set; |
103 | struct nd_percpu_lane __percpu *lane; | 103 | struct nd_percpu_lane __percpu *lane; |
@@ -189,6 +189,7 @@ u64 nd_region_interleave_set_cookie(struct nd_region *nd_region); | |||
189 | void nvdimm_bus_lock(struct device *dev); | 189 | void nvdimm_bus_lock(struct device *dev); |
190 | void nvdimm_bus_unlock(struct device *dev); | 190 | void nvdimm_bus_unlock(struct device *dev); |
191 | bool is_nvdimm_bus_locked(struct device *dev); | 191 | bool is_nvdimm_bus_locked(struct device *dev); |
192 | int nvdimm_revalidate_disk(struct gendisk *disk); | ||
192 | void nvdimm_drvdata_release(struct kref *kref); | 193 | void nvdimm_drvdata_release(struct kref *kref); |
193 | void put_ndd(struct nvdimm_drvdata *ndd); | 194 | void put_ndd(struct nvdimm_drvdata *ndd); |
194 | int nd_label_reserve_dpa(struct nvdimm_drvdata *ndd); | 195 | int nd_label_reserve_dpa(struct nvdimm_drvdata *ndd); |
diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c index a9709db0704c..42b766f33e59 100644 --- a/drivers/nvdimm/pmem.c +++ b/drivers/nvdimm/pmem.c | |||
@@ -104,6 +104,7 @@ static const struct block_device_operations pmem_fops = { | |||
104 | .owner = THIS_MODULE, | 104 | .owner = THIS_MODULE, |
105 | .rw_page = pmem_rw_page, | 105 | .rw_page = pmem_rw_page, |
106 | .direct_access = pmem_direct_access, | 106 | .direct_access = pmem_direct_access, |
107 | .revalidate_disk = nvdimm_revalidate_disk, | ||
107 | }; | 108 | }; |
108 | 109 | ||
109 | static struct pmem_device *pmem_alloc(struct device *dev, | 110 | static struct pmem_device *pmem_alloc(struct device *dev, |
@@ -178,6 +179,7 @@ static int pmem_attach_disk(struct nd_namespace_common *ndns, | |||
178 | pmem->pmem_disk = disk; | 179 | pmem->pmem_disk = disk; |
179 | 180 | ||
180 | add_disk(disk); | 181 | add_disk(disk); |
182 | revalidate_disk(disk); | ||
181 | 183 | ||
182 | return 0; | 184 | return 0; |
183 | } | 185 | } |
diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c index 2cfb3f74bcbf..482ee3e4e04a 100644 --- a/drivers/nvdimm/region_devs.c +++ b/drivers/nvdimm/region_devs.c | |||
@@ -345,11 +345,35 @@ static ssize_t btt_seed_show(struct device *dev, | |||
345 | } | 345 | } |
346 | static DEVICE_ATTR_RO(btt_seed); | 346 | static DEVICE_ATTR_RO(btt_seed); |
347 | 347 | ||
348 | static ssize_t read_only_show(struct device *dev, | ||
349 | struct device_attribute *attr, char *buf) | ||
350 | { | ||
351 | struct nd_region *nd_region = to_nd_region(dev); | ||
352 | |||
353 | return sprintf(buf, "%d\n", nd_region->ro); | ||
354 | } | ||
355 | |||
356 | static ssize_t read_only_store(struct device *dev, | ||
357 | struct device_attribute *attr, const char *buf, size_t len) | ||
358 | { | ||
359 | bool ro; | ||
360 | int rc = strtobool(buf, &ro); | ||
361 | struct nd_region *nd_region = to_nd_region(dev); | ||
362 | |||
363 | if (rc) | ||
364 | return rc; | ||
365 | |||
366 | nd_region->ro = ro; | ||
367 | return len; | ||
368 | } | ||
369 | static DEVICE_ATTR_RW(read_only); | ||
370 | |||
348 | static struct attribute *nd_region_attributes[] = { | 371 | static struct attribute *nd_region_attributes[] = { |
349 | &dev_attr_size.attr, | 372 | &dev_attr_size.attr, |
350 | &dev_attr_nstype.attr, | 373 | &dev_attr_nstype.attr, |
351 | &dev_attr_mappings.attr, | 374 | &dev_attr_mappings.attr, |
352 | &dev_attr_btt_seed.attr, | 375 | &dev_attr_btt_seed.attr, |
376 | &dev_attr_read_only.attr, | ||
353 | &dev_attr_set_cookie.attr, | 377 | &dev_attr_set_cookie.attr, |
354 | &dev_attr_available_size.attr, | 378 | &dev_attr_available_size.attr, |
355 | &dev_attr_namespace_seed.attr, | 379 | &dev_attr_namespace_seed.attr, |
@@ -641,6 +665,7 @@ static struct nd_region *nd_region_create(struct nvdimm_bus *nvdimm_bus, | |||
641 | struct device *dev; | 665 | struct device *dev; |
642 | void *region_buf; | 666 | void *region_buf; |
643 | unsigned int i; | 667 | unsigned int i; |
668 | int ro = 0; | ||
644 | 669 | ||
645 | for (i = 0; i < ndr_desc->num_mappings; i++) { | 670 | for (i = 0; i < ndr_desc->num_mappings; i++) { |
646 | struct nd_mapping *nd_mapping = &ndr_desc->nd_mapping[i]; | 671 | struct nd_mapping *nd_mapping = &ndr_desc->nd_mapping[i]; |
@@ -652,6 +677,9 @@ static struct nd_region *nd_region_create(struct nvdimm_bus *nvdimm_bus, | |||
652 | 677 | ||
653 | return NULL; | 678 | return NULL; |
654 | } | 679 | } |
680 | |||
681 | if (nvdimm->flags & NDD_UNARMED) | ||
682 | ro = 1; | ||
655 | } | 683 | } |
656 | 684 | ||
657 | if (dev_type == &nd_blk_device_type) { | 685 | if (dev_type == &nd_blk_device_type) { |
@@ -707,6 +735,7 @@ static struct nd_region *nd_region_create(struct nvdimm_bus *nvdimm_bus, | |||
707 | nd_region->provider_data = ndr_desc->provider_data; | 735 | nd_region->provider_data = ndr_desc->provider_data; |
708 | nd_region->nd_set = ndr_desc->nd_set; | 736 | nd_region->nd_set = ndr_desc->nd_set; |
709 | nd_region->num_lanes = ndr_desc->num_lanes; | 737 | nd_region->num_lanes = ndr_desc->num_lanes; |
738 | nd_region->ro = ro; | ||
710 | ida_init(&nd_region->ns_ida); | 739 | ida_init(&nd_region->ns_ida); |
711 | ida_init(&nd_region->btt_ida); | 740 | ida_init(&nd_region->btt_ida); |
712 | dev = &nd_region->dev; | 741 | dev = &nd_region->dev; |
diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h index 7fc1b25bdb5d..dc799a29ed1a 100644 --- a/include/linux/libnvdimm.h +++ b/include/linux/libnvdimm.h | |||
@@ -21,6 +21,8 @@ | |||
21 | enum { | 21 | enum { |
22 | /* when a dimm supports both PMEM and BLK access a label is required */ | 22 | /* when a dimm supports both PMEM and BLK access a label is required */ |
23 | NDD_ALIASING = 1 << 0, | 23 | NDD_ALIASING = 1 << 0, |
24 | /* unarmed memory devices may not persist writes */ | ||
25 | NDD_UNARMED = 1 << 1, | ||
24 | 26 | ||
25 | /* need to set a limit somewhere, but yes, this is likely overkill */ | 27 | /* need to set a limit somewhere, but yes, this is likely overkill */ |
26 | ND_IOCTL_MAX_BUFLEN = SZ_4M, | 28 | ND_IOCTL_MAX_BUFLEN = SZ_4M, |
diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c index 7a4a5a5edbe4..4b69b8368de0 100644 --- a/tools/testing/nvdimm/test/nfit.c +++ b/tools/testing/nvdimm/test/nfit.c | |||
@@ -874,6 +874,9 @@ static void nfit_test1_setup(struct nfit_test *t) | |||
874 | memdev->address = 0; | 874 | memdev->address = 0; |
875 | memdev->interleave_index = 0; | 875 | memdev->interleave_index = 0; |
876 | memdev->interleave_ways = 1; | 876 | memdev->interleave_ways = 1; |
877 | memdev->flags = ACPI_NFIT_MEM_SAVE_FAILED | ACPI_NFIT_MEM_RESTORE_FAILED | ||
878 | | ACPI_NFIT_MEM_FLUSH_FAILED | ACPI_NFIT_MEM_HEALTH_OBSERVED | ||
879 | | ACPI_NFIT_MEM_ARMED; | ||
877 | 880 | ||
878 | offset += sizeof(*memdev); | 881 | offset += sizeof(*memdev); |
879 | /* dcr-descriptor0 */ | 882 | /* dcr-descriptor0 */ |