Blame view
drivers/nvdimm/btt_devs.c
8.92 KB
5b497af42 treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-only |
8c2f7e865 libnvdimm: infras... |
2 3 |
/* * Copyright(c) 2013-2015 Intel Corporation. All rights reserved. |
8c2f7e865 libnvdimm: infras... |
4 5 6 7 8 9 10 11 12 13 14 |
*/ #include <linux/blkdev.h> #include <linux/device.h> #include <linux/genhd.h> #include <linux/sizes.h> #include <linux/slab.h> #include <linux/fs.h> #include <linux/mm.h> #include "nd-core.h" #include "btt.h" #include "nd.h" |
8c2f7e865 libnvdimm: infras... |
15 16 17 18 |
static void nd_btt_release(struct device *dev) { struct nd_region *nd_region = to_nd_region(dev->parent); struct nd_btt *nd_btt = to_nd_btt(dev); |
426824d63 libnvdimm: remove... |
19 20 |
dev_dbg(dev, "trace "); |
e1455744b libnvdimm, pfn: '... |
21 |
nd_detach_ndns(&nd_btt->dev, &nd_btt->ndns); |
8c2f7e865 libnvdimm: infras... |
22 23 24 25 |
ida_simple_remove(&nd_region->btt_ida, nd_btt->id); kfree(nd_btt->uuid); kfree(nd_btt); } |
8c2f7e865 libnvdimm: infras... |
26 27 28 29 30 31 32 33 |
struct nd_btt *to_nd_btt(struct device *dev) { struct nd_btt *nd_btt = container_of(dev, struct nd_btt, dev); WARN_ON(!is_nd_btt(dev)); return nd_btt; } EXPORT_SYMBOL(to_nd_btt); |
41cd8b70c libnvdimm, btt: a... |
34 35 |
static const unsigned long btt_lbasize_supported[] = { 512, 520, 528, 4096, 4104, 4160, 4224, 0 }; |
8c2f7e865 libnvdimm: infras... |
36 37 38 39 40 |
static ssize_t sector_size_show(struct device *dev, struct device_attribute *attr, char *buf) { struct nd_btt *nd_btt = to_nd_btt(dev); |
b2c48f9f9 libnvdimm: rename... |
41 |
return nd_size_select_show(nd_btt->lbasize, btt_lbasize_supported, buf); |
8c2f7e865 libnvdimm: infras... |
42 43 44 45 46 47 48 |
} static ssize_t sector_size_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { struct nd_btt *nd_btt = to_nd_btt(dev); ssize_t rc; |
87a30e1f0 driver-core, libn... |
49 |
nd_device_lock(dev); |
8c2f7e865 libnvdimm: infras... |
50 |
nvdimm_bus_lock(dev); |
b2c48f9f9 libnvdimm: rename... |
51 |
rc = nd_size_select_store(dev, buf, &nd_btt->lbasize, |
8c2f7e865 libnvdimm: infras... |
52 |
btt_lbasize_supported); |
426824d63 libnvdimm: remove... |
53 54 55 56 |
dev_dbg(dev, "result: %zd wrote: %s%s", rc, buf, buf[len - 1] == ' ' ? "" : " "); |
8c2f7e865 libnvdimm: infras... |
57 |
nvdimm_bus_unlock(dev); |
87a30e1f0 driver-core, libn... |
58 |
nd_device_unlock(dev); |
8c2f7e865 libnvdimm: infras... |
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
return rc ? rc : len; } static DEVICE_ATTR_RW(sector_size); static ssize_t uuid_show(struct device *dev, struct device_attribute *attr, char *buf) { struct nd_btt *nd_btt = to_nd_btt(dev); if (nd_btt->uuid) return sprintf(buf, "%pUb ", nd_btt->uuid); return sprintf(buf, " "); } static ssize_t uuid_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { struct nd_btt *nd_btt = to_nd_btt(dev); ssize_t rc; |
87a30e1f0 driver-core, libn... |
81 |
nd_device_lock(dev); |
8c2f7e865 libnvdimm: infras... |
82 |
rc = nd_uuid_store(dev, &nd_btt->uuid, buf, len); |
426824d63 libnvdimm: remove... |
83 84 85 86 |
dev_dbg(dev, "result: %zd wrote: %s%s", rc, buf, buf[len - 1] == ' ' ? "" : " "); |
87a30e1f0 driver-core, libn... |
87 |
nd_device_unlock(dev); |
8c2f7e865 libnvdimm: infras... |
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
return rc ? rc : len; } static DEVICE_ATTR_RW(uuid); static ssize_t namespace_show(struct device *dev, struct device_attribute *attr, char *buf) { struct nd_btt *nd_btt = to_nd_btt(dev); ssize_t rc; nvdimm_bus_lock(dev); rc = sprintf(buf, "%s ", nd_btt->ndns ? dev_name(&nd_btt->ndns->dev) : ""); nvdimm_bus_unlock(dev); return rc; } |
8c2f7e865 libnvdimm: infras... |
106 107 108 |
static ssize_t namespace_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { |
e1455744b libnvdimm, pfn: '... |
109 |
struct nd_btt *nd_btt = to_nd_btt(dev); |
8c2f7e865 libnvdimm: infras... |
110 |
ssize_t rc; |
87a30e1f0 driver-core, libn... |
111 |
nd_device_lock(dev); |
4be9c1fc3 libnvdimm: btt_de... |
112 |
nvdimm_bus_lock(dev); |
e1455744b libnvdimm, pfn: '... |
113 |
rc = nd_namespace_store(dev, &nd_btt->ndns, buf, len); |
426824d63 libnvdimm: remove... |
114 115 116 117 |
dev_dbg(dev, "result: %zd wrote: %s%s", rc, buf, buf[len - 1] == ' ' ? "" : " "); |
8c2f7e865 libnvdimm: infras... |
118 |
nvdimm_bus_unlock(dev); |
87a30e1f0 driver-core, libn... |
119 |
nd_device_unlock(dev); |
8c2f7e865 libnvdimm: infras... |
120 121 122 123 |
return rc; } static DEVICE_ATTR_RW(namespace); |
abe8b4e3c nvdimm, btt: add ... |
124 125 126 127 128 |
static ssize_t size_show(struct device *dev, struct device_attribute *attr, char *buf) { struct nd_btt *nd_btt = to_nd_btt(dev); ssize_t rc; |
87a30e1f0 driver-core, libn... |
129 |
nd_device_lock(dev); |
abe8b4e3c nvdimm, btt: add ... |
130 131 132 133 134 135 136 |
if (dev->driver) rc = sprintf(buf, "%llu ", nd_btt->size); else { /* no size to convey if the btt instance is disabled */ rc = -ENXIO; } |
87a30e1f0 driver-core, libn... |
137 |
nd_device_unlock(dev); |
abe8b4e3c nvdimm, btt: add ... |
138 139 140 141 |
return rc; } static DEVICE_ATTR_RO(size); |
9dedc73a4 libnvdimm/btt: Fi... |
142 143 144 145 146 147 148 |
static ssize_t log_zero_flags_show(struct device *dev, struct device_attribute *attr, char *buf) { return sprintf(buf, "Y "); } static DEVICE_ATTR_RO(log_zero_flags); |
8c2f7e865 libnvdimm: infras... |
149 150 151 152 |
static struct attribute *nd_btt_attributes[] = { &dev_attr_sector_size.attr, &dev_attr_namespace.attr, &dev_attr_uuid.attr, |
abe8b4e3c nvdimm, btt: add ... |
153 |
&dev_attr_size.attr, |
9dedc73a4 libnvdimm/btt: Fi... |
154 |
&dev_attr_log_zero_flags.attr, |
8c2f7e865 libnvdimm: infras... |
155 156 157 158 159 160 161 162 163 164 |
NULL, }; static struct attribute_group nd_btt_attribute_group = { .attrs = nd_btt_attributes, }; static const struct attribute_group *nd_btt_attribute_groups[] = { &nd_btt_attribute_group, &nd_device_attribute_group, |
74ae66c3b libnvdimm: Add sy... |
165 |
&nd_numa_attribute_group, |
8c2f7e865 libnvdimm: infras... |
166 167 |
NULL, }; |
78c81cc89 libnvdimm: Move a... |
168 169 170 171 172 173 174 175 176 177 178 |
static const struct device_type nd_btt_device_type = { .name = "nd_btt", .release = nd_btt_release, .groups = nd_btt_attribute_groups, }; bool is_nd_btt(struct device *dev) { return dev->type == &nd_btt_device_type; } EXPORT_SYMBOL(is_nd_btt); |
8c2f7e865 libnvdimm: infras... |
179 180 181 182 183 184 185 186 187 188 189 190 |
static struct device *__nd_btt_create(struct nd_region *nd_region, unsigned long lbasize, u8 *uuid, struct nd_namespace_common *ndns) { struct nd_btt *nd_btt; struct device *dev; nd_btt = kzalloc(sizeof(*nd_btt), GFP_KERNEL); if (!nd_btt) return NULL; nd_btt->id = ida_simple_get(&nd_region->btt_ida, 0, 0, GFP_KERNEL); |
486fa92df libnvdimm/btt: Fi... |
191 192 |
if (nd_btt->id < 0) goto out_nd_btt; |
8c2f7e865 libnvdimm: infras... |
193 194 |
nd_btt->lbasize = lbasize; |
486fa92df libnvdimm/btt: Fi... |
195 |
if (uuid) { |
8c2f7e865 libnvdimm: infras... |
196 |
uuid = kmemdup(uuid, 16, GFP_KERNEL); |
486fa92df libnvdimm/btt: Fi... |
197 198 199 |
if (!uuid) goto out_put_id; } |
8c2f7e865 libnvdimm: infras... |
200 201 202 203 204 |
nd_btt->uuid = uuid; dev = &nd_btt->dev; dev_set_name(dev, "btt%d.%d", nd_region->id, nd_btt->id); dev->parent = &nd_region->dev; dev->type = &nd_btt_device_type; |
8c2f7e865 libnvdimm: infras... |
205 |
device_initialize(&nd_btt->dev); |
e1455744b libnvdimm, pfn: '... |
206 |
if (ndns && !__nd_attach_ndns(&nd_btt->dev, ndns, &nd_btt->ndns)) { |
426824d63 libnvdimm: remove... |
207 208 209 |
dev_dbg(&ndns->dev, "failed, already claimed by %s ", dev_name(ndns->claim)); |
8c2f7e865 libnvdimm: infras... |
210 211 212 213 |
put_device(dev); return NULL; } return dev; |
486fa92df libnvdimm/btt: Fi... |
214 215 216 217 218 219 220 |
out_put_id: ida_simple_remove(&nd_region->btt_ida, nd_btt->id); out_nd_btt: kfree(nd_btt); return NULL; |
8c2f7e865 libnvdimm: infras... |
221 222 223 224 225 |
} struct device *nd_btt_create(struct nd_region *nd_region) { struct device *dev = __nd_btt_create(nd_region, 0, NULL, NULL); |
d4c5725d5 libnvdimm-btt: De... |
226 |
__nd_device_register(dev); |
8c2f7e865 libnvdimm: infras... |
227 228 |
return dev; } |
ab45e7632 libnvdimm, btt: c... |
229 230 231 232 233 234 |
/** * nd_btt_arena_is_valid - check if the metadata layout is valid * @nd_btt: device with BTT geometry and backing device info * @super: pointer to the arena's info block being tested * * Check consistency of the btt info block with itself by validating |
6ec689542 libnvdimm, btt: w... |
235 236 |
* the checksum, and with the parent namespace by verifying the * parent_uuid contained in the info block with the one supplied in. |
ab45e7632 libnvdimm, btt: c... |
237 238 239 240 241 242 |
* * Returns: * false for an invalid info block, true for a valid one */ bool nd_btt_arena_is_valid(struct nd_btt *nd_btt, struct btt_sb *super) { |
6ec689542 libnvdimm, btt: w... |
243 |
const u8 *parent_uuid = nd_dev_to_uuid(&nd_btt->ndns->dev); |
ab45e7632 libnvdimm, btt: c... |
244 245 246 247 |
u64 checksum; if (memcmp(super->signature, BTT_SIG, BTT_SIG_LEN) != 0) return false; |
ef40dda5b uuid: hoist uuid_... |
248 |
if (!guid_is_null((guid_t *)&super->parent_uuid)) |
6ec689542 libnvdimm, btt: w... |
249 250 |
if (memcmp(super->parent_uuid, parent_uuid, 16) != 0) return false; |
ab45e7632 libnvdimm, btt: c... |
251 252 |
checksum = le64_to_cpu(super->checksum); super->checksum = 0; |
e1455744b libnvdimm, pfn: '... |
253 |
if (checksum != nd_sb_checksum((struct nd_gen_sb *) super)) |
ab45e7632 libnvdimm, btt: c... |
254 255 256 257 258 259 260 261 262 263 264 |
return false; super->checksum = cpu_to_le64(checksum); /* TODO: figure out action for this */ if ((le32_to_cpu(super->flags) & IB_FLAG_ERROR_MASK) != 0) dev_info(&nd_btt->dev, "Found arena with an error flag "); return true; } EXPORT_SYMBOL(nd_btt_arena_is_valid); |
14e494542 libnvdimm, btt: B... |
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 |
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); |
8c2f7e865 libnvdimm: infras... |
299 300 301 |
static int __nd_btt_probe(struct nd_btt *nd_btt, struct nd_namespace_common *ndns, struct btt_sb *btt_sb) { |
14e494542 libnvdimm, btt: B... |
302 |
int rc; |
8c2f7e865 libnvdimm: infras... |
303 304 |
if (!btt_sb || !ndns || !nd_btt) return -ENODEV; |
8c2f7e865 libnvdimm: infras... |
305 306 |
if (nvdimm_namespace_capacity(ndns) < SZ_16M) return -ENXIO; |
14e494542 libnvdimm, btt: B... |
307 308 309 |
rc = nd_btt_version(nd_btt, ndns, btt_sb); if (rc < 0) return rc; |
8c2f7e865 libnvdimm: infras... |
310 311 312 313 314 315 316 317 318 319 |
nd_btt->lbasize = le32_to_cpu(btt_sb->external_lbasize); nd_btt->uuid = kmemdup(btt_sb->uuid, 16, GFP_KERNEL); if (!nd_btt->uuid) return -ENOMEM; __nd_device_register(&nd_btt->dev); return 0; } |
200c79da8 libnvdimm, pmem, ... |
320 |
int nd_btt_probe(struct device *dev, struct nd_namespace_common *ndns) |
8c2f7e865 libnvdimm: infras... |
321 322 |
{ int rc; |
e32bc729a libnvdimm, btt, c... |
323 |
struct device *btt_dev; |
8c2f7e865 libnvdimm: infras... |
324 325 326 327 328 |
struct btt_sb *btt_sb; struct nd_region *nd_region = to_nd_region(ndns->dev.parent); if (ndns->force_raw) return -ENODEV; |
b3fde74ea libnvdimm, label:... |
329 330 331 |
switch (ndns->claim_class) { case NVDIMM_CCLASS_NONE: case NVDIMM_CCLASS_BTT: |
14e494542 libnvdimm, btt: B... |
332 |
case NVDIMM_CCLASS_BTT2: |
b3fde74ea libnvdimm, label:... |
333 334 335 336 |
break; default: return -ENODEV; } |
8c2f7e865 libnvdimm: infras... |
337 |
nvdimm_bus_lock(&ndns->dev); |
e32bc729a libnvdimm, btt, c... |
338 |
btt_dev = __nd_btt_create(nd_region, 0, NULL, ndns); |
8c2f7e865 libnvdimm: infras... |
339 |
nvdimm_bus_unlock(&ndns->dev); |
e32bc729a libnvdimm, btt, c... |
340 |
if (!btt_dev) |
8c2f7e865 libnvdimm: infras... |
341 |
return -ENOMEM; |
e32bc729a libnvdimm, btt, c... |
342 343 |
btt_sb = devm_kzalloc(dev, sizeof(*btt_sb), GFP_KERNEL); rc = __nd_btt_probe(to_nd_btt(btt_dev), ndns, btt_sb); |
426824d63 libnvdimm: remove... |
344 345 |
dev_dbg(dev, "btt: %s ", rc == 0 ? dev_name(btt_dev) : "<none>"); |
8c2f7e865 libnvdimm: infras... |
346 |
if (rc < 0) { |
e32bc729a libnvdimm, btt, c... |
347 |
struct nd_btt *nd_btt = to_nd_btt(btt_dev); |
e1455744b libnvdimm, pfn: '... |
348 |
|
452bae0ae libnvdimm: fix nv... |
349 |
nd_detach_ndns(btt_dev, &nd_btt->ndns); |
e32bc729a libnvdimm, btt, c... |
350 |
put_device(btt_dev); |
8c2f7e865 libnvdimm: infras... |
351 352 353 354 355 |
} return rc; } EXPORT_SYMBOL(nd_btt_probe); |