xref: /linux/drivers/nvdimm/pfn_devs.c (revision e1455744)
1*e1455744SDan Williams /*
2*e1455744SDan Williams  * Copyright(c) 2013-2015 Intel Corporation. All rights reserved.
3*e1455744SDan Williams  *
4*e1455744SDan Williams  * This program is free software; you can redistribute it and/or modify
5*e1455744SDan Williams  * it under the terms of version 2 of the GNU General Public License as
6*e1455744SDan Williams  * published by the Free Software Foundation.
7*e1455744SDan Williams  *
8*e1455744SDan Williams  * This program is distributed in the hope that it will be useful, but
9*e1455744SDan Williams  * WITHOUT ANY WARRANTY; without even the implied warranty of
10*e1455744SDan Williams  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11*e1455744SDan Williams  * General Public License for more details.
12*e1455744SDan Williams  */
13*e1455744SDan Williams #include <linux/blkdev.h>
14*e1455744SDan Williams #include <linux/device.h>
15*e1455744SDan Williams #include <linux/genhd.h>
16*e1455744SDan Williams #include <linux/sizes.h>
17*e1455744SDan Williams #include <linux/slab.h>
18*e1455744SDan Williams #include <linux/fs.h>
19*e1455744SDan Williams #include <linux/mm.h>
20*e1455744SDan Williams #include "nd-core.h"
21*e1455744SDan Williams #include "pfn.h"
22*e1455744SDan Williams #include "nd.h"
23*e1455744SDan Williams 
24*e1455744SDan Williams static void nd_pfn_release(struct device *dev)
25*e1455744SDan Williams {
26*e1455744SDan Williams 	struct nd_region *nd_region = to_nd_region(dev->parent);
27*e1455744SDan Williams 	struct nd_pfn *nd_pfn = to_nd_pfn(dev);
28*e1455744SDan Williams 
29*e1455744SDan Williams 	dev_dbg(dev, "%s\n", __func__);
30*e1455744SDan Williams 	nd_detach_ndns(&nd_pfn->dev, &nd_pfn->ndns);
31*e1455744SDan Williams 	ida_simple_remove(&nd_region->pfn_ida, nd_pfn->id);
32*e1455744SDan Williams 	kfree(nd_pfn->uuid);
33*e1455744SDan Williams 	kfree(nd_pfn);
34*e1455744SDan Williams }
35*e1455744SDan Williams 
36*e1455744SDan Williams static struct device_type nd_pfn_device_type = {
37*e1455744SDan Williams 	.name = "nd_pfn",
38*e1455744SDan Williams 	.release = nd_pfn_release,
39*e1455744SDan Williams };
40*e1455744SDan Williams 
41*e1455744SDan Williams bool is_nd_pfn(struct device *dev)
42*e1455744SDan Williams {
43*e1455744SDan Williams 	return dev ? dev->type == &nd_pfn_device_type : false;
44*e1455744SDan Williams }
45*e1455744SDan Williams EXPORT_SYMBOL(is_nd_pfn);
46*e1455744SDan Williams 
47*e1455744SDan Williams struct nd_pfn *to_nd_pfn(struct device *dev)
48*e1455744SDan Williams {
49*e1455744SDan Williams 	struct nd_pfn *nd_pfn = container_of(dev, struct nd_pfn, dev);
50*e1455744SDan Williams 
51*e1455744SDan Williams 	WARN_ON(!is_nd_pfn(dev));
52*e1455744SDan Williams 	return nd_pfn;
53*e1455744SDan Williams }
54*e1455744SDan Williams EXPORT_SYMBOL(to_nd_pfn);
55*e1455744SDan Williams 
56*e1455744SDan Williams static ssize_t mode_show(struct device *dev,
57*e1455744SDan Williams 		struct device_attribute *attr, char *buf)
58*e1455744SDan Williams {
59*e1455744SDan Williams 	struct nd_pfn *nd_pfn = to_nd_pfn(dev);
60*e1455744SDan Williams 
61*e1455744SDan Williams 	switch (nd_pfn->mode) {
62*e1455744SDan Williams 	case PFN_MODE_RAM:
63*e1455744SDan Williams 		return sprintf(buf, "ram\n");
64*e1455744SDan Williams 	case PFN_MODE_PMEM:
65*e1455744SDan Williams 		return sprintf(buf, "pmem\n");
66*e1455744SDan Williams 	default:
67*e1455744SDan Williams 		return sprintf(buf, "none\n");
68*e1455744SDan Williams 	}
69*e1455744SDan Williams }
70*e1455744SDan Williams 
71*e1455744SDan Williams static ssize_t mode_store(struct device *dev,
72*e1455744SDan Williams 		struct device_attribute *attr, const char *buf, size_t len)
73*e1455744SDan Williams {
74*e1455744SDan Williams 	struct nd_pfn *nd_pfn = to_nd_pfn(dev);
75*e1455744SDan Williams 	ssize_t rc = 0;
76*e1455744SDan Williams 
77*e1455744SDan Williams 	device_lock(dev);
78*e1455744SDan Williams 	nvdimm_bus_lock(dev);
79*e1455744SDan Williams 	if (dev->driver)
80*e1455744SDan Williams 		rc = -EBUSY;
81*e1455744SDan Williams 	else {
82*e1455744SDan Williams 		size_t n = len - 1;
83*e1455744SDan Williams 
84*e1455744SDan Williams 		if (strncmp(buf, "pmem\n", n) == 0
85*e1455744SDan Williams 				|| strncmp(buf, "pmem", n) == 0) {
86*e1455744SDan Williams 			/* TODO: allocate from PMEM support */
87*e1455744SDan Williams 			rc = -ENOTTY;
88*e1455744SDan Williams 		} else if (strncmp(buf, "ram\n", n) == 0
89*e1455744SDan Williams 				|| strncmp(buf, "ram", n) == 0)
90*e1455744SDan Williams 			nd_pfn->mode = PFN_MODE_RAM;
91*e1455744SDan Williams 		else if (strncmp(buf, "none\n", n) == 0
92*e1455744SDan Williams 				|| strncmp(buf, "none", n) == 0)
93*e1455744SDan Williams 			nd_pfn->mode = PFN_MODE_NONE;
94*e1455744SDan Williams 		else
95*e1455744SDan Williams 			rc = -EINVAL;
96*e1455744SDan Williams 	}
97*e1455744SDan Williams 	dev_dbg(dev, "%s: result: %zd wrote: %s%s", __func__,
98*e1455744SDan Williams 			rc, buf, buf[len - 1] == '\n' ? "" : "\n");
99*e1455744SDan Williams 	nvdimm_bus_unlock(dev);
100*e1455744SDan Williams 	device_unlock(dev);
101*e1455744SDan Williams 
102*e1455744SDan Williams 	return rc ? rc : len;
103*e1455744SDan Williams }
104*e1455744SDan Williams static DEVICE_ATTR_RW(mode);
105*e1455744SDan Williams 
106*e1455744SDan Williams static ssize_t uuid_show(struct device *dev,
107*e1455744SDan Williams 		struct device_attribute *attr, char *buf)
108*e1455744SDan Williams {
109*e1455744SDan Williams 	struct nd_pfn *nd_pfn = to_nd_pfn(dev);
110*e1455744SDan Williams 
111*e1455744SDan Williams 	if (nd_pfn->uuid)
112*e1455744SDan Williams 		return sprintf(buf, "%pUb\n", nd_pfn->uuid);
113*e1455744SDan Williams 	return sprintf(buf, "\n");
114*e1455744SDan Williams }
115*e1455744SDan Williams 
116*e1455744SDan Williams static ssize_t uuid_store(struct device *dev,
117*e1455744SDan Williams 		struct device_attribute *attr, const char *buf, size_t len)
118*e1455744SDan Williams {
119*e1455744SDan Williams 	struct nd_pfn *nd_pfn = to_nd_pfn(dev);
120*e1455744SDan Williams 	ssize_t rc;
121*e1455744SDan Williams 
122*e1455744SDan Williams 	device_lock(dev);
123*e1455744SDan Williams 	rc = nd_uuid_store(dev, &nd_pfn->uuid, buf, len);
124*e1455744SDan Williams 	dev_dbg(dev, "%s: result: %zd wrote: %s%s", __func__,
125*e1455744SDan Williams 			rc, buf, buf[len - 1] == '\n' ? "" : "\n");
126*e1455744SDan Williams 	device_unlock(dev);
127*e1455744SDan Williams 
128*e1455744SDan Williams 	return rc ? rc : len;
129*e1455744SDan Williams }
130*e1455744SDan Williams static DEVICE_ATTR_RW(uuid);
131*e1455744SDan Williams 
132*e1455744SDan Williams static ssize_t namespace_show(struct device *dev,
133*e1455744SDan Williams 		struct device_attribute *attr, char *buf)
134*e1455744SDan Williams {
135*e1455744SDan Williams 	struct nd_pfn *nd_pfn = to_nd_pfn(dev);
136*e1455744SDan Williams 	ssize_t rc;
137*e1455744SDan Williams 
138*e1455744SDan Williams 	nvdimm_bus_lock(dev);
139*e1455744SDan Williams 	rc = sprintf(buf, "%s\n", nd_pfn->ndns
140*e1455744SDan Williams 			? dev_name(&nd_pfn->ndns->dev) : "");
141*e1455744SDan Williams 	nvdimm_bus_unlock(dev);
142*e1455744SDan Williams 	return rc;
143*e1455744SDan Williams }
144*e1455744SDan Williams 
145*e1455744SDan Williams static ssize_t namespace_store(struct device *dev,
146*e1455744SDan Williams 		struct device_attribute *attr, const char *buf, size_t len)
147*e1455744SDan Williams {
148*e1455744SDan Williams 	struct nd_pfn *nd_pfn = to_nd_pfn(dev);
149*e1455744SDan Williams 	ssize_t rc;
150*e1455744SDan Williams 
151*e1455744SDan Williams 	nvdimm_bus_lock(dev);
152*e1455744SDan Williams 	device_lock(dev);
153*e1455744SDan Williams 	rc = nd_namespace_store(dev, &nd_pfn->ndns, buf, len);
154*e1455744SDan Williams 	dev_dbg(dev, "%s: result: %zd wrote: %s%s", __func__,
155*e1455744SDan Williams 			rc, buf, buf[len - 1] == '\n' ? "" : "\n");
156*e1455744SDan Williams 	device_unlock(dev);
157*e1455744SDan Williams 	nvdimm_bus_unlock(dev);
158*e1455744SDan Williams 
159*e1455744SDan Williams 	return rc;
160*e1455744SDan Williams }
161*e1455744SDan Williams static DEVICE_ATTR_RW(namespace);
162*e1455744SDan Williams 
163*e1455744SDan Williams static struct attribute *nd_pfn_attributes[] = {
164*e1455744SDan Williams 	&dev_attr_mode.attr,
165*e1455744SDan Williams 	&dev_attr_namespace.attr,
166*e1455744SDan Williams 	&dev_attr_uuid.attr,
167*e1455744SDan Williams 	NULL,
168*e1455744SDan Williams };
169*e1455744SDan Williams 
170*e1455744SDan Williams static struct attribute_group nd_pfn_attribute_group = {
171*e1455744SDan Williams 	.attrs = nd_pfn_attributes,
172*e1455744SDan Williams };
173*e1455744SDan Williams 
174*e1455744SDan Williams static const struct attribute_group *nd_pfn_attribute_groups[] = {
175*e1455744SDan Williams 	&nd_pfn_attribute_group,
176*e1455744SDan Williams 	&nd_device_attribute_group,
177*e1455744SDan Williams 	&nd_numa_attribute_group,
178*e1455744SDan Williams 	NULL,
179*e1455744SDan Williams };
180*e1455744SDan Williams 
181*e1455744SDan Williams static struct device *__nd_pfn_create(struct nd_region *nd_region,
182*e1455744SDan Williams 		u8 *uuid, enum nd_pfn_mode mode,
183*e1455744SDan Williams 		struct nd_namespace_common *ndns)
184*e1455744SDan Williams {
185*e1455744SDan Williams 	struct nd_pfn *nd_pfn;
186*e1455744SDan Williams 	struct device *dev;
187*e1455744SDan Williams 
188*e1455744SDan Williams 	/* we can only create pages for contiguous ranged of pmem */
189*e1455744SDan Williams 	if (!is_nd_pmem(&nd_region->dev))
190*e1455744SDan Williams 		return NULL;
191*e1455744SDan Williams 
192*e1455744SDan Williams 	nd_pfn = kzalloc(sizeof(*nd_pfn), GFP_KERNEL);
193*e1455744SDan Williams 	if (!nd_pfn)
194*e1455744SDan Williams 		return NULL;
195*e1455744SDan Williams 
196*e1455744SDan Williams 	nd_pfn->id = ida_simple_get(&nd_region->pfn_ida, 0, 0, GFP_KERNEL);
197*e1455744SDan Williams 	if (nd_pfn->id < 0) {
198*e1455744SDan Williams 		kfree(nd_pfn);
199*e1455744SDan Williams 		return NULL;
200*e1455744SDan Williams 	}
201*e1455744SDan Williams 
202*e1455744SDan Williams 	nd_pfn->mode = mode;
203*e1455744SDan Williams 	if (uuid)
204*e1455744SDan Williams 		uuid = kmemdup(uuid, 16, GFP_KERNEL);
205*e1455744SDan Williams 	nd_pfn->uuid = uuid;
206*e1455744SDan Williams 	dev = &nd_pfn->dev;
207*e1455744SDan Williams 	dev_set_name(dev, "pfn%d.%d", nd_region->id, nd_pfn->id);
208*e1455744SDan Williams 	dev->parent = &nd_region->dev;
209*e1455744SDan Williams 	dev->type = &nd_pfn_device_type;
210*e1455744SDan Williams 	dev->groups = nd_pfn_attribute_groups;
211*e1455744SDan Williams 	device_initialize(&nd_pfn->dev);
212*e1455744SDan Williams 	if (ndns && !__nd_attach_ndns(&nd_pfn->dev, ndns, &nd_pfn->ndns)) {
213*e1455744SDan Williams 		dev_dbg(&ndns->dev, "%s failed, already claimed by %s\n",
214*e1455744SDan Williams 				__func__, dev_name(ndns->claim));
215*e1455744SDan Williams 		put_device(dev);
216*e1455744SDan Williams 		return NULL;
217*e1455744SDan Williams 	}
218*e1455744SDan Williams 	return dev;
219*e1455744SDan Williams }
220*e1455744SDan Williams 
221*e1455744SDan Williams struct device *nd_pfn_create(struct nd_region *nd_region)
222*e1455744SDan Williams {
223*e1455744SDan Williams 	struct device *dev = __nd_pfn_create(nd_region, NULL, PFN_MODE_NONE,
224*e1455744SDan Williams 			NULL);
225*e1455744SDan Williams 
226*e1455744SDan Williams 	if (dev)
227*e1455744SDan Williams 		__nd_device_register(dev);
228*e1455744SDan Williams 	return dev;
229*e1455744SDan Williams }
230*e1455744SDan Williams 
231*e1455744SDan Williams static int nd_pfn_validate(struct nd_pfn *nd_pfn)
232*e1455744SDan Williams {
233*e1455744SDan Williams 	struct nd_namespace_common *ndns = nd_pfn->ndns;
234*e1455744SDan Williams 	struct nd_pfn_sb *pfn_sb = nd_pfn->pfn_sb;
235*e1455744SDan Williams 	struct nd_namespace_io *nsio;
236*e1455744SDan Williams 	u64 checksum, offset;
237*e1455744SDan Williams 
238*e1455744SDan Williams 	if (!pfn_sb || !ndns)
239*e1455744SDan Williams 		return -ENODEV;
240*e1455744SDan Williams 
241*e1455744SDan Williams 	if (!is_nd_pmem(nd_pfn->dev.parent))
242*e1455744SDan Williams 		return -ENODEV;
243*e1455744SDan Williams 
244*e1455744SDan Williams 	/* section alignment for simple hotplug */
245*e1455744SDan Williams 	if (nvdimm_namespace_capacity(ndns) < ND_PFN_ALIGN)
246*e1455744SDan Williams 		return -ENODEV;
247*e1455744SDan Williams 
248*e1455744SDan Williams 	if (nvdimm_read_bytes(ndns, SZ_4K, pfn_sb, sizeof(*pfn_sb)))
249*e1455744SDan Williams 		return -ENXIO;
250*e1455744SDan Williams 
251*e1455744SDan Williams 	if (memcmp(pfn_sb->signature, PFN_SIG, PFN_SIG_LEN) != 0)
252*e1455744SDan Williams 		return -ENODEV;
253*e1455744SDan Williams 
254*e1455744SDan Williams 	checksum = le64_to_cpu(pfn_sb->checksum);
255*e1455744SDan Williams 	pfn_sb->checksum = 0;
256*e1455744SDan Williams 	if (checksum != nd_sb_checksum((struct nd_gen_sb *) pfn_sb))
257*e1455744SDan Williams 		return -ENODEV;
258*e1455744SDan Williams 	pfn_sb->checksum = cpu_to_le64(checksum);
259*e1455744SDan Williams 
260*e1455744SDan Williams 	switch (le32_to_cpu(pfn_sb->mode)) {
261*e1455744SDan Williams 	case PFN_MODE_RAM:
262*e1455744SDan Williams 		break;
263*e1455744SDan Williams 	case PFN_MODE_PMEM:
264*e1455744SDan Williams 		/* TODO: allocate from PMEM support */
265*e1455744SDan Williams 		return -ENOTTY;
266*e1455744SDan Williams 	default:
267*e1455744SDan Williams 		return -ENXIO;
268*e1455744SDan Williams 	}
269*e1455744SDan Williams 
270*e1455744SDan Williams 	if (!nd_pfn->uuid) {
271*e1455744SDan Williams 		/* from probe we allocate */
272*e1455744SDan Williams 		nd_pfn->uuid = kmemdup(pfn_sb->uuid, 16, GFP_KERNEL);
273*e1455744SDan Williams 		if (!nd_pfn->uuid)
274*e1455744SDan Williams 			return -ENOMEM;
275*e1455744SDan Williams 	} else {
276*e1455744SDan Williams 		/* from init we validate */
277*e1455744SDan Williams 		if (memcmp(nd_pfn->uuid, pfn_sb->uuid, 16) != 0)
278*e1455744SDan Williams 			return -EINVAL;
279*e1455744SDan Williams 	}
280*e1455744SDan Williams 
281*e1455744SDan Williams 	/*
282*e1455744SDan Williams 	 * These warnings are verbose because they can only trigger in
283*e1455744SDan Williams 	 * the case where the physical address alignment of the
284*e1455744SDan Williams 	 * namespace has changed since the pfn superblock was
285*e1455744SDan Williams 	 * established.
286*e1455744SDan Williams 	 */
287*e1455744SDan Williams 	offset = le64_to_cpu(pfn_sb->dataoff);
288*e1455744SDan Williams 	nsio = to_nd_namespace_io(&ndns->dev);
289*e1455744SDan Williams 	if ((nsio->res.start + offset) & (ND_PFN_ALIGN - 1)) {
290*e1455744SDan Williams 		dev_err(&nd_pfn->dev,
291*e1455744SDan Williams 				"init failed: %s with offset %#llx not section aligned\n",
292*e1455744SDan Williams 				dev_name(&ndns->dev), offset);
293*e1455744SDan Williams 		return -EBUSY;
294*e1455744SDan Williams 	} else if (offset >= resource_size(&nsio->res)) {
295*e1455744SDan Williams 		dev_err(&nd_pfn->dev, "pfn array size exceeds capacity of %s\n",
296*e1455744SDan Williams 				dev_name(&ndns->dev));
297*e1455744SDan Williams 		return -EBUSY;
298*e1455744SDan Williams 	}
299*e1455744SDan Williams 
300*e1455744SDan Williams 	return 0;
301*e1455744SDan Williams }
302*e1455744SDan Williams 
303*e1455744SDan Williams int nd_pfn_probe(struct nd_namespace_common *ndns, void *drvdata)
304*e1455744SDan Williams {
305*e1455744SDan Williams 	int rc;
306*e1455744SDan Williams 	struct device *dev;
307*e1455744SDan Williams 	struct nd_pfn *nd_pfn;
308*e1455744SDan Williams 	struct nd_pfn_sb *pfn_sb;
309*e1455744SDan Williams 	struct nd_region *nd_region = to_nd_region(ndns->dev.parent);
310*e1455744SDan Williams 
311*e1455744SDan Williams 	if (ndns->force_raw)
312*e1455744SDan Williams 		return -ENODEV;
313*e1455744SDan Williams 
314*e1455744SDan Williams 	nvdimm_bus_lock(&ndns->dev);
315*e1455744SDan Williams 	dev = __nd_pfn_create(nd_region, NULL, PFN_MODE_NONE, ndns);
316*e1455744SDan Williams 	nvdimm_bus_unlock(&ndns->dev);
317*e1455744SDan Williams 	if (!dev)
318*e1455744SDan Williams 		return -ENOMEM;
319*e1455744SDan Williams 	dev_set_drvdata(dev, drvdata);
320*e1455744SDan Williams 	pfn_sb = kzalloc(sizeof(*pfn_sb), GFP_KERNEL);
321*e1455744SDan Williams 	nd_pfn = to_nd_pfn(dev);
322*e1455744SDan Williams 	nd_pfn->pfn_sb = pfn_sb;
323*e1455744SDan Williams 	rc = nd_pfn_validate(nd_pfn);
324*e1455744SDan Williams 	nd_pfn->pfn_sb = NULL;
325*e1455744SDan Williams 	kfree(pfn_sb);
326*e1455744SDan Williams 	dev_dbg(&ndns->dev, "%s: pfn: %s\n", __func__,
327*e1455744SDan Williams 			rc == 0 ? dev_name(dev) : "<none>");
328*e1455744SDan Williams 	if (rc < 0) {
329*e1455744SDan Williams 		__nd_detach_ndns(dev, &nd_pfn->ndns);
330*e1455744SDan Williams 		put_device(dev);
331*e1455744SDan Williams 	} else
332*e1455744SDan Williams 		__nd_device_register(&nd_pfn->dev);
333*e1455744SDan Williams 
334*e1455744SDan Williams 	return rc;
335*e1455744SDan Williams }
336*e1455744SDan Williams EXPORT_SYMBOL(nd_pfn_probe);
337