1a07b4970SChristoph Hellwig /* 2a07b4970SChristoph Hellwig * Configfs interface for the NVMe target. 3a07b4970SChristoph Hellwig * Copyright (c) 2015-2016 HGST, a Western Digital Company. 4a07b4970SChristoph Hellwig * 5a07b4970SChristoph Hellwig * This program is free software; you can redistribute it and/or modify it 6a07b4970SChristoph Hellwig * under the terms and conditions of the GNU General Public License, 7a07b4970SChristoph Hellwig * version 2, as published by the Free Software Foundation. 8a07b4970SChristoph Hellwig * 9a07b4970SChristoph Hellwig * This program is distributed in the hope it will be useful, but WITHOUT 10a07b4970SChristoph Hellwig * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11a07b4970SChristoph Hellwig * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12a07b4970SChristoph Hellwig * more details. 13a07b4970SChristoph Hellwig */ 14a07b4970SChristoph Hellwig #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 15a07b4970SChristoph Hellwig #include <linux/kernel.h> 16a07b4970SChristoph Hellwig #include <linux/module.h> 17a07b4970SChristoph Hellwig #include <linux/slab.h> 18a07b4970SChristoph Hellwig #include <linux/stat.h> 19a07b4970SChristoph Hellwig #include <linux/ctype.h> 20a07b4970SChristoph Hellwig 21a07b4970SChristoph Hellwig #include "nvmet.h" 22a07b4970SChristoph Hellwig 23a07b4970SChristoph Hellwig static struct config_item_type nvmet_host_type; 24a07b4970SChristoph Hellwig static struct config_item_type nvmet_subsys_type; 25a07b4970SChristoph Hellwig 26a07b4970SChristoph Hellwig /* 27a07b4970SChristoph Hellwig * nvmet_port Generic ConfigFS definitions. 28a07b4970SChristoph Hellwig * Used in any place in the ConfigFS tree that refers to an address. 29a07b4970SChristoph Hellwig */ 30a07b4970SChristoph Hellwig static ssize_t nvmet_addr_adrfam_show(struct config_item *item, 31a07b4970SChristoph Hellwig char *page) 32a07b4970SChristoph Hellwig { 33a07b4970SChristoph Hellwig switch (to_nvmet_port(item)->disc_addr.adrfam) { 34a07b4970SChristoph Hellwig case NVMF_ADDR_FAMILY_IP4: 35a07b4970SChristoph Hellwig return sprintf(page, "ipv4\n"); 36a07b4970SChristoph Hellwig case NVMF_ADDR_FAMILY_IP6: 37a07b4970SChristoph Hellwig return sprintf(page, "ipv6\n"); 38a07b4970SChristoph Hellwig case NVMF_ADDR_FAMILY_IB: 39a07b4970SChristoph Hellwig return sprintf(page, "ib\n"); 40a07b4970SChristoph Hellwig default: 41a07b4970SChristoph Hellwig return sprintf(page, "\n"); 42a07b4970SChristoph Hellwig } 43a07b4970SChristoph Hellwig } 44a07b4970SChristoph Hellwig 45a07b4970SChristoph Hellwig static ssize_t nvmet_addr_adrfam_store(struct config_item *item, 46a07b4970SChristoph Hellwig const char *page, size_t count) 47a07b4970SChristoph Hellwig { 48a07b4970SChristoph Hellwig struct nvmet_port *port = to_nvmet_port(item); 49a07b4970SChristoph Hellwig 50a07b4970SChristoph Hellwig if (port->enabled) { 51a07b4970SChristoph Hellwig pr_err("Cannot modify address while enabled\n"); 52a07b4970SChristoph Hellwig pr_err("Disable the address before modifying\n"); 53a07b4970SChristoph Hellwig return -EACCES; 54a07b4970SChristoph Hellwig } 55a07b4970SChristoph Hellwig 56a07b4970SChristoph Hellwig if (sysfs_streq(page, "ipv4")) { 57a07b4970SChristoph Hellwig port->disc_addr.adrfam = NVMF_ADDR_FAMILY_IP4; 58a07b4970SChristoph Hellwig } else if (sysfs_streq(page, "ipv6")) { 59a07b4970SChristoph Hellwig port->disc_addr.adrfam = NVMF_ADDR_FAMILY_IP6; 60a07b4970SChristoph Hellwig } else if (sysfs_streq(page, "ib")) { 61a07b4970SChristoph Hellwig port->disc_addr.adrfam = NVMF_ADDR_FAMILY_IB; 62a07b4970SChristoph Hellwig } else { 63a07b4970SChristoph Hellwig pr_err("Invalid value '%s' for adrfam\n", page); 64a07b4970SChristoph Hellwig return -EINVAL; 65a07b4970SChristoph Hellwig } 66a07b4970SChristoph Hellwig 67a07b4970SChristoph Hellwig return count; 68a07b4970SChristoph Hellwig } 69a07b4970SChristoph Hellwig 70a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_, addr_adrfam); 71a07b4970SChristoph Hellwig 72a07b4970SChristoph Hellwig static ssize_t nvmet_addr_portid_show(struct config_item *item, 73a07b4970SChristoph Hellwig char *page) 74a07b4970SChristoph Hellwig { 75a07b4970SChristoph Hellwig struct nvmet_port *port = to_nvmet_port(item); 76a07b4970SChristoph Hellwig 77a07b4970SChristoph Hellwig return snprintf(page, PAGE_SIZE, "%d\n", 78a07b4970SChristoph Hellwig le16_to_cpu(port->disc_addr.portid)); 79a07b4970SChristoph Hellwig } 80a07b4970SChristoph Hellwig 81a07b4970SChristoph Hellwig static ssize_t nvmet_addr_portid_store(struct config_item *item, 82a07b4970SChristoph Hellwig const char *page, size_t count) 83a07b4970SChristoph Hellwig { 84a07b4970SChristoph Hellwig struct nvmet_port *port = to_nvmet_port(item); 85a07b4970SChristoph Hellwig u16 portid = 0; 86a07b4970SChristoph Hellwig 87a07b4970SChristoph Hellwig if (kstrtou16(page, 0, &portid)) { 88a07b4970SChristoph Hellwig pr_err("Invalid value '%s' for portid\n", page); 89a07b4970SChristoph Hellwig return -EINVAL; 90a07b4970SChristoph Hellwig } 91a07b4970SChristoph Hellwig 92a07b4970SChristoph Hellwig if (port->enabled) { 93a07b4970SChristoph Hellwig pr_err("Cannot modify address while enabled\n"); 94a07b4970SChristoph Hellwig pr_err("Disable the address before modifying\n"); 95a07b4970SChristoph Hellwig return -EACCES; 96a07b4970SChristoph Hellwig } 97a07b4970SChristoph Hellwig port->disc_addr.portid = cpu_to_le16(portid); 98a07b4970SChristoph Hellwig return count; 99a07b4970SChristoph Hellwig } 100a07b4970SChristoph Hellwig 101a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_, addr_portid); 102a07b4970SChristoph Hellwig 103a07b4970SChristoph Hellwig static ssize_t nvmet_addr_traddr_show(struct config_item *item, 104a07b4970SChristoph Hellwig char *page) 105a07b4970SChristoph Hellwig { 106a07b4970SChristoph Hellwig struct nvmet_port *port = to_nvmet_port(item); 107a07b4970SChristoph Hellwig 108a07b4970SChristoph Hellwig return snprintf(page, PAGE_SIZE, "%s\n", 109a07b4970SChristoph Hellwig port->disc_addr.traddr); 110a07b4970SChristoph Hellwig } 111a07b4970SChristoph Hellwig 112a07b4970SChristoph Hellwig static ssize_t nvmet_addr_traddr_store(struct config_item *item, 113a07b4970SChristoph Hellwig const char *page, size_t count) 114a07b4970SChristoph Hellwig { 115a07b4970SChristoph Hellwig struct nvmet_port *port = to_nvmet_port(item); 116a07b4970SChristoph Hellwig 117a07b4970SChristoph Hellwig if (count > NVMF_TRADDR_SIZE) { 118a07b4970SChristoph Hellwig pr_err("Invalid value '%s' for traddr\n", page); 119a07b4970SChristoph Hellwig return -EINVAL; 120a07b4970SChristoph Hellwig } 121a07b4970SChristoph Hellwig 122a07b4970SChristoph Hellwig if (port->enabled) { 123a07b4970SChristoph Hellwig pr_err("Cannot modify address while enabled\n"); 124a07b4970SChristoph Hellwig pr_err("Disable the address before modifying\n"); 125a07b4970SChristoph Hellwig return -EACCES; 126a07b4970SChristoph Hellwig } 127a07b4970SChristoph Hellwig return snprintf(port->disc_addr.traddr, 128a07b4970SChristoph Hellwig sizeof(port->disc_addr.traddr), "%s", page); 129a07b4970SChristoph Hellwig } 130a07b4970SChristoph Hellwig 131a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_, addr_traddr); 132a07b4970SChristoph Hellwig 133a07b4970SChristoph Hellwig static ssize_t nvmet_addr_treq_show(struct config_item *item, 134a07b4970SChristoph Hellwig char *page) 135a07b4970SChristoph Hellwig { 136a07b4970SChristoph Hellwig switch (to_nvmet_port(item)->disc_addr.treq) { 137a07b4970SChristoph Hellwig case NVMF_TREQ_NOT_SPECIFIED: 138a07b4970SChristoph Hellwig return sprintf(page, "not specified\n"); 139a07b4970SChristoph Hellwig case NVMF_TREQ_REQUIRED: 140a07b4970SChristoph Hellwig return sprintf(page, "required\n"); 141a07b4970SChristoph Hellwig case NVMF_TREQ_NOT_REQUIRED: 142a07b4970SChristoph Hellwig return sprintf(page, "not required\n"); 143a07b4970SChristoph Hellwig default: 144a07b4970SChristoph Hellwig return sprintf(page, "\n"); 145a07b4970SChristoph Hellwig } 146a07b4970SChristoph Hellwig } 147a07b4970SChristoph Hellwig 148a07b4970SChristoph Hellwig static ssize_t nvmet_addr_treq_store(struct config_item *item, 149a07b4970SChristoph Hellwig const char *page, size_t count) 150a07b4970SChristoph Hellwig { 151a07b4970SChristoph Hellwig struct nvmet_port *port = to_nvmet_port(item); 152a07b4970SChristoph Hellwig 153a07b4970SChristoph Hellwig if (port->enabled) { 154a07b4970SChristoph Hellwig pr_err("Cannot modify address while enabled\n"); 155a07b4970SChristoph Hellwig pr_err("Disable the address before modifying\n"); 156a07b4970SChristoph Hellwig return -EACCES; 157a07b4970SChristoph Hellwig } 158a07b4970SChristoph Hellwig 159a07b4970SChristoph Hellwig if (sysfs_streq(page, "not specified")) { 160a07b4970SChristoph Hellwig port->disc_addr.treq = NVMF_TREQ_NOT_SPECIFIED; 161a07b4970SChristoph Hellwig } else if (sysfs_streq(page, "required")) { 162a07b4970SChristoph Hellwig port->disc_addr.treq = NVMF_TREQ_REQUIRED; 163a07b4970SChristoph Hellwig } else if (sysfs_streq(page, "not required")) { 164a07b4970SChristoph Hellwig port->disc_addr.treq = NVMF_TREQ_NOT_REQUIRED; 165a07b4970SChristoph Hellwig } else { 166a07b4970SChristoph Hellwig pr_err("Invalid value '%s' for treq\n", page); 167a07b4970SChristoph Hellwig return -EINVAL; 168a07b4970SChristoph Hellwig } 169a07b4970SChristoph Hellwig 170a07b4970SChristoph Hellwig return count; 171a07b4970SChristoph Hellwig } 172a07b4970SChristoph Hellwig 173a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_, addr_treq); 174a07b4970SChristoph Hellwig 175a07b4970SChristoph Hellwig static ssize_t nvmet_addr_trsvcid_show(struct config_item *item, 176a07b4970SChristoph Hellwig char *page) 177a07b4970SChristoph Hellwig { 178a07b4970SChristoph Hellwig struct nvmet_port *port = to_nvmet_port(item); 179a07b4970SChristoph Hellwig 180a07b4970SChristoph Hellwig return snprintf(page, PAGE_SIZE, "%s\n", 181a07b4970SChristoph Hellwig port->disc_addr.trsvcid); 182a07b4970SChristoph Hellwig } 183a07b4970SChristoph Hellwig 184a07b4970SChristoph Hellwig static ssize_t nvmet_addr_trsvcid_store(struct config_item *item, 185a07b4970SChristoph Hellwig const char *page, size_t count) 186a07b4970SChristoph Hellwig { 187a07b4970SChristoph Hellwig struct nvmet_port *port = to_nvmet_port(item); 188a07b4970SChristoph Hellwig 189a07b4970SChristoph Hellwig if (count > NVMF_TRSVCID_SIZE) { 190a07b4970SChristoph Hellwig pr_err("Invalid value '%s' for trsvcid\n", page); 191a07b4970SChristoph Hellwig return -EINVAL; 192a07b4970SChristoph Hellwig } 193a07b4970SChristoph Hellwig if (port->enabled) { 194a07b4970SChristoph Hellwig pr_err("Cannot modify address while enabled\n"); 195a07b4970SChristoph Hellwig pr_err("Disable the address before modifying\n"); 196a07b4970SChristoph Hellwig return -EACCES; 197a07b4970SChristoph Hellwig } 198a07b4970SChristoph Hellwig return snprintf(port->disc_addr.trsvcid, 199a07b4970SChristoph Hellwig sizeof(port->disc_addr.trsvcid), "%s", page); 200a07b4970SChristoph Hellwig } 201a07b4970SChristoph Hellwig 202a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_, addr_trsvcid); 203a07b4970SChristoph Hellwig 204a07b4970SChristoph Hellwig static ssize_t nvmet_addr_trtype_show(struct config_item *item, 205a07b4970SChristoph Hellwig char *page) 206a07b4970SChristoph Hellwig { 207a07b4970SChristoph Hellwig switch (to_nvmet_port(item)->disc_addr.trtype) { 208a07b4970SChristoph Hellwig case NVMF_TRTYPE_RDMA: 209a07b4970SChristoph Hellwig return sprintf(page, "rdma\n"); 210a07b4970SChristoph Hellwig case NVMF_TRTYPE_LOOP: 211a07b4970SChristoph Hellwig return sprintf(page, "loop\n"); 212a07b4970SChristoph Hellwig default: 213a07b4970SChristoph Hellwig return sprintf(page, "\n"); 214a07b4970SChristoph Hellwig } 215a07b4970SChristoph Hellwig } 216a07b4970SChristoph Hellwig 217a07b4970SChristoph Hellwig static void nvmet_port_init_tsas_rdma(struct nvmet_port *port) 218a07b4970SChristoph Hellwig { 219a07b4970SChristoph Hellwig port->disc_addr.trtype = NVMF_TRTYPE_RDMA; 220a07b4970SChristoph Hellwig memset(&port->disc_addr.tsas.rdma, 0, NVMF_TSAS_SIZE); 221a07b4970SChristoph Hellwig port->disc_addr.tsas.rdma.qptype = NVMF_RDMA_QPTYPE_CONNECTED; 222a07b4970SChristoph Hellwig port->disc_addr.tsas.rdma.prtype = NVMF_RDMA_PRTYPE_NOT_SPECIFIED; 223a07b4970SChristoph Hellwig port->disc_addr.tsas.rdma.cms = NVMF_RDMA_CMS_RDMA_CM; 224a07b4970SChristoph Hellwig } 225a07b4970SChristoph Hellwig 226a07b4970SChristoph Hellwig static void nvmet_port_init_tsas_loop(struct nvmet_port *port) 227a07b4970SChristoph Hellwig { 228a07b4970SChristoph Hellwig port->disc_addr.trtype = NVMF_TRTYPE_LOOP; 229a07b4970SChristoph Hellwig memset(&port->disc_addr.tsas, 0, NVMF_TSAS_SIZE); 230a07b4970SChristoph Hellwig } 231a07b4970SChristoph Hellwig 232a07b4970SChristoph Hellwig static ssize_t nvmet_addr_trtype_store(struct config_item *item, 233a07b4970SChristoph Hellwig const char *page, size_t count) 234a07b4970SChristoph Hellwig { 235a07b4970SChristoph Hellwig struct nvmet_port *port = to_nvmet_port(item); 236a07b4970SChristoph Hellwig 237a07b4970SChristoph Hellwig if (port->enabled) { 238a07b4970SChristoph Hellwig pr_err("Cannot modify address while enabled\n"); 239a07b4970SChristoph Hellwig pr_err("Disable the address before modifying\n"); 240a07b4970SChristoph Hellwig return -EACCES; 241a07b4970SChristoph Hellwig } 242a07b4970SChristoph Hellwig 243a07b4970SChristoph Hellwig if (sysfs_streq(page, "rdma")) { 244a07b4970SChristoph Hellwig nvmet_port_init_tsas_rdma(port); 245a07b4970SChristoph Hellwig } else if (sysfs_streq(page, "loop")) { 246a07b4970SChristoph Hellwig nvmet_port_init_tsas_loop(port); 247a07b4970SChristoph Hellwig } else { 248a07b4970SChristoph Hellwig pr_err("Invalid value '%s' for trtype\n", page); 249a07b4970SChristoph Hellwig return -EINVAL; 250a07b4970SChristoph Hellwig } 251a07b4970SChristoph Hellwig 252a07b4970SChristoph Hellwig return count; 253a07b4970SChristoph Hellwig } 254a07b4970SChristoph Hellwig 255a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_, addr_trtype); 256a07b4970SChristoph Hellwig 257a07b4970SChristoph Hellwig /* 258a07b4970SChristoph Hellwig * Namespace structures & file operation functions below 259a07b4970SChristoph Hellwig */ 260a07b4970SChristoph Hellwig static ssize_t nvmet_ns_device_path_show(struct config_item *item, char *page) 261a07b4970SChristoph Hellwig { 262a07b4970SChristoph Hellwig return sprintf(page, "%s\n", to_nvmet_ns(item)->device_path); 263a07b4970SChristoph Hellwig } 264a07b4970SChristoph Hellwig 265a07b4970SChristoph Hellwig static ssize_t nvmet_ns_device_path_store(struct config_item *item, 266a07b4970SChristoph Hellwig const char *page, size_t count) 267a07b4970SChristoph Hellwig { 268a07b4970SChristoph Hellwig struct nvmet_ns *ns = to_nvmet_ns(item); 269a07b4970SChristoph Hellwig struct nvmet_subsys *subsys = ns->subsys; 270a07b4970SChristoph Hellwig int ret; 271a07b4970SChristoph Hellwig 272a07b4970SChristoph Hellwig mutex_lock(&subsys->lock); 273a07b4970SChristoph Hellwig ret = -EBUSY; 274e4fcf07cSSolganik Alexander if (ns->enabled) 275a07b4970SChristoph Hellwig goto out_unlock; 276a07b4970SChristoph Hellwig 277a07b4970SChristoph Hellwig kfree(ns->device_path); 278a07b4970SChristoph Hellwig 279a07b4970SChristoph Hellwig ret = -ENOMEM; 280a07b4970SChristoph Hellwig ns->device_path = kstrdup(page, GFP_KERNEL); 281a07b4970SChristoph Hellwig if (!ns->device_path) 282a07b4970SChristoph Hellwig goto out_unlock; 283a07b4970SChristoph Hellwig 284a07b4970SChristoph Hellwig mutex_unlock(&subsys->lock); 285a07b4970SChristoph Hellwig return count; 286a07b4970SChristoph Hellwig 287a07b4970SChristoph Hellwig out_unlock: 288a07b4970SChristoph Hellwig mutex_unlock(&subsys->lock); 289a07b4970SChristoph Hellwig return ret; 290a07b4970SChristoph Hellwig } 291a07b4970SChristoph Hellwig 292a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_ns_, device_path); 293a07b4970SChristoph Hellwig 294a07b4970SChristoph Hellwig static ssize_t nvmet_ns_device_nguid_show(struct config_item *item, char *page) 295a07b4970SChristoph Hellwig { 296a07b4970SChristoph Hellwig return sprintf(page, "%pUb\n", &to_nvmet_ns(item)->nguid); 297a07b4970SChristoph Hellwig } 298a07b4970SChristoph Hellwig 299a07b4970SChristoph Hellwig static ssize_t nvmet_ns_device_nguid_store(struct config_item *item, 300a07b4970SChristoph Hellwig const char *page, size_t count) 301a07b4970SChristoph Hellwig { 302a07b4970SChristoph Hellwig struct nvmet_ns *ns = to_nvmet_ns(item); 303a07b4970SChristoph Hellwig struct nvmet_subsys *subsys = ns->subsys; 304a07b4970SChristoph Hellwig u8 nguid[16]; 305a07b4970SChristoph Hellwig const char *p = page; 306a07b4970SChristoph Hellwig int i; 307a07b4970SChristoph Hellwig int ret = 0; 308a07b4970SChristoph Hellwig 309a07b4970SChristoph Hellwig mutex_lock(&subsys->lock); 310e4fcf07cSSolganik Alexander if (ns->enabled) { 311a07b4970SChristoph Hellwig ret = -EBUSY; 312a07b4970SChristoph Hellwig goto out_unlock; 313a07b4970SChristoph Hellwig } 314a07b4970SChristoph Hellwig 315a07b4970SChristoph Hellwig for (i = 0; i < 16; i++) { 316a07b4970SChristoph Hellwig if (p + 2 > page + count) { 317a07b4970SChristoph Hellwig ret = -EINVAL; 318a07b4970SChristoph Hellwig goto out_unlock; 319a07b4970SChristoph Hellwig } 320a07b4970SChristoph Hellwig if (!isxdigit(p[0]) || !isxdigit(p[1])) { 321a07b4970SChristoph Hellwig ret = -EINVAL; 322a07b4970SChristoph Hellwig goto out_unlock; 323a07b4970SChristoph Hellwig } 324a07b4970SChristoph Hellwig 325a07b4970SChristoph Hellwig nguid[i] = (hex_to_bin(p[0]) << 4) | hex_to_bin(p[1]); 326a07b4970SChristoph Hellwig p += 2; 327a07b4970SChristoph Hellwig 328a07b4970SChristoph Hellwig if (*p == '-' || *p == ':') 329a07b4970SChristoph Hellwig p++; 330a07b4970SChristoph Hellwig } 331a07b4970SChristoph Hellwig 332a07b4970SChristoph Hellwig memcpy(&ns->nguid, nguid, sizeof(nguid)); 333a07b4970SChristoph Hellwig out_unlock: 334a07b4970SChristoph Hellwig mutex_unlock(&subsys->lock); 335a07b4970SChristoph Hellwig return ret ? ret : count; 336a07b4970SChristoph Hellwig } 337a07b4970SChristoph Hellwig 338a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_ns_, device_nguid); 339a07b4970SChristoph Hellwig 340a07b4970SChristoph Hellwig static ssize_t nvmet_ns_enable_show(struct config_item *item, char *page) 341a07b4970SChristoph Hellwig { 342e4fcf07cSSolganik Alexander return sprintf(page, "%d\n", to_nvmet_ns(item)->enabled); 343a07b4970SChristoph Hellwig } 344a07b4970SChristoph Hellwig 345a07b4970SChristoph Hellwig static ssize_t nvmet_ns_enable_store(struct config_item *item, 346a07b4970SChristoph Hellwig const char *page, size_t count) 347a07b4970SChristoph Hellwig { 348a07b4970SChristoph Hellwig struct nvmet_ns *ns = to_nvmet_ns(item); 349a07b4970SChristoph Hellwig bool enable; 350a07b4970SChristoph Hellwig int ret = 0; 351a07b4970SChristoph Hellwig 352a07b4970SChristoph Hellwig if (strtobool(page, &enable)) 353a07b4970SChristoph Hellwig return -EINVAL; 354a07b4970SChristoph Hellwig 355a07b4970SChristoph Hellwig if (enable) 356a07b4970SChristoph Hellwig ret = nvmet_ns_enable(ns); 357a07b4970SChristoph Hellwig else 358a07b4970SChristoph Hellwig nvmet_ns_disable(ns); 359a07b4970SChristoph Hellwig 360a07b4970SChristoph Hellwig return ret ? ret : count; 361a07b4970SChristoph Hellwig } 362a07b4970SChristoph Hellwig 363a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_ns_, enable); 364a07b4970SChristoph Hellwig 365a07b4970SChristoph Hellwig static struct configfs_attribute *nvmet_ns_attrs[] = { 366a07b4970SChristoph Hellwig &nvmet_ns_attr_device_path, 367a07b4970SChristoph Hellwig &nvmet_ns_attr_device_nguid, 368a07b4970SChristoph Hellwig &nvmet_ns_attr_enable, 369a07b4970SChristoph Hellwig NULL, 370a07b4970SChristoph Hellwig }; 371a07b4970SChristoph Hellwig 372a07b4970SChristoph Hellwig static void nvmet_ns_release(struct config_item *item) 373a07b4970SChristoph Hellwig { 374a07b4970SChristoph Hellwig struct nvmet_ns *ns = to_nvmet_ns(item); 375a07b4970SChristoph Hellwig 376a07b4970SChristoph Hellwig nvmet_ns_free(ns); 377a07b4970SChristoph Hellwig } 378a07b4970SChristoph Hellwig 379a07b4970SChristoph Hellwig static struct configfs_item_operations nvmet_ns_item_ops = { 380a07b4970SChristoph Hellwig .release = nvmet_ns_release, 381a07b4970SChristoph Hellwig }; 382a07b4970SChristoph Hellwig 383a07b4970SChristoph Hellwig static struct config_item_type nvmet_ns_type = { 384a07b4970SChristoph Hellwig .ct_item_ops = &nvmet_ns_item_ops, 385a07b4970SChristoph Hellwig .ct_attrs = nvmet_ns_attrs, 386a07b4970SChristoph Hellwig .ct_owner = THIS_MODULE, 387a07b4970SChristoph Hellwig }; 388a07b4970SChristoph Hellwig 389a07b4970SChristoph Hellwig static struct config_group *nvmet_ns_make(struct config_group *group, 390a07b4970SChristoph Hellwig const char *name) 391a07b4970SChristoph Hellwig { 392a07b4970SChristoph Hellwig struct nvmet_subsys *subsys = namespaces_to_subsys(&group->cg_item); 393a07b4970SChristoph Hellwig struct nvmet_ns *ns; 394a07b4970SChristoph Hellwig int ret; 395a07b4970SChristoph Hellwig u32 nsid; 396a07b4970SChristoph Hellwig 397a07b4970SChristoph Hellwig ret = kstrtou32(name, 0, &nsid); 398a07b4970SChristoph Hellwig if (ret) 399a07b4970SChristoph Hellwig goto out; 400a07b4970SChristoph Hellwig 401a07b4970SChristoph Hellwig ret = -EINVAL; 402a07b4970SChristoph Hellwig if (nsid == 0 || nsid == 0xffffffff) 403a07b4970SChristoph Hellwig goto out; 404a07b4970SChristoph Hellwig 405a07b4970SChristoph Hellwig ret = -ENOMEM; 406a07b4970SChristoph Hellwig ns = nvmet_ns_alloc(subsys, nsid); 407a07b4970SChristoph Hellwig if (!ns) 408a07b4970SChristoph Hellwig goto out; 409a07b4970SChristoph Hellwig config_group_init_type_name(&ns->group, name, &nvmet_ns_type); 410a07b4970SChristoph Hellwig 411a07b4970SChristoph Hellwig pr_info("adding nsid %d to subsystem %s\n", nsid, subsys->subsysnqn); 412a07b4970SChristoph Hellwig 413a07b4970SChristoph Hellwig return &ns->group; 414a07b4970SChristoph Hellwig out: 415a07b4970SChristoph Hellwig return ERR_PTR(ret); 416a07b4970SChristoph Hellwig } 417a07b4970SChristoph Hellwig 418a07b4970SChristoph Hellwig static struct configfs_group_operations nvmet_namespaces_group_ops = { 419a07b4970SChristoph Hellwig .make_group = nvmet_ns_make, 420a07b4970SChristoph Hellwig }; 421a07b4970SChristoph Hellwig 422a07b4970SChristoph Hellwig static struct config_item_type nvmet_namespaces_type = { 423a07b4970SChristoph Hellwig .ct_group_ops = &nvmet_namespaces_group_ops, 424a07b4970SChristoph Hellwig .ct_owner = THIS_MODULE, 425a07b4970SChristoph Hellwig }; 426a07b4970SChristoph Hellwig 427a07b4970SChristoph Hellwig static int nvmet_port_subsys_allow_link(struct config_item *parent, 428a07b4970SChristoph Hellwig struct config_item *target) 429a07b4970SChristoph Hellwig { 430a07b4970SChristoph Hellwig struct nvmet_port *port = to_nvmet_port(parent->ci_parent); 431a07b4970SChristoph Hellwig struct nvmet_subsys *subsys; 432a07b4970SChristoph Hellwig struct nvmet_subsys_link *link, *p; 433a07b4970SChristoph Hellwig int ret; 434a07b4970SChristoph Hellwig 435a07b4970SChristoph Hellwig if (target->ci_type != &nvmet_subsys_type) { 436a07b4970SChristoph Hellwig pr_err("can only link subsystems into the subsystems dir.!\n"); 437a07b4970SChristoph Hellwig return -EINVAL; 438a07b4970SChristoph Hellwig } 439a07b4970SChristoph Hellwig subsys = to_subsys(target); 440a07b4970SChristoph Hellwig link = kmalloc(sizeof(*link), GFP_KERNEL); 441a07b4970SChristoph Hellwig if (!link) 442a07b4970SChristoph Hellwig return -ENOMEM; 443a07b4970SChristoph Hellwig link->subsys = subsys; 444a07b4970SChristoph Hellwig 445a07b4970SChristoph Hellwig down_write(&nvmet_config_sem); 446a07b4970SChristoph Hellwig ret = -EEXIST; 447a07b4970SChristoph Hellwig list_for_each_entry(p, &port->subsystems, entry) { 448a07b4970SChristoph Hellwig if (p->subsys == subsys) 449a07b4970SChristoph Hellwig goto out_free_link; 450a07b4970SChristoph Hellwig } 451a07b4970SChristoph Hellwig 452a07b4970SChristoph Hellwig if (list_empty(&port->subsystems)) { 453a07b4970SChristoph Hellwig ret = nvmet_enable_port(port); 454a07b4970SChristoph Hellwig if (ret) 455a07b4970SChristoph Hellwig goto out_free_link; 456a07b4970SChristoph Hellwig } 457a07b4970SChristoph Hellwig 458a07b4970SChristoph Hellwig list_add_tail(&link->entry, &port->subsystems); 459a07b4970SChristoph Hellwig nvmet_genctr++; 460a07b4970SChristoph Hellwig up_write(&nvmet_config_sem); 461a07b4970SChristoph Hellwig return 0; 462a07b4970SChristoph Hellwig 463a07b4970SChristoph Hellwig out_free_link: 464a07b4970SChristoph Hellwig up_write(&nvmet_config_sem); 465a07b4970SChristoph Hellwig kfree(link); 466a07b4970SChristoph Hellwig return ret; 467a07b4970SChristoph Hellwig } 468a07b4970SChristoph Hellwig 469a07b4970SChristoph Hellwig static int nvmet_port_subsys_drop_link(struct config_item *parent, 470a07b4970SChristoph Hellwig struct config_item *target) 471a07b4970SChristoph Hellwig { 472a07b4970SChristoph Hellwig struct nvmet_port *port = to_nvmet_port(parent->ci_parent); 473a07b4970SChristoph Hellwig struct nvmet_subsys *subsys = to_subsys(target); 474a07b4970SChristoph Hellwig struct nvmet_subsys_link *p; 475a07b4970SChristoph Hellwig 476a07b4970SChristoph Hellwig down_write(&nvmet_config_sem); 477a07b4970SChristoph Hellwig list_for_each_entry(p, &port->subsystems, entry) { 478a07b4970SChristoph Hellwig if (p->subsys == subsys) 479a07b4970SChristoph Hellwig goto found; 480a07b4970SChristoph Hellwig } 481a07b4970SChristoph Hellwig up_write(&nvmet_config_sem); 482a07b4970SChristoph Hellwig return -EINVAL; 483a07b4970SChristoph Hellwig 484a07b4970SChristoph Hellwig found: 485a07b4970SChristoph Hellwig list_del(&p->entry); 486a07b4970SChristoph Hellwig nvmet_genctr++; 487a07b4970SChristoph Hellwig if (list_empty(&port->subsystems)) 488a07b4970SChristoph Hellwig nvmet_disable_port(port); 489a07b4970SChristoph Hellwig up_write(&nvmet_config_sem); 490a07b4970SChristoph Hellwig kfree(p); 491a07b4970SChristoph Hellwig return 0; 492a07b4970SChristoph Hellwig } 493a07b4970SChristoph Hellwig 494a07b4970SChristoph Hellwig static struct configfs_item_operations nvmet_port_subsys_item_ops = { 495a07b4970SChristoph Hellwig .allow_link = nvmet_port_subsys_allow_link, 496a07b4970SChristoph Hellwig .drop_link = nvmet_port_subsys_drop_link, 497a07b4970SChristoph Hellwig }; 498a07b4970SChristoph Hellwig 499a07b4970SChristoph Hellwig static struct config_item_type nvmet_port_subsys_type = { 500a07b4970SChristoph Hellwig .ct_item_ops = &nvmet_port_subsys_item_ops, 501a07b4970SChristoph Hellwig .ct_owner = THIS_MODULE, 502a07b4970SChristoph Hellwig }; 503a07b4970SChristoph Hellwig 504a07b4970SChristoph Hellwig static int nvmet_allowed_hosts_allow_link(struct config_item *parent, 505a07b4970SChristoph Hellwig struct config_item *target) 506a07b4970SChristoph Hellwig { 507a07b4970SChristoph Hellwig struct nvmet_subsys *subsys = to_subsys(parent->ci_parent); 508a07b4970SChristoph Hellwig struct nvmet_host *host; 509a07b4970SChristoph Hellwig struct nvmet_host_link *link, *p; 510a07b4970SChristoph Hellwig int ret; 511a07b4970SChristoph Hellwig 512a07b4970SChristoph Hellwig if (target->ci_type != &nvmet_host_type) { 513a07b4970SChristoph Hellwig pr_err("can only link hosts into the allowed_hosts directory!\n"); 514a07b4970SChristoph Hellwig return -EINVAL; 515a07b4970SChristoph Hellwig } 516a07b4970SChristoph Hellwig 517a07b4970SChristoph Hellwig host = to_host(target); 518a07b4970SChristoph Hellwig link = kmalloc(sizeof(*link), GFP_KERNEL); 519a07b4970SChristoph Hellwig if (!link) 520a07b4970SChristoph Hellwig return -ENOMEM; 521a07b4970SChristoph Hellwig link->host = host; 522a07b4970SChristoph Hellwig 523a07b4970SChristoph Hellwig down_write(&nvmet_config_sem); 524a07b4970SChristoph Hellwig ret = -EINVAL; 525a07b4970SChristoph Hellwig if (subsys->allow_any_host) { 526a07b4970SChristoph Hellwig pr_err("can't add hosts when allow_any_host is set!\n"); 527a07b4970SChristoph Hellwig goto out_free_link; 528a07b4970SChristoph Hellwig } 529a07b4970SChristoph Hellwig 530a07b4970SChristoph Hellwig ret = -EEXIST; 531a07b4970SChristoph Hellwig list_for_each_entry(p, &subsys->hosts, entry) { 532a07b4970SChristoph Hellwig if (!strcmp(nvmet_host_name(p->host), nvmet_host_name(host))) 533a07b4970SChristoph Hellwig goto out_free_link; 534a07b4970SChristoph Hellwig } 535a07b4970SChristoph Hellwig list_add_tail(&link->entry, &subsys->hosts); 536a07b4970SChristoph Hellwig nvmet_genctr++; 537a07b4970SChristoph Hellwig up_write(&nvmet_config_sem); 538a07b4970SChristoph Hellwig return 0; 539a07b4970SChristoph Hellwig out_free_link: 540a07b4970SChristoph Hellwig up_write(&nvmet_config_sem); 541a07b4970SChristoph Hellwig kfree(link); 542a07b4970SChristoph Hellwig return ret; 543a07b4970SChristoph Hellwig } 544a07b4970SChristoph Hellwig 545a07b4970SChristoph Hellwig static int nvmet_allowed_hosts_drop_link(struct config_item *parent, 546a07b4970SChristoph Hellwig struct config_item *target) 547a07b4970SChristoph Hellwig { 548a07b4970SChristoph Hellwig struct nvmet_subsys *subsys = to_subsys(parent->ci_parent); 549a07b4970SChristoph Hellwig struct nvmet_host *host = to_host(target); 550a07b4970SChristoph Hellwig struct nvmet_host_link *p; 551a07b4970SChristoph Hellwig 552a07b4970SChristoph Hellwig down_write(&nvmet_config_sem); 553a07b4970SChristoph Hellwig list_for_each_entry(p, &subsys->hosts, entry) { 554a07b4970SChristoph Hellwig if (!strcmp(nvmet_host_name(p->host), nvmet_host_name(host))) 555a07b4970SChristoph Hellwig goto found; 556a07b4970SChristoph Hellwig } 557a07b4970SChristoph Hellwig up_write(&nvmet_config_sem); 558a07b4970SChristoph Hellwig return -EINVAL; 559a07b4970SChristoph Hellwig 560a07b4970SChristoph Hellwig found: 561a07b4970SChristoph Hellwig list_del(&p->entry); 562a07b4970SChristoph Hellwig nvmet_genctr++; 563a07b4970SChristoph Hellwig up_write(&nvmet_config_sem); 564a07b4970SChristoph Hellwig kfree(p); 565a07b4970SChristoph Hellwig return 0; 566a07b4970SChristoph Hellwig } 567a07b4970SChristoph Hellwig 568a07b4970SChristoph Hellwig static struct configfs_item_operations nvmet_allowed_hosts_item_ops = { 569a07b4970SChristoph Hellwig .allow_link = nvmet_allowed_hosts_allow_link, 570a07b4970SChristoph Hellwig .drop_link = nvmet_allowed_hosts_drop_link, 571a07b4970SChristoph Hellwig }; 572a07b4970SChristoph Hellwig 573a07b4970SChristoph Hellwig static struct config_item_type nvmet_allowed_hosts_type = { 574a07b4970SChristoph Hellwig .ct_item_ops = &nvmet_allowed_hosts_item_ops, 575a07b4970SChristoph Hellwig .ct_owner = THIS_MODULE, 576a07b4970SChristoph Hellwig }; 577a07b4970SChristoph Hellwig 578a07b4970SChristoph Hellwig static ssize_t nvmet_subsys_attr_allow_any_host_show(struct config_item *item, 579a07b4970SChristoph Hellwig char *page) 580a07b4970SChristoph Hellwig { 581a07b4970SChristoph Hellwig return snprintf(page, PAGE_SIZE, "%d\n", 582a07b4970SChristoph Hellwig to_subsys(item)->allow_any_host); 583a07b4970SChristoph Hellwig } 584a07b4970SChristoph Hellwig 585a07b4970SChristoph Hellwig static ssize_t nvmet_subsys_attr_allow_any_host_store(struct config_item *item, 586a07b4970SChristoph Hellwig const char *page, size_t count) 587a07b4970SChristoph Hellwig { 588a07b4970SChristoph Hellwig struct nvmet_subsys *subsys = to_subsys(item); 589a07b4970SChristoph Hellwig bool allow_any_host; 590a07b4970SChristoph Hellwig int ret = 0; 591a07b4970SChristoph Hellwig 592a07b4970SChristoph Hellwig if (strtobool(page, &allow_any_host)) 593a07b4970SChristoph Hellwig return -EINVAL; 594a07b4970SChristoph Hellwig 595a07b4970SChristoph Hellwig down_write(&nvmet_config_sem); 596a07b4970SChristoph Hellwig if (allow_any_host && !list_empty(&subsys->hosts)) { 597a07b4970SChristoph Hellwig pr_err("Can't set allow_any_host when explicit hosts are set!\n"); 598a07b4970SChristoph Hellwig ret = -EINVAL; 599a07b4970SChristoph Hellwig goto out_unlock; 600a07b4970SChristoph Hellwig } 601a07b4970SChristoph Hellwig 602a07b4970SChristoph Hellwig subsys->allow_any_host = allow_any_host; 603a07b4970SChristoph Hellwig out_unlock: 604a07b4970SChristoph Hellwig up_write(&nvmet_config_sem); 605a07b4970SChristoph Hellwig return ret ? ret : count; 606a07b4970SChristoph Hellwig } 607a07b4970SChristoph Hellwig 608a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_subsys_, attr_allow_any_host); 609a07b4970SChristoph Hellwig 610a07b4970SChristoph Hellwig static struct configfs_attribute *nvmet_subsys_attrs[] = { 611a07b4970SChristoph Hellwig &nvmet_subsys_attr_attr_allow_any_host, 612a07b4970SChristoph Hellwig NULL, 613a07b4970SChristoph Hellwig }; 614a07b4970SChristoph Hellwig 615a07b4970SChristoph Hellwig /* 616a07b4970SChristoph Hellwig * Subsystem structures & folder operation functions below 617a07b4970SChristoph Hellwig */ 618a07b4970SChristoph Hellwig static void nvmet_subsys_release(struct config_item *item) 619a07b4970SChristoph Hellwig { 620a07b4970SChristoph Hellwig struct nvmet_subsys *subsys = to_subsys(item); 621a07b4970SChristoph Hellwig 622a07b4970SChristoph Hellwig nvmet_subsys_put(subsys); 623a07b4970SChristoph Hellwig } 624a07b4970SChristoph Hellwig 625a07b4970SChristoph Hellwig static struct configfs_item_operations nvmet_subsys_item_ops = { 626a07b4970SChristoph Hellwig .release = nvmet_subsys_release, 627a07b4970SChristoph Hellwig }; 628a07b4970SChristoph Hellwig 629a07b4970SChristoph Hellwig static struct config_item_type nvmet_subsys_type = { 630a07b4970SChristoph Hellwig .ct_item_ops = &nvmet_subsys_item_ops, 631a07b4970SChristoph Hellwig .ct_attrs = nvmet_subsys_attrs, 632a07b4970SChristoph Hellwig .ct_owner = THIS_MODULE, 633a07b4970SChristoph Hellwig }; 634a07b4970SChristoph Hellwig 635a07b4970SChristoph Hellwig static struct config_group *nvmet_subsys_make(struct config_group *group, 636a07b4970SChristoph Hellwig const char *name) 637a07b4970SChristoph Hellwig { 638a07b4970SChristoph Hellwig struct nvmet_subsys *subsys; 639a07b4970SChristoph Hellwig 640a07b4970SChristoph Hellwig if (sysfs_streq(name, NVME_DISC_SUBSYS_NAME)) { 641a07b4970SChristoph Hellwig pr_err("can't create discovery subsystem through configfs\n"); 642a07b4970SChristoph Hellwig return ERR_PTR(-EINVAL); 643a07b4970SChristoph Hellwig } 644a07b4970SChristoph Hellwig 645a07b4970SChristoph Hellwig subsys = nvmet_subsys_alloc(name, NVME_NQN_NVME); 646a07b4970SChristoph Hellwig if (!subsys) 647a07b4970SChristoph Hellwig return ERR_PTR(-ENOMEM); 648a07b4970SChristoph Hellwig 649a07b4970SChristoph Hellwig config_group_init_type_name(&subsys->group, name, &nvmet_subsys_type); 650a07b4970SChristoph Hellwig 651a07b4970SChristoph Hellwig config_group_init_type_name(&subsys->namespaces_group, 652a07b4970SChristoph Hellwig "namespaces", &nvmet_namespaces_type); 653a07b4970SChristoph Hellwig configfs_add_default_group(&subsys->namespaces_group, &subsys->group); 654a07b4970SChristoph Hellwig 655a07b4970SChristoph Hellwig config_group_init_type_name(&subsys->allowed_hosts_group, 656a07b4970SChristoph Hellwig "allowed_hosts", &nvmet_allowed_hosts_type); 657a07b4970SChristoph Hellwig configfs_add_default_group(&subsys->allowed_hosts_group, 658a07b4970SChristoph Hellwig &subsys->group); 659a07b4970SChristoph Hellwig 660a07b4970SChristoph Hellwig return &subsys->group; 661a07b4970SChristoph Hellwig } 662a07b4970SChristoph Hellwig 663a07b4970SChristoph Hellwig static struct configfs_group_operations nvmet_subsystems_group_ops = { 664a07b4970SChristoph Hellwig .make_group = nvmet_subsys_make, 665a07b4970SChristoph Hellwig }; 666a07b4970SChristoph Hellwig 667a07b4970SChristoph Hellwig static struct config_item_type nvmet_subsystems_type = { 668a07b4970SChristoph Hellwig .ct_group_ops = &nvmet_subsystems_group_ops, 669a07b4970SChristoph Hellwig .ct_owner = THIS_MODULE, 670a07b4970SChristoph Hellwig }; 671a07b4970SChristoph Hellwig 672a07b4970SChristoph Hellwig static ssize_t nvmet_referral_enable_show(struct config_item *item, 673a07b4970SChristoph Hellwig char *page) 674a07b4970SChristoph Hellwig { 675a07b4970SChristoph Hellwig return snprintf(page, PAGE_SIZE, "%d\n", to_nvmet_port(item)->enabled); 676a07b4970SChristoph Hellwig } 677a07b4970SChristoph Hellwig 678a07b4970SChristoph Hellwig static ssize_t nvmet_referral_enable_store(struct config_item *item, 679a07b4970SChristoph Hellwig const char *page, size_t count) 680a07b4970SChristoph Hellwig { 681a07b4970SChristoph Hellwig struct nvmet_port *parent = to_nvmet_port(item->ci_parent->ci_parent); 682a07b4970SChristoph Hellwig struct nvmet_port *port = to_nvmet_port(item); 683a07b4970SChristoph Hellwig bool enable; 684a07b4970SChristoph Hellwig 685a07b4970SChristoph Hellwig if (strtobool(page, &enable)) 686a07b4970SChristoph Hellwig goto inval; 687a07b4970SChristoph Hellwig 688a07b4970SChristoph Hellwig if (enable) 689a07b4970SChristoph Hellwig nvmet_referral_enable(parent, port); 690a07b4970SChristoph Hellwig else 691a07b4970SChristoph Hellwig nvmet_referral_disable(port); 692a07b4970SChristoph Hellwig 693a07b4970SChristoph Hellwig return count; 694a07b4970SChristoph Hellwig inval: 695a07b4970SChristoph Hellwig pr_err("Invalid value '%s' for enable\n", page); 696a07b4970SChristoph Hellwig return -EINVAL; 697a07b4970SChristoph Hellwig } 698a07b4970SChristoph Hellwig 699a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_referral_, enable); 700a07b4970SChristoph Hellwig 701a07b4970SChristoph Hellwig /* 702a07b4970SChristoph Hellwig * Discovery Service subsystem definitions 703a07b4970SChristoph Hellwig */ 704a07b4970SChristoph Hellwig static struct configfs_attribute *nvmet_referral_attrs[] = { 705a07b4970SChristoph Hellwig &nvmet_attr_addr_adrfam, 706a07b4970SChristoph Hellwig &nvmet_attr_addr_portid, 707a07b4970SChristoph Hellwig &nvmet_attr_addr_treq, 708a07b4970SChristoph Hellwig &nvmet_attr_addr_traddr, 709a07b4970SChristoph Hellwig &nvmet_attr_addr_trsvcid, 710a07b4970SChristoph Hellwig &nvmet_attr_addr_trtype, 711a07b4970SChristoph Hellwig &nvmet_referral_attr_enable, 712a07b4970SChristoph Hellwig NULL, 713a07b4970SChristoph Hellwig }; 714a07b4970SChristoph Hellwig 715a07b4970SChristoph Hellwig static void nvmet_referral_release(struct config_item *item) 716a07b4970SChristoph Hellwig { 717a07b4970SChristoph Hellwig struct nvmet_port *port = to_nvmet_port(item); 718a07b4970SChristoph Hellwig 719a07b4970SChristoph Hellwig nvmet_referral_disable(port); 720a07b4970SChristoph Hellwig kfree(port); 721a07b4970SChristoph Hellwig } 722a07b4970SChristoph Hellwig 723a07b4970SChristoph Hellwig static struct configfs_item_operations nvmet_referral_item_ops = { 724a07b4970SChristoph Hellwig .release = nvmet_referral_release, 725a07b4970SChristoph Hellwig }; 726a07b4970SChristoph Hellwig 727a07b4970SChristoph Hellwig static struct config_item_type nvmet_referral_type = { 728a07b4970SChristoph Hellwig .ct_owner = THIS_MODULE, 729a07b4970SChristoph Hellwig .ct_attrs = nvmet_referral_attrs, 730a07b4970SChristoph Hellwig .ct_item_ops = &nvmet_referral_item_ops, 731a07b4970SChristoph Hellwig }; 732a07b4970SChristoph Hellwig 733a07b4970SChristoph Hellwig static struct config_group *nvmet_referral_make( 734a07b4970SChristoph Hellwig struct config_group *group, const char *name) 735a07b4970SChristoph Hellwig { 736a07b4970SChristoph Hellwig struct nvmet_port *port; 737a07b4970SChristoph Hellwig 738a07b4970SChristoph Hellwig port = kzalloc(sizeof(*port), GFP_KERNEL); 739a07b4970SChristoph Hellwig if (!port) 740f98d9ca1SDan Carpenter return ERR_PTR(-ENOMEM); 741a07b4970SChristoph Hellwig 742a07b4970SChristoph Hellwig INIT_LIST_HEAD(&port->entry); 743a07b4970SChristoph Hellwig config_group_init_type_name(&port->group, name, &nvmet_referral_type); 744a07b4970SChristoph Hellwig 745a07b4970SChristoph Hellwig return &port->group; 746a07b4970SChristoph Hellwig } 747a07b4970SChristoph Hellwig 748a07b4970SChristoph Hellwig static struct configfs_group_operations nvmet_referral_group_ops = { 749a07b4970SChristoph Hellwig .make_group = nvmet_referral_make, 750a07b4970SChristoph Hellwig }; 751a07b4970SChristoph Hellwig 752a07b4970SChristoph Hellwig static struct config_item_type nvmet_referrals_type = { 753a07b4970SChristoph Hellwig .ct_owner = THIS_MODULE, 754a07b4970SChristoph Hellwig .ct_group_ops = &nvmet_referral_group_ops, 755a07b4970SChristoph Hellwig }; 756a07b4970SChristoph Hellwig 757a07b4970SChristoph Hellwig /* 758a07b4970SChristoph Hellwig * Ports definitions. 759a07b4970SChristoph Hellwig */ 760a07b4970SChristoph Hellwig static void nvmet_port_release(struct config_item *item) 761a07b4970SChristoph Hellwig { 762a07b4970SChristoph Hellwig struct nvmet_port *port = to_nvmet_port(item); 763a07b4970SChristoph Hellwig 764a07b4970SChristoph Hellwig kfree(port); 765a07b4970SChristoph Hellwig } 766a07b4970SChristoph Hellwig 767a07b4970SChristoph Hellwig static struct configfs_attribute *nvmet_port_attrs[] = { 768a07b4970SChristoph Hellwig &nvmet_attr_addr_adrfam, 769a07b4970SChristoph Hellwig &nvmet_attr_addr_treq, 770a07b4970SChristoph Hellwig &nvmet_attr_addr_traddr, 771a07b4970SChristoph Hellwig &nvmet_attr_addr_trsvcid, 772a07b4970SChristoph Hellwig &nvmet_attr_addr_trtype, 773a07b4970SChristoph Hellwig NULL, 774a07b4970SChristoph Hellwig }; 775a07b4970SChristoph Hellwig 776a07b4970SChristoph Hellwig static struct configfs_item_operations nvmet_port_item_ops = { 777a07b4970SChristoph Hellwig .release = nvmet_port_release, 778a07b4970SChristoph Hellwig }; 779a07b4970SChristoph Hellwig 780a07b4970SChristoph Hellwig static struct config_item_type nvmet_port_type = { 781a07b4970SChristoph Hellwig .ct_attrs = nvmet_port_attrs, 782a07b4970SChristoph Hellwig .ct_item_ops = &nvmet_port_item_ops, 783a07b4970SChristoph Hellwig .ct_owner = THIS_MODULE, 784a07b4970SChristoph Hellwig }; 785a07b4970SChristoph Hellwig 786a07b4970SChristoph Hellwig static struct config_group *nvmet_ports_make(struct config_group *group, 787a07b4970SChristoph Hellwig const char *name) 788a07b4970SChristoph Hellwig { 789a07b4970SChristoph Hellwig struct nvmet_port *port; 790a07b4970SChristoph Hellwig u16 portid; 791a07b4970SChristoph Hellwig 792a07b4970SChristoph Hellwig if (kstrtou16(name, 0, &portid)) 793a07b4970SChristoph Hellwig return ERR_PTR(-EINVAL); 794a07b4970SChristoph Hellwig 795a07b4970SChristoph Hellwig port = kzalloc(sizeof(*port), GFP_KERNEL); 796a07b4970SChristoph Hellwig if (!port) 797f98d9ca1SDan Carpenter return ERR_PTR(-ENOMEM); 798a07b4970SChristoph Hellwig 799a07b4970SChristoph Hellwig INIT_LIST_HEAD(&port->entry); 800a07b4970SChristoph Hellwig INIT_LIST_HEAD(&port->subsystems); 801a07b4970SChristoph Hellwig INIT_LIST_HEAD(&port->referrals); 802a07b4970SChristoph Hellwig 803a07b4970SChristoph Hellwig port->disc_addr.portid = cpu_to_le16(portid); 804a07b4970SChristoph Hellwig config_group_init_type_name(&port->group, name, &nvmet_port_type); 805a07b4970SChristoph Hellwig 806a07b4970SChristoph Hellwig config_group_init_type_name(&port->subsys_group, 807a07b4970SChristoph Hellwig "subsystems", &nvmet_port_subsys_type); 808a07b4970SChristoph Hellwig configfs_add_default_group(&port->subsys_group, &port->group); 809a07b4970SChristoph Hellwig 810a07b4970SChristoph Hellwig config_group_init_type_name(&port->referrals_group, 811a07b4970SChristoph Hellwig "referrals", &nvmet_referrals_type); 812a07b4970SChristoph Hellwig configfs_add_default_group(&port->referrals_group, &port->group); 813a07b4970SChristoph Hellwig 814a07b4970SChristoph Hellwig return &port->group; 815a07b4970SChristoph Hellwig } 816a07b4970SChristoph Hellwig 817a07b4970SChristoph Hellwig static struct configfs_group_operations nvmet_ports_group_ops = { 818a07b4970SChristoph Hellwig .make_group = nvmet_ports_make, 819a07b4970SChristoph Hellwig }; 820a07b4970SChristoph Hellwig 821a07b4970SChristoph Hellwig static struct config_item_type nvmet_ports_type = { 822a07b4970SChristoph Hellwig .ct_group_ops = &nvmet_ports_group_ops, 823a07b4970SChristoph Hellwig .ct_owner = THIS_MODULE, 824a07b4970SChristoph Hellwig }; 825a07b4970SChristoph Hellwig 826a07b4970SChristoph Hellwig static struct config_group nvmet_subsystems_group; 827a07b4970SChristoph Hellwig static struct config_group nvmet_ports_group; 828a07b4970SChristoph Hellwig 829a07b4970SChristoph Hellwig static void nvmet_host_release(struct config_item *item) 830a07b4970SChristoph Hellwig { 831a07b4970SChristoph Hellwig struct nvmet_host *host = to_host(item); 832a07b4970SChristoph Hellwig 833a07b4970SChristoph Hellwig kfree(host); 834a07b4970SChristoph Hellwig } 835a07b4970SChristoph Hellwig 836a07b4970SChristoph Hellwig static struct configfs_item_operations nvmet_host_item_ops = { 837a07b4970SChristoph Hellwig .release = nvmet_host_release, 838a07b4970SChristoph Hellwig }; 839a07b4970SChristoph Hellwig 840a07b4970SChristoph Hellwig static struct config_item_type nvmet_host_type = { 841a07b4970SChristoph Hellwig .ct_item_ops = &nvmet_host_item_ops, 842a07b4970SChristoph Hellwig .ct_owner = THIS_MODULE, 843a07b4970SChristoph Hellwig }; 844a07b4970SChristoph Hellwig 845a07b4970SChristoph Hellwig static struct config_group *nvmet_hosts_make_group(struct config_group *group, 846a07b4970SChristoph Hellwig const char *name) 847a07b4970SChristoph Hellwig { 848a07b4970SChristoph Hellwig struct nvmet_host *host; 849a07b4970SChristoph Hellwig 850a07b4970SChristoph Hellwig host = kzalloc(sizeof(*host), GFP_KERNEL); 851a07b4970SChristoph Hellwig if (!host) 852a07b4970SChristoph Hellwig return ERR_PTR(-ENOMEM); 853a07b4970SChristoph Hellwig 854a07b4970SChristoph Hellwig config_group_init_type_name(&host->group, name, &nvmet_host_type); 855a07b4970SChristoph Hellwig 856a07b4970SChristoph Hellwig return &host->group; 857a07b4970SChristoph Hellwig } 858a07b4970SChristoph Hellwig 859a07b4970SChristoph Hellwig static struct configfs_group_operations nvmet_hosts_group_ops = { 860a07b4970SChristoph Hellwig .make_group = nvmet_hosts_make_group, 861a07b4970SChristoph Hellwig }; 862a07b4970SChristoph Hellwig 863a07b4970SChristoph Hellwig static struct config_item_type nvmet_hosts_type = { 864a07b4970SChristoph Hellwig .ct_group_ops = &nvmet_hosts_group_ops, 865a07b4970SChristoph Hellwig .ct_owner = THIS_MODULE, 866a07b4970SChristoph Hellwig }; 867a07b4970SChristoph Hellwig 868a07b4970SChristoph Hellwig static struct config_group nvmet_hosts_group; 869a07b4970SChristoph Hellwig 870a07b4970SChristoph Hellwig static struct config_item_type nvmet_root_type = { 871a07b4970SChristoph Hellwig .ct_owner = THIS_MODULE, 872a07b4970SChristoph Hellwig }; 873a07b4970SChristoph Hellwig 874a07b4970SChristoph Hellwig static struct configfs_subsystem nvmet_configfs_subsystem = { 875a07b4970SChristoph Hellwig .su_group = { 876a07b4970SChristoph Hellwig .cg_item = { 877a07b4970SChristoph Hellwig .ci_namebuf = "nvmet", 878a07b4970SChristoph Hellwig .ci_type = &nvmet_root_type, 879a07b4970SChristoph Hellwig }, 880a07b4970SChristoph Hellwig }, 881a07b4970SChristoph Hellwig }; 882a07b4970SChristoph Hellwig 883a07b4970SChristoph Hellwig int __init nvmet_init_configfs(void) 884a07b4970SChristoph Hellwig { 885a07b4970SChristoph Hellwig int ret; 886a07b4970SChristoph Hellwig 887a07b4970SChristoph Hellwig config_group_init(&nvmet_configfs_subsystem.su_group); 888a07b4970SChristoph Hellwig mutex_init(&nvmet_configfs_subsystem.su_mutex); 889a07b4970SChristoph Hellwig 890a07b4970SChristoph Hellwig config_group_init_type_name(&nvmet_subsystems_group, 891a07b4970SChristoph Hellwig "subsystems", &nvmet_subsystems_type); 892a07b4970SChristoph Hellwig configfs_add_default_group(&nvmet_subsystems_group, 893a07b4970SChristoph Hellwig &nvmet_configfs_subsystem.su_group); 894a07b4970SChristoph Hellwig 895a07b4970SChristoph Hellwig config_group_init_type_name(&nvmet_ports_group, 896a07b4970SChristoph Hellwig "ports", &nvmet_ports_type); 897a07b4970SChristoph Hellwig configfs_add_default_group(&nvmet_ports_group, 898a07b4970SChristoph Hellwig &nvmet_configfs_subsystem.su_group); 899a07b4970SChristoph Hellwig 900a07b4970SChristoph Hellwig config_group_init_type_name(&nvmet_hosts_group, 901a07b4970SChristoph Hellwig "hosts", &nvmet_hosts_type); 902a07b4970SChristoph Hellwig configfs_add_default_group(&nvmet_hosts_group, 903a07b4970SChristoph Hellwig &nvmet_configfs_subsystem.su_group); 904a07b4970SChristoph Hellwig 905a07b4970SChristoph Hellwig ret = configfs_register_subsystem(&nvmet_configfs_subsystem); 906a07b4970SChristoph Hellwig if (ret) { 907a07b4970SChristoph Hellwig pr_err("configfs_register_subsystem: %d\n", ret); 908a07b4970SChristoph Hellwig return ret; 909a07b4970SChristoph Hellwig } 910a07b4970SChristoph Hellwig 911a07b4970SChristoph Hellwig return 0; 912a07b4970SChristoph Hellwig } 913a07b4970SChristoph Hellwig 914a07b4970SChristoph Hellwig void __exit nvmet_exit_configfs(void) 915a07b4970SChristoph Hellwig { 916a07b4970SChristoph Hellwig configfs_unregister_subsystem(&nvmet_configfs_subsystem); 917a07b4970SChristoph Hellwig } 918