177141dc6SChristoph Hellwig // SPDX-License-Identifier: GPL-2.0 2a07b4970SChristoph Hellwig /* 3a07b4970SChristoph Hellwig * Configfs interface for the NVMe target. 4a07b4970SChristoph Hellwig * Copyright (c) 2015-2016 HGST, a Western Digital Company. 5a07b4970SChristoph Hellwig */ 6a07b4970SChristoph Hellwig #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 7*99722c8aSChristophe JAILLET #include <linux/kstrtox.h> 8a07b4970SChristoph Hellwig #include <linux/kernel.h> 9a07b4970SChristoph Hellwig #include <linux/module.h> 10a07b4970SChristoph Hellwig #include <linux/slab.h> 11a07b4970SChristoph Hellwig #include <linux/stat.h> 12a07b4970SChristoph Hellwig #include <linux/ctype.h> 13c6925093SLogan Gunthorpe #include <linux/pci.h> 14c6925093SLogan Gunthorpe #include <linux/pci-p2pdma.h> 15db1312ddSHannes Reinecke #ifdef CONFIG_NVME_TARGET_AUTH 16db1312ddSHannes Reinecke #include <linux/nvme-auth.h> 17db1312ddSHannes Reinecke #endif 18db1312ddSHannes Reinecke #include <crypto/hash.h> 19db1312ddSHannes Reinecke #include <crypto/kpp.h> 20a07b4970SChristoph Hellwig 21a07b4970SChristoph Hellwig #include "nvmet.h" 22a07b4970SChristoph Hellwig 2366603a31SBhumika Goyal static const struct config_item_type nvmet_host_type; 2466603a31SBhumika Goyal static const struct config_item_type nvmet_subsys_type; 25a07b4970SChristoph Hellwig 26b662a078SJay Sternberg static LIST_HEAD(nvmet_ports_list); 27b662a078SJay Sternberg struct list_head *nvmet_ports = &nvmet_ports_list; 28b662a078SJay Sternberg 2945e2f3c2SChaitanya Kulkarni struct nvmet_type_name_map { 30a5d18612SChristoph Hellwig u8 type; 31a5d18612SChristoph Hellwig const char *name; 3245e2f3c2SChaitanya Kulkarni }; 3345e2f3c2SChaitanya Kulkarni 3445e2f3c2SChaitanya Kulkarni static struct nvmet_type_name_map nvmet_transport[] = { 35a5d18612SChristoph Hellwig { NVMF_TRTYPE_RDMA, "rdma" }, 36a5d18612SChristoph Hellwig { NVMF_TRTYPE_FC, "fc" }, 37ad4f530eSSagi Grimberg { NVMF_TRTYPE_TCP, "tcp" }, 38a5d18612SChristoph Hellwig { NVMF_TRTYPE_LOOP, "loop" }, 39a5d18612SChristoph Hellwig }; 40a5d18612SChristoph Hellwig 417e764179SChaitanya Kulkarni static const struct nvmet_type_name_map nvmet_addr_family[] = { 427e764179SChaitanya Kulkarni { NVMF_ADDR_FAMILY_PCI, "pcie" }, 437e764179SChaitanya Kulkarni { NVMF_ADDR_FAMILY_IP4, "ipv4" }, 447e764179SChaitanya Kulkarni { NVMF_ADDR_FAMILY_IP6, "ipv6" }, 457e764179SChaitanya Kulkarni { NVMF_ADDR_FAMILY_IB, "ib" }, 467e764179SChaitanya Kulkarni { NVMF_ADDR_FAMILY_FC, "fc" }, 47d02abd19SChaitanya Kulkarni { NVMF_ADDR_FAMILY_LOOP, "loop" }, 487e764179SChaitanya Kulkarni }; 497e764179SChaitanya Kulkarni 503ecb5faaSChaitanya Kulkarni static bool nvmet_is_port_enabled(struct nvmet_port *p, const char *caller) 513ecb5faaSChaitanya Kulkarni { 523ecb5faaSChaitanya Kulkarni if (p->enabled) 533ecb5faaSChaitanya Kulkarni pr_err("Disable port '%u' before changing attribute in %s\n", 543ecb5faaSChaitanya Kulkarni le16_to_cpu(p->disc_addr.portid), caller); 553ecb5faaSChaitanya Kulkarni return p->enabled; 563ecb5faaSChaitanya Kulkarni } 573ecb5faaSChaitanya Kulkarni 58a07b4970SChristoph Hellwig /* 59a07b4970SChristoph Hellwig * nvmet_port Generic ConfigFS definitions. 60a07b4970SChristoph Hellwig * Used in any place in the ConfigFS tree that refers to an address. 61a07b4970SChristoph Hellwig */ 627e764179SChaitanya Kulkarni static ssize_t nvmet_addr_adrfam_show(struct config_item *item, char *page) 63a07b4970SChristoph Hellwig { 647e764179SChaitanya Kulkarni u8 adrfam = to_nvmet_port(item)->disc_addr.adrfam; 657e764179SChaitanya Kulkarni int i; 667e764179SChaitanya Kulkarni 677e764179SChaitanya Kulkarni for (i = 1; i < ARRAY_SIZE(nvmet_addr_family); i++) { 687e764179SChaitanya Kulkarni if (nvmet_addr_family[i].type == adrfam) 6998152eb7SChaitanya Kulkarni return snprintf(page, PAGE_SIZE, "%s\n", 7098152eb7SChaitanya Kulkarni nvmet_addr_family[i].name); 71a07b4970SChristoph Hellwig } 727e764179SChaitanya Kulkarni 7398152eb7SChaitanya Kulkarni return snprintf(page, PAGE_SIZE, "\n"); 74a07b4970SChristoph Hellwig } 75a07b4970SChristoph Hellwig 76a07b4970SChristoph Hellwig static ssize_t nvmet_addr_adrfam_store(struct config_item *item, 77a07b4970SChristoph Hellwig const char *page, size_t count) 78a07b4970SChristoph Hellwig { 79a07b4970SChristoph Hellwig struct nvmet_port *port = to_nvmet_port(item); 807e764179SChaitanya Kulkarni int i; 81a07b4970SChristoph Hellwig 823ecb5faaSChaitanya Kulkarni if (nvmet_is_port_enabled(port, __func__)) 83a07b4970SChristoph Hellwig return -EACCES; 84a07b4970SChristoph Hellwig 857e764179SChaitanya Kulkarni for (i = 1; i < ARRAY_SIZE(nvmet_addr_family); i++) { 867e764179SChaitanya Kulkarni if (sysfs_streq(page, nvmet_addr_family[i].name)) 877e764179SChaitanya Kulkarni goto found; 88a07b4970SChristoph Hellwig } 89a07b4970SChristoph Hellwig 907e764179SChaitanya Kulkarni pr_err("Invalid value '%s' for adrfam\n", page); 917e764179SChaitanya Kulkarni return -EINVAL; 927e764179SChaitanya Kulkarni 937e764179SChaitanya Kulkarni found: 94d02abd19SChaitanya Kulkarni port->disc_addr.adrfam = nvmet_addr_family[i].type; 95a07b4970SChristoph Hellwig return count; 96a07b4970SChristoph Hellwig } 97a07b4970SChristoph Hellwig 98a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_, addr_adrfam); 99a07b4970SChristoph Hellwig 100a07b4970SChristoph Hellwig static ssize_t nvmet_addr_portid_show(struct config_item *item, 101a07b4970SChristoph Hellwig char *page) 102a07b4970SChristoph Hellwig { 10373d77c53SChaitanya Kulkarni __le16 portid = to_nvmet_port(item)->disc_addr.portid; 104a07b4970SChristoph Hellwig 10573d77c53SChaitanya Kulkarni return snprintf(page, PAGE_SIZE, "%d\n", le16_to_cpu(portid)); 106a07b4970SChristoph Hellwig } 107a07b4970SChristoph Hellwig 108a07b4970SChristoph Hellwig static ssize_t nvmet_addr_portid_store(struct config_item *item, 109a07b4970SChristoph Hellwig const char *page, size_t count) 110a07b4970SChristoph Hellwig { 111a07b4970SChristoph Hellwig struct nvmet_port *port = to_nvmet_port(item); 112a07b4970SChristoph Hellwig u16 portid = 0; 113a07b4970SChristoph Hellwig 114a07b4970SChristoph Hellwig if (kstrtou16(page, 0, &portid)) { 115a07b4970SChristoph Hellwig pr_err("Invalid value '%s' for portid\n", page); 116a07b4970SChristoph Hellwig return -EINVAL; 117a07b4970SChristoph Hellwig } 118a07b4970SChristoph Hellwig 1193ecb5faaSChaitanya Kulkarni if (nvmet_is_port_enabled(port, __func__)) 120a07b4970SChristoph Hellwig return -EACCES; 1213ecb5faaSChaitanya Kulkarni 122a07b4970SChristoph Hellwig port->disc_addr.portid = cpu_to_le16(portid); 123a07b4970SChristoph Hellwig return count; 124a07b4970SChristoph Hellwig } 125a07b4970SChristoph Hellwig 126a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_, addr_portid); 127a07b4970SChristoph Hellwig 128a07b4970SChristoph Hellwig static ssize_t nvmet_addr_traddr_show(struct config_item *item, 129a07b4970SChristoph Hellwig char *page) 130a07b4970SChristoph Hellwig { 131a07b4970SChristoph Hellwig struct nvmet_port *port = to_nvmet_port(item); 132a07b4970SChristoph Hellwig 13373d77c53SChaitanya Kulkarni return snprintf(page, PAGE_SIZE, "%s\n", port->disc_addr.traddr); 134a07b4970SChristoph Hellwig } 135a07b4970SChristoph Hellwig 136a07b4970SChristoph Hellwig static ssize_t nvmet_addr_traddr_store(struct config_item *item, 137a07b4970SChristoph Hellwig const char *page, size_t count) 138a07b4970SChristoph Hellwig { 139a07b4970SChristoph Hellwig struct nvmet_port *port = to_nvmet_port(item); 140a07b4970SChristoph Hellwig 141a07b4970SChristoph Hellwig if (count > NVMF_TRADDR_SIZE) { 142a07b4970SChristoph Hellwig pr_err("Invalid value '%s' for traddr\n", page); 143a07b4970SChristoph Hellwig return -EINVAL; 144a07b4970SChristoph Hellwig } 145a07b4970SChristoph Hellwig 1463ecb5faaSChaitanya Kulkarni if (nvmet_is_port_enabled(port, __func__)) 147a07b4970SChristoph Hellwig return -EACCES; 1489ba2a5cbSSagi Grimberg 1499ba2a5cbSSagi Grimberg if (sscanf(page, "%s\n", port->disc_addr.traddr) != 1) 1509ba2a5cbSSagi Grimberg return -EINVAL; 1519ba2a5cbSSagi Grimberg return count; 152a07b4970SChristoph Hellwig } 153a07b4970SChristoph Hellwig 154a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_, addr_traddr); 155a07b4970SChristoph Hellwig 15687628e28SChaitanya Kulkarni static const struct nvmet_type_name_map nvmet_addr_treq[] = { 15787628e28SChaitanya Kulkarni { NVMF_TREQ_NOT_SPECIFIED, "not specified" }, 15887628e28SChaitanya Kulkarni { NVMF_TREQ_REQUIRED, "required" }, 15987628e28SChaitanya Kulkarni { NVMF_TREQ_NOT_REQUIRED, "not required" }, 16087628e28SChaitanya Kulkarni }; 16187628e28SChaitanya Kulkarni 16287628e28SChaitanya Kulkarni static ssize_t nvmet_addr_treq_show(struct config_item *item, char *page) 163a07b4970SChristoph Hellwig { 16487628e28SChaitanya Kulkarni u8 treq = to_nvmet_port(item)->disc_addr.treq & 16587628e28SChaitanya Kulkarni NVME_TREQ_SECURE_CHANNEL_MASK; 16687628e28SChaitanya Kulkarni int i; 16787628e28SChaitanya Kulkarni 16887628e28SChaitanya Kulkarni for (i = 0; i < ARRAY_SIZE(nvmet_addr_treq); i++) { 16987628e28SChaitanya Kulkarni if (treq == nvmet_addr_treq[i].type) 17098152eb7SChaitanya Kulkarni return snprintf(page, PAGE_SIZE, "%s\n", 17198152eb7SChaitanya Kulkarni nvmet_addr_treq[i].name); 172a07b4970SChristoph Hellwig } 17387628e28SChaitanya Kulkarni 17498152eb7SChaitanya Kulkarni return snprintf(page, PAGE_SIZE, "\n"); 175a07b4970SChristoph Hellwig } 176a07b4970SChristoph Hellwig 177a07b4970SChristoph Hellwig static ssize_t nvmet_addr_treq_store(struct config_item *item, 178a07b4970SChristoph Hellwig const char *page, size_t count) 179a07b4970SChristoph Hellwig { 180a07b4970SChristoph Hellwig struct nvmet_port *port = to_nvmet_port(item); 1810445e1b5SSagi Grimberg u8 treq = port->disc_addr.treq & ~NVME_TREQ_SECURE_CHANNEL_MASK; 18287628e28SChaitanya Kulkarni int i; 183a07b4970SChristoph Hellwig 1843ecb5faaSChaitanya Kulkarni if (nvmet_is_port_enabled(port, __func__)) 185a07b4970SChristoph Hellwig return -EACCES; 186a07b4970SChristoph Hellwig 18787628e28SChaitanya Kulkarni for (i = 0; i < ARRAY_SIZE(nvmet_addr_treq); i++) { 18887628e28SChaitanya Kulkarni if (sysfs_streq(page, nvmet_addr_treq[i].name)) 18987628e28SChaitanya Kulkarni goto found; 19087628e28SChaitanya Kulkarni } 19187628e28SChaitanya Kulkarni 192a07b4970SChristoph Hellwig pr_err("Invalid value '%s' for treq\n", page); 193a07b4970SChristoph Hellwig return -EINVAL; 194a07b4970SChristoph Hellwig 19587628e28SChaitanya Kulkarni found: 19687628e28SChaitanya Kulkarni treq |= nvmet_addr_treq[i].type; 19787628e28SChaitanya Kulkarni port->disc_addr.treq = treq; 198a07b4970SChristoph Hellwig return count; 199a07b4970SChristoph Hellwig } 200a07b4970SChristoph Hellwig 201a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_, addr_treq); 202a07b4970SChristoph Hellwig 203a07b4970SChristoph Hellwig static ssize_t nvmet_addr_trsvcid_show(struct config_item *item, 204a07b4970SChristoph Hellwig char *page) 205a07b4970SChristoph Hellwig { 206a07b4970SChristoph Hellwig struct nvmet_port *port = to_nvmet_port(item); 207a07b4970SChristoph Hellwig 20873d77c53SChaitanya Kulkarni return snprintf(page, PAGE_SIZE, "%s\n", port->disc_addr.trsvcid); 209a07b4970SChristoph Hellwig } 210a07b4970SChristoph Hellwig 211a07b4970SChristoph Hellwig static ssize_t nvmet_addr_trsvcid_store(struct config_item *item, 212a07b4970SChristoph Hellwig const char *page, size_t count) 213a07b4970SChristoph Hellwig { 214a07b4970SChristoph Hellwig struct nvmet_port *port = to_nvmet_port(item); 215a07b4970SChristoph Hellwig 216a07b4970SChristoph Hellwig if (count > NVMF_TRSVCID_SIZE) { 217a07b4970SChristoph Hellwig pr_err("Invalid value '%s' for trsvcid\n", page); 218a07b4970SChristoph Hellwig return -EINVAL; 219a07b4970SChristoph Hellwig } 2203ecb5faaSChaitanya Kulkarni if (nvmet_is_port_enabled(port, __func__)) 221a07b4970SChristoph Hellwig return -EACCES; 2229ba2a5cbSSagi Grimberg 2239ba2a5cbSSagi Grimberg if (sscanf(page, "%s\n", port->disc_addr.trsvcid) != 1) 2249ba2a5cbSSagi Grimberg return -EINVAL; 2259ba2a5cbSSagi Grimberg return count; 226a07b4970SChristoph Hellwig } 227a07b4970SChristoph Hellwig 228a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_, addr_trsvcid); 229a07b4970SChristoph Hellwig 2300d5ee2b2SSteve Wise static ssize_t nvmet_param_inline_data_size_show(struct config_item *item, 2310d5ee2b2SSteve Wise char *page) 2320d5ee2b2SSteve Wise { 2330d5ee2b2SSteve Wise struct nvmet_port *port = to_nvmet_port(item); 2340d5ee2b2SSteve Wise 2350d5ee2b2SSteve Wise return snprintf(page, PAGE_SIZE, "%d\n", port->inline_data_size); 2360d5ee2b2SSteve Wise } 2370d5ee2b2SSteve Wise 2380d5ee2b2SSteve Wise static ssize_t nvmet_param_inline_data_size_store(struct config_item *item, 2390d5ee2b2SSteve Wise const char *page, size_t count) 2400d5ee2b2SSteve Wise { 2410d5ee2b2SSteve Wise struct nvmet_port *port = to_nvmet_port(item); 2420d5ee2b2SSteve Wise int ret; 2430d5ee2b2SSteve Wise 2443ecb5faaSChaitanya Kulkarni if (nvmet_is_port_enabled(port, __func__)) 2450d5ee2b2SSteve Wise return -EACCES; 2460d5ee2b2SSteve Wise ret = kstrtoint(page, 0, &port->inline_data_size); 2470d5ee2b2SSteve Wise if (ret) { 2480d5ee2b2SSteve Wise pr_err("Invalid value '%s' for inline_data_size\n", page); 2490d5ee2b2SSteve Wise return -EINVAL; 2500d5ee2b2SSteve Wise } 2510d5ee2b2SSteve Wise return count; 2520d5ee2b2SSteve Wise } 2530d5ee2b2SSteve Wise 2540d5ee2b2SSteve Wise CONFIGFS_ATTR(nvmet_, param_inline_data_size); 2550d5ee2b2SSteve Wise 256ea52ac1cSIsrael Rukshin #ifdef CONFIG_BLK_DEV_INTEGRITY 257ea52ac1cSIsrael Rukshin static ssize_t nvmet_param_pi_enable_show(struct config_item *item, 258ea52ac1cSIsrael Rukshin char *page) 259ea52ac1cSIsrael Rukshin { 260ea52ac1cSIsrael Rukshin struct nvmet_port *port = to_nvmet_port(item); 261ea52ac1cSIsrael Rukshin 262ea52ac1cSIsrael Rukshin return snprintf(page, PAGE_SIZE, "%d\n", port->pi_enable); 263ea52ac1cSIsrael Rukshin } 264ea52ac1cSIsrael Rukshin 265ea52ac1cSIsrael Rukshin static ssize_t nvmet_param_pi_enable_store(struct config_item *item, 266ea52ac1cSIsrael Rukshin const char *page, size_t count) 267ea52ac1cSIsrael Rukshin { 268ea52ac1cSIsrael Rukshin struct nvmet_port *port = to_nvmet_port(item); 269ea52ac1cSIsrael Rukshin bool val; 270ea52ac1cSIsrael Rukshin 271*99722c8aSChristophe JAILLET if (kstrtobool(page, &val)) 272ea52ac1cSIsrael Rukshin return -EINVAL; 273ea52ac1cSIsrael Rukshin 274cc345622SIsrael Rukshin if (nvmet_is_port_enabled(port, __func__)) 275ea52ac1cSIsrael Rukshin return -EACCES; 276ea52ac1cSIsrael Rukshin 277ea52ac1cSIsrael Rukshin port->pi_enable = val; 278ea52ac1cSIsrael Rukshin return count; 279ea52ac1cSIsrael Rukshin } 280ea52ac1cSIsrael Rukshin 281ea52ac1cSIsrael Rukshin CONFIGFS_ATTR(nvmet_, param_pi_enable); 282ea52ac1cSIsrael Rukshin #endif 283ea52ac1cSIsrael Rukshin 284a07b4970SChristoph Hellwig static ssize_t nvmet_addr_trtype_show(struct config_item *item, 285a07b4970SChristoph Hellwig char *page) 286a07b4970SChristoph Hellwig { 287a5d18612SChristoph Hellwig struct nvmet_port *port = to_nvmet_port(item); 288a5d18612SChristoph Hellwig int i; 289a5d18612SChristoph Hellwig 29045e2f3c2SChaitanya Kulkarni for (i = 0; i < ARRAY_SIZE(nvmet_transport); i++) { 29145e2f3c2SChaitanya Kulkarni if (port->disc_addr.trtype == nvmet_transport[i].type) 29298152eb7SChaitanya Kulkarni return snprintf(page, PAGE_SIZE, 29398152eb7SChaitanya Kulkarni "%s\n", nvmet_transport[i].name); 294a07b4970SChristoph Hellwig } 295a5d18612SChristoph Hellwig 296a5d18612SChristoph Hellwig return sprintf(page, "\n"); 297a07b4970SChristoph Hellwig } 298a07b4970SChristoph Hellwig 299a07b4970SChristoph Hellwig static void nvmet_port_init_tsas_rdma(struct nvmet_port *port) 300a07b4970SChristoph Hellwig { 301a07b4970SChristoph Hellwig port->disc_addr.tsas.rdma.qptype = NVMF_RDMA_QPTYPE_CONNECTED; 302a07b4970SChristoph Hellwig port->disc_addr.tsas.rdma.prtype = NVMF_RDMA_PRTYPE_NOT_SPECIFIED; 303a07b4970SChristoph Hellwig port->disc_addr.tsas.rdma.cms = NVMF_RDMA_CMS_RDMA_CM; 304a07b4970SChristoph Hellwig } 305a07b4970SChristoph Hellwig 306a07b4970SChristoph Hellwig static ssize_t nvmet_addr_trtype_store(struct config_item *item, 307a07b4970SChristoph Hellwig const char *page, size_t count) 308a07b4970SChristoph Hellwig { 309a07b4970SChristoph Hellwig struct nvmet_port *port = to_nvmet_port(item); 310a5d18612SChristoph Hellwig int i; 311a07b4970SChristoph Hellwig 3123ecb5faaSChaitanya Kulkarni if (nvmet_is_port_enabled(port, __func__)) 313a07b4970SChristoph Hellwig return -EACCES; 314a07b4970SChristoph Hellwig 31545e2f3c2SChaitanya Kulkarni for (i = 0; i < ARRAY_SIZE(nvmet_transport); i++) { 31645e2f3c2SChaitanya Kulkarni if (sysfs_streq(page, nvmet_transport[i].name)) 317a5d18612SChristoph Hellwig goto found; 318a07b4970SChristoph Hellwig } 319a07b4970SChristoph Hellwig 320a5d18612SChristoph Hellwig pr_err("Invalid value '%s' for trtype\n", page); 321a5d18612SChristoph Hellwig return -EINVAL; 3227e764179SChaitanya Kulkarni 323a5d18612SChristoph Hellwig found: 324a5d18612SChristoph Hellwig memset(&port->disc_addr.tsas, 0, NVMF_TSAS_SIZE); 32545e2f3c2SChaitanya Kulkarni port->disc_addr.trtype = nvmet_transport[i].type; 326a5d18612SChristoph Hellwig if (port->disc_addr.trtype == NVMF_TRTYPE_RDMA) 327a5d18612SChristoph Hellwig nvmet_port_init_tsas_rdma(port); 328a07b4970SChristoph Hellwig return count; 329a07b4970SChristoph Hellwig } 330a07b4970SChristoph Hellwig 331a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_, addr_trtype); 332a07b4970SChristoph Hellwig 333a07b4970SChristoph Hellwig /* 334a07b4970SChristoph Hellwig * Namespace structures & file operation functions below 335a07b4970SChristoph Hellwig */ 336a07b4970SChristoph Hellwig static ssize_t nvmet_ns_device_path_show(struct config_item *item, char *page) 337a07b4970SChristoph Hellwig { 338a07b4970SChristoph Hellwig return sprintf(page, "%s\n", to_nvmet_ns(item)->device_path); 339a07b4970SChristoph Hellwig } 340a07b4970SChristoph Hellwig 341a07b4970SChristoph Hellwig static ssize_t nvmet_ns_device_path_store(struct config_item *item, 342a07b4970SChristoph Hellwig const char *page, size_t count) 343a07b4970SChristoph Hellwig { 344a07b4970SChristoph Hellwig struct nvmet_ns *ns = to_nvmet_ns(item); 345a07b4970SChristoph Hellwig struct nvmet_subsys *subsys = ns->subsys; 3465613d312SHannes Reinecke size_t len; 347a07b4970SChristoph Hellwig int ret; 348a07b4970SChristoph Hellwig 349a07b4970SChristoph Hellwig mutex_lock(&subsys->lock); 350a07b4970SChristoph Hellwig ret = -EBUSY; 351e4fcf07cSSolganik Alexander if (ns->enabled) 352a07b4970SChristoph Hellwig goto out_unlock; 353a07b4970SChristoph Hellwig 3545613d312SHannes Reinecke ret = -EINVAL; 3555613d312SHannes Reinecke len = strcspn(page, "\n"); 3565613d312SHannes Reinecke if (!len) 3575613d312SHannes Reinecke goto out_unlock; 358a07b4970SChristoph Hellwig 3595613d312SHannes Reinecke kfree(ns->device_path); 360a07b4970SChristoph Hellwig ret = -ENOMEM; 36109bb8986SChen Zhou ns->device_path = kmemdup_nul(page, len, GFP_KERNEL); 362a07b4970SChristoph Hellwig if (!ns->device_path) 363a07b4970SChristoph Hellwig goto out_unlock; 364a07b4970SChristoph Hellwig 365a07b4970SChristoph Hellwig mutex_unlock(&subsys->lock); 366a07b4970SChristoph Hellwig return count; 367a07b4970SChristoph Hellwig 368a07b4970SChristoph Hellwig out_unlock: 369a07b4970SChristoph Hellwig mutex_unlock(&subsys->lock); 370a07b4970SChristoph Hellwig return ret; 371a07b4970SChristoph Hellwig } 372a07b4970SChristoph Hellwig 373a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_ns_, device_path); 374a07b4970SChristoph Hellwig 375c6925093SLogan Gunthorpe #ifdef CONFIG_PCI_P2PDMA 376c6925093SLogan Gunthorpe static ssize_t nvmet_ns_p2pmem_show(struct config_item *item, char *page) 377c6925093SLogan Gunthorpe { 378c6925093SLogan Gunthorpe struct nvmet_ns *ns = to_nvmet_ns(item); 379c6925093SLogan Gunthorpe 380c6925093SLogan Gunthorpe return pci_p2pdma_enable_show(page, ns->p2p_dev, ns->use_p2pmem); 381c6925093SLogan Gunthorpe } 382c6925093SLogan Gunthorpe 383c6925093SLogan Gunthorpe static ssize_t nvmet_ns_p2pmem_store(struct config_item *item, 384c6925093SLogan Gunthorpe const char *page, size_t count) 385c6925093SLogan Gunthorpe { 386c6925093SLogan Gunthorpe struct nvmet_ns *ns = to_nvmet_ns(item); 387c6925093SLogan Gunthorpe struct pci_dev *p2p_dev = NULL; 388c6925093SLogan Gunthorpe bool use_p2pmem; 389c6925093SLogan Gunthorpe int ret = count; 390c6925093SLogan Gunthorpe int error; 391c6925093SLogan Gunthorpe 392c6925093SLogan Gunthorpe mutex_lock(&ns->subsys->lock); 393c6925093SLogan Gunthorpe if (ns->enabled) { 394c6925093SLogan Gunthorpe ret = -EBUSY; 395c6925093SLogan Gunthorpe goto out_unlock; 396c6925093SLogan Gunthorpe } 397c6925093SLogan Gunthorpe 398c6925093SLogan Gunthorpe error = pci_p2pdma_enable_store(page, &p2p_dev, &use_p2pmem); 399c6925093SLogan Gunthorpe if (error) { 400c6925093SLogan Gunthorpe ret = error; 401c6925093SLogan Gunthorpe goto out_unlock; 402c6925093SLogan Gunthorpe } 403c6925093SLogan Gunthorpe 404c6925093SLogan Gunthorpe ns->use_p2pmem = use_p2pmem; 405c6925093SLogan Gunthorpe pci_dev_put(ns->p2p_dev); 406c6925093SLogan Gunthorpe ns->p2p_dev = p2p_dev; 407c6925093SLogan Gunthorpe 408c6925093SLogan Gunthorpe out_unlock: 409c6925093SLogan Gunthorpe mutex_unlock(&ns->subsys->lock); 410c6925093SLogan Gunthorpe 411c6925093SLogan Gunthorpe return ret; 412c6925093SLogan Gunthorpe } 413c6925093SLogan Gunthorpe 414c6925093SLogan Gunthorpe CONFIGFS_ATTR(nvmet_ns_, p2pmem); 415c6925093SLogan Gunthorpe #endif /* CONFIG_PCI_P2PDMA */ 416c6925093SLogan Gunthorpe 417430c7befSJohannes Thumshirn static ssize_t nvmet_ns_device_uuid_show(struct config_item *item, char *page) 418430c7befSJohannes Thumshirn { 419430c7befSJohannes Thumshirn return sprintf(page, "%pUb\n", &to_nvmet_ns(item)->uuid); 420430c7befSJohannes Thumshirn } 421430c7befSJohannes Thumshirn 422430c7befSJohannes Thumshirn static ssize_t nvmet_ns_device_uuid_store(struct config_item *item, 423430c7befSJohannes Thumshirn const char *page, size_t count) 424430c7befSJohannes Thumshirn { 425430c7befSJohannes Thumshirn struct nvmet_ns *ns = to_nvmet_ns(item); 426430c7befSJohannes Thumshirn struct nvmet_subsys *subsys = ns->subsys; 427430c7befSJohannes Thumshirn int ret = 0; 428430c7befSJohannes Thumshirn 429430c7befSJohannes Thumshirn mutex_lock(&subsys->lock); 430430c7befSJohannes Thumshirn if (ns->enabled) { 431430c7befSJohannes Thumshirn ret = -EBUSY; 432430c7befSJohannes Thumshirn goto out_unlock; 433430c7befSJohannes Thumshirn } 434430c7befSJohannes Thumshirn 435430c7befSJohannes Thumshirn if (uuid_parse(page, &ns->uuid)) 436430c7befSJohannes Thumshirn ret = -EINVAL; 437430c7befSJohannes Thumshirn 438430c7befSJohannes Thumshirn out_unlock: 439430c7befSJohannes Thumshirn mutex_unlock(&subsys->lock); 440430c7befSJohannes Thumshirn return ret ? ret : count; 441430c7befSJohannes Thumshirn } 442430c7befSJohannes Thumshirn 443f871749aSMax Gurtovoy CONFIGFS_ATTR(nvmet_ns_, device_uuid); 444f871749aSMax Gurtovoy 445a07b4970SChristoph Hellwig static ssize_t nvmet_ns_device_nguid_show(struct config_item *item, char *page) 446a07b4970SChristoph Hellwig { 447a07b4970SChristoph Hellwig return sprintf(page, "%pUb\n", &to_nvmet_ns(item)->nguid); 448a07b4970SChristoph Hellwig } 449a07b4970SChristoph Hellwig 450a07b4970SChristoph Hellwig static ssize_t nvmet_ns_device_nguid_store(struct config_item *item, 451a07b4970SChristoph Hellwig const char *page, size_t count) 452a07b4970SChristoph Hellwig { 453a07b4970SChristoph Hellwig struct nvmet_ns *ns = to_nvmet_ns(item); 454a07b4970SChristoph Hellwig struct nvmet_subsys *subsys = ns->subsys; 455a07b4970SChristoph Hellwig u8 nguid[16]; 456a07b4970SChristoph Hellwig const char *p = page; 457a07b4970SChristoph Hellwig int i; 458a07b4970SChristoph Hellwig int ret = 0; 459a07b4970SChristoph Hellwig 460a07b4970SChristoph Hellwig mutex_lock(&subsys->lock); 461e4fcf07cSSolganik Alexander if (ns->enabled) { 462a07b4970SChristoph Hellwig ret = -EBUSY; 463a07b4970SChristoph Hellwig goto out_unlock; 464a07b4970SChristoph Hellwig } 465a07b4970SChristoph Hellwig 466a07b4970SChristoph Hellwig for (i = 0; i < 16; i++) { 467a07b4970SChristoph Hellwig if (p + 2 > page + count) { 468a07b4970SChristoph Hellwig ret = -EINVAL; 469a07b4970SChristoph Hellwig goto out_unlock; 470a07b4970SChristoph Hellwig } 471a07b4970SChristoph Hellwig if (!isxdigit(p[0]) || !isxdigit(p[1])) { 472a07b4970SChristoph Hellwig ret = -EINVAL; 473a07b4970SChristoph Hellwig goto out_unlock; 474a07b4970SChristoph Hellwig } 475a07b4970SChristoph Hellwig 476a07b4970SChristoph Hellwig nguid[i] = (hex_to_bin(p[0]) << 4) | hex_to_bin(p[1]); 477a07b4970SChristoph Hellwig p += 2; 478a07b4970SChristoph Hellwig 479a07b4970SChristoph Hellwig if (*p == '-' || *p == ':') 480a07b4970SChristoph Hellwig p++; 481a07b4970SChristoph Hellwig } 482a07b4970SChristoph Hellwig 483a07b4970SChristoph Hellwig memcpy(&ns->nguid, nguid, sizeof(nguid)); 484a07b4970SChristoph Hellwig out_unlock: 485a07b4970SChristoph Hellwig mutex_unlock(&subsys->lock); 486a07b4970SChristoph Hellwig return ret ? ret : count; 487a07b4970SChristoph Hellwig } 488a07b4970SChristoph Hellwig 489a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_ns_, device_nguid); 490a07b4970SChristoph Hellwig 49162ac0d32SChristoph Hellwig static ssize_t nvmet_ns_ana_grpid_show(struct config_item *item, char *page) 49262ac0d32SChristoph Hellwig { 49362ac0d32SChristoph Hellwig return sprintf(page, "%u\n", to_nvmet_ns(item)->anagrpid); 49462ac0d32SChristoph Hellwig } 49562ac0d32SChristoph Hellwig 49662ac0d32SChristoph Hellwig static ssize_t nvmet_ns_ana_grpid_store(struct config_item *item, 49762ac0d32SChristoph Hellwig const char *page, size_t count) 49862ac0d32SChristoph Hellwig { 49962ac0d32SChristoph Hellwig struct nvmet_ns *ns = to_nvmet_ns(item); 50062ac0d32SChristoph Hellwig u32 oldgrpid, newgrpid; 50162ac0d32SChristoph Hellwig int ret; 50262ac0d32SChristoph Hellwig 50362ac0d32SChristoph Hellwig ret = kstrtou32(page, 0, &newgrpid); 50462ac0d32SChristoph Hellwig if (ret) 50562ac0d32SChristoph Hellwig return ret; 50662ac0d32SChristoph Hellwig 50762ac0d32SChristoph Hellwig if (newgrpid < 1 || newgrpid > NVMET_MAX_ANAGRPS) 50862ac0d32SChristoph Hellwig return -EINVAL; 50962ac0d32SChristoph Hellwig 51062ac0d32SChristoph Hellwig down_write(&nvmet_ana_sem); 51162ac0d32SChristoph Hellwig oldgrpid = ns->anagrpid; 51262ac0d32SChristoph Hellwig nvmet_ana_group_enabled[newgrpid]++; 51362ac0d32SChristoph Hellwig ns->anagrpid = newgrpid; 51462ac0d32SChristoph Hellwig nvmet_ana_group_enabled[oldgrpid]--; 51562ac0d32SChristoph Hellwig nvmet_ana_chgcnt++; 51662ac0d32SChristoph Hellwig up_write(&nvmet_ana_sem); 51762ac0d32SChristoph Hellwig 51862ac0d32SChristoph Hellwig nvmet_send_ana_event(ns->subsys, NULL); 51962ac0d32SChristoph Hellwig return count; 52062ac0d32SChristoph Hellwig } 52162ac0d32SChristoph Hellwig 52262ac0d32SChristoph Hellwig CONFIGFS_ATTR(nvmet_ns_, ana_grpid); 52362ac0d32SChristoph Hellwig 524a07b4970SChristoph Hellwig static ssize_t nvmet_ns_enable_show(struct config_item *item, char *page) 525a07b4970SChristoph Hellwig { 526e4fcf07cSSolganik Alexander return sprintf(page, "%d\n", to_nvmet_ns(item)->enabled); 527a07b4970SChristoph Hellwig } 528a07b4970SChristoph Hellwig 529a07b4970SChristoph Hellwig static ssize_t nvmet_ns_enable_store(struct config_item *item, 530a07b4970SChristoph Hellwig const char *page, size_t count) 531a07b4970SChristoph Hellwig { 532a07b4970SChristoph Hellwig struct nvmet_ns *ns = to_nvmet_ns(item); 533a07b4970SChristoph Hellwig bool enable; 534a07b4970SChristoph Hellwig int ret = 0; 535a07b4970SChristoph Hellwig 536*99722c8aSChristophe JAILLET if (kstrtobool(page, &enable)) 537a07b4970SChristoph Hellwig return -EINVAL; 538a07b4970SChristoph Hellwig 539a07b4970SChristoph Hellwig if (enable) 540a07b4970SChristoph Hellwig ret = nvmet_ns_enable(ns); 541a07b4970SChristoph Hellwig else 542a07b4970SChristoph Hellwig nvmet_ns_disable(ns); 543a07b4970SChristoph Hellwig 544a07b4970SChristoph Hellwig return ret ? ret : count; 545a07b4970SChristoph Hellwig } 546a07b4970SChristoph Hellwig 547a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_ns_, enable); 548a07b4970SChristoph Hellwig 54955eb942eSChaitanya Kulkarni static ssize_t nvmet_ns_buffered_io_show(struct config_item *item, char *page) 55055eb942eSChaitanya Kulkarni { 55155eb942eSChaitanya Kulkarni return sprintf(page, "%d\n", to_nvmet_ns(item)->buffered_io); 55255eb942eSChaitanya Kulkarni } 55355eb942eSChaitanya Kulkarni 55455eb942eSChaitanya Kulkarni static ssize_t nvmet_ns_buffered_io_store(struct config_item *item, 55555eb942eSChaitanya Kulkarni const char *page, size_t count) 55655eb942eSChaitanya Kulkarni { 55755eb942eSChaitanya Kulkarni struct nvmet_ns *ns = to_nvmet_ns(item); 55855eb942eSChaitanya Kulkarni bool val; 55955eb942eSChaitanya Kulkarni 560*99722c8aSChristophe JAILLET if (kstrtobool(page, &val)) 56155eb942eSChaitanya Kulkarni return -EINVAL; 56255eb942eSChaitanya Kulkarni 56355eb942eSChaitanya Kulkarni mutex_lock(&ns->subsys->lock); 56455eb942eSChaitanya Kulkarni if (ns->enabled) { 56555eb942eSChaitanya Kulkarni pr_err("disable ns before setting buffered_io value.\n"); 56655eb942eSChaitanya Kulkarni mutex_unlock(&ns->subsys->lock); 56755eb942eSChaitanya Kulkarni return -EINVAL; 56855eb942eSChaitanya Kulkarni } 56955eb942eSChaitanya Kulkarni 57055eb942eSChaitanya Kulkarni ns->buffered_io = val; 57155eb942eSChaitanya Kulkarni mutex_unlock(&ns->subsys->lock); 57255eb942eSChaitanya Kulkarni return count; 57355eb942eSChaitanya Kulkarni } 57455eb942eSChaitanya Kulkarni 57555eb942eSChaitanya Kulkarni CONFIGFS_ATTR(nvmet_ns_, buffered_io); 57655eb942eSChaitanya Kulkarni 5771f357548SChaitanya Kulkarni static ssize_t nvmet_ns_revalidate_size_store(struct config_item *item, 5781f357548SChaitanya Kulkarni const char *page, size_t count) 5791f357548SChaitanya Kulkarni { 5801f357548SChaitanya Kulkarni struct nvmet_ns *ns = to_nvmet_ns(item); 5811f357548SChaitanya Kulkarni bool val; 5821f357548SChaitanya Kulkarni 583*99722c8aSChristophe JAILLET if (kstrtobool(page, &val)) 5841f357548SChaitanya Kulkarni return -EINVAL; 5851f357548SChaitanya Kulkarni 5861f357548SChaitanya Kulkarni if (!val) 5871f357548SChaitanya Kulkarni return -EINVAL; 5881f357548SChaitanya Kulkarni 5891f357548SChaitanya Kulkarni mutex_lock(&ns->subsys->lock); 5901f357548SChaitanya Kulkarni if (!ns->enabled) { 5911f357548SChaitanya Kulkarni pr_err("enable ns before revalidate.\n"); 5921f357548SChaitanya Kulkarni mutex_unlock(&ns->subsys->lock); 5931f357548SChaitanya Kulkarni return -EINVAL; 5941f357548SChaitanya Kulkarni } 595da783733SChristoph Hellwig if (nvmet_ns_revalidate(ns)) 596da783733SChristoph Hellwig nvmet_ns_changed(ns->subsys, ns->nsid); 5971f357548SChaitanya Kulkarni mutex_unlock(&ns->subsys->lock); 5981f357548SChaitanya Kulkarni return count; 5991f357548SChaitanya Kulkarni } 6001f357548SChaitanya Kulkarni 6011f357548SChaitanya Kulkarni CONFIGFS_ATTR_WO(nvmet_ns_, revalidate_size); 6021f357548SChaitanya Kulkarni 603a07b4970SChristoph Hellwig static struct configfs_attribute *nvmet_ns_attrs[] = { 604a07b4970SChristoph Hellwig &nvmet_ns_attr_device_path, 605a07b4970SChristoph Hellwig &nvmet_ns_attr_device_nguid, 606430c7befSJohannes Thumshirn &nvmet_ns_attr_device_uuid, 60762ac0d32SChristoph Hellwig &nvmet_ns_attr_ana_grpid, 608a07b4970SChristoph Hellwig &nvmet_ns_attr_enable, 60955eb942eSChaitanya Kulkarni &nvmet_ns_attr_buffered_io, 6101f357548SChaitanya Kulkarni &nvmet_ns_attr_revalidate_size, 611c6925093SLogan Gunthorpe #ifdef CONFIG_PCI_P2PDMA 612c6925093SLogan Gunthorpe &nvmet_ns_attr_p2pmem, 613c6925093SLogan Gunthorpe #endif 614a07b4970SChristoph Hellwig NULL, 615a07b4970SChristoph Hellwig }; 616a07b4970SChristoph Hellwig 617a07b4970SChristoph Hellwig static void nvmet_ns_release(struct config_item *item) 618a07b4970SChristoph Hellwig { 619a07b4970SChristoph Hellwig struct nvmet_ns *ns = to_nvmet_ns(item); 620a07b4970SChristoph Hellwig 621a07b4970SChristoph Hellwig nvmet_ns_free(ns); 622a07b4970SChristoph Hellwig } 623a07b4970SChristoph Hellwig 624a07b4970SChristoph Hellwig static struct configfs_item_operations nvmet_ns_item_ops = { 625a07b4970SChristoph Hellwig .release = nvmet_ns_release, 626a07b4970SChristoph Hellwig }; 627a07b4970SChristoph Hellwig 62866603a31SBhumika Goyal static const struct config_item_type nvmet_ns_type = { 629a07b4970SChristoph Hellwig .ct_item_ops = &nvmet_ns_item_ops, 630a07b4970SChristoph Hellwig .ct_attrs = nvmet_ns_attrs, 631a07b4970SChristoph Hellwig .ct_owner = THIS_MODULE, 632a07b4970SChristoph Hellwig }; 633a07b4970SChristoph Hellwig 634a07b4970SChristoph Hellwig static struct config_group *nvmet_ns_make(struct config_group *group, 635a07b4970SChristoph Hellwig const char *name) 636a07b4970SChristoph Hellwig { 637a07b4970SChristoph Hellwig struct nvmet_subsys *subsys = namespaces_to_subsys(&group->cg_item); 638a07b4970SChristoph Hellwig struct nvmet_ns *ns; 639a07b4970SChristoph Hellwig int ret; 640a07b4970SChristoph Hellwig u32 nsid; 641a07b4970SChristoph Hellwig 642a07b4970SChristoph Hellwig ret = kstrtou32(name, 0, &nsid); 643a07b4970SChristoph Hellwig if (ret) 644a07b4970SChristoph Hellwig goto out; 645a07b4970SChristoph Hellwig 646a07b4970SChristoph Hellwig ret = -EINVAL; 6475ba89503SMikhail Skorzhinskii if (nsid == 0 || nsid == NVME_NSID_ALL) { 6485ba89503SMikhail Skorzhinskii pr_err("invalid nsid %#x", nsid); 649a07b4970SChristoph Hellwig goto out; 6505ba89503SMikhail Skorzhinskii } 651a07b4970SChristoph Hellwig 652a07b4970SChristoph Hellwig ret = -ENOMEM; 653a07b4970SChristoph Hellwig ns = nvmet_ns_alloc(subsys, nsid); 654a07b4970SChristoph Hellwig if (!ns) 655a07b4970SChristoph Hellwig goto out; 656a07b4970SChristoph Hellwig config_group_init_type_name(&ns->group, name, &nvmet_ns_type); 657a07b4970SChristoph Hellwig 658a07b4970SChristoph Hellwig pr_info("adding nsid %d to subsystem %s\n", nsid, subsys->subsysnqn); 659a07b4970SChristoph Hellwig 660a07b4970SChristoph Hellwig return &ns->group; 661a07b4970SChristoph Hellwig out: 662a07b4970SChristoph Hellwig return ERR_PTR(ret); 663a07b4970SChristoph Hellwig } 664a07b4970SChristoph Hellwig 665a07b4970SChristoph Hellwig static struct configfs_group_operations nvmet_namespaces_group_ops = { 666a07b4970SChristoph Hellwig .make_group = nvmet_ns_make, 667a07b4970SChristoph Hellwig }; 668a07b4970SChristoph Hellwig 66966603a31SBhumika Goyal static const struct config_item_type nvmet_namespaces_type = { 670a07b4970SChristoph Hellwig .ct_group_ops = &nvmet_namespaces_group_ops, 671a07b4970SChristoph Hellwig .ct_owner = THIS_MODULE, 672a07b4970SChristoph Hellwig }; 673a07b4970SChristoph Hellwig 674cae5b01aSLogan Gunthorpe #ifdef CONFIG_NVME_TARGET_PASSTHRU 675cae5b01aSLogan Gunthorpe 676cae5b01aSLogan Gunthorpe static ssize_t nvmet_passthru_device_path_show(struct config_item *item, 677cae5b01aSLogan Gunthorpe char *page) 678cae5b01aSLogan Gunthorpe { 679cae5b01aSLogan Gunthorpe struct nvmet_subsys *subsys = to_subsys(item->ci_parent); 680cae5b01aSLogan Gunthorpe 681cae5b01aSLogan Gunthorpe return snprintf(page, PAGE_SIZE, "%s\n", subsys->passthru_ctrl_path); 682cae5b01aSLogan Gunthorpe } 683cae5b01aSLogan Gunthorpe 684cae5b01aSLogan Gunthorpe static ssize_t nvmet_passthru_device_path_store(struct config_item *item, 685cae5b01aSLogan Gunthorpe const char *page, size_t count) 686cae5b01aSLogan Gunthorpe { 687cae5b01aSLogan Gunthorpe struct nvmet_subsys *subsys = to_subsys(item->ci_parent); 688cae5b01aSLogan Gunthorpe size_t len; 689cae5b01aSLogan Gunthorpe int ret; 690cae5b01aSLogan Gunthorpe 691cae5b01aSLogan Gunthorpe mutex_lock(&subsys->lock); 692cae5b01aSLogan Gunthorpe 693cae5b01aSLogan Gunthorpe ret = -EBUSY; 694cae5b01aSLogan Gunthorpe if (subsys->passthru_ctrl) 695cae5b01aSLogan Gunthorpe goto out_unlock; 696cae5b01aSLogan Gunthorpe 697cae5b01aSLogan Gunthorpe ret = -EINVAL; 698cae5b01aSLogan Gunthorpe len = strcspn(page, "\n"); 699cae5b01aSLogan Gunthorpe if (!len) 700cae5b01aSLogan Gunthorpe goto out_unlock; 701cae5b01aSLogan Gunthorpe 702cae5b01aSLogan Gunthorpe kfree(subsys->passthru_ctrl_path); 703cae5b01aSLogan Gunthorpe ret = -ENOMEM; 704cae5b01aSLogan Gunthorpe subsys->passthru_ctrl_path = kstrndup(page, len, GFP_KERNEL); 705cae5b01aSLogan Gunthorpe if (!subsys->passthru_ctrl_path) 706cae5b01aSLogan Gunthorpe goto out_unlock; 707cae5b01aSLogan Gunthorpe 708cae5b01aSLogan Gunthorpe mutex_unlock(&subsys->lock); 709cae5b01aSLogan Gunthorpe 710cae5b01aSLogan Gunthorpe return count; 711cae5b01aSLogan Gunthorpe out_unlock: 712cae5b01aSLogan Gunthorpe mutex_unlock(&subsys->lock); 713cae5b01aSLogan Gunthorpe return ret; 714cae5b01aSLogan Gunthorpe } 715cae5b01aSLogan Gunthorpe CONFIGFS_ATTR(nvmet_passthru_, device_path); 716cae5b01aSLogan Gunthorpe 717cae5b01aSLogan Gunthorpe static ssize_t nvmet_passthru_enable_show(struct config_item *item, 718cae5b01aSLogan Gunthorpe char *page) 719cae5b01aSLogan Gunthorpe { 720cae5b01aSLogan Gunthorpe struct nvmet_subsys *subsys = to_subsys(item->ci_parent); 721cae5b01aSLogan Gunthorpe 722cae5b01aSLogan Gunthorpe return sprintf(page, "%d\n", subsys->passthru_ctrl ? 1 : 0); 723cae5b01aSLogan Gunthorpe } 724cae5b01aSLogan Gunthorpe 725cae5b01aSLogan Gunthorpe static ssize_t nvmet_passthru_enable_store(struct config_item *item, 726cae5b01aSLogan Gunthorpe const char *page, size_t count) 727cae5b01aSLogan Gunthorpe { 728cae5b01aSLogan Gunthorpe struct nvmet_subsys *subsys = to_subsys(item->ci_parent); 729cae5b01aSLogan Gunthorpe bool enable; 730cae5b01aSLogan Gunthorpe int ret = 0; 731cae5b01aSLogan Gunthorpe 732*99722c8aSChristophe JAILLET if (kstrtobool(page, &enable)) 733cae5b01aSLogan Gunthorpe return -EINVAL; 734cae5b01aSLogan Gunthorpe 735cae5b01aSLogan Gunthorpe if (enable) 736cae5b01aSLogan Gunthorpe ret = nvmet_passthru_ctrl_enable(subsys); 737cae5b01aSLogan Gunthorpe else 738cae5b01aSLogan Gunthorpe nvmet_passthru_ctrl_disable(subsys); 739cae5b01aSLogan Gunthorpe 740cae5b01aSLogan Gunthorpe return ret ? ret : count; 741cae5b01aSLogan Gunthorpe } 742cae5b01aSLogan Gunthorpe CONFIGFS_ATTR(nvmet_passthru_, enable); 743cae5b01aSLogan Gunthorpe 744a2f6a2b8SChaitanya Kulkarni static ssize_t nvmet_passthru_admin_timeout_show(struct config_item *item, 745a2f6a2b8SChaitanya Kulkarni char *page) 746a2f6a2b8SChaitanya Kulkarni { 747a2f6a2b8SChaitanya Kulkarni return sprintf(page, "%u\n", to_subsys(item->ci_parent)->admin_timeout); 748a2f6a2b8SChaitanya Kulkarni } 749a2f6a2b8SChaitanya Kulkarni 750a2f6a2b8SChaitanya Kulkarni static ssize_t nvmet_passthru_admin_timeout_store(struct config_item *item, 751a2f6a2b8SChaitanya Kulkarni const char *page, size_t count) 752a2f6a2b8SChaitanya Kulkarni { 753a2f6a2b8SChaitanya Kulkarni struct nvmet_subsys *subsys = to_subsys(item->ci_parent); 754a2f6a2b8SChaitanya Kulkarni unsigned int timeout; 755a2f6a2b8SChaitanya Kulkarni 756a2f6a2b8SChaitanya Kulkarni if (kstrtouint(page, 0, &timeout)) 757a2f6a2b8SChaitanya Kulkarni return -EINVAL; 758a2f6a2b8SChaitanya Kulkarni subsys->admin_timeout = timeout; 759a2f6a2b8SChaitanya Kulkarni return count; 760a2f6a2b8SChaitanya Kulkarni } 761a2f6a2b8SChaitanya Kulkarni CONFIGFS_ATTR(nvmet_passthru_, admin_timeout); 762a2f6a2b8SChaitanya Kulkarni 76347e9730cSChaitanya Kulkarni static ssize_t nvmet_passthru_io_timeout_show(struct config_item *item, 76447e9730cSChaitanya Kulkarni char *page) 76547e9730cSChaitanya Kulkarni { 76647e9730cSChaitanya Kulkarni return sprintf(page, "%u\n", to_subsys(item->ci_parent)->io_timeout); 76747e9730cSChaitanya Kulkarni } 76847e9730cSChaitanya Kulkarni 76947e9730cSChaitanya Kulkarni static ssize_t nvmet_passthru_io_timeout_store(struct config_item *item, 77047e9730cSChaitanya Kulkarni const char *page, size_t count) 77147e9730cSChaitanya Kulkarni { 77247e9730cSChaitanya Kulkarni struct nvmet_subsys *subsys = to_subsys(item->ci_parent); 77347e9730cSChaitanya Kulkarni unsigned int timeout; 77447e9730cSChaitanya Kulkarni 77547e9730cSChaitanya Kulkarni if (kstrtouint(page, 0, &timeout)) 77647e9730cSChaitanya Kulkarni return -EINVAL; 77747e9730cSChaitanya Kulkarni subsys->io_timeout = timeout; 77847e9730cSChaitanya Kulkarni return count; 77947e9730cSChaitanya Kulkarni } 78047e9730cSChaitanya Kulkarni CONFIGFS_ATTR(nvmet_passthru_, io_timeout); 78147e9730cSChaitanya Kulkarni 78234ad6151SAlan Adamson static ssize_t nvmet_passthru_clear_ids_show(struct config_item *item, 78334ad6151SAlan Adamson char *page) 78434ad6151SAlan Adamson { 78534ad6151SAlan Adamson return sprintf(page, "%u\n", to_subsys(item->ci_parent)->clear_ids); 78634ad6151SAlan Adamson } 78734ad6151SAlan Adamson 78834ad6151SAlan Adamson static ssize_t nvmet_passthru_clear_ids_store(struct config_item *item, 78934ad6151SAlan Adamson const char *page, size_t count) 79034ad6151SAlan Adamson { 79134ad6151SAlan Adamson struct nvmet_subsys *subsys = to_subsys(item->ci_parent); 79234ad6151SAlan Adamson unsigned int clear_ids; 79334ad6151SAlan Adamson 79434ad6151SAlan Adamson if (kstrtouint(page, 0, &clear_ids)) 79534ad6151SAlan Adamson return -EINVAL; 79634ad6151SAlan Adamson subsys->clear_ids = clear_ids; 79734ad6151SAlan Adamson return count; 79834ad6151SAlan Adamson } 79934ad6151SAlan Adamson CONFIGFS_ATTR(nvmet_passthru_, clear_ids); 80034ad6151SAlan Adamson 801cae5b01aSLogan Gunthorpe static struct configfs_attribute *nvmet_passthru_attrs[] = { 802cae5b01aSLogan Gunthorpe &nvmet_passthru_attr_device_path, 803cae5b01aSLogan Gunthorpe &nvmet_passthru_attr_enable, 804a2f6a2b8SChaitanya Kulkarni &nvmet_passthru_attr_admin_timeout, 80547e9730cSChaitanya Kulkarni &nvmet_passthru_attr_io_timeout, 80634ad6151SAlan Adamson &nvmet_passthru_attr_clear_ids, 807cae5b01aSLogan Gunthorpe NULL, 808cae5b01aSLogan Gunthorpe }; 809cae5b01aSLogan Gunthorpe 810cae5b01aSLogan Gunthorpe static const struct config_item_type nvmet_passthru_type = { 811cae5b01aSLogan Gunthorpe .ct_attrs = nvmet_passthru_attrs, 812cae5b01aSLogan Gunthorpe .ct_owner = THIS_MODULE, 813cae5b01aSLogan Gunthorpe }; 814cae5b01aSLogan Gunthorpe 815cae5b01aSLogan Gunthorpe static void nvmet_add_passthru_group(struct nvmet_subsys *subsys) 816cae5b01aSLogan Gunthorpe { 817cae5b01aSLogan Gunthorpe config_group_init_type_name(&subsys->passthru_group, 818cae5b01aSLogan Gunthorpe "passthru", &nvmet_passthru_type); 819cae5b01aSLogan Gunthorpe configfs_add_default_group(&subsys->passthru_group, 820cae5b01aSLogan Gunthorpe &subsys->group); 821cae5b01aSLogan Gunthorpe } 822cae5b01aSLogan Gunthorpe 823cae5b01aSLogan Gunthorpe #else /* CONFIG_NVME_TARGET_PASSTHRU */ 824cae5b01aSLogan Gunthorpe 825cae5b01aSLogan Gunthorpe static void nvmet_add_passthru_group(struct nvmet_subsys *subsys) 826cae5b01aSLogan Gunthorpe { 827cae5b01aSLogan Gunthorpe } 828cae5b01aSLogan Gunthorpe 829cae5b01aSLogan Gunthorpe #endif /* CONFIG_NVME_TARGET_PASSTHRU */ 830cae5b01aSLogan Gunthorpe 831a07b4970SChristoph Hellwig static int nvmet_port_subsys_allow_link(struct config_item *parent, 832a07b4970SChristoph Hellwig struct config_item *target) 833a07b4970SChristoph Hellwig { 834a07b4970SChristoph Hellwig struct nvmet_port *port = to_nvmet_port(parent->ci_parent); 835a07b4970SChristoph Hellwig struct nvmet_subsys *subsys; 836a07b4970SChristoph Hellwig struct nvmet_subsys_link *link, *p; 837a07b4970SChristoph Hellwig int ret; 838a07b4970SChristoph Hellwig 839a07b4970SChristoph Hellwig if (target->ci_type != &nvmet_subsys_type) { 840a07b4970SChristoph Hellwig pr_err("can only link subsystems into the subsystems dir.!\n"); 841a07b4970SChristoph Hellwig return -EINVAL; 842a07b4970SChristoph Hellwig } 843a07b4970SChristoph Hellwig subsys = to_subsys(target); 844a07b4970SChristoph Hellwig link = kmalloc(sizeof(*link), GFP_KERNEL); 845a07b4970SChristoph Hellwig if (!link) 846a07b4970SChristoph Hellwig return -ENOMEM; 847a07b4970SChristoph Hellwig link->subsys = subsys; 848a07b4970SChristoph Hellwig 849a07b4970SChristoph Hellwig down_write(&nvmet_config_sem); 850a07b4970SChristoph Hellwig ret = -EEXIST; 851a07b4970SChristoph Hellwig list_for_each_entry(p, &port->subsystems, entry) { 852a07b4970SChristoph Hellwig if (p->subsys == subsys) 853a07b4970SChristoph Hellwig goto out_free_link; 854a07b4970SChristoph Hellwig } 855a07b4970SChristoph Hellwig 856a07b4970SChristoph Hellwig if (list_empty(&port->subsystems)) { 857a07b4970SChristoph Hellwig ret = nvmet_enable_port(port); 858a07b4970SChristoph Hellwig if (ret) 859a07b4970SChristoph Hellwig goto out_free_link; 860a07b4970SChristoph Hellwig } 861a07b4970SChristoph Hellwig 862a07b4970SChristoph Hellwig list_add_tail(&link->entry, &port->subsystems); 863b662a078SJay Sternberg nvmet_port_disc_changed(port, subsys); 864b662a078SJay Sternberg 865a07b4970SChristoph Hellwig up_write(&nvmet_config_sem); 866a07b4970SChristoph Hellwig return 0; 867a07b4970SChristoph Hellwig 868a07b4970SChristoph Hellwig out_free_link: 869a07b4970SChristoph Hellwig up_write(&nvmet_config_sem); 870a07b4970SChristoph Hellwig kfree(link); 871a07b4970SChristoph Hellwig return ret; 872a07b4970SChristoph Hellwig } 873a07b4970SChristoph Hellwig 874e16769d4SAndrzej Pietrasiewicz static void nvmet_port_subsys_drop_link(struct config_item *parent, 875a07b4970SChristoph Hellwig struct config_item *target) 876a07b4970SChristoph Hellwig { 877a07b4970SChristoph Hellwig struct nvmet_port *port = to_nvmet_port(parent->ci_parent); 878a07b4970SChristoph Hellwig struct nvmet_subsys *subsys = to_subsys(target); 879a07b4970SChristoph Hellwig struct nvmet_subsys_link *p; 880a07b4970SChristoph Hellwig 881a07b4970SChristoph Hellwig down_write(&nvmet_config_sem); 882a07b4970SChristoph Hellwig list_for_each_entry(p, &port->subsystems, entry) { 883a07b4970SChristoph Hellwig if (p->subsys == subsys) 884a07b4970SChristoph Hellwig goto found; 885a07b4970SChristoph Hellwig } 886a07b4970SChristoph Hellwig up_write(&nvmet_config_sem); 887e16769d4SAndrzej Pietrasiewicz return; 888a07b4970SChristoph Hellwig 889a07b4970SChristoph Hellwig found: 890a07b4970SChristoph Hellwig list_del(&p->entry); 8913aed8673SLogan Gunthorpe nvmet_port_del_ctrls(port, subsys); 892b662a078SJay Sternberg nvmet_port_disc_changed(port, subsys); 893b662a078SJay Sternberg 894a07b4970SChristoph Hellwig if (list_empty(&port->subsystems)) 895a07b4970SChristoph Hellwig nvmet_disable_port(port); 896a07b4970SChristoph Hellwig up_write(&nvmet_config_sem); 897a07b4970SChristoph Hellwig kfree(p); 898a07b4970SChristoph Hellwig } 899a07b4970SChristoph Hellwig 900a07b4970SChristoph Hellwig static struct configfs_item_operations nvmet_port_subsys_item_ops = { 901a07b4970SChristoph Hellwig .allow_link = nvmet_port_subsys_allow_link, 902a07b4970SChristoph Hellwig .drop_link = nvmet_port_subsys_drop_link, 903a07b4970SChristoph Hellwig }; 904a07b4970SChristoph Hellwig 90566603a31SBhumika Goyal static const struct config_item_type nvmet_port_subsys_type = { 906a07b4970SChristoph Hellwig .ct_item_ops = &nvmet_port_subsys_item_ops, 907a07b4970SChristoph Hellwig .ct_owner = THIS_MODULE, 908a07b4970SChristoph Hellwig }; 909a07b4970SChristoph Hellwig 910a07b4970SChristoph Hellwig static int nvmet_allowed_hosts_allow_link(struct config_item *parent, 911a07b4970SChristoph Hellwig struct config_item *target) 912a07b4970SChristoph Hellwig { 913a07b4970SChristoph Hellwig struct nvmet_subsys *subsys = to_subsys(parent->ci_parent); 914a07b4970SChristoph Hellwig struct nvmet_host *host; 915a07b4970SChristoph Hellwig struct nvmet_host_link *link, *p; 916a07b4970SChristoph Hellwig int ret; 917a07b4970SChristoph Hellwig 918a07b4970SChristoph Hellwig if (target->ci_type != &nvmet_host_type) { 919a07b4970SChristoph Hellwig pr_err("can only link hosts into the allowed_hosts directory!\n"); 920a07b4970SChristoph Hellwig return -EINVAL; 921a07b4970SChristoph Hellwig } 922a07b4970SChristoph Hellwig 923a07b4970SChristoph Hellwig host = to_host(target); 924a07b4970SChristoph Hellwig link = kmalloc(sizeof(*link), GFP_KERNEL); 925a07b4970SChristoph Hellwig if (!link) 926a07b4970SChristoph Hellwig return -ENOMEM; 927a07b4970SChristoph Hellwig link->host = host; 928a07b4970SChristoph Hellwig 929a07b4970SChristoph Hellwig down_write(&nvmet_config_sem); 930a07b4970SChristoph Hellwig ret = -EINVAL; 931a07b4970SChristoph Hellwig if (subsys->allow_any_host) { 932a07b4970SChristoph Hellwig pr_err("can't add hosts when allow_any_host is set!\n"); 933a07b4970SChristoph Hellwig goto out_free_link; 934a07b4970SChristoph Hellwig } 935a07b4970SChristoph Hellwig 936a07b4970SChristoph Hellwig ret = -EEXIST; 937a07b4970SChristoph Hellwig list_for_each_entry(p, &subsys->hosts, entry) { 938a07b4970SChristoph Hellwig if (!strcmp(nvmet_host_name(p->host), nvmet_host_name(host))) 939a07b4970SChristoph Hellwig goto out_free_link; 940a07b4970SChristoph Hellwig } 941a07b4970SChristoph Hellwig list_add_tail(&link->entry, &subsys->hosts); 942b662a078SJay Sternberg nvmet_subsys_disc_changed(subsys, host); 943b662a078SJay Sternberg 944a07b4970SChristoph Hellwig up_write(&nvmet_config_sem); 945a07b4970SChristoph Hellwig return 0; 946a07b4970SChristoph Hellwig out_free_link: 947a07b4970SChristoph Hellwig up_write(&nvmet_config_sem); 948a07b4970SChristoph Hellwig kfree(link); 949a07b4970SChristoph Hellwig return ret; 950a07b4970SChristoph Hellwig } 951a07b4970SChristoph Hellwig 952e16769d4SAndrzej Pietrasiewicz static void nvmet_allowed_hosts_drop_link(struct config_item *parent, 953a07b4970SChristoph Hellwig struct config_item *target) 954a07b4970SChristoph Hellwig { 955a07b4970SChristoph Hellwig struct nvmet_subsys *subsys = to_subsys(parent->ci_parent); 956a07b4970SChristoph Hellwig struct nvmet_host *host = to_host(target); 957a07b4970SChristoph Hellwig struct nvmet_host_link *p; 958a07b4970SChristoph Hellwig 959a07b4970SChristoph Hellwig down_write(&nvmet_config_sem); 960a07b4970SChristoph Hellwig list_for_each_entry(p, &subsys->hosts, entry) { 961a07b4970SChristoph Hellwig if (!strcmp(nvmet_host_name(p->host), nvmet_host_name(host))) 962a07b4970SChristoph Hellwig goto found; 963a07b4970SChristoph Hellwig } 964a07b4970SChristoph Hellwig up_write(&nvmet_config_sem); 965e16769d4SAndrzej Pietrasiewicz return; 966a07b4970SChristoph Hellwig 967a07b4970SChristoph Hellwig found: 968a07b4970SChristoph Hellwig list_del(&p->entry); 969b662a078SJay Sternberg nvmet_subsys_disc_changed(subsys, host); 970b662a078SJay Sternberg 971a07b4970SChristoph Hellwig up_write(&nvmet_config_sem); 972a07b4970SChristoph Hellwig kfree(p); 973a07b4970SChristoph Hellwig } 974a07b4970SChristoph Hellwig 975a07b4970SChristoph Hellwig static struct configfs_item_operations nvmet_allowed_hosts_item_ops = { 976a07b4970SChristoph Hellwig .allow_link = nvmet_allowed_hosts_allow_link, 977a07b4970SChristoph Hellwig .drop_link = nvmet_allowed_hosts_drop_link, 978a07b4970SChristoph Hellwig }; 979a07b4970SChristoph Hellwig 98066603a31SBhumika Goyal static const struct config_item_type nvmet_allowed_hosts_type = { 981a07b4970SChristoph Hellwig .ct_item_ops = &nvmet_allowed_hosts_item_ops, 982a07b4970SChristoph Hellwig .ct_owner = THIS_MODULE, 983a07b4970SChristoph Hellwig }; 984a07b4970SChristoph Hellwig 985a07b4970SChristoph Hellwig static ssize_t nvmet_subsys_attr_allow_any_host_show(struct config_item *item, 986a07b4970SChristoph Hellwig char *page) 987a07b4970SChristoph Hellwig { 988a07b4970SChristoph Hellwig return snprintf(page, PAGE_SIZE, "%d\n", 989a07b4970SChristoph Hellwig to_subsys(item)->allow_any_host); 990a07b4970SChristoph Hellwig } 991a07b4970SChristoph Hellwig 992a07b4970SChristoph Hellwig static ssize_t nvmet_subsys_attr_allow_any_host_store(struct config_item *item, 993a07b4970SChristoph Hellwig const char *page, size_t count) 994a07b4970SChristoph Hellwig { 995a07b4970SChristoph Hellwig struct nvmet_subsys *subsys = to_subsys(item); 996a07b4970SChristoph Hellwig bool allow_any_host; 997a07b4970SChristoph Hellwig int ret = 0; 998a07b4970SChristoph Hellwig 999*99722c8aSChristophe JAILLET if (kstrtobool(page, &allow_any_host)) 1000a07b4970SChristoph Hellwig return -EINVAL; 1001a07b4970SChristoph Hellwig 1002a07b4970SChristoph Hellwig down_write(&nvmet_config_sem); 1003a07b4970SChristoph Hellwig if (allow_any_host && !list_empty(&subsys->hosts)) { 1004a07b4970SChristoph Hellwig pr_err("Can't set allow_any_host when explicit hosts are set!\n"); 1005a07b4970SChristoph Hellwig ret = -EINVAL; 1006a07b4970SChristoph Hellwig goto out_unlock; 1007a07b4970SChristoph Hellwig } 1008a07b4970SChristoph Hellwig 1009b662a078SJay Sternberg if (subsys->allow_any_host != allow_any_host) { 1010a07b4970SChristoph Hellwig subsys->allow_any_host = allow_any_host; 1011b662a078SJay Sternberg nvmet_subsys_disc_changed(subsys, NULL); 1012b662a078SJay Sternberg } 1013b662a078SJay Sternberg 1014a07b4970SChristoph Hellwig out_unlock: 1015a07b4970SChristoph Hellwig up_write(&nvmet_config_sem); 1016a07b4970SChristoph Hellwig return ret ? ret : count; 1017a07b4970SChristoph Hellwig } 1018a07b4970SChristoph Hellwig 1019a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_subsys_, attr_allow_any_host); 1020a07b4970SChristoph Hellwig 102141528f80SJohannes Thumshirn static ssize_t nvmet_subsys_attr_version_show(struct config_item *item, 1022c61d788bSJohannes Thumshirn char *page) 1023c61d788bSJohannes Thumshirn { 1024c61d788bSJohannes Thumshirn struct nvmet_subsys *subsys = to_subsys(item); 1025c61d788bSJohannes Thumshirn 1026c61d788bSJohannes Thumshirn if (NVME_TERTIARY(subsys->ver)) 1027a0f0dbaaSChaitanya Kulkarni return snprintf(page, PAGE_SIZE, "%llu.%llu.%llu\n", 1028a0f0dbaaSChaitanya Kulkarni NVME_MAJOR(subsys->ver), 1029a0f0dbaaSChaitanya Kulkarni NVME_MINOR(subsys->ver), 1030a0f0dbaaSChaitanya Kulkarni NVME_TERTIARY(subsys->ver)); 1031527123c7SChaitanya Kulkarni 1032a0f0dbaaSChaitanya Kulkarni return snprintf(page, PAGE_SIZE, "%llu.%llu\n", 1033a0f0dbaaSChaitanya Kulkarni NVME_MAJOR(subsys->ver), 1034a0f0dbaaSChaitanya Kulkarni NVME_MINOR(subsys->ver)); 1035c61d788bSJohannes Thumshirn } 1036c61d788bSJohannes Thumshirn 103787fd4cc1SNoam Gottlieb static ssize_t 103887fd4cc1SNoam Gottlieb nvmet_subsys_attr_version_store_locked(struct nvmet_subsys *subsys, 1039c61d788bSJohannes Thumshirn const char *page, size_t count) 1040c61d788bSJohannes Thumshirn { 1041c61d788bSJohannes Thumshirn int major, minor, tertiary = 0; 1042c61d788bSJohannes Thumshirn int ret; 1043c61d788bSJohannes Thumshirn 104487fd4cc1SNoam Gottlieb if (subsys->subsys_discovered) { 104587fd4cc1SNoam Gottlieb if (NVME_TERTIARY(subsys->ver)) 104687fd4cc1SNoam Gottlieb pr_err("Can't set version number. %llu.%llu.%llu is already assigned\n", 104787fd4cc1SNoam Gottlieb NVME_MAJOR(subsys->ver), 104887fd4cc1SNoam Gottlieb NVME_MINOR(subsys->ver), 104987fd4cc1SNoam Gottlieb NVME_TERTIARY(subsys->ver)); 105087fd4cc1SNoam Gottlieb else 105187fd4cc1SNoam Gottlieb pr_err("Can't set version number. %llu.%llu is already assigned\n", 105287fd4cc1SNoam Gottlieb NVME_MAJOR(subsys->ver), 105387fd4cc1SNoam Gottlieb NVME_MINOR(subsys->ver)); 105487fd4cc1SNoam Gottlieb return -EINVAL; 105587fd4cc1SNoam Gottlieb } 105687fd4cc1SNoam Gottlieb 1057ba76af67SLogan Gunthorpe /* passthru subsystems use the underlying controller's version */ 1058ab7a2737SChristoph Hellwig if (nvmet_is_passthru_subsys(subsys)) 1059ba76af67SLogan Gunthorpe return -EINVAL; 1060ba76af67SLogan Gunthorpe 1061c61d788bSJohannes Thumshirn ret = sscanf(page, "%d.%d.%d\n", &major, &minor, &tertiary); 1062c61d788bSJohannes Thumshirn if (ret != 2 && ret != 3) 1063c61d788bSJohannes Thumshirn return -EINVAL; 1064c61d788bSJohannes Thumshirn 1065c61d788bSJohannes Thumshirn subsys->ver = NVME_VS(major, minor, tertiary); 1066c61d788bSJohannes Thumshirn 1067c61d788bSJohannes Thumshirn return count; 1068c61d788bSJohannes Thumshirn } 106987fd4cc1SNoam Gottlieb 107087fd4cc1SNoam Gottlieb static ssize_t nvmet_subsys_attr_version_store(struct config_item *item, 107187fd4cc1SNoam Gottlieb const char *page, size_t count) 107287fd4cc1SNoam Gottlieb { 107387fd4cc1SNoam Gottlieb struct nvmet_subsys *subsys = to_subsys(item); 107487fd4cc1SNoam Gottlieb ssize_t ret; 107587fd4cc1SNoam Gottlieb 107687fd4cc1SNoam Gottlieb down_write(&nvmet_config_sem); 107787fd4cc1SNoam Gottlieb mutex_lock(&subsys->lock); 107887fd4cc1SNoam Gottlieb ret = nvmet_subsys_attr_version_store_locked(subsys, page, count); 107987fd4cc1SNoam Gottlieb mutex_unlock(&subsys->lock); 108087fd4cc1SNoam Gottlieb up_write(&nvmet_config_sem); 108187fd4cc1SNoam Gottlieb 108287fd4cc1SNoam Gottlieb return ret; 108387fd4cc1SNoam Gottlieb } 108441528f80SJohannes Thumshirn CONFIGFS_ATTR(nvmet_subsys_, attr_version); 1085c61d788bSJohannes Thumshirn 1086e13b0615SNoam Gottlieb /* See Section 1.5 of NVMe 1.4 */ 1087e13b0615SNoam Gottlieb static bool nvmet_is_ascii(const char c) 1088e13b0615SNoam Gottlieb { 1089e13b0615SNoam Gottlieb return c >= 0x20 && c <= 0x7e; 1090e13b0615SNoam Gottlieb } 1091e13b0615SNoam Gottlieb 1092fcbc5459SJohannes Thumshirn static ssize_t nvmet_subsys_attr_serial_show(struct config_item *item, 1093fcbc5459SJohannes Thumshirn char *page) 1094fcbc5459SJohannes Thumshirn { 1095fcbc5459SJohannes Thumshirn struct nvmet_subsys *subsys = to_subsys(item); 1096fcbc5459SJohannes Thumshirn 10970bd46e22SDan Carpenter return snprintf(page, PAGE_SIZE, "%.*s\n", 1098f0406481SHannes Reinecke NVMET_SN_MAX_SIZE, subsys->serial); 1099fcbc5459SJohannes Thumshirn } 1100fcbc5459SJohannes Thumshirn 11017ae023c5SNoam Gottlieb static ssize_t 11027ae023c5SNoam Gottlieb nvmet_subsys_attr_serial_store_locked(struct nvmet_subsys *subsys, 1103fcbc5459SJohannes Thumshirn const char *page, size_t count) 1104fcbc5459SJohannes Thumshirn { 1105e13b0615SNoam Gottlieb int pos, len = strcspn(page, "\n"); 1106d3a9b0caSChaitanya Kulkarni 11077ae023c5SNoam Gottlieb if (subsys->subsys_discovered) { 11087ae023c5SNoam Gottlieb pr_err("Can't set serial number. %s is already assigned\n", 11097ae023c5SNoam Gottlieb subsys->serial); 11107ae023c5SNoam Gottlieb return -EINVAL; 11117ae023c5SNoam Gottlieb } 11127ae023c5SNoam Gottlieb 1113e13b0615SNoam Gottlieb if (!len || len > NVMET_SN_MAX_SIZE) { 1114e13b0615SNoam Gottlieb pr_err("Serial Number can not be empty or exceed %d Bytes\n", 1115e13b0615SNoam Gottlieb NVMET_SN_MAX_SIZE); 1116d3a9b0caSChaitanya Kulkarni return -EINVAL; 1117e13b0615SNoam Gottlieb } 1118e13b0615SNoam Gottlieb 1119e13b0615SNoam Gottlieb for (pos = 0; pos < len; pos++) { 1120e13b0615SNoam Gottlieb if (!nvmet_is_ascii(page[pos])) { 1121e13b0615SNoam Gottlieb pr_err("Serial Number must contain only ASCII strings\n"); 1122e13b0615SNoam Gottlieb return -EINVAL; 1123e13b0615SNoam Gottlieb } 1124e13b0615SNoam Gottlieb } 1125fcbc5459SJohannes Thumshirn 11267ae023c5SNoam Gottlieb memcpy_and_pad(subsys->serial, NVMET_SN_MAX_SIZE, page, len, ' '); 11277ae023c5SNoam Gottlieb 11287ae023c5SNoam Gottlieb return count; 11297ae023c5SNoam Gottlieb } 11307ae023c5SNoam Gottlieb 11317ae023c5SNoam Gottlieb static ssize_t nvmet_subsys_attr_serial_store(struct config_item *item, 11327ae023c5SNoam Gottlieb const char *page, size_t count) 11337ae023c5SNoam Gottlieb { 11347ae023c5SNoam Gottlieb struct nvmet_subsys *subsys = to_subsys(item); 11357ae023c5SNoam Gottlieb ssize_t ret; 11367ae023c5SNoam Gottlieb 1137fcbc5459SJohannes Thumshirn down_write(&nvmet_config_sem); 1138e13b0615SNoam Gottlieb mutex_lock(&subsys->lock); 11397ae023c5SNoam Gottlieb ret = nvmet_subsys_attr_serial_store_locked(subsys, page, count); 1140e13b0615SNoam Gottlieb mutex_unlock(&subsys->lock); 1141fcbc5459SJohannes Thumshirn up_write(&nvmet_config_sem); 1142fcbc5459SJohannes Thumshirn 11437ae023c5SNoam Gottlieb return ret; 1144fcbc5459SJohannes Thumshirn } 1145fcbc5459SJohannes Thumshirn CONFIGFS_ATTR(nvmet_subsys_, attr_serial); 1146fcbc5459SJohannes Thumshirn 114794a39d61SChaitanya Kulkarni static ssize_t nvmet_subsys_attr_cntlid_min_show(struct config_item *item, 114894a39d61SChaitanya Kulkarni char *page) 114994a39d61SChaitanya Kulkarni { 115094a39d61SChaitanya Kulkarni return snprintf(page, PAGE_SIZE, "%u\n", to_subsys(item)->cntlid_min); 115194a39d61SChaitanya Kulkarni } 115294a39d61SChaitanya Kulkarni 115394a39d61SChaitanya Kulkarni static ssize_t nvmet_subsys_attr_cntlid_min_store(struct config_item *item, 115494a39d61SChaitanya Kulkarni const char *page, size_t cnt) 115594a39d61SChaitanya Kulkarni { 115694a39d61SChaitanya Kulkarni u16 cntlid_min; 115794a39d61SChaitanya Kulkarni 115894a39d61SChaitanya Kulkarni if (sscanf(page, "%hu\n", &cntlid_min) != 1) 115994a39d61SChaitanya Kulkarni return -EINVAL; 116094a39d61SChaitanya Kulkarni 116194a39d61SChaitanya Kulkarni if (cntlid_min == 0) 116294a39d61SChaitanya Kulkarni return -EINVAL; 116394a39d61SChaitanya Kulkarni 116494a39d61SChaitanya Kulkarni down_write(&nvmet_config_sem); 116594a39d61SChaitanya Kulkarni if (cntlid_min >= to_subsys(item)->cntlid_max) 116694a39d61SChaitanya Kulkarni goto out_unlock; 116794a39d61SChaitanya Kulkarni to_subsys(item)->cntlid_min = cntlid_min; 116894a39d61SChaitanya Kulkarni up_write(&nvmet_config_sem); 116994a39d61SChaitanya Kulkarni return cnt; 117094a39d61SChaitanya Kulkarni 117194a39d61SChaitanya Kulkarni out_unlock: 117294a39d61SChaitanya Kulkarni up_write(&nvmet_config_sem); 117394a39d61SChaitanya Kulkarni return -EINVAL; 117494a39d61SChaitanya Kulkarni } 117594a39d61SChaitanya Kulkarni CONFIGFS_ATTR(nvmet_subsys_, attr_cntlid_min); 117694a39d61SChaitanya Kulkarni 117794a39d61SChaitanya Kulkarni static ssize_t nvmet_subsys_attr_cntlid_max_show(struct config_item *item, 117894a39d61SChaitanya Kulkarni char *page) 117994a39d61SChaitanya Kulkarni { 118094a39d61SChaitanya Kulkarni return snprintf(page, PAGE_SIZE, "%u\n", to_subsys(item)->cntlid_max); 118194a39d61SChaitanya Kulkarni } 118294a39d61SChaitanya Kulkarni 118394a39d61SChaitanya Kulkarni static ssize_t nvmet_subsys_attr_cntlid_max_store(struct config_item *item, 118494a39d61SChaitanya Kulkarni const char *page, size_t cnt) 118594a39d61SChaitanya Kulkarni { 118694a39d61SChaitanya Kulkarni u16 cntlid_max; 118794a39d61SChaitanya Kulkarni 118894a39d61SChaitanya Kulkarni if (sscanf(page, "%hu\n", &cntlid_max) != 1) 118994a39d61SChaitanya Kulkarni return -EINVAL; 119094a39d61SChaitanya Kulkarni 119194a39d61SChaitanya Kulkarni if (cntlid_max == 0) 119294a39d61SChaitanya Kulkarni return -EINVAL; 119394a39d61SChaitanya Kulkarni 119494a39d61SChaitanya Kulkarni down_write(&nvmet_config_sem); 119594a39d61SChaitanya Kulkarni if (cntlid_max <= to_subsys(item)->cntlid_min) 119694a39d61SChaitanya Kulkarni goto out_unlock; 119794a39d61SChaitanya Kulkarni to_subsys(item)->cntlid_max = cntlid_max; 119894a39d61SChaitanya Kulkarni up_write(&nvmet_config_sem); 119994a39d61SChaitanya Kulkarni return cnt; 120094a39d61SChaitanya Kulkarni 120194a39d61SChaitanya Kulkarni out_unlock: 120294a39d61SChaitanya Kulkarni up_write(&nvmet_config_sem); 120394a39d61SChaitanya Kulkarni return -EINVAL; 120494a39d61SChaitanya Kulkarni } 120594a39d61SChaitanya Kulkarni CONFIGFS_ATTR(nvmet_subsys_, attr_cntlid_max); 120694a39d61SChaitanya Kulkarni 1207013b7ebeSMark Ruijter static ssize_t nvmet_subsys_attr_model_show(struct config_item *item, 1208013b7ebeSMark Ruijter char *page) 1209013b7ebeSMark Ruijter { 1210013b7ebeSMark Ruijter struct nvmet_subsys *subsys = to_subsys(item); 1211013b7ebeSMark Ruijter 12120d148efdSNoam Gottlieb return snprintf(page, PAGE_SIZE, "%s\n", subsys->model_number); 1213013b7ebeSMark Ruijter } 1214013b7ebeSMark Ruijter 1215d9f273b7SMax Gurtovoy static ssize_t nvmet_subsys_attr_model_store_locked(struct nvmet_subsys *subsys, 1216013b7ebeSMark Ruijter const char *page, size_t count) 1217013b7ebeSMark Ruijter { 1218013b7ebeSMark Ruijter int pos = 0, len; 1219013b7ebeSMark Ruijter 12200d148efdSNoam Gottlieb if (subsys->subsys_discovered) { 1221d9f273b7SMax Gurtovoy pr_err("Can't set model number. %s is already assigned\n", 1222d9f273b7SMax Gurtovoy subsys->model_number); 1223d9f273b7SMax Gurtovoy return -EINVAL; 1224d9f273b7SMax Gurtovoy } 1225d9f273b7SMax Gurtovoy 1226013b7ebeSMark Ruijter len = strcspn(page, "\n"); 1227013b7ebeSMark Ruijter if (!len) 1228013b7ebeSMark Ruijter return -EINVAL; 1229013b7ebeSMark Ruijter 123048b4c010SNoam Gottlieb if (len > NVMET_MN_MAX_SIZE) { 1231ccc1003bSColin Ian King pr_err("Model number size can not exceed %d Bytes\n", 123248b4c010SNoam Gottlieb NVMET_MN_MAX_SIZE); 123348b4c010SNoam Gottlieb return -EINVAL; 123448b4c010SNoam Gottlieb } 123548b4c010SNoam Gottlieb 1236013b7ebeSMark Ruijter for (pos = 0; pos < len; pos++) { 1237013b7ebeSMark Ruijter if (!nvmet_is_ascii(page[pos])) 1238013b7ebeSMark Ruijter return -EINVAL; 1239013b7ebeSMark Ruijter } 1240013b7ebeSMark Ruijter 1241d9f273b7SMax Gurtovoy subsys->model_number = kmemdup_nul(page, len, GFP_KERNEL); 1242d9f273b7SMax Gurtovoy if (!subsys->model_number) 1243013b7ebeSMark Ruijter return -ENOMEM; 1244d9f273b7SMax Gurtovoy return count; 1245013b7ebeSMark Ruijter } 1246d9f273b7SMax Gurtovoy 1247d9f273b7SMax Gurtovoy static ssize_t nvmet_subsys_attr_model_store(struct config_item *item, 1248d9f273b7SMax Gurtovoy const char *page, size_t count) 1249d9f273b7SMax Gurtovoy { 1250d9f273b7SMax Gurtovoy struct nvmet_subsys *subsys = to_subsys(item); 1251d9f273b7SMax Gurtovoy ssize_t ret; 1252013b7ebeSMark Ruijter 1253013b7ebeSMark Ruijter down_write(&nvmet_config_sem); 1254013b7ebeSMark Ruijter mutex_lock(&subsys->lock); 1255d9f273b7SMax Gurtovoy ret = nvmet_subsys_attr_model_store_locked(subsys, page, count); 1256013b7ebeSMark Ruijter mutex_unlock(&subsys->lock); 1257013b7ebeSMark Ruijter up_write(&nvmet_config_sem); 1258013b7ebeSMark Ruijter 1259d9f273b7SMax Gurtovoy return ret; 1260013b7ebeSMark Ruijter } 1261013b7ebeSMark Ruijter CONFIGFS_ATTR(nvmet_subsys_, attr_model); 1262013b7ebeSMark Ruijter 126323855abdSAleksandr Miloserdov static ssize_t nvmet_subsys_attr_ieee_oui_show(struct config_item *item, 126423855abdSAleksandr Miloserdov char *page) 126523855abdSAleksandr Miloserdov { 126623855abdSAleksandr Miloserdov struct nvmet_subsys *subsys = to_subsys(item); 126723855abdSAleksandr Miloserdov 126823855abdSAleksandr Miloserdov return sysfs_emit(page, "0x%06x\n", subsys->ieee_oui); 126923855abdSAleksandr Miloserdov } 127023855abdSAleksandr Miloserdov 127123855abdSAleksandr Miloserdov static ssize_t nvmet_subsys_attr_ieee_oui_store_locked(struct nvmet_subsys *subsys, 127223855abdSAleksandr Miloserdov const char *page, size_t count) 127323855abdSAleksandr Miloserdov { 127423855abdSAleksandr Miloserdov uint32_t val = 0; 127523855abdSAleksandr Miloserdov int ret; 127623855abdSAleksandr Miloserdov 127723855abdSAleksandr Miloserdov if (subsys->subsys_discovered) { 127823855abdSAleksandr Miloserdov pr_err("Can't set IEEE OUI. 0x%06x is already assigned\n", 127923855abdSAleksandr Miloserdov subsys->ieee_oui); 128023855abdSAleksandr Miloserdov return -EINVAL; 128123855abdSAleksandr Miloserdov } 128223855abdSAleksandr Miloserdov 128323855abdSAleksandr Miloserdov ret = kstrtou32(page, 0, &val); 128423855abdSAleksandr Miloserdov if (ret < 0) 128523855abdSAleksandr Miloserdov return ret; 128623855abdSAleksandr Miloserdov 128723855abdSAleksandr Miloserdov if (val >= 0x1000000) 128823855abdSAleksandr Miloserdov return -EINVAL; 128923855abdSAleksandr Miloserdov 129023855abdSAleksandr Miloserdov subsys->ieee_oui = val; 129123855abdSAleksandr Miloserdov 129223855abdSAleksandr Miloserdov return count; 129323855abdSAleksandr Miloserdov } 129423855abdSAleksandr Miloserdov 129523855abdSAleksandr Miloserdov static ssize_t nvmet_subsys_attr_ieee_oui_store(struct config_item *item, 129623855abdSAleksandr Miloserdov const char *page, size_t count) 129723855abdSAleksandr Miloserdov { 129823855abdSAleksandr Miloserdov struct nvmet_subsys *subsys = to_subsys(item); 129923855abdSAleksandr Miloserdov ssize_t ret; 130023855abdSAleksandr Miloserdov 130123855abdSAleksandr Miloserdov down_write(&nvmet_config_sem); 130223855abdSAleksandr Miloserdov mutex_lock(&subsys->lock); 130323855abdSAleksandr Miloserdov ret = nvmet_subsys_attr_ieee_oui_store_locked(subsys, page, count); 130423855abdSAleksandr Miloserdov mutex_unlock(&subsys->lock); 130523855abdSAleksandr Miloserdov up_write(&nvmet_config_sem); 130623855abdSAleksandr Miloserdov 130723855abdSAleksandr Miloserdov return ret; 130823855abdSAleksandr Miloserdov } 130923855abdSAleksandr Miloserdov CONFIGFS_ATTR(nvmet_subsys_, attr_ieee_oui); 131023855abdSAleksandr Miloserdov 131168c5444cSAleksandr Miloserdov static ssize_t nvmet_subsys_attr_firmware_show(struct config_item *item, 131268c5444cSAleksandr Miloserdov char *page) 131368c5444cSAleksandr Miloserdov { 131468c5444cSAleksandr Miloserdov struct nvmet_subsys *subsys = to_subsys(item); 131568c5444cSAleksandr Miloserdov 131668c5444cSAleksandr Miloserdov return sysfs_emit(page, "%s\n", subsys->firmware_rev); 131768c5444cSAleksandr Miloserdov } 131868c5444cSAleksandr Miloserdov 131968c5444cSAleksandr Miloserdov static ssize_t nvmet_subsys_attr_firmware_store_locked(struct nvmet_subsys *subsys, 132068c5444cSAleksandr Miloserdov const char *page, size_t count) 132168c5444cSAleksandr Miloserdov { 132268c5444cSAleksandr Miloserdov int pos = 0, len; 132368c5444cSAleksandr Miloserdov char *val; 132468c5444cSAleksandr Miloserdov 132568c5444cSAleksandr Miloserdov if (subsys->subsys_discovered) { 132668c5444cSAleksandr Miloserdov pr_err("Can't set firmware revision. %s is already assigned\n", 132768c5444cSAleksandr Miloserdov subsys->firmware_rev); 132868c5444cSAleksandr Miloserdov return -EINVAL; 132968c5444cSAleksandr Miloserdov } 133068c5444cSAleksandr Miloserdov 133168c5444cSAleksandr Miloserdov len = strcspn(page, "\n"); 133268c5444cSAleksandr Miloserdov if (!len) 133368c5444cSAleksandr Miloserdov return -EINVAL; 133468c5444cSAleksandr Miloserdov 133568c5444cSAleksandr Miloserdov if (len > NVMET_FR_MAX_SIZE) { 133668c5444cSAleksandr Miloserdov pr_err("Firmware revision size can not exceed %d Bytes\n", 133768c5444cSAleksandr Miloserdov NVMET_FR_MAX_SIZE); 133868c5444cSAleksandr Miloserdov return -EINVAL; 133968c5444cSAleksandr Miloserdov } 134068c5444cSAleksandr Miloserdov 134168c5444cSAleksandr Miloserdov for (pos = 0; pos < len; pos++) { 134268c5444cSAleksandr Miloserdov if (!nvmet_is_ascii(page[pos])) 134368c5444cSAleksandr Miloserdov return -EINVAL; 134468c5444cSAleksandr Miloserdov } 134568c5444cSAleksandr Miloserdov 134668c5444cSAleksandr Miloserdov val = kmemdup_nul(page, len, GFP_KERNEL); 134768c5444cSAleksandr Miloserdov if (!val) 134868c5444cSAleksandr Miloserdov return -ENOMEM; 134968c5444cSAleksandr Miloserdov 135068c5444cSAleksandr Miloserdov kfree(subsys->firmware_rev); 135168c5444cSAleksandr Miloserdov 135268c5444cSAleksandr Miloserdov subsys->firmware_rev = val; 135368c5444cSAleksandr Miloserdov 135468c5444cSAleksandr Miloserdov return count; 135568c5444cSAleksandr Miloserdov } 135668c5444cSAleksandr Miloserdov 135768c5444cSAleksandr Miloserdov static ssize_t nvmet_subsys_attr_firmware_store(struct config_item *item, 135868c5444cSAleksandr Miloserdov const char *page, size_t count) 135968c5444cSAleksandr Miloserdov { 136068c5444cSAleksandr Miloserdov struct nvmet_subsys *subsys = to_subsys(item); 136168c5444cSAleksandr Miloserdov ssize_t ret; 136268c5444cSAleksandr Miloserdov 136368c5444cSAleksandr Miloserdov down_write(&nvmet_config_sem); 136468c5444cSAleksandr Miloserdov mutex_lock(&subsys->lock); 136568c5444cSAleksandr Miloserdov ret = nvmet_subsys_attr_firmware_store_locked(subsys, page, count); 136668c5444cSAleksandr Miloserdov mutex_unlock(&subsys->lock); 136768c5444cSAleksandr Miloserdov up_write(&nvmet_config_sem); 136868c5444cSAleksandr Miloserdov 136968c5444cSAleksandr Miloserdov return ret; 137068c5444cSAleksandr Miloserdov } 137168c5444cSAleksandr Miloserdov CONFIGFS_ATTR(nvmet_subsys_, attr_firmware); 137268c5444cSAleksandr Miloserdov 1373ea52ac1cSIsrael Rukshin #ifdef CONFIG_BLK_DEV_INTEGRITY 1374ea52ac1cSIsrael Rukshin static ssize_t nvmet_subsys_attr_pi_enable_show(struct config_item *item, 1375ea52ac1cSIsrael Rukshin char *page) 1376ea52ac1cSIsrael Rukshin { 1377ea52ac1cSIsrael Rukshin return snprintf(page, PAGE_SIZE, "%d\n", to_subsys(item)->pi_support); 1378ea52ac1cSIsrael Rukshin } 1379ea52ac1cSIsrael Rukshin 1380ea52ac1cSIsrael Rukshin static ssize_t nvmet_subsys_attr_pi_enable_store(struct config_item *item, 1381ea52ac1cSIsrael Rukshin const char *page, size_t count) 1382ea52ac1cSIsrael Rukshin { 1383ea52ac1cSIsrael Rukshin struct nvmet_subsys *subsys = to_subsys(item); 1384ea52ac1cSIsrael Rukshin bool pi_enable; 1385ea52ac1cSIsrael Rukshin 1386*99722c8aSChristophe JAILLET if (kstrtobool(page, &pi_enable)) 1387ea52ac1cSIsrael Rukshin return -EINVAL; 1388ea52ac1cSIsrael Rukshin 1389ea52ac1cSIsrael Rukshin subsys->pi_support = pi_enable; 1390ea52ac1cSIsrael Rukshin return count; 1391ea52ac1cSIsrael Rukshin } 1392ea52ac1cSIsrael Rukshin CONFIGFS_ATTR(nvmet_subsys_, attr_pi_enable); 1393ea52ac1cSIsrael Rukshin #endif 1394ea52ac1cSIsrael Rukshin 13953e980f59SDaniel Wagner static ssize_t nvmet_subsys_attr_qid_max_show(struct config_item *item, 13963e980f59SDaniel Wagner char *page) 13973e980f59SDaniel Wagner { 13983e980f59SDaniel Wagner return snprintf(page, PAGE_SIZE, "%u\n", to_subsys(item)->max_qid); 13993e980f59SDaniel Wagner } 14003e980f59SDaniel Wagner 14013e980f59SDaniel Wagner static ssize_t nvmet_subsys_attr_qid_max_store(struct config_item *item, 14023e980f59SDaniel Wagner const char *page, size_t cnt) 14033e980f59SDaniel Wagner { 14042be2cd52SDaniel Wagner struct nvmet_subsys *subsys = to_subsys(item); 14052be2cd52SDaniel Wagner struct nvmet_ctrl *ctrl; 14063e980f59SDaniel Wagner u16 qid_max; 14073e980f59SDaniel Wagner 14083e980f59SDaniel Wagner if (sscanf(page, "%hu\n", &qid_max) != 1) 14093e980f59SDaniel Wagner return -EINVAL; 14103e980f59SDaniel Wagner 14113e980f59SDaniel Wagner if (qid_max < 1 || qid_max > NVMET_NR_QUEUES) 14123e980f59SDaniel Wagner return -EINVAL; 14133e980f59SDaniel Wagner 14143e980f59SDaniel Wagner down_write(&nvmet_config_sem); 14152be2cd52SDaniel Wagner subsys->max_qid = qid_max; 14162be2cd52SDaniel Wagner 14172be2cd52SDaniel Wagner /* Force reconnect */ 14182be2cd52SDaniel Wagner list_for_each_entry(ctrl, &subsys->ctrls, subsys_entry) 14192be2cd52SDaniel Wagner ctrl->ops->delete_ctrl(ctrl); 14203e980f59SDaniel Wagner up_write(&nvmet_config_sem); 14212be2cd52SDaniel Wagner 14223e980f59SDaniel Wagner return cnt; 14233e980f59SDaniel Wagner } 14243e980f59SDaniel Wagner CONFIGFS_ATTR(nvmet_subsys_, attr_qid_max); 14253e980f59SDaniel Wagner 1426a07b4970SChristoph Hellwig static struct configfs_attribute *nvmet_subsys_attrs[] = { 1427a07b4970SChristoph Hellwig &nvmet_subsys_attr_attr_allow_any_host, 142841528f80SJohannes Thumshirn &nvmet_subsys_attr_attr_version, 1429fcbc5459SJohannes Thumshirn &nvmet_subsys_attr_attr_serial, 143094a39d61SChaitanya Kulkarni &nvmet_subsys_attr_attr_cntlid_min, 143194a39d61SChaitanya Kulkarni &nvmet_subsys_attr_attr_cntlid_max, 1432013b7ebeSMark Ruijter &nvmet_subsys_attr_attr_model, 14333e980f59SDaniel Wagner &nvmet_subsys_attr_attr_qid_max, 143423855abdSAleksandr Miloserdov &nvmet_subsys_attr_attr_ieee_oui, 143568c5444cSAleksandr Miloserdov &nvmet_subsys_attr_attr_firmware, 1436ea52ac1cSIsrael Rukshin #ifdef CONFIG_BLK_DEV_INTEGRITY 1437ea52ac1cSIsrael Rukshin &nvmet_subsys_attr_attr_pi_enable, 1438ea52ac1cSIsrael Rukshin #endif 1439a07b4970SChristoph Hellwig NULL, 1440a07b4970SChristoph Hellwig }; 1441a07b4970SChristoph Hellwig 1442a07b4970SChristoph Hellwig /* 1443a07b4970SChristoph Hellwig * Subsystem structures & folder operation functions below 1444a07b4970SChristoph Hellwig */ 1445a07b4970SChristoph Hellwig static void nvmet_subsys_release(struct config_item *item) 1446a07b4970SChristoph Hellwig { 1447a07b4970SChristoph Hellwig struct nvmet_subsys *subsys = to_subsys(item); 1448a07b4970SChristoph Hellwig 1449344770b0SSagi Grimberg nvmet_subsys_del_ctrls(subsys); 1450a07b4970SChristoph Hellwig nvmet_subsys_put(subsys); 1451a07b4970SChristoph Hellwig } 1452a07b4970SChristoph Hellwig 1453a07b4970SChristoph Hellwig static struct configfs_item_operations nvmet_subsys_item_ops = { 1454a07b4970SChristoph Hellwig .release = nvmet_subsys_release, 1455a07b4970SChristoph Hellwig }; 1456a07b4970SChristoph Hellwig 145766603a31SBhumika Goyal static const struct config_item_type nvmet_subsys_type = { 1458a07b4970SChristoph Hellwig .ct_item_ops = &nvmet_subsys_item_ops, 1459a07b4970SChristoph Hellwig .ct_attrs = nvmet_subsys_attrs, 1460a07b4970SChristoph Hellwig .ct_owner = THIS_MODULE, 1461a07b4970SChristoph Hellwig }; 1462a07b4970SChristoph Hellwig 1463a07b4970SChristoph Hellwig static struct config_group *nvmet_subsys_make(struct config_group *group, 1464a07b4970SChristoph Hellwig const char *name) 1465a07b4970SChristoph Hellwig { 1466a07b4970SChristoph Hellwig struct nvmet_subsys *subsys; 1467a07b4970SChristoph Hellwig 1468a07b4970SChristoph Hellwig if (sysfs_streq(name, NVME_DISC_SUBSYS_NAME)) { 1469a07b4970SChristoph Hellwig pr_err("can't create discovery subsystem through configfs\n"); 1470a07b4970SChristoph Hellwig return ERR_PTR(-EINVAL); 1471a07b4970SChristoph Hellwig } 1472a07b4970SChristoph Hellwig 1473a07b4970SChristoph Hellwig subsys = nvmet_subsys_alloc(name, NVME_NQN_NVME); 14746b7e631bSMinwoo Im if (IS_ERR(subsys)) 14756b7e631bSMinwoo Im return ERR_CAST(subsys); 1476a07b4970SChristoph Hellwig 1477a07b4970SChristoph Hellwig config_group_init_type_name(&subsys->group, name, &nvmet_subsys_type); 1478a07b4970SChristoph Hellwig 1479a07b4970SChristoph Hellwig config_group_init_type_name(&subsys->namespaces_group, 1480a07b4970SChristoph Hellwig "namespaces", &nvmet_namespaces_type); 1481a07b4970SChristoph Hellwig configfs_add_default_group(&subsys->namespaces_group, &subsys->group); 1482a07b4970SChristoph Hellwig 1483a07b4970SChristoph Hellwig config_group_init_type_name(&subsys->allowed_hosts_group, 1484a07b4970SChristoph Hellwig "allowed_hosts", &nvmet_allowed_hosts_type); 1485a07b4970SChristoph Hellwig configfs_add_default_group(&subsys->allowed_hosts_group, 1486a07b4970SChristoph Hellwig &subsys->group); 1487a07b4970SChristoph Hellwig 1488cae5b01aSLogan Gunthorpe nvmet_add_passthru_group(subsys); 1489cae5b01aSLogan Gunthorpe 1490a07b4970SChristoph Hellwig return &subsys->group; 1491a07b4970SChristoph Hellwig } 1492a07b4970SChristoph Hellwig 1493a07b4970SChristoph Hellwig static struct configfs_group_operations nvmet_subsystems_group_ops = { 1494a07b4970SChristoph Hellwig .make_group = nvmet_subsys_make, 1495a07b4970SChristoph Hellwig }; 1496a07b4970SChristoph Hellwig 149766603a31SBhumika Goyal static const struct config_item_type nvmet_subsystems_type = { 1498a07b4970SChristoph Hellwig .ct_group_ops = &nvmet_subsystems_group_ops, 1499a07b4970SChristoph Hellwig .ct_owner = THIS_MODULE, 1500a07b4970SChristoph Hellwig }; 1501a07b4970SChristoph Hellwig 1502a07b4970SChristoph Hellwig static ssize_t nvmet_referral_enable_show(struct config_item *item, 1503a07b4970SChristoph Hellwig char *page) 1504a07b4970SChristoph Hellwig { 1505a07b4970SChristoph Hellwig return snprintf(page, PAGE_SIZE, "%d\n", to_nvmet_port(item)->enabled); 1506a07b4970SChristoph Hellwig } 1507a07b4970SChristoph Hellwig 1508a07b4970SChristoph Hellwig static ssize_t nvmet_referral_enable_store(struct config_item *item, 1509a07b4970SChristoph Hellwig const char *page, size_t count) 1510a07b4970SChristoph Hellwig { 1511a07b4970SChristoph Hellwig struct nvmet_port *parent = to_nvmet_port(item->ci_parent->ci_parent); 1512a07b4970SChristoph Hellwig struct nvmet_port *port = to_nvmet_port(item); 1513a07b4970SChristoph Hellwig bool enable; 1514a07b4970SChristoph Hellwig 1515*99722c8aSChristophe JAILLET if (kstrtobool(page, &enable)) 1516a07b4970SChristoph Hellwig goto inval; 1517a07b4970SChristoph Hellwig 1518a07b4970SChristoph Hellwig if (enable) 1519a07b4970SChristoph Hellwig nvmet_referral_enable(parent, port); 1520a07b4970SChristoph Hellwig else 1521b662a078SJay Sternberg nvmet_referral_disable(parent, port); 1522a07b4970SChristoph Hellwig 1523a07b4970SChristoph Hellwig return count; 1524a07b4970SChristoph Hellwig inval: 1525a07b4970SChristoph Hellwig pr_err("Invalid value '%s' for enable\n", page); 1526a07b4970SChristoph Hellwig return -EINVAL; 1527a07b4970SChristoph Hellwig } 1528a07b4970SChristoph Hellwig 1529a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_referral_, enable); 1530a07b4970SChristoph Hellwig 1531a07b4970SChristoph Hellwig /* 1532a07b4970SChristoph Hellwig * Discovery Service subsystem definitions 1533a07b4970SChristoph Hellwig */ 1534a07b4970SChristoph Hellwig static struct configfs_attribute *nvmet_referral_attrs[] = { 1535a07b4970SChristoph Hellwig &nvmet_attr_addr_adrfam, 1536a07b4970SChristoph Hellwig &nvmet_attr_addr_portid, 1537a07b4970SChristoph Hellwig &nvmet_attr_addr_treq, 1538a07b4970SChristoph Hellwig &nvmet_attr_addr_traddr, 1539a07b4970SChristoph Hellwig &nvmet_attr_addr_trsvcid, 1540a07b4970SChristoph Hellwig &nvmet_attr_addr_trtype, 1541a07b4970SChristoph Hellwig &nvmet_referral_attr_enable, 1542a07b4970SChristoph Hellwig NULL, 1543a07b4970SChristoph Hellwig }; 1544a07b4970SChristoph Hellwig 1545f0e656e4SSagi Grimberg static void nvmet_referral_notify(struct config_group *group, 1546f0e656e4SSagi Grimberg struct config_item *item) 1547a07b4970SChristoph Hellwig { 1548b662a078SJay Sternberg struct nvmet_port *parent = to_nvmet_port(item->ci_parent->ci_parent); 1549a07b4970SChristoph Hellwig struct nvmet_port *port = to_nvmet_port(item); 1550a07b4970SChristoph Hellwig 1551b662a078SJay Sternberg nvmet_referral_disable(parent, port); 1552f0e656e4SSagi Grimberg } 1553f0e656e4SSagi Grimberg 1554f0e656e4SSagi Grimberg static void nvmet_referral_release(struct config_item *item) 1555f0e656e4SSagi Grimberg { 1556f0e656e4SSagi Grimberg struct nvmet_port *port = to_nvmet_port(item); 1557f0e656e4SSagi Grimberg 1558a07b4970SChristoph Hellwig kfree(port); 1559a07b4970SChristoph Hellwig } 1560a07b4970SChristoph Hellwig 1561a07b4970SChristoph Hellwig static struct configfs_item_operations nvmet_referral_item_ops = { 1562a07b4970SChristoph Hellwig .release = nvmet_referral_release, 1563a07b4970SChristoph Hellwig }; 1564a07b4970SChristoph Hellwig 156566603a31SBhumika Goyal static const struct config_item_type nvmet_referral_type = { 1566a07b4970SChristoph Hellwig .ct_owner = THIS_MODULE, 1567a07b4970SChristoph Hellwig .ct_attrs = nvmet_referral_attrs, 1568a07b4970SChristoph Hellwig .ct_item_ops = &nvmet_referral_item_ops, 1569a07b4970SChristoph Hellwig }; 1570a07b4970SChristoph Hellwig 1571a07b4970SChristoph Hellwig static struct config_group *nvmet_referral_make( 1572a07b4970SChristoph Hellwig struct config_group *group, const char *name) 1573a07b4970SChristoph Hellwig { 1574a07b4970SChristoph Hellwig struct nvmet_port *port; 1575a07b4970SChristoph Hellwig 1576a07b4970SChristoph Hellwig port = kzalloc(sizeof(*port), GFP_KERNEL); 1577a07b4970SChristoph Hellwig if (!port) 1578f98d9ca1SDan Carpenter return ERR_PTR(-ENOMEM); 1579a07b4970SChristoph Hellwig 1580a07b4970SChristoph Hellwig INIT_LIST_HEAD(&port->entry); 1581a07b4970SChristoph Hellwig config_group_init_type_name(&port->group, name, &nvmet_referral_type); 1582a07b4970SChristoph Hellwig 1583a07b4970SChristoph Hellwig return &port->group; 1584a07b4970SChristoph Hellwig } 1585a07b4970SChristoph Hellwig 1586a07b4970SChristoph Hellwig static struct configfs_group_operations nvmet_referral_group_ops = { 1587a07b4970SChristoph Hellwig .make_group = nvmet_referral_make, 1588f0e656e4SSagi Grimberg .disconnect_notify = nvmet_referral_notify, 1589a07b4970SChristoph Hellwig }; 1590a07b4970SChristoph Hellwig 159166603a31SBhumika Goyal static const struct config_item_type nvmet_referrals_type = { 1592a07b4970SChristoph Hellwig .ct_owner = THIS_MODULE, 1593a07b4970SChristoph Hellwig .ct_group_ops = &nvmet_referral_group_ops, 1594a07b4970SChristoph Hellwig }; 1595a07b4970SChristoph Hellwig 159674255969SChristoph Hellwig static struct nvmet_type_name_map nvmet_ana_state[] = { 159762ac0d32SChristoph Hellwig { NVME_ANA_OPTIMIZED, "optimized" }, 159862ac0d32SChristoph Hellwig { NVME_ANA_NONOPTIMIZED, "non-optimized" }, 159962ac0d32SChristoph Hellwig { NVME_ANA_INACCESSIBLE, "inaccessible" }, 160062ac0d32SChristoph Hellwig { NVME_ANA_PERSISTENT_LOSS, "persistent-loss" }, 160162ac0d32SChristoph Hellwig { NVME_ANA_CHANGE, "change" }, 160262ac0d32SChristoph Hellwig }; 160362ac0d32SChristoph Hellwig 160462ac0d32SChristoph Hellwig static ssize_t nvmet_ana_group_ana_state_show(struct config_item *item, 160562ac0d32SChristoph Hellwig char *page) 160662ac0d32SChristoph Hellwig { 160762ac0d32SChristoph Hellwig struct nvmet_ana_group *grp = to_ana_group(item); 160862ac0d32SChristoph Hellwig enum nvme_ana_state state = grp->port->ana_state[grp->grpid]; 160962ac0d32SChristoph Hellwig int i; 161062ac0d32SChristoph Hellwig 161184b8d0d7SChaitanya Kulkarni for (i = 0; i < ARRAY_SIZE(nvmet_ana_state); i++) { 161284b8d0d7SChaitanya Kulkarni if (state == nvmet_ana_state[i].type) 161384b8d0d7SChaitanya Kulkarni return sprintf(page, "%s\n", nvmet_ana_state[i].name); 161462ac0d32SChristoph Hellwig } 161562ac0d32SChristoph Hellwig 161662ac0d32SChristoph Hellwig return sprintf(page, "\n"); 161762ac0d32SChristoph Hellwig } 161862ac0d32SChristoph Hellwig 161962ac0d32SChristoph Hellwig static ssize_t nvmet_ana_group_ana_state_store(struct config_item *item, 162062ac0d32SChristoph Hellwig const char *page, size_t count) 162162ac0d32SChristoph Hellwig { 162262ac0d32SChristoph Hellwig struct nvmet_ana_group *grp = to_ana_group(item); 162384b8d0d7SChaitanya Kulkarni enum nvme_ana_state *ana_state = grp->port->ana_state; 162462ac0d32SChristoph Hellwig int i; 162562ac0d32SChristoph Hellwig 162684b8d0d7SChaitanya Kulkarni for (i = 0; i < ARRAY_SIZE(nvmet_ana_state); i++) { 162784b8d0d7SChaitanya Kulkarni if (sysfs_streq(page, nvmet_ana_state[i].name)) 162862ac0d32SChristoph Hellwig goto found; 162962ac0d32SChristoph Hellwig } 163062ac0d32SChristoph Hellwig 163162ac0d32SChristoph Hellwig pr_err("Invalid value '%s' for ana_state\n", page); 163262ac0d32SChristoph Hellwig return -EINVAL; 163362ac0d32SChristoph Hellwig 163462ac0d32SChristoph Hellwig found: 163562ac0d32SChristoph Hellwig down_write(&nvmet_ana_sem); 163684b8d0d7SChaitanya Kulkarni ana_state[grp->grpid] = (enum nvme_ana_state) nvmet_ana_state[i].type; 163762ac0d32SChristoph Hellwig nvmet_ana_chgcnt++; 163862ac0d32SChristoph Hellwig up_write(&nvmet_ana_sem); 163962ac0d32SChristoph Hellwig nvmet_port_send_ana_event(grp->port); 164062ac0d32SChristoph Hellwig return count; 164162ac0d32SChristoph Hellwig } 164262ac0d32SChristoph Hellwig 164362ac0d32SChristoph Hellwig CONFIGFS_ATTR(nvmet_ana_group_, ana_state); 164462ac0d32SChristoph Hellwig 164562ac0d32SChristoph Hellwig static struct configfs_attribute *nvmet_ana_group_attrs[] = { 164662ac0d32SChristoph Hellwig &nvmet_ana_group_attr_ana_state, 164762ac0d32SChristoph Hellwig NULL, 164862ac0d32SChristoph Hellwig }; 164962ac0d32SChristoph Hellwig 165062ac0d32SChristoph Hellwig static void nvmet_ana_group_release(struct config_item *item) 165162ac0d32SChristoph Hellwig { 165262ac0d32SChristoph Hellwig struct nvmet_ana_group *grp = to_ana_group(item); 165362ac0d32SChristoph Hellwig 165462ac0d32SChristoph Hellwig if (grp == &grp->port->ana_default_group) 165562ac0d32SChristoph Hellwig return; 165662ac0d32SChristoph Hellwig 165762ac0d32SChristoph Hellwig down_write(&nvmet_ana_sem); 165862ac0d32SChristoph Hellwig grp->port->ana_state[grp->grpid] = NVME_ANA_INACCESSIBLE; 165962ac0d32SChristoph Hellwig nvmet_ana_group_enabled[grp->grpid]--; 166062ac0d32SChristoph Hellwig up_write(&nvmet_ana_sem); 166162ac0d32SChristoph Hellwig 166262ac0d32SChristoph Hellwig nvmet_port_send_ana_event(grp->port); 166362ac0d32SChristoph Hellwig kfree(grp); 166462ac0d32SChristoph Hellwig } 166562ac0d32SChristoph Hellwig 166662ac0d32SChristoph Hellwig static struct configfs_item_operations nvmet_ana_group_item_ops = { 166762ac0d32SChristoph Hellwig .release = nvmet_ana_group_release, 166862ac0d32SChristoph Hellwig }; 166962ac0d32SChristoph Hellwig 167062ac0d32SChristoph Hellwig static const struct config_item_type nvmet_ana_group_type = { 167162ac0d32SChristoph Hellwig .ct_item_ops = &nvmet_ana_group_item_ops, 167262ac0d32SChristoph Hellwig .ct_attrs = nvmet_ana_group_attrs, 167362ac0d32SChristoph Hellwig .ct_owner = THIS_MODULE, 167462ac0d32SChristoph Hellwig }; 167562ac0d32SChristoph Hellwig 167662ac0d32SChristoph Hellwig static struct config_group *nvmet_ana_groups_make_group( 167762ac0d32SChristoph Hellwig struct config_group *group, const char *name) 167862ac0d32SChristoph Hellwig { 167962ac0d32SChristoph Hellwig struct nvmet_port *port = ana_groups_to_port(&group->cg_item); 168062ac0d32SChristoph Hellwig struct nvmet_ana_group *grp; 168162ac0d32SChristoph Hellwig u32 grpid; 168262ac0d32SChristoph Hellwig int ret; 168362ac0d32SChristoph Hellwig 168462ac0d32SChristoph Hellwig ret = kstrtou32(name, 0, &grpid); 168562ac0d32SChristoph Hellwig if (ret) 168662ac0d32SChristoph Hellwig goto out; 168762ac0d32SChristoph Hellwig 168862ac0d32SChristoph Hellwig ret = -EINVAL; 168962ac0d32SChristoph Hellwig if (grpid <= 1 || grpid > NVMET_MAX_ANAGRPS) 169062ac0d32SChristoph Hellwig goto out; 169162ac0d32SChristoph Hellwig 169262ac0d32SChristoph Hellwig ret = -ENOMEM; 169362ac0d32SChristoph Hellwig grp = kzalloc(sizeof(*grp), GFP_KERNEL); 169462ac0d32SChristoph Hellwig if (!grp) 169562ac0d32SChristoph Hellwig goto out; 169662ac0d32SChristoph Hellwig grp->port = port; 169762ac0d32SChristoph Hellwig grp->grpid = grpid; 169862ac0d32SChristoph Hellwig 169962ac0d32SChristoph Hellwig down_write(&nvmet_ana_sem); 170062ac0d32SChristoph Hellwig nvmet_ana_group_enabled[grpid]++; 170162ac0d32SChristoph Hellwig up_write(&nvmet_ana_sem); 170262ac0d32SChristoph Hellwig 170362ac0d32SChristoph Hellwig nvmet_port_send_ana_event(grp->port); 170462ac0d32SChristoph Hellwig 170562ac0d32SChristoph Hellwig config_group_init_type_name(&grp->group, name, &nvmet_ana_group_type); 170662ac0d32SChristoph Hellwig return &grp->group; 170762ac0d32SChristoph Hellwig out: 170862ac0d32SChristoph Hellwig return ERR_PTR(ret); 170962ac0d32SChristoph Hellwig } 171062ac0d32SChristoph Hellwig 171162ac0d32SChristoph Hellwig static struct configfs_group_operations nvmet_ana_groups_group_ops = { 171262ac0d32SChristoph Hellwig .make_group = nvmet_ana_groups_make_group, 171362ac0d32SChristoph Hellwig }; 171462ac0d32SChristoph Hellwig 171562ac0d32SChristoph Hellwig static const struct config_item_type nvmet_ana_groups_type = { 171662ac0d32SChristoph Hellwig .ct_group_ops = &nvmet_ana_groups_group_ops, 171762ac0d32SChristoph Hellwig .ct_owner = THIS_MODULE, 171862ac0d32SChristoph Hellwig }; 171962ac0d32SChristoph Hellwig 1720a07b4970SChristoph Hellwig /* 1721a07b4970SChristoph Hellwig * Ports definitions. 1722a07b4970SChristoph Hellwig */ 1723a07b4970SChristoph Hellwig static void nvmet_port_release(struct config_item *item) 1724a07b4970SChristoph Hellwig { 1725a07b4970SChristoph Hellwig struct nvmet_port *port = to_nvmet_port(item); 1726a07b4970SChristoph Hellwig 1727e3e19dccSIsrael Rukshin /* Let inflight controllers teardown complete */ 17288832cf92SSagi Grimberg flush_workqueue(nvmet_wq); 1729b662a078SJay Sternberg list_del(&port->global_entry); 1730b662a078SJay Sternberg 173172efd25dSChristoph Hellwig kfree(port->ana_state); 1732a07b4970SChristoph Hellwig kfree(port); 1733a07b4970SChristoph Hellwig } 1734a07b4970SChristoph Hellwig 1735a07b4970SChristoph Hellwig static struct configfs_attribute *nvmet_port_attrs[] = { 1736a07b4970SChristoph Hellwig &nvmet_attr_addr_adrfam, 1737a07b4970SChristoph Hellwig &nvmet_attr_addr_treq, 1738a07b4970SChristoph Hellwig &nvmet_attr_addr_traddr, 1739a07b4970SChristoph Hellwig &nvmet_attr_addr_trsvcid, 1740a07b4970SChristoph Hellwig &nvmet_attr_addr_trtype, 17410d5ee2b2SSteve Wise &nvmet_attr_param_inline_data_size, 1742ea52ac1cSIsrael Rukshin #ifdef CONFIG_BLK_DEV_INTEGRITY 1743ea52ac1cSIsrael Rukshin &nvmet_attr_param_pi_enable, 1744ea52ac1cSIsrael Rukshin #endif 1745a07b4970SChristoph Hellwig NULL, 1746a07b4970SChristoph Hellwig }; 1747a07b4970SChristoph Hellwig 1748a07b4970SChristoph Hellwig static struct configfs_item_operations nvmet_port_item_ops = { 1749a07b4970SChristoph Hellwig .release = nvmet_port_release, 1750a07b4970SChristoph Hellwig }; 1751a07b4970SChristoph Hellwig 175266603a31SBhumika Goyal static const struct config_item_type nvmet_port_type = { 1753a07b4970SChristoph Hellwig .ct_attrs = nvmet_port_attrs, 1754a07b4970SChristoph Hellwig .ct_item_ops = &nvmet_port_item_ops, 1755a07b4970SChristoph Hellwig .ct_owner = THIS_MODULE, 1756a07b4970SChristoph Hellwig }; 1757a07b4970SChristoph Hellwig 1758a07b4970SChristoph Hellwig static struct config_group *nvmet_ports_make(struct config_group *group, 1759a07b4970SChristoph Hellwig const char *name) 1760a07b4970SChristoph Hellwig { 1761a07b4970SChristoph Hellwig struct nvmet_port *port; 1762a07b4970SChristoph Hellwig u16 portid; 176362ac0d32SChristoph Hellwig u32 i; 1764a07b4970SChristoph Hellwig 1765a07b4970SChristoph Hellwig if (kstrtou16(name, 0, &portid)) 1766a07b4970SChristoph Hellwig return ERR_PTR(-EINVAL); 1767a07b4970SChristoph Hellwig 1768a07b4970SChristoph Hellwig port = kzalloc(sizeof(*port), GFP_KERNEL); 1769a07b4970SChristoph Hellwig if (!port) 1770f98d9ca1SDan Carpenter return ERR_PTR(-ENOMEM); 1771a07b4970SChristoph Hellwig 177272efd25dSChristoph Hellwig port->ana_state = kcalloc(NVMET_MAX_ANAGRPS + 1, 177372efd25dSChristoph Hellwig sizeof(*port->ana_state), GFP_KERNEL); 177472efd25dSChristoph Hellwig if (!port->ana_state) { 177572efd25dSChristoph Hellwig kfree(port); 177672efd25dSChristoph Hellwig return ERR_PTR(-ENOMEM); 177772efd25dSChristoph Hellwig } 177872efd25dSChristoph Hellwig 177962ac0d32SChristoph Hellwig for (i = 1; i <= NVMET_MAX_ANAGRPS; i++) { 178062ac0d32SChristoph Hellwig if (i == NVMET_DEFAULT_ANA_GRPID) 178162ac0d32SChristoph Hellwig port->ana_state[1] = NVME_ANA_OPTIMIZED; 178262ac0d32SChristoph Hellwig else 178362ac0d32SChristoph Hellwig port->ana_state[i] = NVME_ANA_INACCESSIBLE; 178462ac0d32SChristoph Hellwig } 178572efd25dSChristoph Hellwig 1786b662a078SJay Sternberg list_add(&port->global_entry, &nvmet_ports_list); 1787b662a078SJay Sternberg 1788a07b4970SChristoph Hellwig INIT_LIST_HEAD(&port->entry); 1789a07b4970SChristoph Hellwig INIT_LIST_HEAD(&port->subsystems); 1790a07b4970SChristoph Hellwig INIT_LIST_HEAD(&port->referrals); 17910d5ee2b2SSteve Wise port->inline_data_size = -1; /* < 0 == let the transport choose */ 1792a07b4970SChristoph Hellwig 1793a07b4970SChristoph Hellwig port->disc_addr.portid = cpu_to_le16(portid); 1794d02abd19SChaitanya Kulkarni port->disc_addr.adrfam = NVMF_ADDR_FAMILY_MAX; 17959b95d2fbSSagi Grimberg port->disc_addr.treq = NVMF_TREQ_DISABLE_SQFLOW; 1796a07b4970SChristoph Hellwig config_group_init_type_name(&port->group, name, &nvmet_port_type); 1797a07b4970SChristoph Hellwig 1798a07b4970SChristoph Hellwig config_group_init_type_name(&port->subsys_group, 1799a07b4970SChristoph Hellwig "subsystems", &nvmet_port_subsys_type); 1800a07b4970SChristoph Hellwig configfs_add_default_group(&port->subsys_group, &port->group); 1801a07b4970SChristoph Hellwig 1802a07b4970SChristoph Hellwig config_group_init_type_name(&port->referrals_group, 1803a07b4970SChristoph Hellwig "referrals", &nvmet_referrals_type); 1804a07b4970SChristoph Hellwig configfs_add_default_group(&port->referrals_group, &port->group); 1805a07b4970SChristoph Hellwig 180662ac0d32SChristoph Hellwig config_group_init_type_name(&port->ana_groups_group, 180762ac0d32SChristoph Hellwig "ana_groups", &nvmet_ana_groups_type); 180862ac0d32SChristoph Hellwig configfs_add_default_group(&port->ana_groups_group, &port->group); 180962ac0d32SChristoph Hellwig 181062ac0d32SChristoph Hellwig port->ana_default_group.port = port; 181162ac0d32SChristoph Hellwig port->ana_default_group.grpid = NVMET_DEFAULT_ANA_GRPID; 181262ac0d32SChristoph Hellwig config_group_init_type_name(&port->ana_default_group.group, 181362ac0d32SChristoph Hellwig __stringify(NVMET_DEFAULT_ANA_GRPID), 181462ac0d32SChristoph Hellwig &nvmet_ana_group_type); 181562ac0d32SChristoph Hellwig configfs_add_default_group(&port->ana_default_group.group, 181662ac0d32SChristoph Hellwig &port->ana_groups_group); 181762ac0d32SChristoph Hellwig 1818a07b4970SChristoph Hellwig return &port->group; 1819a07b4970SChristoph Hellwig } 1820a07b4970SChristoph Hellwig 1821a07b4970SChristoph Hellwig static struct configfs_group_operations nvmet_ports_group_ops = { 1822a07b4970SChristoph Hellwig .make_group = nvmet_ports_make, 1823a07b4970SChristoph Hellwig }; 1824a07b4970SChristoph Hellwig 182566603a31SBhumika Goyal static const struct config_item_type nvmet_ports_type = { 1826a07b4970SChristoph Hellwig .ct_group_ops = &nvmet_ports_group_ops, 1827a07b4970SChristoph Hellwig .ct_owner = THIS_MODULE, 1828a07b4970SChristoph Hellwig }; 1829a07b4970SChristoph Hellwig 1830a07b4970SChristoph Hellwig static struct config_group nvmet_subsystems_group; 1831a07b4970SChristoph Hellwig static struct config_group nvmet_ports_group; 1832a07b4970SChristoph Hellwig 1833db1312ddSHannes Reinecke #ifdef CONFIG_NVME_TARGET_AUTH 1834db1312ddSHannes Reinecke static ssize_t nvmet_host_dhchap_key_show(struct config_item *item, 1835db1312ddSHannes Reinecke char *page) 1836db1312ddSHannes Reinecke { 1837db1312ddSHannes Reinecke u8 *dhchap_secret = to_host(item)->dhchap_secret; 1838db1312ddSHannes Reinecke 1839db1312ddSHannes Reinecke if (!dhchap_secret) 1840db1312ddSHannes Reinecke return sprintf(page, "\n"); 1841db1312ddSHannes Reinecke return sprintf(page, "%s\n", dhchap_secret); 1842db1312ddSHannes Reinecke } 1843db1312ddSHannes Reinecke 1844db1312ddSHannes Reinecke static ssize_t nvmet_host_dhchap_key_store(struct config_item *item, 1845db1312ddSHannes Reinecke const char *page, size_t count) 1846db1312ddSHannes Reinecke { 1847db1312ddSHannes Reinecke struct nvmet_host *host = to_host(item); 1848db1312ddSHannes Reinecke int ret; 1849db1312ddSHannes Reinecke 1850db1312ddSHannes Reinecke ret = nvmet_auth_set_key(host, page, false); 1851db1312ddSHannes Reinecke /* 1852db1312ddSHannes Reinecke * Re-authentication is a soft state, so keep the 1853db1312ddSHannes Reinecke * current authentication valid until the host 1854db1312ddSHannes Reinecke * requests re-authentication. 1855db1312ddSHannes Reinecke */ 1856db1312ddSHannes Reinecke return ret < 0 ? ret : count; 1857db1312ddSHannes Reinecke } 1858db1312ddSHannes Reinecke 1859db1312ddSHannes Reinecke CONFIGFS_ATTR(nvmet_host_, dhchap_key); 1860db1312ddSHannes Reinecke 1861db1312ddSHannes Reinecke static ssize_t nvmet_host_dhchap_ctrl_key_show(struct config_item *item, 1862db1312ddSHannes Reinecke char *page) 1863db1312ddSHannes Reinecke { 1864db1312ddSHannes Reinecke u8 *dhchap_secret = to_host(item)->dhchap_ctrl_secret; 1865db1312ddSHannes Reinecke 1866db1312ddSHannes Reinecke if (!dhchap_secret) 1867db1312ddSHannes Reinecke return sprintf(page, "\n"); 1868db1312ddSHannes Reinecke return sprintf(page, "%s\n", dhchap_secret); 1869db1312ddSHannes Reinecke } 1870db1312ddSHannes Reinecke 1871db1312ddSHannes Reinecke static ssize_t nvmet_host_dhchap_ctrl_key_store(struct config_item *item, 1872db1312ddSHannes Reinecke const char *page, size_t count) 1873db1312ddSHannes Reinecke { 1874db1312ddSHannes Reinecke struct nvmet_host *host = to_host(item); 1875db1312ddSHannes Reinecke int ret; 1876db1312ddSHannes Reinecke 1877db1312ddSHannes Reinecke ret = nvmet_auth_set_key(host, page, true); 1878db1312ddSHannes Reinecke /* 1879db1312ddSHannes Reinecke * Re-authentication is a soft state, so keep the 1880db1312ddSHannes Reinecke * current authentication valid until the host 1881db1312ddSHannes Reinecke * requests re-authentication. 1882db1312ddSHannes Reinecke */ 1883db1312ddSHannes Reinecke return ret < 0 ? ret : count; 1884db1312ddSHannes Reinecke } 1885db1312ddSHannes Reinecke 1886db1312ddSHannes Reinecke CONFIGFS_ATTR(nvmet_host_, dhchap_ctrl_key); 1887db1312ddSHannes Reinecke 1888db1312ddSHannes Reinecke static ssize_t nvmet_host_dhchap_hash_show(struct config_item *item, 1889db1312ddSHannes Reinecke char *page) 1890db1312ddSHannes Reinecke { 1891db1312ddSHannes Reinecke struct nvmet_host *host = to_host(item); 1892db1312ddSHannes Reinecke const char *hash_name = nvme_auth_hmac_name(host->dhchap_hash_id); 1893db1312ddSHannes Reinecke 1894db1312ddSHannes Reinecke return sprintf(page, "%s\n", hash_name ? hash_name : "none"); 1895db1312ddSHannes Reinecke } 1896db1312ddSHannes Reinecke 1897db1312ddSHannes Reinecke static ssize_t nvmet_host_dhchap_hash_store(struct config_item *item, 1898db1312ddSHannes Reinecke const char *page, size_t count) 1899db1312ddSHannes Reinecke { 1900db1312ddSHannes Reinecke struct nvmet_host *host = to_host(item); 1901db1312ddSHannes Reinecke u8 hmac_id; 1902db1312ddSHannes Reinecke 1903db1312ddSHannes Reinecke hmac_id = nvme_auth_hmac_id(page); 1904db1312ddSHannes Reinecke if (hmac_id == NVME_AUTH_HASH_INVALID) 1905db1312ddSHannes Reinecke return -EINVAL; 1906db1312ddSHannes Reinecke if (!crypto_has_shash(nvme_auth_hmac_name(hmac_id), 0, 0)) 1907db1312ddSHannes Reinecke return -ENOTSUPP; 1908db1312ddSHannes Reinecke host->dhchap_hash_id = hmac_id; 1909db1312ddSHannes Reinecke return count; 1910db1312ddSHannes Reinecke } 1911db1312ddSHannes Reinecke 1912db1312ddSHannes Reinecke CONFIGFS_ATTR(nvmet_host_, dhchap_hash); 1913db1312ddSHannes Reinecke 19147a277c37SHannes Reinecke static ssize_t nvmet_host_dhchap_dhgroup_show(struct config_item *item, 19157a277c37SHannes Reinecke char *page) 19167a277c37SHannes Reinecke { 19177a277c37SHannes Reinecke struct nvmet_host *host = to_host(item); 19187a277c37SHannes Reinecke const char *dhgroup = nvme_auth_dhgroup_name(host->dhchap_dhgroup_id); 19197a277c37SHannes Reinecke 19207a277c37SHannes Reinecke return sprintf(page, "%s\n", dhgroup ? dhgroup : "none"); 19217a277c37SHannes Reinecke } 19227a277c37SHannes Reinecke 19237a277c37SHannes Reinecke static ssize_t nvmet_host_dhchap_dhgroup_store(struct config_item *item, 19247a277c37SHannes Reinecke const char *page, size_t count) 19257a277c37SHannes Reinecke { 19267a277c37SHannes Reinecke struct nvmet_host *host = to_host(item); 19277a277c37SHannes Reinecke int dhgroup_id; 19287a277c37SHannes Reinecke 19297a277c37SHannes Reinecke dhgroup_id = nvme_auth_dhgroup_id(page); 19307a277c37SHannes Reinecke if (dhgroup_id == NVME_AUTH_DHGROUP_INVALID) 19317a277c37SHannes Reinecke return -EINVAL; 19327a277c37SHannes Reinecke if (dhgroup_id != NVME_AUTH_DHGROUP_NULL) { 19337a277c37SHannes Reinecke const char *kpp = nvme_auth_dhgroup_kpp(dhgroup_id); 19347a277c37SHannes Reinecke 19357a277c37SHannes Reinecke if (!crypto_has_kpp(kpp, 0, 0)) 19367a277c37SHannes Reinecke return -EINVAL; 19377a277c37SHannes Reinecke } 19387a277c37SHannes Reinecke host->dhchap_dhgroup_id = dhgroup_id; 19397a277c37SHannes Reinecke return count; 19407a277c37SHannes Reinecke } 19417a277c37SHannes Reinecke 19427a277c37SHannes Reinecke CONFIGFS_ATTR(nvmet_host_, dhchap_dhgroup); 19437a277c37SHannes Reinecke 1944db1312ddSHannes Reinecke static struct configfs_attribute *nvmet_host_attrs[] = { 1945db1312ddSHannes Reinecke &nvmet_host_attr_dhchap_key, 1946db1312ddSHannes Reinecke &nvmet_host_attr_dhchap_ctrl_key, 1947db1312ddSHannes Reinecke &nvmet_host_attr_dhchap_hash, 19487a277c37SHannes Reinecke &nvmet_host_attr_dhchap_dhgroup, 1949db1312ddSHannes Reinecke NULL, 1950db1312ddSHannes Reinecke }; 1951db1312ddSHannes Reinecke #endif /* CONFIG_NVME_TARGET_AUTH */ 1952db1312ddSHannes Reinecke 1953a07b4970SChristoph Hellwig static void nvmet_host_release(struct config_item *item) 1954a07b4970SChristoph Hellwig { 1955a07b4970SChristoph Hellwig struct nvmet_host *host = to_host(item); 1956ee8cd008SChristoph Hellwig 1957db1312ddSHannes Reinecke #ifdef CONFIG_NVME_TARGET_AUTH 1958db1312ddSHannes Reinecke kfree(host->dhchap_secret); 1959db1312ddSHannes Reinecke #endif 1960a07b4970SChristoph Hellwig kfree(host); 1961a07b4970SChristoph Hellwig } 1962a07b4970SChristoph Hellwig 1963a07b4970SChristoph Hellwig static struct configfs_item_operations nvmet_host_item_ops = { 1964a07b4970SChristoph Hellwig .release = nvmet_host_release, 1965a07b4970SChristoph Hellwig }; 1966a07b4970SChristoph Hellwig 196766603a31SBhumika Goyal static const struct config_item_type nvmet_host_type = { 1968a07b4970SChristoph Hellwig .ct_item_ops = &nvmet_host_item_ops, 1969db1312ddSHannes Reinecke #ifdef CONFIG_NVME_TARGET_AUTH 1970db1312ddSHannes Reinecke .ct_attrs = nvmet_host_attrs, 1971db1312ddSHannes Reinecke #endif 1972a07b4970SChristoph Hellwig .ct_owner = THIS_MODULE, 1973a07b4970SChristoph Hellwig }; 1974a07b4970SChristoph Hellwig 1975a07b4970SChristoph Hellwig static struct config_group *nvmet_hosts_make_group(struct config_group *group, 1976a07b4970SChristoph Hellwig const char *name) 1977a07b4970SChristoph Hellwig { 1978a07b4970SChristoph Hellwig struct nvmet_host *host; 1979a07b4970SChristoph Hellwig 1980a07b4970SChristoph Hellwig host = kzalloc(sizeof(*host), GFP_KERNEL); 1981a07b4970SChristoph Hellwig if (!host) 1982a07b4970SChristoph Hellwig return ERR_PTR(-ENOMEM); 1983a07b4970SChristoph Hellwig 1984db1312ddSHannes Reinecke #ifdef CONFIG_NVME_TARGET_AUTH 1985db1312ddSHannes Reinecke /* Default to SHA256 */ 1986db1312ddSHannes Reinecke host->dhchap_hash_id = NVME_AUTH_HASH_SHA256; 1987db1312ddSHannes Reinecke #endif 1988db1312ddSHannes Reinecke 1989a07b4970SChristoph Hellwig config_group_init_type_name(&host->group, name, &nvmet_host_type); 1990a07b4970SChristoph Hellwig 1991a07b4970SChristoph Hellwig return &host->group; 1992a07b4970SChristoph Hellwig } 1993a07b4970SChristoph Hellwig 1994a07b4970SChristoph Hellwig static struct configfs_group_operations nvmet_hosts_group_ops = { 1995a07b4970SChristoph Hellwig .make_group = nvmet_hosts_make_group, 1996a07b4970SChristoph Hellwig }; 1997a07b4970SChristoph Hellwig 199866603a31SBhumika Goyal static const struct config_item_type nvmet_hosts_type = { 1999a07b4970SChristoph Hellwig .ct_group_ops = &nvmet_hosts_group_ops, 2000a07b4970SChristoph Hellwig .ct_owner = THIS_MODULE, 2001a07b4970SChristoph Hellwig }; 2002a07b4970SChristoph Hellwig 2003a07b4970SChristoph Hellwig static struct config_group nvmet_hosts_group; 2004a07b4970SChristoph Hellwig 200566603a31SBhumika Goyal static const struct config_item_type nvmet_root_type = { 2006a07b4970SChristoph Hellwig .ct_owner = THIS_MODULE, 2007a07b4970SChristoph Hellwig }; 2008a07b4970SChristoph Hellwig 2009a07b4970SChristoph Hellwig static struct configfs_subsystem nvmet_configfs_subsystem = { 2010a07b4970SChristoph Hellwig .su_group = { 2011a07b4970SChristoph Hellwig .cg_item = { 2012a07b4970SChristoph Hellwig .ci_namebuf = "nvmet", 2013a07b4970SChristoph Hellwig .ci_type = &nvmet_root_type, 2014a07b4970SChristoph Hellwig }, 2015a07b4970SChristoph Hellwig }, 2016a07b4970SChristoph Hellwig }; 2017a07b4970SChristoph Hellwig 2018a07b4970SChristoph Hellwig int __init nvmet_init_configfs(void) 2019a07b4970SChristoph Hellwig { 2020a07b4970SChristoph Hellwig int ret; 2021a07b4970SChristoph Hellwig 2022a07b4970SChristoph Hellwig config_group_init(&nvmet_configfs_subsystem.su_group); 2023a07b4970SChristoph Hellwig mutex_init(&nvmet_configfs_subsystem.su_mutex); 2024a07b4970SChristoph Hellwig 2025a07b4970SChristoph Hellwig config_group_init_type_name(&nvmet_subsystems_group, 2026a07b4970SChristoph Hellwig "subsystems", &nvmet_subsystems_type); 2027a07b4970SChristoph Hellwig configfs_add_default_group(&nvmet_subsystems_group, 2028a07b4970SChristoph Hellwig &nvmet_configfs_subsystem.su_group); 2029a07b4970SChristoph Hellwig 2030a07b4970SChristoph Hellwig config_group_init_type_name(&nvmet_ports_group, 2031a07b4970SChristoph Hellwig "ports", &nvmet_ports_type); 2032a07b4970SChristoph Hellwig configfs_add_default_group(&nvmet_ports_group, 2033a07b4970SChristoph Hellwig &nvmet_configfs_subsystem.su_group); 2034a07b4970SChristoph Hellwig 2035a07b4970SChristoph Hellwig config_group_init_type_name(&nvmet_hosts_group, 2036a07b4970SChristoph Hellwig "hosts", &nvmet_hosts_type); 2037a07b4970SChristoph Hellwig configfs_add_default_group(&nvmet_hosts_group, 2038a07b4970SChristoph Hellwig &nvmet_configfs_subsystem.su_group); 2039a07b4970SChristoph Hellwig 2040a07b4970SChristoph Hellwig ret = configfs_register_subsystem(&nvmet_configfs_subsystem); 2041a07b4970SChristoph Hellwig if (ret) { 2042a07b4970SChristoph Hellwig pr_err("configfs_register_subsystem: %d\n", ret); 2043a07b4970SChristoph Hellwig return ret; 2044a07b4970SChristoph Hellwig } 2045a07b4970SChristoph Hellwig 2046a07b4970SChristoph Hellwig return 0; 2047a07b4970SChristoph Hellwig } 2048a07b4970SChristoph Hellwig 2049a07b4970SChristoph Hellwig void __exit nvmet_exit_configfs(void) 2050a07b4970SChristoph Hellwig { 2051a07b4970SChristoph Hellwig configfs_unregister_subsystem(&nvmet_configfs_subsystem); 2052a07b4970SChristoph Hellwig } 2053