libnvdimm, pmem: add libnvdimm support to the pmem driver
[deliverable/linux.git] / drivers / nvdimm / bus.c
CommitLineData
45def22c
DW
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#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
62232e45 14#include <linux/vmalloc.h>
45def22c 15#include <linux/uaccess.h>
3d88002e 16#include <linux/module.h>
45def22c 17#include <linux/fcntl.h>
e6dfb2de 18#include <linux/async.h>
62232e45 19#include <linux/ndctl.h>
4d88a97a 20#include <linux/sched.h>
45def22c
DW
21#include <linux/slab.h>
22#include <linux/fs.h>
23#include <linux/io.h>
62232e45 24#include <linux/mm.h>
4d88a97a 25#include <linux/nd.h>
45def22c 26#include "nd-core.h"
4d88a97a 27#include "nd.h"
45def22c 28
62232e45 29int nvdimm_major;
45def22c
DW
30static int nvdimm_bus_major;
31static struct class *nd_class;
32
4d88a97a
DW
33static int to_nd_device_type(struct device *dev)
34{
35 if (is_nvdimm(dev))
36 return ND_DEVICE_DIMM;
3d88002e
DW
37 else if (is_nd_pmem(dev))
38 return ND_DEVICE_REGION_PMEM;
39 else if (is_nd_blk(dev))
40 return ND_DEVICE_REGION_BLK;
41 else if (is_nd_pmem(dev->parent) || is_nd_blk(dev->parent))
42 return nd_region_to_nstype(to_nd_region(dev->parent));
4d88a97a
DW
43
44 return 0;
45}
46
47static int nvdimm_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
48{
49 return add_uevent_var(env, "MODALIAS=" ND_DEVICE_MODALIAS_FMT,
50 to_nd_device_type(dev));
51}
52
53static int nvdimm_bus_match(struct device *dev, struct device_driver *drv)
54{
55 struct nd_device_driver *nd_drv = to_nd_device_driver(drv);
56
57 return test_bit(to_nd_device_type(dev), &nd_drv->type);
58}
59
3d88002e
DW
60static struct module *to_bus_provider(struct device *dev)
61{
62 /* pin bus providers while regions are enabled */
63 if (is_nd_pmem(dev) || is_nd_blk(dev)) {
64 struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev);
65
66 return nvdimm_bus->module;
67 }
68 return NULL;
69}
70
4d88a97a
DW
71static int nvdimm_bus_probe(struct device *dev)
72{
73 struct nd_device_driver *nd_drv = to_nd_device_driver(dev->driver);
3d88002e 74 struct module *provider = to_bus_provider(dev);
4d88a97a
DW
75 struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev);
76 int rc;
77
3d88002e
DW
78 if (!try_module_get(provider))
79 return -ENXIO;
80
4d88a97a
DW
81 rc = nd_drv->probe(dev);
82 dev_dbg(&nvdimm_bus->dev, "%s.probe(%s) = %d\n", dev->driver->name,
83 dev_name(dev), rc);
3d88002e
DW
84 if (rc != 0)
85 module_put(provider);
4d88a97a
DW
86 return rc;
87}
88
89static int nvdimm_bus_remove(struct device *dev)
90{
91 struct nd_device_driver *nd_drv = to_nd_device_driver(dev->driver);
3d88002e 92 struct module *provider = to_bus_provider(dev);
4d88a97a
DW
93 struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev);
94 int rc;
95
96 rc = nd_drv->remove(dev);
97 dev_dbg(&nvdimm_bus->dev, "%s.remove(%s) = %d\n", dev->driver->name,
98 dev_name(dev), rc);
3d88002e 99 module_put(provider);
4d88a97a
DW
100 return rc;
101}
102
103static struct bus_type nvdimm_bus_type = {
e6dfb2de 104 .name = "nd",
4d88a97a
DW
105 .uevent = nvdimm_bus_uevent,
106 .match = nvdimm_bus_match,
107 .probe = nvdimm_bus_probe,
108 .remove = nvdimm_bus_remove,
109};
110
111static ASYNC_DOMAIN_EXCLUSIVE(nd_async_domain);
112
113void nd_synchronize(void)
114{
115 async_synchronize_full_domain(&nd_async_domain);
116}
117EXPORT_SYMBOL_GPL(nd_synchronize);
118
119static void nd_async_device_register(void *d, async_cookie_t cookie)
120{
121 struct device *dev = d;
122
123 if (device_add(dev) != 0) {
124 dev_err(dev, "%s: failed\n", __func__);
125 put_device(dev);
126 }
127 put_device(dev);
128}
129
130static void nd_async_device_unregister(void *d, async_cookie_t cookie)
131{
132 struct device *dev = d;
133
134 device_unregister(dev);
135 put_device(dev);
136}
137
138void nd_device_register(struct device *dev)
139{
140 dev->bus = &nvdimm_bus_type;
141 device_initialize(dev);
142 get_device(dev);
143 async_schedule_domain(nd_async_device_register, dev,
144 &nd_async_domain);
145}
146EXPORT_SYMBOL(nd_device_register);
147
148void nd_device_unregister(struct device *dev, enum nd_async_mode mode)
149{
150 switch (mode) {
151 case ND_ASYNC:
152 get_device(dev);
153 async_schedule_domain(nd_async_device_unregister, dev,
154 &nd_async_domain);
155 break;
156 case ND_SYNC:
157 nd_synchronize();
158 device_unregister(dev);
159 break;
160 }
161}
162EXPORT_SYMBOL(nd_device_unregister);
163
164/**
165 * __nd_driver_register() - register a region or a namespace driver
166 * @nd_drv: driver to register
167 * @owner: automatically set by nd_driver_register() macro
168 * @mod_name: automatically set by nd_driver_register() macro
169 */
170int __nd_driver_register(struct nd_device_driver *nd_drv, struct module *owner,
171 const char *mod_name)
172{
173 struct device_driver *drv = &nd_drv->drv;
174
175 if (!nd_drv->type) {
176 pr_debug("driver type bitmask not set (%pf)\n",
177 __builtin_return_address(0));
178 return -EINVAL;
179 }
180
181 if (!nd_drv->probe || !nd_drv->remove) {
182 pr_debug("->probe() and ->remove() must be specified\n");
183 return -EINVAL;
184 }
185
186 drv->bus = &nvdimm_bus_type;
187 drv->owner = owner;
188 drv->mod_name = mod_name;
189
190 return driver_register(drv);
191}
192EXPORT_SYMBOL(__nd_driver_register);
193
194static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
195 char *buf)
196{
197 return sprintf(buf, ND_DEVICE_MODALIAS_FMT "\n",
198 to_nd_device_type(dev));
199}
200static DEVICE_ATTR_RO(modalias);
201
202static ssize_t devtype_show(struct device *dev, struct device_attribute *attr,
203 char *buf)
204{
205 return sprintf(buf, "%s\n", dev->type->name);
206}
207static DEVICE_ATTR_RO(devtype);
208
209static struct attribute *nd_device_attributes[] = {
210 &dev_attr_modalias.attr,
211 &dev_attr_devtype.attr,
212 NULL,
213};
214
215/**
216 * nd_device_attribute_group - generic attributes for all devices on an nd bus
217 */
218struct attribute_group nd_device_attribute_group = {
219 .attrs = nd_device_attributes,
e6dfb2de 220};
4d88a97a 221EXPORT_SYMBOL_GPL(nd_device_attribute_group);
e6dfb2de 222
45def22c
DW
223int nvdimm_bus_create_ndctl(struct nvdimm_bus *nvdimm_bus)
224{
225 dev_t devt = MKDEV(nvdimm_bus_major, nvdimm_bus->id);
226 struct device *dev;
227
228 dev = device_create(nd_class, &nvdimm_bus->dev, devt, nvdimm_bus,
229 "ndctl%d", nvdimm_bus->id);
230
231 if (IS_ERR(dev)) {
232 dev_dbg(&nvdimm_bus->dev, "failed to register ndctl%d: %ld\n",
233 nvdimm_bus->id, PTR_ERR(dev));
234 return PTR_ERR(dev);
235 }
236 return 0;
237}
238
239void nvdimm_bus_destroy_ndctl(struct nvdimm_bus *nvdimm_bus)
240{
241 device_destroy(nd_class, MKDEV(nvdimm_bus_major, nvdimm_bus->id));
242}
243
62232e45
DW
244static const struct nd_cmd_desc __nd_cmd_dimm_descs[] = {
245 [ND_CMD_IMPLEMENTED] = { },
246 [ND_CMD_SMART] = {
247 .out_num = 2,
248 .out_sizes = { 4, 8, },
249 },
250 [ND_CMD_SMART_THRESHOLD] = {
251 .out_num = 2,
252 .out_sizes = { 4, 8, },
253 },
254 [ND_CMD_DIMM_FLAGS] = {
255 .out_num = 2,
256 .out_sizes = { 4, 4 },
257 },
258 [ND_CMD_GET_CONFIG_SIZE] = {
259 .out_num = 3,
260 .out_sizes = { 4, 4, 4, },
261 },
262 [ND_CMD_GET_CONFIG_DATA] = {
263 .in_num = 2,
264 .in_sizes = { 4, 4, },
265 .out_num = 2,
266 .out_sizes = { 4, UINT_MAX, },
267 },
268 [ND_CMD_SET_CONFIG_DATA] = {
269 .in_num = 3,
270 .in_sizes = { 4, 4, UINT_MAX, },
271 .out_num = 1,
272 .out_sizes = { 4, },
273 },
274 [ND_CMD_VENDOR] = {
275 .in_num = 3,
276 .in_sizes = { 4, 4, UINT_MAX, },
277 .out_num = 3,
278 .out_sizes = { 4, 4, UINT_MAX, },
279 },
280};
281
282const struct nd_cmd_desc *nd_cmd_dimm_desc(int cmd)
283{
284 if (cmd < ARRAY_SIZE(__nd_cmd_dimm_descs))
285 return &__nd_cmd_dimm_descs[cmd];
286 return NULL;
287}
288EXPORT_SYMBOL_GPL(nd_cmd_dimm_desc);
289
290static const struct nd_cmd_desc __nd_cmd_bus_descs[] = {
291 [ND_CMD_IMPLEMENTED] = { },
292 [ND_CMD_ARS_CAP] = {
293 .in_num = 2,
294 .in_sizes = { 8, 8, },
295 .out_num = 2,
296 .out_sizes = { 4, 4, },
297 },
298 [ND_CMD_ARS_START] = {
299 .in_num = 4,
300 .in_sizes = { 8, 8, 2, 6, },
301 .out_num = 1,
302 .out_sizes = { 4, },
303 },
304 [ND_CMD_ARS_STATUS] = {
305 .out_num = 2,
306 .out_sizes = { 4, UINT_MAX, },
307 },
308};
309
310const struct nd_cmd_desc *nd_cmd_bus_desc(int cmd)
311{
312 if (cmd < ARRAY_SIZE(__nd_cmd_bus_descs))
313 return &__nd_cmd_bus_descs[cmd];
314 return NULL;
315}
316EXPORT_SYMBOL_GPL(nd_cmd_bus_desc);
317
318u32 nd_cmd_in_size(struct nvdimm *nvdimm, int cmd,
319 const struct nd_cmd_desc *desc, int idx, void *buf)
320{
321 if (idx >= desc->in_num)
322 return UINT_MAX;
323
324 if (desc->in_sizes[idx] < UINT_MAX)
325 return desc->in_sizes[idx];
326
327 if (nvdimm && cmd == ND_CMD_SET_CONFIG_DATA && idx == 2) {
328 struct nd_cmd_set_config_hdr *hdr = buf;
329
330 return hdr->in_length;
331 } else if (nvdimm && cmd == ND_CMD_VENDOR && idx == 2) {
332 struct nd_cmd_vendor_hdr *hdr = buf;
333
334 return hdr->in_length;
335 }
336
337 return UINT_MAX;
338}
339EXPORT_SYMBOL_GPL(nd_cmd_in_size);
340
341u32 nd_cmd_out_size(struct nvdimm *nvdimm, int cmd,
342 const struct nd_cmd_desc *desc, int idx, const u32 *in_field,
343 const u32 *out_field)
344{
345 if (idx >= desc->out_num)
346 return UINT_MAX;
347
348 if (desc->out_sizes[idx] < UINT_MAX)
349 return desc->out_sizes[idx];
350
351 if (nvdimm && cmd == ND_CMD_GET_CONFIG_DATA && idx == 1)
352 return in_field[1];
353 else if (nvdimm && cmd == ND_CMD_VENDOR && idx == 2)
354 return out_field[1];
355 else if (!nvdimm && cmd == ND_CMD_ARS_STATUS && idx == 1)
356 return ND_CMD_ARS_STATUS_MAX;
357
358 return UINT_MAX;
359}
360EXPORT_SYMBOL_GPL(nd_cmd_out_size);
361
362static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm,
363 int read_only, unsigned int ioctl_cmd, unsigned long arg)
364{
365 struct nvdimm_bus_descriptor *nd_desc = nvdimm_bus->nd_desc;
366 size_t buf_len = 0, in_len = 0, out_len = 0;
367 static char out_env[ND_CMD_MAX_ENVELOPE];
368 static char in_env[ND_CMD_MAX_ENVELOPE];
369 const struct nd_cmd_desc *desc = NULL;
370 unsigned int cmd = _IOC_NR(ioctl_cmd);
371 void __user *p = (void __user *) arg;
372 struct device *dev = &nvdimm_bus->dev;
373 const char *cmd_name, *dimm_name;
374 unsigned long dsm_mask;
375 void *buf;
376 int rc, i;
377
378 if (nvdimm) {
379 desc = nd_cmd_dimm_desc(cmd);
380 cmd_name = nvdimm_cmd_name(cmd);
381 dsm_mask = nvdimm->dsm_mask ? *(nvdimm->dsm_mask) : 0;
382 dimm_name = dev_name(&nvdimm->dev);
383 } else {
384 desc = nd_cmd_bus_desc(cmd);
385 cmd_name = nvdimm_bus_cmd_name(cmd);
386 dsm_mask = nd_desc->dsm_mask;
387 dimm_name = "bus";
388 }
389
390 if (!desc || (desc->out_num + desc->in_num == 0) ||
391 !test_bit(cmd, &dsm_mask))
392 return -ENOTTY;
393
394 /* fail write commands (when read-only) */
395 if (read_only)
396 switch (ioctl_cmd) {
397 case ND_IOCTL_VENDOR:
398 case ND_IOCTL_SET_CONFIG_DATA:
399 case ND_IOCTL_ARS_START:
400 dev_dbg(&nvdimm_bus->dev, "'%s' command while read-only.\n",
401 nvdimm ? nvdimm_cmd_name(cmd)
402 : nvdimm_bus_cmd_name(cmd));
403 return -EPERM;
404 default:
405 break;
406 }
407
408 /* process an input envelope */
409 for (i = 0; i < desc->in_num; i++) {
410 u32 in_size, copy;
411
412 in_size = nd_cmd_in_size(nvdimm, cmd, desc, i, in_env);
413 if (in_size == UINT_MAX) {
414 dev_err(dev, "%s:%s unknown input size cmd: %s field: %d\n",
415 __func__, dimm_name, cmd_name, i);
416 return -ENXIO;
417 }
418 if (!access_ok(VERIFY_READ, p + in_len, in_size))
419 return -EFAULT;
420 if (in_len < sizeof(in_env))
421 copy = min_t(u32, sizeof(in_env) - in_len, in_size);
422 else
423 copy = 0;
424 if (copy && copy_from_user(&in_env[in_len], p + in_len, copy))
425 return -EFAULT;
426 in_len += in_size;
427 }
428
429 /* process an output envelope */
430 for (i = 0; i < desc->out_num; i++) {
431 u32 out_size = nd_cmd_out_size(nvdimm, cmd, desc, i,
432 (u32 *) in_env, (u32 *) out_env);
433 u32 copy;
434
435 if (out_size == UINT_MAX) {
436 dev_dbg(dev, "%s:%s unknown output size cmd: %s field: %d\n",
437 __func__, dimm_name, cmd_name, i);
438 return -EFAULT;
439 }
440 if (!access_ok(VERIFY_WRITE, p + in_len + out_len, out_size))
441 return -EFAULT;
442 if (out_len < sizeof(out_env))
443 copy = min_t(u32, sizeof(out_env) - out_len, out_size);
444 else
445 copy = 0;
446 if (copy && copy_from_user(&out_env[out_len],
447 p + in_len + out_len, copy))
448 return -EFAULT;
449 out_len += out_size;
450 }
451
452 buf_len = out_len + in_len;
453 if (!access_ok(VERIFY_WRITE, p, sizeof(buf_len)))
454 return -EFAULT;
455
456 if (buf_len > ND_IOCTL_MAX_BUFLEN) {
457 dev_dbg(dev, "%s:%s cmd: %s buf_len: %zu > %d\n", __func__,
458 dimm_name, cmd_name, buf_len,
459 ND_IOCTL_MAX_BUFLEN);
460 return -EINVAL;
461 }
462
463 buf = vmalloc(buf_len);
464 if (!buf)
465 return -ENOMEM;
466
467 if (copy_from_user(buf, p, buf_len)) {
468 rc = -EFAULT;
469 goto out;
470 }
471
472 rc = nd_desc->ndctl(nd_desc, nvdimm, cmd, buf, buf_len);
473 if (rc < 0)
474 goto out;
475 if (copy_to_user(p, buf, buf_len))
476 rc = -EFAULT;
477 out:
478 vfree(buf);
479 return rc;
480}
481
45def22c
DW
482static long nd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
483{
62232e45
DW
484 long id = (long) file->private_data;
485 int rc = -ENXIO, read_only;
486 struct nvdimm_bus *nvdimm_bus;
487
488 read_only = (O_RDWR != (file->f_flags & O_ACCMODE));
489 mutex_lock(&nvdimm_bus_list_mutex);
490 list_for_each_entry(nvdimm_bus, &nvdimm_bus_list, list) {
491 if (nvdimm_bus->id == id) {
492 rc = __nd_ioctl(nvdimm_bus, NULL, read_only, cmd, arg);
493 break;
494 }
495 }
496 mutex_unlock(&nvdimm_bus_list_mutex);
497
498 return rc;
499}
500
501static int match_dimm(struct device *dev, void *data)
502{
503 long id = (long) data;
504
505 if (is_nvdimm(dev)) {
506 struct nvdimm *nvdimm = to_nvdimm(dev);
507
508 return nvdimm->id == id;
509 }
510
511 return 0;
512}
513
514static long nvdimm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
515{
516 int rc = -ENXIO, read_only;
517 struct nvdimm_bus *nvdimm_bus;
518
519 read_only = (O_RDWR != (file->f_flags & O_ACCMODE));
520 mutex_lock(&nvdimm_bus_list_mutex);
521 list_for_each_entry(nvdimm_bus, &nvdimm_bus_list, list) {
522 struct device *dev = device_find_child(&nvdimm_bus->dev,
523 file->private_data, match_dimm);
524 struct nvdimm *nvdimm;
525
526 if (!dev)
527 continue;
528
529 nvdimm = to_nvdimm(dev);
530 rc = __nd_ioctl(nvdimm_bus, nvdimm, read_only, cmd, arg);
531 put_device(dev);
532 break;
533 }
534 mutex_unlock(&nvdimm_bus_list_mutex);
535
536 return rc;
537}
538
539static int nd_open(struct inode *inode, struct file *file)
540{
541 long minor = iminor(inode);
542
543 file->private_data = (void *) minor;
544 return 0;
45def22c
DW
545}
546
547static const struct file_operations nvdimm_bus_fops = {
548 .owner = THIS_MODULE,
62232e45 549 .open = nd_open,
45def22c
DW
550 .unlocked_ioctl = nd_ioctl,
551 .compat_ioctl = nd_ioctl,
552 .llseek = noop_llseek,
553};
554
62232e45
DW
555static const struct file_operations nvdimm_fops = {
556 .owner = THIS_MODULE,
557 .open = nd_open,
558 .unlocked_ioctl = nvdimm_ioctl,
559 .compat_ioctl = nvdimm_ioctl,
560 .llseek = noop_llseek,
561};
562
45def22c
DW
563int __init nvdimm_bus_init(void)
564{
565 int rc;
566
e6dfb2de
DW
567 rc = bus_register(&nvdimm_bus_type);
568 if (rc)
569 return rc;
570
45def22c
DW
571 rc = register_chrdev(0, "ndctl", &nvdimm_bus_fops);
572 if (rc < 0)
62232e45 573 goto err_bus_chrdev;
45def22c
DW
574 nvdimm_bus_major = rc;
575
62232e45
DW
576 rc = register_chrdev(0, "dimmctl", &nvdimm_fops);
577 if (rc < 0)
578 goto err_dimm_chrdev;
579 nvdimm_major = rc;
580
45def22c
DW
581 nd_class = class_create(THIS_MODULE, "nd");
582 if (IS_ERR(nd_class))
583 goto err_class;
584
585 return 0;
586
587 err_class:
62232e45
DW
588 unregister_chrdev(nvdimm_major, "dimmctl");
589 err_dimm_chrdev:
45def22c 590 unregister_chrdev(nvdimm_bus_major, "ndctl");
62232e45 591 err_bus_chrdev:
e6dfb2de 592 bus_unregister(&nvdimm_bus_type);
45def22c
DW
593
594 return rc;
595}
596
4d88a97a 597void nvdimm_bus_exit(void)
45def22c
DW
598{
599 class_destroy(nd_class);
600 unregister_chrdev(nvdimm_bus_major, "ndctl");
62232e45 601 unregister_chrdev(nvdimm_major, "dimmctl");
e6dfb2de 602 bus_unregister(&nvdimm_bus_type);
45def22c 603}
This page took 0.080989 seconds and 5 git commands to generate.