18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright(c) 2013-2015 Intel Corporation. All rights reserved. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci#include <linux/blkdev.h> 68c2ecf20Sopenharmony_ci#include <linux/device.h> 78c2ecf20Sopenharmony_ci#include <linux/genhd.h> 88c2ecf20Sopenharmony_ci#include <linux/sizes.h> 98c2ecf20Sopenharmony_ci#include <linux/slab.h> 108c2ecf20Sopenharmony_ci#include <linux/fs.h> 118c2ecf20Sopenharmony_ci#include <linux/mm.h> 128c2ecf20Sopenharmony_ci#include "nd-core.h" 138c2ecf20Sopenharmony_ci#include "btt.h" 148c2ecf20Sopenharmony_ci#include "nd.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_cistatic void nd_btt_release(struct device *dev) 178c2ecf20Sopenharmony_ci{ 188c2ecf20Sopenharmony_ci struct nd_region *nd_region = to_nd_region(dev->parent); 198c2ecf20Sopenharmony_ci struct nd_btt *nd_btt = to_nd_btt(dev); 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci dev_dbg(dev, "trace\n"); 228c2ecf20Sopenharmony_ci nd_detach_ndns(&nd_btt->dev, &nd_btt->ndns); 238c2ecf20Sopenharmony_ci ida_simple_remove(&nd_region->btt_ida, nd_btt->id); 248c2ecf20Sopenharmony_ci kfree(nd_btt->uuid); 258c2ecf20Sopenharmony_ci kfree(nd_btt); 268c2ecf20Sopenharmony_ci} 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistruct nd_btt *to_nd_btt(struct device *dev) 298c2ecf20Sopenharmony_ci{ 308c2ecf20Sopenharmony_ci struct nd_btt *nd_btt = container_of(dev, struct nd_btt, dev); 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci WARN_ON(!is_nd_btt(dev)); 338c2ecf20Sopenharmony_ci return nd_btt; 348c2ecf20Sopenharmony_ci} 358c2ecf20Sopenharmony_ciEXPORT_SYMBOL(to_nd_btt); 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic const unsigned long btt_lbasize_supported[] = { 512, 520, 528, 388c2ecf20Sopenharmony_ci 4096, 4104, 4160, 4224, 0 }; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic ssize_t sector_size_show(struct device *dev, 418c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci struct nd_btt *nd_btt = to_nd_btt(dev); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci return nd_size_select_show(nd_btt->lbasize, btt_lbasize_supported, buf); 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic ssize_t sector_size_store(struct device *dev, 498c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t len) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci struct nd_btt *nd_btt = to_nd_btt(dev); 528c2ecf20Sopenharmony_ci ssize_t rc; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci nd_device_lock(dev); 558c2ecf20Sopenharmony_ci nvdimm_bus_lock(dev); 568c2ecf20Sopenharmony_ci rc = nd_size_select_store(dev, buf, &nd_btt->lbasize, 578c2ecf20Sopenharmony_ci btt_lbasize_supported); 588c2ecf20Sopenharmony_ci dev_dbg(dev, "result: %zd wrote: %s%s", rc, buf, 598c2ecf20Sopenharmony_ci buf[len - 1] == '\n' ? "" : "\n"); 608c2ecf20Sopenharmony_ci nvdimm_bus_unlock(dev); 618c2ecf20Sopenharmony_ci nd_device_unlock(dev); 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci return rc ? rc : len; 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(sector_size); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic ssize_t uuid_show(struct device *dev, 688c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci struct nd_btt *nd_btt = to_nd_btt(dev); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci if (nd_btt->uuid) 738c2ecf20Sopenharmony_ci return sprintf(buf, "%pUb\n", nd_btt->uuid); 748c2ecf20Sopenharmony_ci return sprintf(buf, "\n"); 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic ssize_t uuid_store(struct device *dev, 788c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t len) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci struct nd_btt *nd_btt = to_nd_btt(dev); 818c2ecf20Sopenharmony_ci ssize_t rc; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci nd_device_lock(dev); 848c2ecf20Sopenharmony_ci rc = nd_uuid_store(dev, &nd_btt->uuid, buf, len); 858c2ecf20Sopenharmony_ci dev_dbg(dev, "result: %zd wrote: %s%s", rc, buf, 868c2ecf20Sopenharmony_ci buf[len - 1] == '\n' ? "" : "\n"); 878c2ecf20Sopenharmony_ci nd_device_unlock(dev); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci return rc ? rc : len; 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(uuid); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic ssize_t namespace_show(struct device *dev, 948c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci struct nd_btt *nd_btt = to_nd_btt(dev); 978c2ecf20Sopenharmony_ci ssize_t rc; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci nvdimm_bus_lock(dev); 1008c2ecf20Sopenharmony_ci rc = sprintf(buf, "%s\n", nd_btt->ndns 1018c2ecf20Sopenharmony_ci ? dev_name(&nd_btt->ndns->dev) : ""); 1028c2ecf20Sopenharmony_ci nvdimm_bus_unlock(dev); 1038c2ecf20Sopenharmony_ci return rc; 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic ssize_t namespace_store(struct device *dev, 1078c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t len) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci struct nd_btt *nd_btt = to_nd_btt(dev); 1108c2ecf20Sopenharmony_ci ssize_t rc; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci nd_device_lock(dev); 1138c2ecf20Sopenharmony_ci nvdimm_bus_lock(dev); 1148c2ecf20Sopenharmony_ci rc = nd_namespace_store(dev, &nd_btt->ndns, buf, len); 1158c2ecf20Sopenharmony_ci dev_dbg(dev, "result: %zd wrote: %s%s", rc, buf, 1168c2ecf20Sopenharmony_ci buf[len - 1] == '\n' ? "" : "\n"); 1178c2ecf20Sopenharmony_ci nvdimm_bus_unlock(dev); 1188c2ecf20Sopenharmony_ci nd_device_unlock(dev); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci return rc; 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(namespace); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic ssize_t size_show(struct device *dev, 1258c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci struct nd_btt *nd_btt = to_nd_btt(dev); 1288c2ecf20Sopenharmony_ci ssize_t rc; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci nd_device_lock(dev); 1318c2ecf20Sopenharmony_ci if (dev->driver) 1328c2ecf20Sopenharmony_ci rc = sprintf(buf, "%llu\n", nd_btt->size); 1338c2ecf20Sopenharmony_ci else { 1348c2ecf20Sopenharmony_ci /* no size to convey if the btt instance is disabled */ 1358c2ecf20Sopenharmony_ci rc = -ENXIO; 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci nd_device_unlock(dev); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci return rc; 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(size); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic ssize_t log_zero_flags_show(struct device *dev, 1448c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci return sprintf(buf, "Y\n"); 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(log_zero_flags); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic struct attribute *nd_btt_attributes[] = { 1518c2ecf20Sopenharmony_ci &dev_attr_sector_size.attr, 1528c2ecf20Sopenharmony_ci &dev_attr_namespace.attr, 1538c2ecf20Sopenharmony_ci &dev_attr_uuid.attr, 1548c2ecf20Sopenharmony_ci &dev_attr_size.attr, 1558c2ecf20Sopenharmony_ci &dev_attr_log_zero_flags.attr, 1568c2ecf20Sopenharmony_ci NULL, 1578c2ecf20Sopenharmony_ci}; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_cistatic struct attribute_group nd_btt_attribute_group = { 1608c2ecf20Sopenharmony_ci .attrs = nd_btt_attributes, 1618c2ecf20Sopenharmony_ci}; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic const struct attribute_group *nd_btt_attribute_groups[] = { 1648c2ecf20Sopenharmony_ci &nd_btt_attribute_group, 1658c2ecf20Sopenharmony_ci &nd_device_attribute_group, 1668c2ecf20Sopenharmony_ci &nd_numa_attribute_group, 1678c2ecf20Sopenharmony_ci NULL, 1688c2ecf20Sopenharmony_ci}; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic const struct device_type nd_btt_device_type = { 1718c2ecf20Sopenharmony_ci .name = "nd_btt", 1728c2ecf20Sopenharmony_ci .release = nd_btt_release, 1738c2ecf20Sopenharmony_ci .groups = nd_btt_attribute_groups, 1748c2ecf20Sopenharmony_ci}; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cibool is_nd_btt(struct device *dev) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci return dev->type == &nd_btt_device_type; 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ciEXPORT_SYMBOL(is_nd_btt); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_cistatic struct device *__nd_btt_create(struct nd_region *nd_region, 1838c2ecf20Sopenharmony_ci unsigned long lbasize, u8 *uuid, 1848c2ecf20Sopenharmony_ci struct nd_namespace_common *ndns) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci struct nd_btt *nd_btt; 1878c2ecf20Sopenharmony_ci struct device *dev; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci nd_btt = kzalloc(sizeof(*nd_btt), GFP_KERNEL); 1908c2ecf20Sopenharmony_ci if (!nd_btt) 1918c2ecf20Sopenharmony_ci return NULL; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci nd_btt->id = ida_simple_get(&nd_region->btt_ida, 0, 0, GFP_KERNEL); 1948c2ecf20Sopenharmony_ci if (nd_btt->id < 0) 1958c2ecf20Sopenharmony_ci goto out_nd_btt; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci nd_btt->lbasize = lbasize; 1988c2ecf20Sopenharmony_ci if (uuid) { 1998c2ecf20Sopenharmony_ci uuid = kmemdup(uuid, 16, GFP_KERNEL); 2008c2ecf20Sopenharmony_ci if (!uuid) 2018c2ecf20Sopenharmony_ci goto out_put_id; 2028c2ecf20Sopenharmony_ci } 2038c2ecf20Sopenharmony_ci nd_btt->uuid = uuid; 2048c2ecf20Sopenharmony_ci dev = &nd_btt->dev; 2058c2ecf20Sopenharmony_ci dev_set_name(dev, "btt%d.%d", nd_region->id, nd_btt->id); 2068c2ecf20Sopenharmony_ci dev->parent = &nd_region->dev; 2078c2ecf20Sopenharmony_ci dev->type = &nd_btt_device_type; 2088c2ecf20Sopenharmony_ci device_initialize(&nd_btt->dev); 2098c2ecf20Sopenharmony_ci if (ndns && !__nd_attach_ndns(&nd_btt->dev, ndns, &nd_btt->ndns)) { 2108c2ecf20Sopenharmony_ci dev_dbg(&ndns->dev, "failed, already claimed by %s\n", 2118c2ecf20Sopenharmony_ci dev_name(ndns->claim)); 2128c2ecf20Sopenharmony_ci put_device(dev); 2138c2ecf20Sopenharmony_ci return NULL; 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci return dev; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ciout_put_id: 2188c2ecf20Sopenharmony_ci ida_simple_remove(&nd_region->btt_ida, nd_btt->id); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ciout_nd_btt: 2218c2ecf20Sopenharmony_ci kfree(nd_btt); 2228c2ecf20Sopenharmony_ci return NULL; 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_cistruct device *nd_btt_create(struct nd_region *nd_region) 2268c2ecf20Sopenharmony_ci{ 2278c2ecf20Sopenharmony_ci struct device *dev = __nd_btt_create(nd_region, 0, NULL, NULL); 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci __nd_device_register(dev); 2308c2ecf20Sopenharmony_ci return dev; 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci/** 2348c2ecf20Sopenharmony_ci * nd_btt_arena_is_valid - check if the metadata layout is valid 2358c2ecf20Sopenharmony_ci * @nd_btt: device with BTT geometry and backing device info 2368c2ecf20Sopenharmony_ci * @super: pointer to the arena's info block being tested 2378c2ecf20Sopenharmony_ci * 2388c2ecf20Sopenharmony_ci * Check consistency of the btt info block with itself by validating 2398c2ecf20Sopenharmony_ci * the checksum, and with the parent namespace by verifying the 2408c2ecf20Sopenharmony_ci * parent_uuid contained in the info block with the one supplied in. 2418c2ecf20Sopenharmony_ci * 2428c2ecf20Sopenharmony_ci * Returns: 2438c2ecf20Sopenharmony_ci * false for an invalid info block, true for a valid one 2448c2ecf20Sopenharmony_ci */ 2458c2ecf20Sopenharmony_cibool nd_btt_arena_is_valid(struct nd_btt *nd_btt, struct btt_sb *super) 2468c2ecf20Sopenharmony_ci{ 2478c2ecf20Sopenharmony_ci const u8 *parent_uuid = nd_dev_to_uuid(&nd_btt->ndns->dev); 2488c2ecf20Sopenharmony_ci u64 checksum; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci if (memcmp(super->signature, BTT_SIG, BTT_SIG_LEN) != 0) 2518c2ecf20Sopenharmony_ci return false; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci if (!guid_is_null((guid_t *)&super->parent_uuid)) 2548c2ecf20Sopenharmony_ci if (memcmp(super->parent_uuid, parent_uuid, 16) != 0) 2558c2ecf20Sopenharmony_ci return false; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci checksum = le64_to_cpu(super->checksum); 2588c2ecf20Sopenharmony_ci super->checksum = 0; 2598c2ecf20Sopenharmony_ci if (checksum != nd_sb_checksum((struct nd_gen_sb *) super)) 2608c2ecf20Sopenharmony_ci return false; 2618c2ecf20Sopenharmony_ci super->checksum = cpu_to_le64(checksum); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci /* TODO: figure out action for this */ 2648c2ecf20Sopenharmony_ci if ((le32_to_cpu(super->flags) & IB_FLAG_ERROR_MASK) != 0) 2658c2ecf20Sopenharmony_ci dev_info(&nd_btt->dev, "Found arena with an error flag\n"); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci return true; 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ciEXPORT_SYMBOL(nd_btt_arena_is_valid); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ciint nd_btt_version(struct nd_btt *nd_btt, struct nd_namespace_common *ndns, 2728c2ecf20Sopenharmony_ci struct btt_sb *btt_sb) 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci if (ndns->claim_class == NVDIMM_CCLASS_BTT2) { 2758c2ecf20Sopenharmony_ci /* Probe/setup for BTT v2.0 */ 2768c2ecf20Sopenharmony_ci nd_btt->initial_offset = 0; 2778c2ecf20Sopenharmony_ci nd_btt->version_major = 2; 2788c2ecf20Sopenharmony_ci nd_btt->version_minor = 0; 2798c2ecf20Sopenharmony_ci if (nvdimm_read_bytes(ndns, 0, btt_sb, sizeof(*btt_sb), 0)) 2808c2ecf20Sopenharmony_ci return -ENXIO; 2818c2ecf20Sopenharmony_ci if (!nd_btt_arena_is_valid(nd_btt, btt_sb)) 2828c2ecf20Sopenharmony_ci return -ENODEV; 2838c2ecf20Sopenharmony_ci if ((le16_to_cpu(btt_sb->version_major) != 2) || 2848c2ecf20Sopenharmony_ci (le16_to_cpu(btt_sb->version_minor) != 0)) 2858c2ecf20Sopenharmony_ci return -ENODEV; 2868c2ecf20Sopenharmony_ci } else { 2878c2ecf20Sopenharmony_ci /* 2888c2ecf20Sopenharmony_ci * Probe/setup for BTT v1.1 (NVDIMM_CCLASS_NONE or 2898c2ecf20Sopenharmony_ci * NVDIMM_CCLASS_BTT) 2908c2ecf20Sopenharmony_ci */ 2918c2ecf20Sopenharmony_ci nd_btt->initial_offset = SZ_4K; 2928c2ecf20Sopenharmony_ci nd_btt->version_major = 1; 2938c2ecf20Sopenharmony_ci nd_btt->version_minor = 1; 2948c2ecf20Sopenharmony_ci if (nvdimm_read_bytes(ndns, SZ_4K, btt_sb, sizeof(*btt_sb), 0)) 2958c2ecf20Sopenharmony_ci return -ENXIO; 2968c2ecf20Sopenharmony_ci if (!nd_btt_arena_is_valid(nd_btt, btt_sb)) 2978c2ecf20Sopenharmony_ci return -ENODEV; 2988c2ecf20Sopenharmony_ci if ((le16_to_cpu(btt_sb->version_major) != 1) || 2998c2ecf20Sopenharmony_ci (le16_to_cpu(btt_sb->version_minor) != 1)) 3008c2ecf20Sopenharmony_ci return -ENODEV; 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci return 0; 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ciEXPORT_SYMBOL(nd_btt_version); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_cistatic int __nd_btt_probe(struct nd_btt *nd_btt, 3078c2ecf20Sopenharmony_ci struct nd_namespace_common *ndns, struct btt_sb *btt_sb) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci int rc; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci if (!btt_sb || !ndns || !nd_btt) 3128c2ecf20Sopenharmony_ci return -ENODEV; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci if (nvdimm_namespace_capacity(ndns) < SZ_16M) 3158c2ecf20Sopenharmony_ci return -ENXIO; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci rc = nd_btt_version(nd_btt, ndns, btt_sb); 3188c2ecf20Sopenharmony_ci if (rc < 0) 3198c2ecf20Sopenharmony_ci return rc; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci nd_btt->lbasize = le32_to_cpu(btt_sb->external_lbasize); 3228c2ecf20Sopenharmony_ci nd_btt->uuid = kmemdup(btt_sb->uuid, 16, GFP_KERNEL); 3238c2ecf20Sopenharmony_ci if (!nd_btt->uuid) 3248c2ecf20Sopenharmony_ci return -ENOMEM; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci __nd_device_register(&nd_btt->dev); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci return 0; 3298c2ecf20Sopenharmony_ci} 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ciint nd_btt_probe(struct device *dev, struct nd_namespace_common *ndns) 3328c2ecf20Sopenharmony_ci{ 3338c2ecf20Sopenharmony_ci int rc; 3348c2ecf20Sopenharmony_ci struct device *btt_dev; 3358c2ecf20Sopenharmony_ci struct btt_sb *btt_sb; 3368c2ecf20Sopenharmony_ci struct nd_region *nd_region = to_nd_region(ndns->dev.parent); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci if (ndns->force_raw) 3398c2ecf20Sopenharmony_ci return -ENODEV; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci switch (ndns->claim_class) { 3428c2ecf20Sopenharmony_ci case NVDIMM_CCLASS_NONE: 3438c2ecf20Sopenharmony_ci case NVDIMM_CCLASS_BTT: 3448c2ecf20Sopenharmony_ci case NVDIMM_CCLASS_BTT2: 3458c2ecf20Sopenharmony_ci break; 3468c2ecf20Sopenharmony_ci default: 3478c2ecf20Sopenharmony_ci return -ENODEV; 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci nvdimm_bus_lock(&ndns->dev); 3518c2ecf20Sopenharmony_ci btt_dev = __nd_btt_create(nd_region, 0, NULL, ndns); 3528c2ecf20Sopenharmony_ci nvdimm_bus_unlock(&ndns->dev); 3538c2ecf20Sopenharmony_ci if (!btt_dev) 3548c2ecf20Sopenharmony_ci return -ENOMEM; 3558c2ecf20Sopenharmony_ci btt_sb = devm_kzalloc(dev, sizeof(*btt_sb), GFP_KERNEL); 3568c2ecf20Sopenharmony_ci rc = __nd_btt_probe(to_nd_btt(btt_dev), ndns, btt_sb); 3578c2ecf20Sopenharmony_ci dev_dbg(dev, "btt: %s\n", rc == 0 ? dev_name(btt_dev) : "<none>"); 3588c2ecf20Sopenharmony_ci if (rc < 0) { 3598c2ecf20Sopenharmony_ci struct nd_btt *nd_btt = to_nd_btt(btt_dev); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci nd_detach_ndns(btt_dev, &nd_btt->ndns); 3628c2ecf20Sopenharmony_ci put_device(btt_dev); 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci return rc; 3668c2ecf20Sopenharmony_ci} 3678c2ecf20Sopenharmony_ciEXPORT_SYMBOL(nd_btt_probe); 368