aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/lightnvm
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-10-07 17:42:05 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-10-07 17:42:05 -0400
commit513a4befae06c4469abfb836e8f71977de58c636 (patch)
tree18cc7d0b01a7fd2352de734e99a4ca5c29ad5fac /drivers/lightnvm
parent87840a2b7e048018d18d60bdac5c09224de85370 (diff)
parent997198ba1ed691c09457120576c27dbd953d0557 (diff)
Merge branch 'for-4.9/block' of git://git.kernel.dk/linux-block
Pull block layer updates from Jens Axboe: "This is the main pull request for block layer changes in 4.9. As mentioned at the last merge window, I've changed things up and now do just one branch for core block layer changes, and driver changes. This avoids dependencies between the two branches. Outside of this main pull request, there are two topical branches coming as well. This pull request contains: - A set of fixes, and a conversion to blk-mq, of nbd. From Josef. - Set of fixes and updates for lightnvm from Matias, Simon, and Arnd. Followup dependency fix from Geert. - General fixes from Bart, Baoyou, Guoqing, and Linus W. - CFQ async write starvation fix from Glauber. - Add supprot for delayed kick of the requeue list, from Mike. - Pull out the scalable bitmap code from blk-mq-tag.c and make it generally available under the name of sbitmap. Only blk-mq-tag uses it for now, but the blk-mq scheduling bits will use it as well. From Omar. - bdev thaw error progagation from Pierre. - Improve the blk polling statistics, and allow the user to clear them. From Stephen. - Set of minor cleanups from Christoph in block/blk-mq. - Set of cleanups and optimizations from me for block/blk-mq. - Various nvme/nvmet/nvmeof fixes from the various folks" * 'for-4.9/block' of git://git.kernel.dk/linux-block: (54 commits) fs/block_dev.c: return the right error in thaw_bdev() nvme: Pass pointers, not dma addresses, to nvme_get/set_features() nvme/scsi: Remove power management support nvmet: Make dsm number of ranges zero based nvmet: Use direct IO for writes admin-cmd: Added smart-log command support. nvme-fabrics: Add host_traddr options field to host infrastructure nvme-fabrics: revise host transport option descriptions nvme-fabrics: rework nvmf_get_address() for variable options nbd: use BLK_MQ_F_BLOCKING blkcg: Annotate blkg_hint correctly cfq: fix starvation of asynchronous writes blk-mq: add flag for drivers wanting blocking ->queue_rq() blk-mq: remove non-blocking pass in blk_mq_map_request blk-mq: get rid of manual run of queue with __blk_mq_run_hw_queue() block: export bio_free_pages to other modules lightnvm: propagate device_add() error code lightnvm: expose device geometry through sysfs lightnvm: control life of nvm_dev in driver blk-mq: register device instead of disk ...
Diffstat (limited to 'drivers/lightnvm')
-rw-r--r--drivers/lightnvm/Kconfig2
-rw-r--r--drivers/lightnvm/Makefile2
-rw-r--r--drivers/lightnvm/core.c55
-rw-r--r--drivers/lightnvm/lightnvm.h35
-rw-r--r--drivers/lightnvm/sysfs.c198
5 files changed, 258 insertions, 34 deletions
diff --git a/drivers/lightnvm/Kconfig b/drivers/lightnvm/Kconfig
index 61c68a1f054a..2f5d5f4a4c75 100644
--- a/drivers/lightnvm/Kconfig
+++ b/drivers/lightnvm/Kconfig
@@ -4,7 +4,7 @@
4 4
5menuconfig NVM 5menuconfig NVM
6 bool "Open-Channel SSD target support" 6 bool "Open-Channel SSD target support"
7 depends on BLOCK 7 depends on BLOCK && HAS_DMA
8 help 8 help
9 Say Y here to get to enable Open-channel SSDs. 9 Say Y here to get to enable Open-channel SSDs.
10 10
diff --git a/drivers/lightnvm/Makefile b/drivers/lightnvm/Makefile
index a7a0a22cf1a5..1f6b6521016a 100644
--- a/drivers/lightnvm/Makefile
+++ b/drivers/lightnvm/Makefile
@@ -2,6 +2,6 @@
2# Makefile for Open-Channel SSDs. 2# Makefile for Open-Channel SSDs.
3# 3#
4 4
5obj-$(CONFIG_NVM) := core.o sysblk.o 5obj-$(CONFIG_NVM) := core.o sysblk.o sysfs.o
6obj-$(CONFIG_NVM_GENNVM) += gennvm.o 6obj-$(CONFIG_NVM_GENNVM) += gennvm.o
7obj-$(CONFIG_NVM_RRPC) += rrpc.o 7obj-$(CONFIG_NVM_RRPC) += rrpc.o
diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c
index c784ddcd4405..1cac0f8bc0dc 100644
--- a/drivers/lightnvm/core.c
+++ b/drivers/lightnvm/core.c
@@ -27,6 +27,8 @@
27#include <linux/lightnvm.h> 27#include <linux/lightnvm.h>
28#include <linux/sched/sysctl.h> 28#include <linux/sched/sysctl.h>
29 29
30#include "lightnvm.h"
31
30static LIST_HEAD(nvm_tgt_types); 32static LIST_HEAD(nvm_tgt_types);
31static DECLARE_RWSEM(nvm_tgtt_lock); 33static DECLARE_RWSEM(nvm_tgtt_lock);
32static LIST_HEAD(nvm_mgrs); 34static LIST_HEAD(nvm_mgrs);
@@ -581,6 +583,8 @@ static int nvm_core_init(struct nvm_dev *dev)
581 mutex_init(&dev->mlock); 583 mutex_init(&dev->mlock);
582 spin_lock_init(&dev->lock); 584 spin_lock_init(&dev->lock);
583 585
586 blk_queue_logical_block_size(dev->q, dev->sec_size);
587
584 return 0; 588 return 0;
585err_fmtype: 589err_fmtype:
586 kfree(dev->lun_map); 590 kfree(dev->lun_map);
@@ -596,15 +600,19 @@ static void nvm_free_mgr(struct nvm_dev *dev)
596 dev->mt = NULL; 600 dev->mt = NULL;
597} 601}
598 602
599static void nvm_free(struct nvm_dev *dev) 603void nvm_free(struct nvm_dev *dev)
600{ 604{
601 if (!dev) 605 if (!dev)
602 return; 606 return;
603 607
604 nvm_free_mgr(dev); 608 nvm_free_mgr(dev);
605 609
610 if (dev->dma_pool)
611 dev->ops->destroy_dma_pool(dev->dma_pool);
612
606 kfree(dev->lptbl); 613 kfree(dev->lptbl);
607 kfree(dev->lun_map); 614 kfree(dev->lun_map);
615 kfree(dev);
608} 616}
609 617
610static int nvm_init(struct nvm_dev *dev) 618static int nvm_init(struct nvm_dev *dev)
@@ -651,30 +659,19 @@ err:
651 659
652static void nvm_exit(struct nvm_dev *dev) 660static void nvm_exit(struct nvm_dev *dev)
653{ 661{
654 if (dev->dma_pool) 662 nvm_sysfs_unregister_dev(dev);
655 dev->ops->destroy_dma_pool(dev->dma_pool); 663}
656 nvm_free(dev);
657 664
658 pr_info("nvm: successfully unloaded\n"); 665struct nvm_dev *nvm_alloc_dev(int node)
666{
667 return kzalloc_node(sizeof(struct nvm_dev), GFP_KERNEL, node);
659} 668}
669EXPORT_SYMBOL(nvm_alloc_dev);
660 670
661int nvm_register(struct request_queue *q, char *disk_name, 671int nvm_register(struct nvm_dev *dev)
662 struct nvm_dev_ops *ops)
663{ 672{
664 struct nvm_dev *dev;
665 int ret; 673 int ret;
666 674
667 if (!ops->identity)
668 return -EINVAL;
669
670 dev = kzalloc(sizeof(struct nvm_dev), GFP_KERNEL);
671 if (!dev)
672 return -ENOMEM;
673
674 dev->q = q;
675 dev->ops = ops;
676 strncpy(dev->name, disk_name, DISK_NAME_LEN);
677
678 ret = nvm_init(dev); 675 ret = nvm_init(dev);
679 if (ret) 676 if (ret)
680 goto err_init; 677 goto err_init;
@@ -694,6 +691,10 @@ int nvm_register(struct request_queue *q, char *disk_name,
694 } 691 }
695 } 692 }
696 693
694 ret = nvm_sysfs_register_dev(dev);
695 if (ret)
696 goto err_ppalist;
697
697 if (dev->identity.cap & NVM_ID_DCAP_BBLKMGMT) { 698 if (dev->identity.cap & NVM_ID_DCAP_BBLKMGMT) {
698 ret = nvm_get_sysblock(dev, &dev->sb); 699 ret = nvm_get_sysblock(dev, &dev->sb);
699 if (!ret) 700 if (!ret)
@@ -710,31 +711,21 @@ int nvm_register(struct request_queue *q, char *disk_name,
710 up_write(&nvm_lock); 711 up_write(&nvm_lock);
711 712
712 return 0; 713 return 0;
714err_ppalist:
715 dev->ops->destroy_dma_pool(dev->dma_pool);
713err_init: 716err_init:
714 kfree(dev->lun_map); 717 kfree(dev->lun_map);
715 kfree(dev);
716 return ret; 718 return ret;
717} 719}
718EXPORT_SYMBOL(nvm_register); 720EXPORT_SYMBOL(nvm_register);
719 721
720void nvm_unregister(char *disk_name) 722void nvm_unregister(struct nvm_dev *dev)
721{ 723{
722 struct nvm_dev *dev;
723
724 down_write(&nvm_lock); 724 down_write(&nvm_lock);
725 dev = nvm_find_nvm_dev(disk_name);
726 if (!dev) {
727 pr_err("nvm: could not find device %s to unregister\n",
728 disk_name);
729 up_write(&nvm_lock);
730 return;
731 }
732
733 list_del(&dev->devices); 725 list_del(&dev->devices);
734 up_write(&nvm_lock); 726 up_write(&nvm_lock);
735 727
736 nvm_exit(dev); 728 nvm_exit(dev);
737 kfree(dev);
738} 729}
739EXPORT_SYMBOL(nvm_unregister); 730EXPORT_SYMBOL(nvm_unregister);
740 731
diff --git a/drivers/lightnvm/lightnvm.h b/drivers/lightnvm/lightnvm.h
new file mode 100644
index 000000000000..305c181509a6
--- /dev/null
+++ b/drivers/lightnvm/lightnvm.h
@@ -0,0 +1,35 @@
1/*
2 * Copyright (C) 2016 CNEX Labs. All rights reserved.
3 * Initial release: Matias Bjorling <matias@cnexlabs.com>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License version
7 * 2 as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; see the file COPYING. If not, write to
16 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
17 * USA.
18 *
19 */
20
21#ifndef LIGHTNVM_H
22#define LIGHTNVM_H
23
24#include <linux/lightnvm.h>
25
26/* core -> sysfs.c */
27int __must_check nvm_sysfs_register_dev(struct nvm_dev *);
28void nvm_sysfs_unregister_dev(struct nvm_dev *);
29int nvm_sysfs_register(void);
30void nvm_sysfs_unregister(void);
31
32/* sysfs > core */
33void nvm_free(struct nvm_dev *);
34
35#endif
diff --git a/drivers/lightnvm/sysfs.c b/drivers/lightnvm/sysfs.c
new file mode 100644
index 000000000000..0338c27ab95a
--- /dev/null
+++ b/drivers/lightnvm/sysfs.c
@@ -0,0 +1,198 @@
1#include <linux/kernel.h>
2#include <linux/lightnvm.h>
3#include <linux/miscdevice.h>
4#include <linux/kobject.h>
5#include <linux/blk-mq.h>
6
7#include "lightnvm.h"
8
9static ssize_t nvm_dev_attr_show(struct device *dev,
10 struct device_attribute *dattr, char *page)
11{
12 struct nvm_dev *ndev = container_of(dev, struct nvm_dev, dev);
13 struct nvm_id *id = &ndev->identity;
14 struct nvm_id_group *grp = &id->groups[0];
15 struct attribute *attr = &dattr->attr;
16
17 if (strcmp(attr->name, "version") == 0) {
18 return scnprintf(page, PAGE_SIZE, "%u\n", id->ver_id);
19 } else if (strcmp(attr->name, "vendor_opcode") == 0) {
20 return scnprintf(page, PAGE_SIZE, "%u\n", id->vmnt);
21 } else if (strcmp(attr->name, "capabilities") == 0) {
22 return scnprintf(page, PAGE_SIZE, "%u\n", id->cap);
23 } else if (strcmp(attr->name, "device_mode") == 0) {
24 return scnprintf(page, PAGE_SIZE, "%u\n", id->dom);
25 } else if (strcmp(attr->name, "media_manager") == 0) {
26 if (!ndev->mt)
27 return scnprintf(page, PAGE_SIZE, "%s\n", "none");
28 return scnprintf(page, PAGE_SIZE, "%s\n", ndev->mt->name);
29 } else if (strcmp(attr->name, "ppa_format") == 0) {
30 return scnprintf(page, PAGE_SIZE,
31 "0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
32 id->ppaf.ch_offset, id->ppaf.ch_len,
33 id->ppaf.lun_offset, id->ppaf.lun_len,
34 id->ppaf.pln_offset, id->ppaf.pln_len,
35 id->ppaf.blk_offset, id->ppaf.blk_len,
36 id->ppaf.pg_offset, id->ppaf.pg_len,
37 id->ppaf.sect_offset, id->ppaf.sect_len);
38 } else if (strcmp(attr->name, "media_type") == 0) { /* u8 */
39 return scnprintf(page, PAGE_SIZE, "%u\n", grp->mtype);
40 } else if (strcmp(attr->name, "flash_media_type") == 0) {
41 return scnprintf(page, PAGE_SIZE, "%u\n", grp->fmtype);
42 } else if (strcmp(attr->name, "num_channels") == 0) {
43 return scnprintf(page, PAGE_SIZE, "%u\n", grp->num_ch);
44 } else if (strcmp(attr->name, "num_luns") == 0) {
45 return scnprintf(page, PAGE_SIZE, "%u\n", grp->num_lun);
46 } else if (strcmp(attr->name, "num_planes") == 0) {
47 return scnprintf(page, PAGE_SIZE, "%u\n", grp->num_pln);
48 } else if (strcmp(attr->name, "num_blocks") == 0) { /* u16 */
49 return scnprintf(page, PAGE_SIZE, "%u\n", grp->num_blk);
50 } else if (strcmp(attr->name, "num_pages") == 0) {
51 return scnprintf(page, PAGE_SIZE, "%u\n", grp->num_pg);
52 } else if (strcmp(attr->name, "page_size") == 0) {
53 return scnprintf(page, PAGE_SIZE, "%u\n", grp->fpg_sz);
54 } else if (strcmp(attr->name, "hw_sector_size") == 0) {
55 return scnprintf(page, PAGE_SIZE, "%u\n", grp->csecs);
56 } else if (strcmp(attr->name, "oob_sector_size") == 0) {/* u32 */
57 return scnprintf(page, PAGE_SIZE, "%u\n", grp->sos);
58 } else if (strcmp(attr->name, "read_typ") == 0) {
59 return scnprintf(page, PAGE_SIZE, "%u\n", grp->trdt);
60 } else if (strcmp(attr->name, "read_max") == 0) {
61 return scnprintf(page, PAGE_SIZE, "%u\n", grp->trdm);
62 } else if (strcmp(attr->name, "prog_typ") == 0) {
63 return scnprintf(page, PAGE_SIZE, "%u\n", grp->tprt);
64 } else if (strcmp(attr->name, "prog_max") == 0) {
65 return scnprintf(page, PAGE_SIZE, "%u\n", grp->tprm);
66 } else if (strcmp(attr->name, "erase_typ") == 0) {
67 return scnprintf(page, PAGE_SIZE, "%u\n", grp->tbet);
68 } else if (strcmp(attr->name, "erase_max") == 0) {
69 return scnprintf(page, PAGE_SIZE, "%u\n", grp->tbem);
70 } else if (strcmp(attr->name, "multiplane_modes") == 0) {
71 return scnprintf(page, PAGE_SIZE, "0x%08x\n", grp->mpos);
72 } else if (strcmp(attr->name, "media_capabilities") == 0) {
73 return scnprintf(page, PAGE_SIZE, "0x%08x\n", grp->mccap);
74 } else if (strcmp(attr->name, "max_phys_secs") == 0) {
75 return scnprintf(page, PAGE_SIZE, "%u\n",
76 ndev->ops->max_phys_sect);
77 } else {
78 return scnprintf(page,
79 PAGE_SIZE,
80 "Unhandled attr(%s) in `nvm_dev_attr_show`\n",
81 attr->name);
82 }
83}
84
85#define NVM_DEV_ATTR_RO(_name) \
86 DEVICE_ATTR(_name, S_IRUGO, nvm_dev_attr_show, NULL)
87
88static NVM_DEV_ATTR_RO(version);
89static NVM_DEV_ATTR_RO(vendor_opcode);
90static NVM_DEV_ATTR_RO(capabilities);
91static NVM_DEV_ATTR_RO(device_mode);
92static NVM_DEV_ATTR_RO(ppa_format);
93static NVM_DEV_ATTR_RO(media_manager);
94
95static NVM_DEV_ATTR_RO(media_type);
96static NVM_DEV_ATTR_RO(flash_media_type);
97static NVM_DEV_ATTR_RO(num_channels);
98static NVM_DEV_ATTR_RO(num_luns);
99static NVM_DEV_ATTR_RO(num_planes);
100static NVM_DEV_ATTR_RO(num_blocks);
101static NVM_DEV_ATTR_RO(num_pages);
102static NVM_DEV_ATTR_RO(page_size);
103static NVM_DEV_ATTR_RO(hw_sector_size);
104static NVM_DEV_ATTR_RO(oob_sector_size);
105static NVM_DEV_ATTR_RO(read_typ);
106static NVM_DEV_ATTR_RO(read_max);
107static NVM_DEV_ATTR_RO(prog_typ);
108static NVM_DEV_ATTR_RO(prog_max);
109static NVM_DEV_ATTR_RO(erase_typ);
110static NVM_DEV_ATTR_RO(erase_max);
111static NVM_DEV_ATTR_RO(multiplane_modes);
112static NVM_DEV_ATTR_RO(media_capabilities);
113static NVM_DEV_ATTR_RO(max_phys_secs);
114
115#define NVM_DEV_ATTR(_name) (dev_attr_##_name##)
116
117static struct attribute *nvm_dev_attrs[] = {
118 &dev_attr_version.attr,
119 &dev_attr_vendor_opcode.attr,
120 &dev_attr_capabilities.attr,
121 &dev_attr_device_mode.attr,
122 &dev_attr_media_manager.attr,
123
124 &dev_attr_ppa_format.attr,
125 &dev_attr_media_type.attr,
126 &dev_attr_flash_media_type.attr,
127 &dev_attr_num_channels.attr,
128 &dev_attr_num_luns.attr,
129 &dev_attr_num_planes.attr,
130 &dev_attr_num_blocks.attr,
131 &dev_attr_num_pages.attr,
132 &dev_attr_page_size.attr,
133 &dev_attr_hw_sector_size.attr,
134 &dev_attr_oob_sector_size.attr,
135 &dev_attr_read_typ.attr,
136 &dev_attr_read_max.attr,
137 &dev_attr_prog_typ.attr,
138 &dev_attr_prog_max.attr,
139 &dev_attr_erase_typ.attr,
140 &dev_attr_erase_max.attr,
141 &dev_attr_multiplane_modes.attr,
142 &dev_attr_media_capabilities.attr,
143 &dev_attr_max_phys_secs.attr,
144 NULL,
145};
146
147static struct attribute_group nvm_dev_attr_group = {
148 .name = "lightnvm",
149 .attrs = nvm_dev_attrs,
150};
151
152static const struct attribute_group *nvm_dev_attr_groups[] = {
153 &nvm_dev_attr_group,
154 NULL,
155};
156
157static void nvm_dev_release(struct device *device)
158{
159 struct nvm_dev *dev = container_of(device, struct nvm_dev, dev);
160 struct request_queue *q = dev->q;
161
162 pr_debug("nvm/sysfs: `nvm_dev_release`\n");
163
164 blk_mq_unregister_dev(device, q);
165
166 nvm_free(dev);
167}
168
169static struct device_type nvm_type = {
170 .name = "lightnvm",
171 .groups = nvm_dev_attr_groups,
172 .release = nvm_dev_release,
173};
174
175int nvm_sysfs_register_dev(struct nvm_dev *dev)
176{
177 int ret;
178
179 if (!dev->parent_dev)
180 return 0;
181
182 dev->dev.parent = dev->parent_dev;
183 dev_set_name(&dev->dev, "%s", dev->name);
184 dev->dev.type = &nvm_type;
185 device_initialize(&dev->dev);
186 ret = device_add(&dev->dev);
187
188 if (!ret)
189 blk_mq_register_dev(&dev->dev, dev->q);
190
191 return ret;
192}
193
194void nvm_sysfs_unregister_dev(struct nvm_dev *dev)
195{
196 if (dev && dev->parent_dev)
197 kobject_put(&dev->dev.kobj);
198}