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