xref: /openbmc/linux/drivers/nvdimm/core.c (revision 9b9c2cd4)
1 /*
2  * Copyright(c) 2013-2015 Intel Corporation. All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of version 2 of the GNU General Public License as
6  * published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  */
13 #include <linux/libnvdimm.h>
14 #include <linux/export.h>
15 #include <linux/module.h>
16 #include <linux/blkdev.h>
17 #include <linux/device.h>
18 #include <linux/ctype.h>
19 #include <linux/ndctl.h>
20 #include <linux/mutex.h>
21 #include <linux/slab.h>
22 #include "nd-core.h"
23 #include "nd.h"
24 
25 LIST_HEAD(nvdimm_bus_list);
26 DEFINE_MUTEX(nvdimm_bus_list_mutex);
27 static DEFINE_IDA(nd_ida);
28 
29 void nvdimm_bus_lock(struct device *dev)
30 {
31 	struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev);
32 
33 	if (!nvdimm_bus)
34 		return;
35 	mutex_lock(&nvdimm_bus->reconfig_mutex);
36 }
37 EXPORT_SYMBOL(nvdimm_bus_lock);
38 
39 void nvdimm_bus_unlock(struct device *dev)
40 {
41 	struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev);
42 
43 	if (!nvdimm_bus)
44 		return;
45 	mutex_unlock(&nvdimm_bus->reconfig_mutex);
46 }
47 EXPORT_SYMBOL(nvdimm_bus_unlock);
48 
49 bool is_nvdimm_bus_locked(struct device *dev)
50 {
51 	struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev);
52 
53 	if (!nvdimm_bus)
54 		return false;
55 	return mutex_is_locked(&nvdimm_bus->reconfig_mutex);
56 }
57 EXPORT_SYMBOL(is_nvdimm_bus_locked);
58 
59 u64 nd_fletcher64(void *addr, size_t len, bool le)
60 {
61 	u32 *buf = addr;
62 	u32 lo32 = 0;
63 	u64 hi32 = 0;
64 	int i;
65 
66 	for (i = 0; i < len / sizeof(u32); i++) {
67 		lo32 += le ? le32_to_cpu((__le32) buf[i]) : buf[i];
68 		hi32 += lo32;
69 	}
70 
71 	return hi32 << 32 | lo32;
72 }
73 EXPORT_SYMBOL_GPL(nd_fletcher64);
74 
75 static void nvdimm_bus_release(struct device *dev)
76 {
77 	struct nvdimm_bus *nvdimm_bus;
78 
79 	nvdimm_bus = container_of(dev, struct nvdimm_bus, dev);
80 	ida_simple_remove(&nd_ida, nvdimm_bus->id);
81 	kfree(nvdimm_bus);
82 }
83 
84 struct nvdimm_bus *to_nvdimm_bus(struct device *dev)
85 {
86 	struct nvdimm_bus *nvdimm_bus;
87 
88 	nvdimm_bus = container_of(dev, struct nvdimm_bus, dev);
89 	WARN_ON(nvdimm_bus->dev.release != nvdimm_bus_release);
90 	return nvdimm_bus;
91 }
92 EXPORT_SYMBOL_GPL(to_nvdimm_bus);
93 
94 struct nvdimm_bus_descriptor *to_nd_desc(struct nvdimm_bus *nvdimm_bus)
95 {
96 	/* struct nvdimm_bus definition is private to libnvdimm */
97 	return nvdimm_bus->nd_desc;
98 }
99 EXPORT_SYMBOL_GPL(to_nd_desc);
100 
101 struct nvdimm_bus *walk_to_nvdimm_bus(struct device *nd_dev)
102 {
103 	struct device *dev;
104 
105 	for (dev = nd_dev; dev; dev = dev->parent)
106 		if (dev->release == nvdimm_bus_release)
107 			break;
108 	dev_WARN_ONCE(nd_dev, !dev, "invalid dev, not on nd bus\n");
109 	if (dev)
110 		return to_nvdimm_bus(dev);
111 	return NULL;
112 }
113 
114 static bool is_uuid_sep(char sep)
115 {
116 	if (sep == '\n' || sep == '-' || sep == ':' || sep == '\0')
117 		return true;
118 	return false;
119 }
120 
121 static int nd_uuid_parse(struct device *dev, u8 *uuid_out, const char *buf,
122 		size_t len)
123 {
124 	const char *str = buf;
125 	u8 uuid[16];
126 	int i;
127 
128 	for (i = 0; i < 16; i++) {
129 		if (!isxdigit(str[0]) || !isxdigit(str[1])) {
130 			dev_dbg(dev, "%s: pos: %d buf[%zd]: %c buf[%zd]: %c\n",
131 					__func__, i, str - buf, str[0],
132 					str + 1 - buf, str[1]);
133 			return -EINVAL;
134 		}
135 
136 		uuid[i] = (hex_to_bin(str[0]) << 4) | hex_to_bin(str[1]);
137 		str += 2;
138 		if (is_uuid_sep(*str))
139 			str++;
140 	}
141 
142 	memcpy(uuid_out, uuid, sizeof(uuid));
143 	return 0;
144 }
145 
146 /**
147  * nd_uuid_store: common implementation for writing 'uuid' sysfs attributes
148  * @dev: container device for the uuid property
149  * @uuid_out: uuid buffer to replace
150  * @buf: raw sysfs buffer to parse
151  *
152  * Enforce that uuids can only be changed while the device is disabled
153  * (driver detached)
154  * LOCKING: expects device_lock() is held on entry
155  */
156 int nd_uuid_store(struct device *dev, u8 **uuid_out, const char *buf,
157 		size_t len)
158 {
159 	u8 uuid[16];
160 	int rc;
161 
162 	if (dev->driver)
163 		return -EBUSY;
164 
165 	rc = nd_uuid_parse(dev, uuid, buf, len);
166 	if (rc)
167 		return rc;
168 
169 	kfree(*uuid_out);
170 	*uuid_out = kmemdup(uuid, sizeof(uuid), GFP_KERNEL);
171 	if (!(*uuid_out))
172 		return -ENOMEM;
173 
174 	return 0;
175 }
176 
177 ssize_t nd_sector_size_show(unsigned long current_lbasize,
178 		const unsigned long *supported, char *buf)
179 {
180 	ssize_t len = 0;
181 	int i;
182 
183 	for (i = 0; supported[i]; i++)
184 		if (current_lbasize == supported[i])
185 			len += sprintf(buf + len, "[%ld] ", supported[i]);
186 		else
187 			len += sprintf(buf + len, "%ld ", supported[i]);
188 	len += sprintf(buf + len, "\n");
189 	return len;
190 }
191 
192 ssize_t nd_sector_size_store(struct device *dev, const char *buf,
193 		unsigned long *current_lbasize, const unsigned long *supported)
194 {
195 	unsigned long lbasize;
196 	int rc, i;
197 
198 	if (dev->driver)
199 		return -EBUSY;
200 
201 	rc = kstrtoul(buf, 0, &lbasize);
202 	if (rc)
203 		return rc;
204 
205 	for (i = 0; supported[i]; i++)
206 		if (lbasize == supported[i])
207 			break;
208 
209 	if (supported[i]) {
210 		*current_lbasize = lbasize;
211 		return 0;
212 	} else {
213 		return -EINVAL;
214 	}
215 }
216 
217 void __nd_iostat_start(struct bio *bio, unsigned long *start)
218 {
219 	struct gendisk *disk = bio->bi_bdev->bd_disk;
220 	const int rw = bio_data_dir(bio);
221 	int cpu = part_stat_lock();
222 
223 	*start = jiffies;
224 	part_round_stats(cpu, &disk->part0);
225 	part_stat_inc(cpu, &disk->part0, ios[rw]);
226 	part_stat_add(cpu, &disk->part0, sectors[rw], bio_sectors(bio));
227 	part_inc_in_flight(&disk->part0, rw);
228 	part_stat_unlock();
229 }
230 EXPORT_SYMBOL(__nd_iostat_start);
231 
232 void nd_iostat_end(struct bio *bio, unsigned long start)
233 {
234 	struct gendisk *disk = bio->bi_bdev->bd_disk;
235 	unsigned long duration = jiffies - start;
236 	const int rw = bio_data_dir(bio);
237 	int cpu = part_stat_lock();
238 
239 	part_stat_add(cpu, &disk->part0, ticks[rw], duration);
240 	part_round_stats(cpu, &disk->part0);
241 	part_dec_in_flight(&disk->part0, rw);
242 	part_stat_unlock();
243 }
244 EXPORT_SYMBOL(nd_iostat_end);
245 
246 static ssize_t commands_show(struct device *dev,
247 		struct device_attribute *attr, char *buf)
248 {
249 	int cmd, len = 0;
250 	struct nvdimm_bus *nvdimm_bus = to_nvdimm_bus(dev);
251 	struct nvdimm_bus_descriptor *nd_desc = nvdimm_bus->nd_desc;
252 
253 	for_each_set_bit(cmd, &nd_desc->dsm_mask, BITS_PER_LONG)
254 		len += sprintf(buf + len, "%s ", nvdimm_bus_cmd_name(cmd));
255 	len += sprintf(buf + len, "\n");
256 	return len;
257 }
258 static DEVICE_ATTR_RO(commands);
259 
260 static const char *nvdimm_bus_provider(struct nvdimm_bus *nvdimm_bus)
261 {
262 	struct nvdimm_bus_descriptor *nd_desc = nvdimm_bus->nd_desc;
263 	struct device *parent = nvdimm_bus->dev.parent;
264 
265 	if (nd_desc->provider_name)
266 		return nd_desc->provider_name;
267 	else if (parent)
268 		return dev_name(parent);
269 	else
270 		return "unknown";
271 }
272 
273 static ssize_t provider_show(struct device *dev,
274 		struct device_attribute *attr, char *buf)
275 {
276 	struct nvdimm_bus *nvdimm_bus = to_nvdimm_bus(dev);
277 
278 	return sprintf(buf, "%s\n", nvdimm_bus_provider(nvdimm_bus));
279 }
280 static DEVICE_ATTR_RO(provider);
281 
282 static int flush_namespaces(struct device *dev, void *data)
283 {
284 	device_lock(dev);
285 	device_unlock(dev);
286 	return 0;
287 }
288 
289 static int flush_regions_dimms(struct device *dev, void *data)
290 {
291 	device_lock(dev);
292 	device_unlock(dev);
293 	device_for_each_child(dev, NULL, flush_namespaces);
294 	return 0;
295 }
296 
297 static ssize_t wait_probe_show(struct device *dev,
298 		struct device_attribute *attr, char *buf)
299 {
300 	nd_synchronize();
301 	device_for_each_child(dev, NULL, flush_regions_dimms);
302 	return sprintf(buf, "1\n");
303 }
304 static DEVICE_ATTR_RO(wait_probe);
305 
306 static struct attribute *nvdimm_bus_attributes[] = {
307 	&dev_attr_commands.attr,
308 	&dev_attr_wait_probe.attr,
309 	&dev_attr_provider.attr,
310 	NULL,
311 };
312 
313 struct attribute_group nvdimm_bus_attribute_group = {
314 	.attrs = nvdimm_bus_attributes,
315 };
316 EXPORT_SYMBOL_GPL(nvdimm_bus_attribute_group);
317 
318 struct nvdimm_bus *__nvdimm_bus_register(struct device *parent,
319 		struct nvdimm_bus_descriptor *nd_desc, struct module *module)
320 {
321 	struct nvdimm_bus *nvdimm_bus;
322 	int rc;
323 
324 	nvdimm_bus = kzalloc(sizeof(*nvdimm_bus), GFP_KERNEL);
325 	if (!nvdimm_bus)
326 		return NULL;
327 	INIT_LIST_HEAD(&nvdimm_bus->list);
328 	init_waitqueue_head(&nvdimm_bus->probe_wait);
329 	nvdimm_bus->id = ida_simple_get(&nd_ida, 0, 0, GFP_KERNEL);
330 	mutex_init(&nvdimm_bus->reconfig_mutex);
331 	if (nvdimm_bus->id < 0) {
332 		kfree(nvdimm_bus);
333 		return NULL;
334 	}
335 	nvdimm_bus->nd_desc = nd_desc;
336 	nvdimm_bus->module = module;
337 	nvdimm_bus->dev.parent = parent;
338 	nvdimm_bus->dev.release = nvdimm_bus_release;
339 	nvdimm_bus->dev.groups = nd_desc->attr_groups;
340 	dev_set_name(&nvdimm_bus->dev, "ndbus%d", nvdimm_bus->id);
341 	rc = device_register(&nvdimm_bus->dev);
342 	if (rc) {
343 		dev_dbg(&nvdimm_bus->dev, "registration failed: %d\n", rc);
344 		goto err;
345 	}
346 
347 	rc = nvdimm_bus_create_ndctl(nvdimm_bus);
348 	if (rc)
349 		goto err;
350 
351 	mutex_lock(&nvdimm_bus_list_mutex);
352 	list_add_tail(&nvdimm_bus->list, &nvdimm_bus_list);
353 	mutex_unlock(&nvdimm_bus_list_mutex);
354 
355 	return nvdimm_bus;
356  err:
357 	put_device(&nvdimm_bus->dev);
358 	return NULL;
359 }
360 EXPORT_SYMBOL_GPL(__nvdimm_bus_register);
361 
362 static int child_unregister(struct device *dev, void *data)
363 {
364 	/*
365 	 * the singular ndctl class device per bus needs to be
366 	 * "device_destroy"ed, so skip it here
367 	 *
368 	 * i.e. remove classless children
369 	 */
370 	if (dev->class)
371 		/* pass */;
372 	else
373 		nd_device_unregister(dev, ND_SYNC);
374 	return 0;
375 }
376 
377 void nvdimm_bus_unregister(struct nvdimm_bus *nvdimm_bus)
378 {
379 	if (!nvdimm_bus)
380 		return;
381 
382 	mutex_lock(&nvdimm_bus_list_mutex);
383 	list_del_init(&nvdimm_bus->list);
384 	mutex_unlock(&nvdimm_bus_list_mutex);
385 
386 	nd_synchronize();
387 	device_for_each_child(&nvdimm_bus->dev, NULL, child_unregister);
388 	nvdimm_bus_destroy_ndctl(nvdimm_bus);
389 
390 	device_unregister(&nvdimm_bus->dev);
391 }
392 EXPORT_SYMBOL_GPL(nvdimm_bus_unregister);
393 
394 #ifdef CONFIG_BLK_DEV_INTEGRITY
395 int nd_integrity_init(struct gendisk *disk, unsigned long meta_size)
396 {
397 	struct blk_integrity bi;
398 
399 	if (meta_size == 0)
400 		return 0;
401 
402 	bi.profile = NULL;
403 	bi.tuple_size = meta_size;
404 	bi.tag_size = meta_size;
405 
406 	blk_integrity_register(disk, &bi);
407 	blk_queue_max_integrity_segments(disk->queue, 1);
408 
409 	return 0;
410 }
411 EXPORT_SYMBOL(nd_integrity_init);
412 
413 #else /* CONFIG_BLK_DEV_INTEGRITY */
414 int nd_integrity_init(struct gendisk *disk, unsigned long meta_size)
415 {
416 	return 0;
417 }
418 EXPORT_SYMBOL(nd_integrity_init);
419 
420 #endif
421 
422 static __init int libnvdimm_init(void)
423 {
424 	int rc;
425 
426 	rc = nvdimm_bus_init();
427 	if (rc)
428 		return rc;
429 	rc = nvdimm_init();
430 	if (rc)
431 		goto err_dimm;
432 	rc = nd_region_init();
433 	if (rc)
434 		goto err_region;
435 	return 0;
436  err_region:
437 	nvdimm_exit();
438  err_dimm:
439 	nvdimm_bus_exit();
440 	return rc;
441 }
442 
443 static __exit void libnvdimm_exit(void)
444 {
445 	WARN_ON(!list_empty(&nvdimm_bus_list));
446 	nd_region_exit();
447 	nvdimm_exit();
448 	nvdimm_bus_exit();
449 }
450 
451 MODULE_LICENSE("GPL v2");
452 MODULE_AUTHOR("Intel Corporation");
453 subsys_initcall(libnvdimm_init);
454 module_exit(libnvdimm_exit);
455