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"); 40885aa401SJames Smart case NVMF_ADDR_FAMILY_FC: 41885aa401SJames Smart return sprintf(page, "fc\n"); 42a07b4970SChristoph Hellwig default: 43a07b4970SChristoph Hellwig return sprintf(page, "\n"); 44a07b4970SChristoph Hellwig } 45a07b4970SChristoph Hellwig } 46a07b4970SChristoph Hellwig 47a07b4970SChristoph Hellwig static ssize_t nvmet_addr_adrfam_store(struct config_item *item, 48a07b4970SChristoph Hellwig const char *page, size_t count) 49a07b4970SChristoph Hellwig { 50a07b4970SChristoph Hellwig struct nvmet_port *port = to_nvmet_port(item); 51a07b4970SChristoph Hellwig 52a07b4970SChristoph Hellwig if (port->enabled) { 53a07b4970SChristoph Hellwig pr_err("Cannot modify address while enabled\n"); 54a07b4970SChristoph Hellwig pr_err("Disable the address before modifying\n"); 55a07b4970SChristoph Hellwig return -EACCES; 56a07b4970SChristoph Hellwig } 57a07b4970SChristoph Hellwig 58a07b4970SChristoph Hellwig if (sysfs_streq(page, "ipv4")) { 59a07b4970SChristoph Hellwig port->disc_addr.adrfam = NVMF_ADDR_FAMILY_IP4; 60a07b4970SChristoph Hellwig } else if (sysfs_streq(page, "ipv6")) { 61a07b4970SChristoph Hellwig port->disc_addr.adrfam = NVMF_ADDR_FAMILY_IP6; 62a07b4970SChristoph Hellwig } else if (sysfs_streq(page, "ib")) { 63a07b4970SChristoph Hellwig port->disc_addr.adrfam = NVMF_ADDR_FAMILY_IB; 64885aa401SJames Smart } else if (sysfs_streq(page, "fc")) { 65885aa401SJames Smart port->disc_addr.adrfam = NVMF_ADDR_FAMILY_FC; 66a07b4970SChristoph Hellwig } else { 67a07b4970SChristoph Hellwig pr_err("Invalid value '%s' for adrfam\n", page); 68a07b4970SChristoph Hellwig return -EINVAL; 69a07b4970SChristoph Hellwig } 70a07b4970SChristoph Hellwig 71a07b4970SChristoph Hellwig return count; 72a07b4970SChristoph Hellwig } 73a07b4970SChristoph Hellwig 74a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_, addr_adrfam); 75a07b4970SChristoph Hellwig 76a07b4970SChristoph Hellwig static ssize_t nvmet_addr_portid_show(struct config_item *item, 77a07b4970SChristoph Hellwig char *page) 78a07b4970SChristoph Hellwig { 79a07b4970SChristoph Hellwig struct nvmet_port *port = to_nvmet_port(item); 80a07b4970SChristoph Hellwig 81a07b4970SChristoph Hellwig return snprintf(page, PAGE_SIZE, "%d\n", 82a07b4970SChristoph Hellwig le16_to_cpu(port->disc_addr.portid)); 83a07b4970SChristoph Hellwig } 84a07b4970SChristoph Hellwig 85a07b4970SChristoph Hellwig static ssize_t nvmet_addr_portid_store(struct config_item *item, 86a07b4970SChristoph Hellwig const char *page, size_t count) 87a07b4970SChristoph Hellwig { 88a07b4970SChristoph Hellwig struct nvmet_port *port = to_nvmet_port(item); 89a07b4970SChristoph Hellwig u16 portid = 0; 90a07b4970SChristoph Hellwig 91a07b4970SChristoph Hellwig if (kstrtou16(page, 0, &portid)) { 92a07b4970SChristoph Hellwig pr_err("Invalid value '%s' for portid\n", page); 93a07b4970SChristoph Hellwig return -EINVAL; 94a07b4970SChristoph Hellwig } 95a07b4970SChristoph Hellwig 96a07b4970SChristoph Hellwig if (port->enabled) { 97a07b4970SChristoph Hellwig pr_err("Cannot modify address while enabled\n"); 98a07b4970SChristoph Hellwig pr_err("Disable the address before modifying\n"); 99a07b4970SChristoph Hellwig return -EACCES; 100a07b4970SChristoph Hellwig } 101a07b4970SChristoph Hellwig port->disc_addr.portid = cpu_to_le16(portid); 102a07b4970SChristoph Hellwig return count; 103a07b4970SChristoph Hellwig } 104a07b4970SChristoph Hellwig 105a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_, addr_portid); 106a07b4970SChristoph Hellwig 107a07b4970SChristoph Hellwig static ssize_t nvmet_addr_traddr_show(struct config_item *item, 108a07b4970SChristoph Hellwig char *page) 109a07b4970SChristoph Hellwig { 110a07b4970SChristoph Hellwig struct nvmet_port *port = to_nvmet_port(item); 111a07b4970SChristoph Hellwig 112a07b4970SChristoph Hellwig return snprintf(page, PAGE_SIZE, "%s\n", 113a07b4970SChristoph Hellwig port->disc_addr.traddr); 114a07b4970SChristoph Hellwig } 115a07b4970SChristoph Hellwig 116a07b4970SChristoph Hellwig static ssize_t nvmet_addr_traddr_store(struct config_item *item, 117a07b4970SChristoph Hellwig const char *page, size_t count) 118a07b4970SChristoph Hellwig { 119a07b4970SChristoph Hellwig struct nvmet_port *port = to_nvmet_port(item); 120a07b4970SChristoph Hellwig 121a07b4970SChristoph Hellwig if (count > NVMF_TRADDR_SIZE) { 122a07b4970SChristoph Hellwig pr_err("Invalid value '%s' for traddr\n", page); 123a07b4970SChristoph Hellwig return -EINVAL; 124a07b4970SChristoph Hellwig } 125a07b4970SChristoph Hellwig 126a07b4970SChristoph Hellwig if (port->enabled) { 127a07b4970SChristoph Hellwig pr_err("Cannot modify address while enabled\n"); 128a07b4970SChristoph Hellwig pr_err("Disable the address before modifying\n"); 129a07b4970SChristoph Hellwig return -EACCES; 130a07b4970SChristoph Hellwig } 131a07b4970SChristoph Hellwig return snprintf(port->disc_addr.traddr, 132a07b4970SChristoph Hellwig sizeof(port->disc_addr.traddr), "%s", page); 133a07b4970SChristoph Hellwig } 134a07b4970SChristoph Hellwig 135a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_, addr_traddr); 136a07b4970SChristoph Hellwig 137a07b4970SChristoph Hellwig static ssize_t nvmet_addr_treq_show(struct config_item *item, 138a07b4970SChristoph Hellwig char *page) 139a07b4970SChristoph Hellwig { 140a07b4970SChristoph Hellwig switch (to_nvmet_port(item)->disc_addr.treq) { 141a07b4970SChristoph Hellwig case NVMF_TREQ_NOT_SPECIFIED: 142a07b4970SChristoph Hellwig return sprintf(page, "not specified\n"); 143a07b4970SChristoph Hellwig case NVMF_TREQ_REQUIRED: 144a07b4970SChristoph Hellwig return sprintf(page, "required\n"); 145a07b4970SChristoph Hellwig case NVMF_TREQ_NOT_REQUIRED: 146a07b4970SChristoph Hellwig return sprintf(page, "not required\n"); 147a07b4970SChristoph Hellwig default: 148a07b4970SChristoph Hellwig return sprintf(page, "\n"); 149a07b4970SChristoph Hellwig } 150a07b4970SChristoph Hellwig } 151a07b4970SChristoph Hellwig 152a07b4970SChristoph Hellwig static ssize_t nvmet_addr_treq_store(struct config_item *item, 153a07b4970SChristoph Hellwig const char *page, size_t count) 154a07b4970SChristoph Hellwig { 155a07b4970SChristoph Hellwig struct nvmet_port *port = to_nvmet_port(item); 156a07b4970SChristoph Hellwig 157a07b4970SChristoph Hellwig if (port->enabled) { 158a07b4970SChristoph Hellwig pr_err("Cannot modify address while enabled\n"); 159a07b4970SChristoph Hellwig pr_err("Disable the address before modifying\n"); 160a07b4970SChristoph Hellwig return -EACCES; 161a07b4970SChristoph Hellwig } 162a07b4970SChristoph Hellwig 163a07b4970SChristoph Hellwig if (sysfs_streq(page, "not specified")) { 164a07b4970SChristoph Hellwig port->disc_addr.treq = NVMF_TREQ_NOT_SPECIFIED; 165a07b4970SChristoph Hellwig } else if (sysfs_streq(page, "required")) { 166a07b4970SChristoph Hellwig port->disc_addr.treq = NVMF_TREQ_REQUIRED; 167a07b4970SChristoph Hellwig } else if (sysfs_streq(page, "not required")) { 168a07b4970SChristoph Hellwig port->disc_addr.treq = NVMF_TREQ_NOT_REQUIRED; 169a07b4970SChristoph Hellwig } else { 170a07b4970SChristoph Hellwig pr_err("Invalid value '%s' for treq\n", page); 171a07b4970SChristoph Hellwig return -EINVAL; 172a07b4970SChristoph Hellwig } 173a07b4970SChristoph Hellwig 174a07b4970SChristoph Hellwig return count; 175a07b4970SChristoph Hellwig } 176a07b4970SChristoph Hellwig 177a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_, addr_treq); 178a07b4970SChristoph Hellwig 179a07b4970SChristoph Hellwig static ssize_t nvmet_addr_trsvcid_show(struct config_item *item, 180a07b4970SChristoph Hellwig char *page) 181a07b4970SChristoph Hellwig { 182a07b4970SChristoph Hellwig struct nvmet_port *port = to_nvmet_port(item); 183a07b4970SChristoph Hellwig 184a07b4970SChristoph Hellwig return snprintf(page, PAGE_SIZE, "%s\n", 185a07b4970SChristoph Hellwig port->disc_addr.trsvcid); 186a07b4970SChristoph Hellwig } 187a07b4970SChristoph Hellwig 188a07b4970SChristoph Hellwig static ssize_t nvmet_addr_trsvcid_store(struct config_item *item, 189a07b4970SChristoph Hellwig const char *page, size_t count) 190a07b4970SChristoph Hellwig { 191a07b4970SChristoph Hellwig struct nvmet_port *port = to_nvmet_port(item); 192a07b4970SChristoph Hellwig 193a07b4970SChristoph Hellwig if (count > NVMF_TRSVCID_SIZE) { 194a07b4970SChristoph Hellwig pr_err("Invalid value '%s' for trsvcid\n", page); 195a07b4970SChristoph Hellwig return -EINVAL; 196a07b4970SChristoph Hellwig } 197a07b4970SChristoph Hellwig if (port->enabled) { 198a07b4970SChristoph Hellwig pr_err("Cannot modify address while enabled\n"); 199a07b4970SChristoph Hellwig pr_err("Disable the address before modifying\n"); 200a07b4970SChristoph Hellwig return -EACCES; 201a07b4970SChristoph Hellwig } 202a07b4970SChristoph Hellwig return snprintf(port->disc_addr.trsvcid, 203a07b4970SChristoph Hellwig sizeof(port->disc_addr.trsvcid), "%s", page); 204a07b4970SChristoph Hellwig } 205a07b4970SChristoph Hellwig 206a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_, addr_trsvcid); 207a07b4970SChristoph Hellwig 208a07b4970SChristoph Hellwig static ssize_t nvmet_addr_trtype_show(struct config_item *item, 209a07b4970SChristoph Hellwig char *page) 210a07b4970SChristoph Hellwig { 211a07b4970SChristoph Hellwig switch (to_nvmet_port(item)->disc_addr.trtype) { 212a07b4970SChristoph Hellwig case NVMF_TRTYPE_RDMA: 213a07b4970SChristoph Hellwig return sprintf(page, "rdma\n"); 214a07b4970SChristoph Hellwig case NVMF_TRTYPE_LOOP: 215a07b4970SChristoph Hellwig return sprintf(page, "loop\n"); 216885aa401SJames Smart case NVMF_TRTYPE_FC: 217885aa401SJames Smart return sprintf(page, "fc\n"); 218a07b4970SChristoph Hellwig default: 219a07b4970SChristoph Hellwig return sprintf(page, "\n"); 220a07b4970SChristoph Hellwig } 221a07b4970SChristoph Hellwig } 222a07b4970SChristoph Hellwig 223a07b4970SChristoph Hellwig static void nvmet_port_init_tsas_rdma(struct nvmet_port *port) 224a07b4970SChristoph Hellwig { 225a07b4970SChristoph Hellwig port->disc_addr.trtype = NVMF_TRTYPE_RDMA; 226a07b4970SChristoph Hellwig memset(&port->disc_addr.tsas.rdma, 0, NVMF_TSAS_SIZE); 227a07b4970SChristoph Hellwig port->disc_addr.tsas.rdma.qptype = NVMF_RDMA_QPTYPE_CONNECTED; 228a07b4970SChristoph Hellwig port->disc_addr.tsas.rdma.prtype = NVMF_RDMA_PRTYPE_NOT_SPECIFIED; 229a07b4970SChristoph Hellwig port->disc_addr.tsas.rdma.cms = NVMF_RDMA_CMS_RDMA_CM; 230a07b4970SChristoph Hellwig } 231a07b4970SChristoph Hellwig 232a07b4970SChristoph Hellwig static void nvmet_port_init_tsas_loop(struct nvmet_port *port) 233a07b4970SChristoph Hellwig { 234a07b4970SChristoph Hellwig port->disc_addr.trtype = NVMF_TRTYPE_LOOP; 235a07b4970SChristoph Hellwig memset(&port->disc_addr.tsas, 0, NVMF_TSAS_SIZE); 236a07b4970SChristoph Hellwig } 237a07b4970SChristoph Hellwig 238885aa401SJames Smart static void nvmet_port_init_tsas_fc(struct nvmet_port *port) 239885aa401SJames Smart { 240885aa401SJames Smart port->disc_addr.trtype = NVMF_TRTYPE_FC; 241885aa401SJames Smart memset(&port->disc_addr.tsas, 0, NVMF_TSAS_SIZE); 242885aa401SJames Smart } 243885aa401SJames Smart 244a07b4970SChristoph Hellwig static ssize_t nvmet_addr_trtype_store(struct config_item *item, 245a07b4970SChristoph Hellwig const char *page, size_t count) 246a07b4970SChristoph Hellwig { 247a07b4970SChristoph Hellwig struct nvmet_port *port = to_nvmet_port(item); 248a07b4970SChristoph Hellwig 249a07b4970SChristoph Hellwig if (port->enabled) { 250a07b4970SChristoph Hellwig pr_err("Cannot modify address while enabled\n"); 251a07b4970SChristoph Hellwig pr_err("Disable the address before modifying\n"); 252a07b4970SChristoph Hellwig return -EACCES; 253a07b4970SChristoph Hellwig } 254a07b4970SChristoph Hellwig 255a07b4970SChristoph Hellwig if (sysfs_streq(page, "rdma")) { 256a07b4970SChristoph Hellwig nvmet_port_init_tsas_rdma(port); 257a07b4970SChristoph Hellwig } else if (sysfs_streq(page, "loop")) { 258a07b4970SChristoph Hellwig nvmet_port_init_tsas_loop(port); 259885aa401SJames Smart } else if (sysfs_streq(page, "fc")) { 260885aa401SJames Smart nvmet_port_init_tsas_fc(port); 261a07b4970SChristoph Hellwig } else { 262a07b4970SChristoph Hellwig pr_err("Invalid value '%s' for trtype\n", page); 263a07b4970SChristoph Hellwig return -EINVAL; 264a07b4970SChristoph Hellwig } 265a07b4970SChristoph Hellwig 266a07b4970SChristoph Hellwig return count; 267a07b4970SChristoph Hellwig } 268a07b4970SChristoph Hellwig 269a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_, addr_trtype); 270a07b4970SChristoph Hellwig 271a07b4970SChristoph Hellwig /* 272a07b4970SChristoph Hellwig * Namespace structures & file operation functions below 273a07b4970SChristoph Hellwig */ 274a07b4970SChristoph Hellwig static ssize_t nvmet_ns_device_path_show(struct config_item *item, char *page) 275a07b4970SChristoph Hellwig { 276a07b4970SChristoph Hellwig return sprintf(page, "%s\n", to_nvmet_ns(item)->device_path); 277a07b4970SChristoph Hellwig } 278a07b4970SChristoph Hellwig 279a07b4970SChristoph Hellwig static ssize_t nvmet_ns_device_path_store(struct config_item *item, 280a07b4970SChristoph Hellwig const char *page, size_t count) 281a07b4970SChristoph Hellwig { 282a07b4970SChristoph Hellwig struct nvmet_ns *ns = to_nvmet_ns(item); 283a07b4970SChristoph Hellwig struct nvmet_subsys *subsys = ns->subsys; 284a07b4970SChristoph Hellwig int ret; 285a07b4970SChristoph Hellwig 286a07b4970SChristoph Hellwig mutex_lock(&subsys->lock); 287a07b4970SChristoph Hellwig ret = -EBUSY; 288e4fcf07cSSolganik Alexander if (ns->enabled) 289a07b4970SChristoph Hellwig goto out_unlock; 290a07b4970SChristoph Hellwig 291a07b4970SChristoph Hellwig kfree(ns->device_path); 292a07b4970SChristoph Hellwig 293a07b4970SChristoph Hellwig ret = -ENOMEM; 294a07b4970SChristoph Hellwig ns->device_path = kstrdup(page, GFP_KERNEL); 295a07b4970SChristoph Hellwig if (!ns->device_path) 296a07b4970SChristoph Hellwig goto out_unlock; 297a07b4970SChristoph Hellwig 298a07b4970SChristoph Hellwig mutex_unlock(&subsys->lock); 299a07b4970SChristoph Hellwig return count; 300a07b4970SChristoph Hellwig 301a07b4970SChristoph Hellwig out_unlock: 302a07b4970SChristoph Hellwig mutex_unlock(&subsys->lock); 303a07b4970SChristoph Hellwig return ret; 304a07b4970SChristoph Hellwig } 305a07b4970SChristoph Hellwig 306a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_ns_, device_path); 307a07b4970SChristoph Hellwig 308430c7befSJohannes Thumshirn static ssize_t nvmet_ns_device_uuid_show(struct config_item *item, char *page) 309430c7befSJohannes Thumshirn { 310430c7befSJohannes Thumshirn return sprintf(page, "%pUb\n", &to_nvmet_ns(item)->uuid); 311430c7befSJohannes Thumshirn } 312430c7befSJohannes Thumshirn 313430c7befSJohannes Thumshirn static ssize_t nvmet_ns_device_uuid_store(struct config_item *item, 314430c7befSJohannes Thumshirn const char *page, size_t count) 315430c7befSJohannes Thumshirn { 316430c7befSJohannes Thumshirn struct nvmet_ns *ns = to_nvmet_ns(item); 317430c7befSJohannes Thumshirn struct nvmet_subsys *subsys = ns->subsys; 318430c7befSJohannes Thumshirn int ret = 0; 319430c7befSJohannes Thumshirn 320430c7befSJohannes Thumshirn 321430c7befSJohannes Thumshirn mutex_lock(&subsys->lock); 322430c7befSJohannes Thumshirn if (ns->enabled) { 323430c7befSJohannes Thumshirn ret = -EBUSY; 324430c7befSJohannes Thumshirn goto out_unlock; 325430c7befSJohannes Thumshirn } 326430c7befSJohannes Thumshirn 327430c7befSJohannes Thumshirn 328430c7befSJohannes Thumshirn if (uuid_parse(page, &ns->uuid)) 329430c7befSJohannes Thumshirn ret = -EINVAL; 330430c7befSJohannes Thumshirn 331430c7befSJohannes Thumshirn out_unlock: 332430c7befSJohannes Thumshirn mutex_unlock(&subsys->lock); 333430c7befSJohannes Thumshirn return ret ? ret : count; 334430c7befSJohannes Thumshirn } 335430c7befSJohannes Thumshirn 336a07b4970SChristoph Hellwig static ssize_t nvmet_ns_device_nguid_show(struct config_item *item, char *page) 337a07b4970SChristoph Hellwig { 338a07b4970SChristoph Hellwig return sprintf(page, "%pUb\n", &to_nvmet_ns(item)->nguid); 339a07b4970SChristoph Hellwig } 340a07b4970SChristoph Hellwig 341430c7befSJohannes Thumshirn CONFIGFS_ATTR(nvmet_ns_, device_uuid); 342430c7befSJohannes Thumshirn 343a07b4970SChristoph Hellwig static ssize_t nvmet_ns_device_nguid_store(struct config_item *item, 344a07b4970SChristoph Hellwig const char *page, size_t count) 345a07b4970SChristoph Hellwig { 346a07b4970SChristoph Hellwig struct nvmet_ns *ns = to_nvmet_ns(item); 347a07b4970SChristoph Hellwig struct nvmet_subsys *subsys = ns->subsys; 348a07b4970SChristoph Hellwig u8 nguid[16]; 349a07b4970SChristoph Hellwig const char *p = page; 350a07b4970SChristoph Hellwig int i; 351a07b4970SChristoph Hellwig int ret = 0; 352a07b4970SChristoph Hellwig 353a07b4970SChristoph Hellwig mutex_lock(&subsys->lock); 354e4fcf07cSSolganik Alexander if (ns->enabled) { 355a07b4970SChristoph Hellwig ret = -EBUSY; 356a07b4970SChristoph Hellwig goto out_unlock; 357a07b4970SChristoph Hellwig } 358a07b4970SChristoph Hellwig 359a07b4970SChristoph Hellwig for (i = 0; i < 16; i++) { 360a07b4970SChristoph Hellwig if (p + 2 > page + count) { 361a07b4970SChristoph Hellwig ret = -EINVAL; 362a07b4970SChristoph Hellwig goto out_unlock; 363a07b4970SChristoph Hellwig } 364a07b4970SChristoph Hellwig if (!isxdigit(p[0]) || !isxdigit(p[1])) { 365a07b4970SChristoph Hellwig ret = -EINVAL; 366a07b4970SChristoph Hellwig goto out_unlock; 367a07b4970SChristoph Hellwig } 368a07b4970SChristoph Hellwig 369a07b4970SChristoph Hellwig nguid[i] = (hex_to_bin(p[0]) << 4) | hex_to_bin(p[1]); 370a07b4970SChristoph Hellwig p += 2; 371a07b4970SChristoph Hellwig 372a07b4970SChristoph Hellwig if (*p == '-' || *p == ':') 373a07b4970SChristoph Hellwig p++; 374a07b4970SChristoph Hellwig } 375a07b4970SChristoph Hellwig 376a07b4970SChristoph Hellwig memcpy(&ns->nguid, nguid, sizeof(nguid)); 377a07b4970SChristoph Hellwig out_unlock: 378a07b4970SChristoph Hellwig mutex_unlock(&subsys->lock); 379a07b4970SChristoph Hellwig return ret ? ret : count; 380a07b4970SChristoph Hellwig } 381a07b4970SChristoph Hellwig 382a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_ns_, device_nguid); 383a07b4970SChristoph Hellwig 384a07b4970SChristoph Hellwig static ssize_t nvmet_ns_enable_show(struct config_item *item, char *page) 385a07b4970SChristoph Hellwig { 386e4fcf07cSSolganik Alexander return sprintf(page, "%d\n", to_nvmet_ns(item)->enabled); 387a07b4970SChristoph Hellwig } 388a07b4970SChristoph Hellwig 389a07b4970SChristoph Hellwig static ssize_t nvmet_ns_enable_store(struct config_item *item, 390a07b4970SChristoph Hellwig const char *page, size_t count) 391a07b4970SChristoph Hellwig { 392a07b4970SChristoph Hellwig struct nvmet_ns *ns = to_nvmet_ns(item); 393a07b4970SChristoph Hellwig bool enable; 394a07b4970SChristoph Hellwig int ret = 0; 395a07b4970SChristoph Hellwig 396a07b4970SChristoph Hellwig if (strtobool(page, &enable)) 397a07b4970SChristoph Hellwig return -EINVAL; 398a07b4970SChristoph Hellwig 399a07b4970SChristoph Hellwig if (enable) 400a07b4970SChristoph Hellwig ret = nvmet_ns_enable(ns); 401a07b4970SChristoph Hellwig else 402a07b4970SChristoph Hellwig nvmet_ns_disable(ns); 403a07b4970SChristoph Hellwig 404a07b4970SChristoph Hellwig return ret ? ret : count; 405a07b4970SChristoph Hellwig } 406a07b4970SChristoph Hellwig 407a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_ns_, enable); 408a07b4970SChristoph Hellwig 409a07b4970SChristoph Hellwig static struct configfs_attribute *nvmet_ns_attrs[] = { 410a07b4970SChristoph Hellwig &nvmet_ns_attr_device_path, 411a07b4970SChristoph Hellwig &nvmet_ns_attr_device_nguid, 412430c7befSJohannes Thumshirn &nvmet_ns_attr_device_uuid, 413a07b4970SChristoph Hellwig &nvmet_ns_attr_enable, 414a07b4970SChristoph Hellwig NULL, 415a07b4970SChristoph Hellwig }; 416a07b4970SChristoph Hellwig 417a07b4970SChristoph Hellwig static void nvmet_ns_release(struct config_item *item) 418a07b4970SChristoph Hellwig { 419a07b4970SChristoph Hellwig struct nvmet_ns *ns = to_nvmet_ns(item); 420a07b4970SChristoph Hellwig 421a07b4970SChristoph Hellwig nvmet_ns_free(ns); 422a07b4970SChristoph Hellwig } 423a07b4970SChristoph Hellwig 424a07b4970SChristoph Hellwig static struct configfs_item_operations nvmet_ns_item_ops = { 425a07b4970SChristoph Hellwig .release = nvmet_ns_release, 426a07b4970SChristoph Hellwig }; 427a07b4970SChristoph Hellwig 428a07b4970SChristoph Hellwig static struct config_item_type nvmet_ns_type = { 429a07b4970SChristoph Hellwig .ct_item_ops = &nvmet_ns_item_ops, 430a07b4970SChristoph Hellwig .ct_attrs = nvmet_ns_attrs, 431a07b4970SChristoph Hellwig .ct_owner = THIS_MODULE, 432a07b4970SChristoph Hellwig }; 433a07b4970SChristoph Hellwig 434a07b4970SChristoph Hellwig static struct config_group *nvmet_ns_make(struct config_group *group, 435a07b4970SChristoph Hellwig const char *name) 436a07b4970SChristoph Hellwig { 437a07b4970SChristoph Hellwig struct nvmet_subsys *subsys = namespaces_to_subsys(&group->cg_item); 438a07b4970SChristoph Hellwig struct nvmet_ns *ns; 439a07b4970SChristoph Hellwig int ret; 440a07b4970SChristoph Hellwig u32 nsid; 441a07b4970SChristoph Hellwig 442a07b4970SChristoph Hellwig ret = kstrtou32(name, 0, &nsid); 443a07b4970SChristoph Hellwig if (ret) 444a07b4970SChristoph Hellwig goto out; 445a07b4970SChristoph Hellwig 446a07b4970SChristoph Hellwig ret = -EINVAL; 447a07b4970SChristoph Hellwig if (nsid == 0 || nsid == 0xffffffff) 448a07b4970SChristoph Hellwig goto out; 449a07b4970SChristoph Hellwig 450a07b4970SChristoph Hellwig ret = -ENOMEM; 451a07b4970SChristoph Hellwig ns = nvmet_ns_alloc(subsys, nsid); 452a07b4970SChristoph Hellwig if (!ns) 453a07b4970SChristoph Hellwig goto out; 454a07b4970SChristoph Hellwig config_group_init_type_name(&ns->group, name, &nvmet_ns_type); 455a07b4970SChristoph Hellwig 456a07b4970SChristoph Hellwig pr_info("adding nsid %d to subsystem %s\n", nsid, subsys->subsysnqn); 457a07b4970SChristoph Hellwig 458a07b4970SChristoph Hellwig return &ns->group; 459a07b4970SChristoph Hellwig out: 460a07b4970SChristoph Hellwig return ERR_PTR(ret); 461a07b4970SChristoph Hellwig } 462a07b4970SChristoph Hellwig 463a07b4970SChristoph Hellwig static struct configfs_group_operations nvmet_namespaces_group_ops = { 464a07b4970SChristoph Hellwig .make_group = nvmet_ns_make, 465a07b4970SChristoph Hellwig }; 466a07b4970SChristoph Hellwig 467a07b4970SChristoph Hellwig static struct config_item_type nvmet_namespaces_type = { 468a07b4970SChristoph Hellwig .ct_group_ops = &nvmet_namespaces_group_ops, 469a07b4970SChristoph Hellwig .ct_owner = THIS_MODULE, 470a07b4970SChristoph Hellwig }; 471a07b4970SChristoph Hellwig 472a07b4970SChristoph Hellwig static int nvmet_port_subsys_allow_link(struct config_item *parent, 473a07b4970SChristoph Hellwig struct config_item *target) 474a07b4970SChristoph Hellwig { 475a07b4970SChristoph Hellwig struct nvmet_port *port = to_nvmet_port(parent->ci_parent); 476a07b4970SChristoph Hellwig struct nvmet_subsys *subsys; 477a07b4970SChristoph Hellwig struct nvmet_subsys_link *link, *p; 478a07b4970SChristoph Hellwig int ret; 479a07b4970SChristoph Hellwig 480a07b4970SChristoph Hellwig if (target->ci_type != &nvmet_subsys_type) { 481a07b4970SChristoph Hellwig pr_err("can only link subsystems into the subsystems dir.!\n"); 482a07b4970SChristoph Hellwig return -EINVAL; 483a07b4970SChristoph Hellwig } 484a07b4970SChristoph Hellwig subsys = to_subsys(target); 485a07b4970SChristoph Hellwig link = kmalloc(sizeof(*link), GFP_KERNEL); 486a07b4970SChristoph Hellwig if (!link) 487a07b4970SChristoph Hellwig return -ENOMEM; 488a07b4970SChristoph Hellwig link->subsys = subsys; 489a07b4970SChristoph Hellwig 490a07b4970SChristoph Hellwig down_write(&nvmet_config_sem); 491a07b4970SChristoph Hellwig ret = -EEXIST; 492a07b4970SChristoph Hellwig list_for_each_entry(p, &port->subsystems, entry) { 493a07b4970SChristoph Hellwig if (p->subsys == subsys) 494a07b4970SChristoph Hellwig goto out_free_link; 495a07b4970SChristoph Hellwig } 496a07b4970SChristoph Hellwig 497a07b4970SChristoph Hellwig if (list_empty(&port->subsystems)) { 498a07b4970SChristoph Hellwig ret = nvmet_enable_port(port); 499a07b4970SChristoph Hellwig if (ret) 500a07b4970SChristoph Hellwig goto out_free_link; 501a07b4970SChristoph Hellwig } 502a07b4970SChristoph Hellwig 503a07b4970SChristoph Hellwig list_add_tail(&link->entry, &port->subsystems); 504a07b4970SChristoph Hellwig nvmet_genctr++; 505a07b4970SChristoph Hellwig up_write(&nvmet_config_sem); 506a07b4970SChristoph Hellwig return 0; 507a07b4970SChristoph Hellwig 508a07b4970SChristoph Hellwig out_free_link: 509a07b4970SChristoph Hellwig up_write(&nvmet_config_sem); 510a07b4970SChristoph Hellwig kfree(link); 511a07b4970SChristoph Hellwig return ret; 512a07b4970SChristoph Hellwig } 513a07b4970SChristoph Hellwig 514e16769d4SAndrzej Pietrasiewicz static void nvmet_port_subsys_drop_link(struct config_item *parent, 515a07b4970SChristoph Hellwig struct config_item *target) 516a07b4970SChristoph Hellwig { 517a07b4970SChristoph Hellwig struct nvmet_port *port = to_nvmet_port(parent->ci_parent); 518a07b4970SChristoph Hellwig struct nvmet_subsys *subsys = to_subsys(target); 519a07b4970SChristoph Hellwig struct nvmet_subsys_link *p; 520a07b4970SChristoph Hellwig 521a07b4970SChristoph Hellwig down_write(&nvmet_config_sem); 522a07b4970SChristoph Hellwig list_for_each_entry(p, &port->subsystems, entry) { 523a07b4970SChristoph Hellwig if (p->subsys == subsys) 524a07b4970SChristoph Hellwig goto found; 525a07b4970SChristoph Hellwig } 526a07b4970SChristoph Hellwig up_write(&nvmet_config_sem); 527e16769d4SAndrzej Pietrasiewicz return; 528a07b4970SChristoph Hellwig 529a07b4970SChristoph Hellwig found: 530a07b4970SChristoph Hellwig list_del(&p->entry); 531a07b4970SChristoph Hellwig nvmet_genctr++; 532a07b4970SChristoph Hellwig if (list_empty(&port->subsystems)) 533a07b4970SChristoph Hellwig nvmet_disable_port(port); 534a07b4970SChristoph Hellwig up_write(&nvmet_config_sem); 535a07b4970SChristoph Hellwig kfree(p); 536a07b4970SChristoph Hellwig } 537a07b4970SChristoph Hellwig 538a07b4970SChristoph Hellwig static struct configfs_item_operations nvmet_port_subsys_item_ops = { 539a07b4970SChristoph Hellwig .allow_link = nvmet_port_subsys_allow_link, 540a07b4970SChristoph Hellwig .drop_link = nvmet_port_subsys_drop_link, 541a07b4970SChristoph Hellwig }; 542a07b4970SChristoph Hellwig 543a07b4970SChristoph Hellwig static struct config_item_type nvmet_port_subsys_type = { 544a07b4970SChristoph Hellwig .ct_item_ops = &nvmet_port_subsys_item_ops, 545a07b4970SChristoph Hellwig .ct_owner = THIS_MODULE, 546a07b4970SChristoph Hellwig }; 547a07b4970SChristoph Hellwig 548a07b4970SChristoph Hellwig static int nvmet_allowed_hosts_allow_link(struct config_item *parent, 549a07b4970SChristoph Hellwig struct config_item *target) 550a07b4970SChristoph Hellwig { 551a07b4970SChristoph Hellwig struct nvmet_subsys *subsys = to_subsys(parent->ci_parent); 552a07b4970SChristoph Hellwig struct nvmet_host *host; 553a07b4970SChristoph Hellwig struct nvmet_host_link *link, *p; 554a07b4970SChristoph Hellwig int ret; 555a07b4970SChristoph Hellwig 556a07b4970SChristoph Hellwig if (target->ci_type != &nvmet_host_type) { 557a07b4970SChristoph Hellwig pr_err("can only link hosts into the allowed_hosts directory!\n"); 558a07b4970SChristoph Hellwig return -EINVAL; 559a07b4970SChristoph Hellwig } 560a07b4970SChristoph Hellwig 561a07b4970SChristoph Hellwig host = to_host(target); 562a07b4970SChristoph Hellwig link = kmalloc(sizeof(*link), GFP_KERNEL); 563a07b4970SChristoph Hellwig if (!link) 564a07b4970SChristoph Hellwig return -ENOMEM; 565a07b4970SChristoph Hellwig link->host = host; 566a07b4970SChristoph Hellwig 567a07b4970SChristoph Hellwig down_write(&nvmet_config_sem); 568a07b4970SChristoph Hellwig ret = -EINVAL; 569a07b4970SChristoph Hellwig if (subsys->allow_any_host) { 570a07b4970SChristoph Hellwig pr_err("can't add hosts when allow_any_host is set!\n"); 571a07b4970SChristoph Hellwig goto out_free_link; 572a07b4970SChristoph Hellwig } 573a07b4970SChristoph Hellwig 574a07b4970SChristoph Hellwig ret = -EEXIST; 575a07b4970SChristoph Hellwig list_for_each_entry(p, &subsys->hosts, entry) { 576a07b4970SChristoph Hellwig if (!strcmp(nvmet_host_name(p->host), nvmet_host_name(host))) 577a07b4970SChristoph Hellwig goto out_free_link; 578a07b4970SChristoph Hellwig } 579a07b4970SChristoph Hellwig list_add_tail(&link->entry, &subsys->hosts); 580a07b4970SChristoph Hellwig nvmet_genctr++; 581a07b4970SChristoph Hellwig up_write(&nvmet_config_sem); 582a07b4970SChristoph Hellwig return 0; 583a07b4970SChristoph Hellwig out_free_link: 584a07b4970SChristoph Hellwig up_write(&nvmet_config_sem); 585a07b4970SChristoph Hellwig kfree(link); 586a07b4970SChristoph Hellwig return ret; 587a07b4970SChristoph Hellwig } 588a07b4970SChristoph Hellwig 589e16769d4SAndrzej Pietrasiewicz static void nvmet_allowed_hosts_drop_link(struct config_item *parent, 590a07b4970SChristoph Hellwig struct config_item *target) 591a07b4970SChristoph Hellwig { 592a07b4970SChristoph Hellwig struct nvmet_subsys *subsys = to_subsys(parent->ci_parent); 593a07b4970SChristoph Hellwig struct nvmet_host *host = to_host(target); 594a07b4970SChristoph Hellwig struct nvmet_host_link *p; 595a07b4970SChristoph Hellwig 596a07b4970SChristoph Hellwig down_write(&nvmet_config_sem); 597a07b4970SChristoph Hellwig list_for_each_entry(p, &subsys->hosts, entry) { 598a07b4970SChristoph Hellwig if (!strcmp(nvmet_host_name(p->host), nvmet_host_name(host))) 599a07b4970SChristoph Hellwig goto found; 600a07b4970SChristoph Hellwig } 601a07b4970SChristoph Hellwig up_write(&nvmet_config_sem); 602e16769d4SAndrzej Pietrasiewicz return; 603a07b4970SChristoph Hellwig 604a07b4970SChristoph Hellwig found: 605a07b4970SChristoph Hellwig list_del(&p->entry); 606a07b4970SChristoph Hellwig nvmet_genctr++; 607a07b4970SChristoph Hellwig up_write(&nvmet_config_sem); 608a07b4970SChristoph Hellwig kfree(p); 609a07b4970SChristoph Hellwig } 610a07b4970SChristoph Hellwig 611a07b4970SChristoph Hellwig static struct configfs_item_operations nvmet_allowed_hosts_item_ops = { 612a07b4970SChristoph Hellwig .allow_link = nvmet_allowed_hosts_allow_link, 613a07b4970SChristoph Hellwig .drop_link = nvmet_allowed_hosts_drop_link, 614a07b4970SChristoph Hellwig }; 615a07b4970SChristoph Hellwig 616a07b4970SChristoph Hellwig static struct config_item_type nvmet_allowed_hosts_type = { 617a07b4970SChristoph Hellwig .ct_item_ops = &nvmet_allowed_hosts_item_ops, 618a07b4970SChristoph Hellwig .ct_owner = THIS_MODULE, 619a07b4970SChristoph Hellwig }; 620a07b4970SChristoph Hellwig 621a07b4970SChristoph Hellwig static ssize_t nvmet_subsys_attr_allow_any_host_show(struct config_item *item, 622a07b4970SChristoph Hellwig char *page) 623a07b4970SChristoph Hellwig { 624a07b4970SChristoph Hellwig return snprintf(page, PAGE_SIZE, "%d\n", 625a07b4970SChristoph Hellwig to_subsys(item)->allow_any_host); 626a07b4970SChristoph Hellwig } 627a07b4970SChristoph Hellwig 628a07b4970SChristoph Hellwig static ssize_t nvmet_subsys_attr_allow_any_host_store(struct config_item *item, 629a07b4970SChristoph Hellwig const char *page, size_t count) 630a07b4970SChristoph Hellwig { 631a07b4970SChristoph Hellwig struct nvmet_subsys *subsys = to_subsys(item); 632a07b4970SChristoph Hellwig bool allow_any_host; 633a07b4970SChristoph Hellwig int ret = 0; 634a07b4970SChristoph Hellwig 635a07b4970SChristoph Hellwig if (strtobool(page, &allow_any_host)) 636a07b4970SChristoph Hellwig return -EINVAL; 637a07b4970SChristoph Hellwig 638a07b4970SChristoph Hellwig down_write(&nvmet_config_sem); 639a07b4970SChristoph Hellwig if (allow_any_host && !list_empty(&subsys->hosts)) { 640a07b4970SChristoph Hellwig pr_err("Can't set allow_any_host when explicit hosts are set!\n"); 641a07b4970SChristoph Hellwig ret = -EINVAL; 642a07b4970SChristoph Hellwig goto out_unlock; 643a07b4970SChristoph Hellwig } 644a07b4970SChristoph Hellwig 645a07b4970SChristoph Hellwig subsys->allow_any_host = allow_any_host; 646a07b4970SChristoph Hellwig out_unlock: 647a07b4970SChristoph Hellwig up_write(&nvmet_config_sem); 648a07b4970SChristoph Hellwig return ret ? ret : count; 649a07b4970SChristoph Hellwig } 650a07b4970SChristoph Hellwig 651a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_subsys_, attr_allow_any_host); 652a07b4970SChristoph Hellwig 65341528f80SJohannes Thumshirn static ssize_t nvmet_subsys_attr_version_show(struct config_item *item, 654c61d788bSJohannes Thumshirn char *page) 655c61d788bSJohannes Thumshirn { 656c61d788bSJohannes Thumshirn struct nvmet_subsys *subsys = to_subsys(item); 657c61d788bSJohannes Thumshirn 658c61d788bSJohannes Thumshirn if (NVME_TERTIARY(subsys->ver)) 659c61d788bSJohannes Thumshirn return snprintf(page, PAGE_SIZE, "%d.%d.%d\n", 660c61d788bSJohannes Thumshirn (int)NVME_MAJOR(subsys->ver), 661c61d788bSJohannes Thumshirn (int)NVME_MINOR(subsys->ver), 662c61d788bSJohannes Thumshirn (int)NVME_TERTIARY(subsys->ver)); 663c61d788bSJohannes Thumshirn else 664c61d788bSJohannes Thumshirn return snprintf(page, PAGE_SIZE, "%d.%d\n", 665c61d788bSJohannes Thumshirn (int)NVME_MAJOR(subsys->ver), 666c61d788bSJohannes Thumshirn (int)NVME_MINOR(subsys->ver)); 667c61d788bSJohannes Thumshirn } 668c61d788bSJohannes Thumshirn 66941528f80SJohannes Thumshirn static ssize_t nvmet_subsys_attr_version_store(struct config_item *item, 670c61d788bSJohannes Thumshirn const char *page, size_t count) 671c61d788bSJohannes Thumshirn { 672c61d788bSJohannes Thumshirn struct nvmet_subsys *subsys = to_subsys(item); 673c61d788bSJohannes Thumshirn int major, minor, tertiary = 0; 674c61d788bSJohannes Thumshirn int ret; 675c61d788bSJohannes Thumshirn 676c61d788bSJohannes Thumshirn 677c61d788bSJohannes Thumshirn ret = sscanf(page, "%d.%d.%d\n", &major, &minor, &tertiary); 678c61d788bSJohannes Thumshirn if (ret != 2 && ret != 3) 679c61d788bSJohannes Thumshirn return -EINVAL; 680c61d788bSJohannes Thumshirn 681c61d788bSJohannes Thumshirn down_write(&nvmet_config_sem); 682c61d788bSJohannes Thumshirn subsys->ver = NVME_VS(major, minor, tertiary); 683c61d788bSJohannes Thumshirn up_write(&nvmet_config_sem); 684c61d788bSJohannes Thumshirn 685c61d788bSJohannes Thumshirn return count; 686c61d788bSJohannes Thumshirn } 68741528f80SJohannes Thumshirn CONFIGFS_ATTR(nvmet_subsys_, attr_version); 688c61d788bSJohannes Thumshirn 689fcbc5459SJohannes Thumshirn static ssize_t nvmet_subsys_attr_serial_show(struct config_item *item, 690fcbc5459SJohannes Thumshirn char *page) 691fcbc5459SJohannes Thumshirn { 692fcbc5459SJohannes Thumshirn struct nvmet_subsys *subsys = to_subsys(item); 693fcbc5459SJohannes Thumshirn 694fcbc5459SJohannes Thumshirn return snprintf(page, PAGE_SIZE, "%llx\n", subsys->serial); 695fcbc5459SJohannes Thumshirn } 696fcbc5459SJohannes Thumshirn 697fcbc5459SJohannes Thumshirn static ssize_t nvmet_subsys_attr_serial_store(struct config_item *item, 698fcbc5459SJohannes Thumshirn const char *page, size_t count) 699fcbc5459SJohannes Thumshirn { 700fcbc5459SJohannes Thumshirn struct nvmet_subsys *subsys = to_subsys(item); 701fcbc5459SJohannes Thumshirn 702fcbc5459SJohannes Thumshirn down_write(&nvmet_config_sem); 703fcbc5459SJohannes Thumshirn sscanf(page, "%llx\n", &subsys->serial); 704fcbc5459SJohannes Thumshirn up_write(&nvmet_config_sem); 705fcbc5459SJohannes Thumshirn 706fcbc5459SJohannes Thumshirn return count; 707fcbc5459SJohannes Thumshirn } 708fcbc5459SJohannes Thumshirn CONFIGFS_ATTR(nvmet_subsys_, attr_serial); 709fcbc5459SJohannes Thumshirn 710a07b4970SChristoph Hellwig static struct configfs_attribute *nvmet_subsys_attrs[] = { 711a07b4970SChristoph Hellwig &nvmet_subsys_attr_attr_allow_any_host, 71241528f80SJohannes Thumshirn &nvmet_subsys_attr_attr_version, 713fcbc5459SJohannes Thumshirn &nvmet_subsys_attr_attr_serial, 714a07b4970SChristoph Hellwig NULL, 715a07b4970SChristoph Hellwig }; 716a07b4970SChristoph Hellwig 717a07b4970SChristoph Hellwig /* 718a07b4970SChristoph Hellwig * Subsystem structures & folder operation functions below 719a07b4970SChristoph Hellwig */ 720a07b4970SChristoph Hellwig static void nvmet_subsys_release(struct config_item *item) 721a07b4970SChristoph Hellwig { 722a07b4970SChristoph Hellwig struct nvmet_subsys *subsys = to_subsys(item); 723a07b4970SChristoph Hellwig 724344770b0SSagi Grimberg nvmet_subsys_del_ctrls(subsys); 725a07b4970SChristoph Hellwig nvmet_subsys_put(subsys); 726a07b4970SChristoph Hellwig } 727a07b4970SChristoph Hellwig 728a07b4970SChristoph Hellwig static struct configfs_item_operations nvmet_subsys_item_ops = { 729a07b4970SChristoph Hellwig .release = nvmet_subsys_release, 730a07b4970SChristoph Hellwig }; 731a07b4970SChristoph Hellwig 732a07b4970SChristoph Hellwig static struct config_item_type nvmet_subsys_type = { 733a07b4970SChristoph Hellwig .ct_item_ops = &nvmet_subsys_item_ops, 734a07b4970SChristoph Hellwig .ct_attrs = nvmet_subsys_attrs, 735a07b4970SChristoph Hellwig .ct_owner = THIS_MODULE, 736a07b4970SChristoph Hellwig }; 737a07b4970SChristoph Hellwig 738a07b4970SChristoph Hellwig static struct config_group *nvmet_subsys_make(struct config_group *group, 739a07b4970SChristoph Hellwig const char *name) 740a07b4970SChristoph Hellwig { 741a07b4970SChristoph Hellwig struct nvmet_subsys *subsys; 742a07b4970SChristoph Hellwig 743a07b4970SChristoph Hellwig if (sysfs_streq(name, NVME_DISC_SUBSYS_NAME)) { 744a07b4970SChristoph Hellwig pr_err("can't create discovery subsystem through configfs\n"); 745a07b4970SChristoph Hellwig return ERR_PTR(-EINVAL); 746a07b4970SChristoph Hellwig } 747a07b4970SChristoph Hellwig 748a07b4970SChristoph Hellwig subsys = nvmet_subsys_alloc(name, NVME_NQN_NVME); 749a07b4970SChristoph Hellwig if (!subsys) 750a07b4970SChristoph Hellwig return ERR_PTR(-ENOMEM); 751a07b4970SChristoph Hellwig 752a07b4970SChristoph Hellwig config_group_init_type_name(&subsys->group, name, &nvmet_subsys_type); 753a07b4970SChristoph Hellwig 754a07b4970SChristoph Hellwig config_group_init_type_name(&subsys->namespaces_group, 755a07b4970SChristoph Hellwig "namespaces", &nvmet_namespaces_type); 756a07b4970SChristoph Hellwig configfs_add_default_group(&subsys->namespaces_group, &subsys->group); 757a07b4970SChristoph Hellwig 758a07b4970SChristoph Hellwig config_group_init_type_name(&subsys->allowed_hosts_group, 759a07b4970SChristoph Hellwig "allowed_hosts", &nvmet_allowed_hosts_type); 760a07b4970SChristoph Hellwig configfs_add_default_group(&subsys->allowed_hosts_group, 761a07b4970SChristoph Hellwig &subsys->group); 762a07b4970SChristoph Hellwig 763a07b4970SChristoph Hellwig return &subsys->group; 764a07b4970SChristoph Hellwig } 765a07b4970SChristoph Hellwig 766a07b4970SChristoph Hellwig static struct configfs_group_operations nvmet_subsystems_group_ops = { 767a07b4970SChristoph Hellwig .make_group = nvmet_subsys_make, 768a07b4970SChristoph Hellwig }; 769a07b4970SChristoph Hellwig 770a07b4970SChristoph Hellwig static struct config_item_type nvmet_subsystems_type = { 771a07b4970SChristoph Hellwig .ct_group_ops = &nvmet_subsystems_group_ops, 772a07b4970SChristoph Hellwig .ct_owner = THIS_MODULE, 773a07b4970SChristoph Hellwig }; 774a07b4970SChristoph Hellwig 775a07b4970SChristoph Hellwig static ssize_t nvmet_referral_enable_show(struct config_item *item, 776a07b4970SChristoph Hellwig char *page) 777a07b4970SChristoph Hellwig { 778a07b4970SChristoph Hellwig return snprintf(page, PAGE_SIZE, "%d\n", to_nvmet_port(item)->enabled); 779a07b4970SChristoph Hellwig } 780a07b4970SChristoph Hellwig 781a07b4970SChristoph Hellwig static ssize_t nvmet_referral_enable_store(struct config_item *item, 782a07b4970SChristoph Hellwig const char *page, size_t count) 783a07b4970SChristoph Hellwig { 784a07b4970SChristoph Hellwig struct nvmet_port *parent = to_nvmet_port(item->ci_parent->ci_parent); 785a07b4970SChristoph Hellwig struct nvmet_port *port = to_nvmet_port(item); 786a07b4970SChristoph Hellwig bool enable; 787a07b4970SChristoph Hellwig 788a07b4970SChristoph Hellwig if (strtobool(page, &enable)) 789a07b4970SChristoph Hellwig goto inval; 790a07b4970SChristoph Hellwig 791a07b4970SChristoph Hellwig if (enable) 792a07b4970SChristoph Hellwig nvmet_referral_enable(parent, port); 793a07b4970SChristoph Hellwig else 794a07b4970SChristoph Hellwig nvmet_referral_disable(port); 795a07b4970SChristoph Hellwig 796a07b4970SChristoph Hellwig return count; 797a07b4970SChristoph Hellwig inval: 798a07b4970SChristoph Hellwig pr_err("Invalid value '%s' for enable\n", page); 799a07b4970SChristoph Hellwig return -EINVAL; 800a07b4970SChristoph Hellwig } 801a07b4970SChristoph Hellwig 802a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_referral_, enable); 803a07b4970SChristoph Hellwig 804a07b4970SChristoph Hellwig /* 805a07b4970SChristoph Hellwig * Discovery Service subsystem definitions 806a07b4970SChristoph Hellwig */ 807a07b4970SChristoph Hellwig static struct configfs_attribute *nvmet_referral_attrs[] = { 808a07b4970SChristoph Hellwig &nvmet_attr_addr_adrfam, 809a07b4970SChristoph Hellwig &nvmet_attr_addr_portid, 810a07b4970SChristoph Hellwig &nvmet_attr_addr_treq, 811a07b4970SChristoph Hellwig &nvmet_attr_addr_traddr, 812a07b4970SChristoph Hellwig &nvmet_attr_addr_trsvcid, 813a07b4970SChristoph Hellwig &nvmet_attr_addr_trtype, 814a07b4970SChristoph Hellwig &nvmet_referral_attr_enable, 815a07b4970SChristoph Hellwig NULL, 816a07b4970SChristoph Hellwig }; 817a07b4970SChristoph Hellwig 818a07b4970SChristoph Hellwig static void nvmet_referral_release(struct config_item *item) 819a07b4970SChristoph Hellwig { 820a07b4970SChristoph Hellwig struct nvmet_port *port = to_nvmet_port(item); 821a07b4970SChristoph Hellwig 822a07b4970SChristoph Hellwig nvmet_referral_disable(port); 823a07b4970SChristoph Hellwig kfree(port); 824a07b4970SChristoph Hellwig } 825a07b4970SChristoph Hellwig 826a07b4970SChristoph Hellwig static struct configfs_item_operations nvmet_referral_item_ops = { 827a07b4970SChristoph Hellwig .release = nvmet_referral_release, 828a07b4970SChristoph Hellwig }; 829a07b4970SChristoph Hellwig 830a07b4970SChristoph Hellwig static struct config_item_type nvmet_referral_type = { 831a07b4970SChristoph Hellwig .ct_owner = THIS_MODULE, 832a07b4970SChristoph Hellwig .ct_attrs = nvmet_referral_attrs, 833a07b4970SChristoph Hellwig .ct_item_ops = &nvmet_referral_item_ops, 834a07b4970SChristoph Hellwig }; 835a07b4970SChristoph Hellwig 836a07b4970SChristoph Hellwig static struct config_group *nvmet_referral_make( 837a07b4970SChristoph Hellwig struct config_group *group, const char *name) 838a07b4970SChristoph Hellwig { 839a07b4970SChristoph Hellwig struct nvmet_port *port; 840a07b4970SChristoph Hellwig 841a07b4970SChristoph Hellwig port = kzalloc(sizeof(*port), GFP_KERNEL); 842a07b4970SChristoph Hellwig if (!port) 843f98d9ca1SDan Carpenter return ERR_PTR(-ENOMEM); 844a07b4970SChristoph Hellwig 845a07b4970SChristoph Hellwig INIT_LIST_HEAD(&port->entry); 846a07b4970SChristoph Hellwig config_group_init_type_name(&port->group, name, &nvmet_referral_type); 847a07b4970SChristoph Hellwig 848a07b4970SChristoph Hellwig return &port->group; 849a07b4970SChristoph Hellwig } 850a07b4970SChristoph Hellwig 851a07b4970SChristoph Hellwig static struct configfs_group_operations nvmet_referral_group_ops = { 852a07b4970SChristoph Hellwig .make_group = nvmet_referral_make, 853a07b4970SChristoph Hellwig }; 854a07b4970SChristoph Hellwig 855a07b4970SChristoph Hellwig static struct config_item_type nvmet_referrals_type = { 856a07b4970SChristoph Hellwig .ct_owner = THIS_MODULE, 857a07b4970SChristoph Hellwig .ct_group_ops = &nvmet_referral_group_ops, 858a07b4970SChristoph Hellwig }; 859a07b4970SChristoph Hellwig 860a07b4970SChristoph Hellwig /* 861a07b4970SChristoph Hellwig * Ports definitions. 862a07b4970SChristoph Hellwig */ 863a07b4970SChristoph Hellwig static void nvmet_port_release(struct config_item *item) 864a07b4970SChristoph Hellwig { 865a07b4970SChristoph Hellwig struct nvmet_port *port = to_nvmet_port(item); 866a07b4970SChristoph Hellwig 867a07b4970SChristoph Hellwig kfree(port); 868a07b4970SChristoph Hellwig } 869a07b4970SChristoph Hellwig 870a07b4970SChristoph Hellwig static struct configfs_attribute *nvmet_port_attrs[] = { 871a07b4970SChristoph Hellwig &nvmet_attr_addr_adrfam, 872a07b4970SChristoph Hellwig &nvmet_attr_addr_treq, 873a07b4970SChristoph Hellwig &nvmet_attr_addr_traddr, 874a07b4970SChristoph Hellwig &nvmet_attr_addr_trsvcid, 875a07b4970SChristoph Hellwig &nvmet_attr_addr_trtype, 876a07b4970SChristoph Hellwig NULL, 877a07b4970SChristoph Hellwig }; 878a07b4970SChristoph Hellwig 879a07b4970SChristoph Hellwig static struct configfs_item_operations nvmet_port_item_ops = { 880a07b4970SChristoph Hellwig .release = nvmet_port_release, 881a07b4970SChristoph Hellwig }; 882a07b4970SChristoph Hellwig 883a07b4970SChristoph Hellwig static struct config_item_type nvmet_port_type = { 884a07b4970SChristoph Hellwig .ct_attrs = nvmet_port_attrs, 885a07b4970SChristoph Hellwig .ct_item_ops = &nvmet_port_item_ops, 886a07b4970SChristoph Hellwig .ct_owner = THIS_MODULE, 887a07b4970SChristoph Hellwig }; 888a07b4970SChristoph Hellwig 889a07b4970SChristoph Hellwig static struct config_group *nvmet_ports_make(struct config_group *group, 890a07b4970SChristoph Hellwig const char *name) 891a07b4970SChristoph Hellwig { 892a07b4970SChristoph Hellwig struct nvmet_port *port; 893a07b4970SChristoph Hellwig u16 portid; 894a07b4970SChristoph Hellwig 895a07b4970SChristoph Hellwig if (kstrtou16(name, 0, &portid)) 896a07b4970SChristoph Hellwig return ERR_PTR(-EINVAL); 897a07b4970SChristoph Hellwig 898a07b4970SChristoph Hellwig port = kzalloc(sizeof(*port), GFP_KERNEL); 899a07b4970SChristoph Hellwig if (!port) 900f98d9ca1SDan Carpenter return ERR_PTR(-ENOMEM); 901a07b4970SChristoph Hellwig 902a07b4970SChristoph Hellwig INIT_LIST_HEAD(&port->entry); 903a07b4970SChristoph Hellwig INIT_LIST_HEAD(&port->subsystems); 904a07b4970SChristoph Hellwig INIT_LIST_HEAD(&port->referrals); 905a07b4970SChristoph Hellwig 906a07b4970SChristoph Hellwig port->disc_addr.portid = cpu_to_le16(portid); 907a07b4970SChristoph Hellwig config_group_init_type_name(&port->group, name, &nvmet_port_type); 908a07b4970SChristoph Hellwig 909a07b4970SChristoph Hellwig config_group_init_type_name(&port->subsys_group, 910a07b4970SChristoph Hellwig "subsystems", &nvmet_port_subsys_type); 911a07b4970SChristoph Hellwig configfs_add_default_group(&port->subsys_group, &port->group); 912a07b4970SChristoph Hellwig 913a07b4970SChristoph Hellwig config_group_init_type_name(&port->referrals_group, 914a07b4970SChristoph Hellwig "referrals", &nvmet_referrals_type); 915a07b4970SChristoph Hellwig configfs_add_default_group(&port->referrals_group, &port->group); 916a07b4970SChristoph Hellwig 917a07b4970SChristoph Hellwig return &port->group; 918a07b4970SChristoph Hellwig } 919a07b4970SChristoph Hellwig 920a07b4970SChristoph Hellwig static struct configfs_group_operations nvmet_ports_group_ops = { 921a07b4970SChristoph Hellwig .make_group = nvmet_ports_make, 922a07b4970SChristoph Hellwig }; 923a07b4970SChristoph Hellwig 924a07b4970SChristoph Hellwig static struct config_item_type nvmet_ports_type = { 925a07b4970SChristoph Hellwig .ct_group_ops = &nvmet_ports_group_ops, 926a07b4970SChristoph Hellwig .ct_owner = THIS_MODULE, 927a07b4970SChristoph Hellwig }; 928a07b4970SChristoph Hellwig 929a07b4970SChristoph Hellwig static struct config_group nvmet_subsystems_group; 930a07b4970SChristoph Hellwig static struct config_group nvmet_ports_group; 931a07b4970SChristoph Hellwig 932a07b4970SChristoph Hellwig static void nvmet_host_release(struct config_item *item) 933a07b4970SChristoph Hellwig { 934a07b4970SChristoph Hellwig struct nvmet_host *host = to_host(item); 935a07b4970SChristoph Hellwig 936a07b4970SChristoph Hellwig kfree(host); 937a07b4970SChristoph Hellwig } 938a07b4970SChristoph Hellwig 939a07b4970SChristoph Hellwig static struct configfs_item_operations nvmet_host_item_ops = { 940a07b4970SChristoph Hellwig .release = nvmet_host_release, 941a07b4970SChristoph Hellwig }; 942a07b4970SChristoph Hellwig 943a07b4970SChristoph Hellwig static struct config_item_type nvmet_host_type = { 944a07b4970SChristoph Hellwig .ct_item_ops = &nvmet_host_item_ops, 945a07b4970SChristoph Hellwig .ct_owner = THIS_MODULE, 946a07b4970SChristoph Hellwig }; 947a07b4970SChristoph Hellwig 948a07b4970SChristoph Hellwig static struct config_group *nvmet_hosts_make_group(struct config_group *group, 949a07b4970SChristoph Hellwig const char *name) 950a07b4970SChristoph Hellwig { 951a07b4970SChristoph Hellwig struct nvmet_host *host; 952a07b4970SChristoph Hellwig 953a07b4970SChristoph Hellwig host = kzalloc(sizeof(*host), GFP_KERNEL); 954a07b4970SChristoph Hellwig if (!host) 955a07b4970SChristoph Hellwig return ERR_PTR(-ENOMEM); 956a07b4970SChristoph Hellwig 957a07b4970SChristoph Hellwig config_group_init_type_name(&host->group, name, &nvmet_host_type); 958a07b4970SChristoph Hellwig 959a07b4970SChristoph Hellwig return &host->group; 960a07b4970SChristoph Hellwig } 961a07b4970SChristoph Hellwig 962a07b4970SChristoph Hellwig static struct configfs_group_operations nvmet_hosts_group_ops = { 963a07b4970SChristoph Hellwig .make_group = nvmet_hosts_make_group, 964a07b4970SChristoph Hellwig }; 965a07b4970SChristoph Hellwig 966a07b4970SChristoph Hellwig static struct config_item_type nvmet_hosts_type = { 967a07b4970SChristoph Hellwig .ct_group_ops = &nvmet_hosts_group_ops, 968a07b4970SChristoph Hellwig .ct_owner = THIS_MODULE, 969a07b4970SChristoph Hellwig }; 970a07b4970SChristoph Hellwig 971a07b4970SChristoph Hellwig static struct config_group nvmet_hosts_group; 972a07b4970SChristoph Hellwig 973a07b4970SChristoph Hellwig static struct config_item_type nvmet_root_type = { 974a07b4970SChristoph Hellwig .ct_owner = THIS_MODULE, 975a07b4970SChristoph Hellwig }; 976a07b4970SChristoph Hellwig 977a07b4970SChristoph Hellwig static struct configfs_subsystem nvmet_configfs_subsystem = { 978a07b4970SChristoph Hellwig .su_group = { 979a07b4970SChristoph Hellwig .cg_item = { 980a07b4970SChristoph Hellwig .ci_namebuf = "nvmet", 981a07b4970SChristoph Hellwig .ci_type = &nvmet_root_type, 982a07b4970SChristoph Hellwig }, 983a07b4970SChristoph Hellwig }, 984a07b4970SChristoph Hellwig }; 985a07b4970SChristoph Hellwig 986a07b4970SChristoph Hellwig int __init nvmet_init_configfs(void) 987a07b4970SChristoph Hellwig { 988a07b4970SChristoph Hellwig int ret; 989a07b4970SChristoph Hellwig 990a07b4970SChristoph Hellwig config_group_init(&nvmet_configfs_subsystem.su_group); 991a07b4970SChristoph Hellwig mutex_init(&nvmet_configfs_subsystem.su_mutex); 992a07b4970SChristoph Hellwig 993a07b4970SChristoph Hellwig config_group_init_type_name(&nvmet_subsystems_group, 994a07b4970SChristoph Hellwig "subsystems", &nvmet_subsystems_type); 995a07b4970SChristoph Hellwig configfs_add_default_group(&nvmet_subsystems_group, 996a07b4970SChristoph Hellwig &nvmet_configfs_subsystem.su_group); 997a07b4970SChristoph Hellwig 998a07b4970SChristoph Hellwig config_group_init_type_name(&nvmet_ports_group, 999a07b4970SChristoph Hellwig "ports", &nvmet_ports_type); 1000a07b4970SChristoph Hellwig configfs_add_default_group(&nvmet_ports_group, 1001a07b4970SChristoph Hellwig &nvmet_configfs_subsystem.su_group); 1002a07b4970SChristoph Hellwig 1003a07b4970SChristoph Hellwig config_group_init_type_name(&nvmet_hosts_group, 1004a07b4970SChristoph Hellwig "hosts", &nvmet_hosts_type); 1005a07b4970SChristoph Hellwig configfs_add_default_group(&nvmet_hosts_group, 1006a07b4970SChristoph Hellwig &nvmet_configfs_subsystem.su_group); 1007a07b4970SChristoph Hellwig 1008a07b4970SChristoph Hellwig ret = configfs_register_subsystem(&nvmet_configfs_subsystem); 1009a07b4970SChristoph Hellwig if (ret) { 1010a07b4970SChristoph Hellwig pr_err("configfs_register_subsystem: %d\n", ret); 1011a07b4970SChristoph Hellwig return ret; 1012a07b4970SChristoph Hellwig } 1013a07b4970SChristoph Hellwig 1014a07b4970SChristoph Hellwig return 0; 1015a07b4970SChristoph Hellwig } 1016a07b4970SChristoph Hellwig 1017a07b4970SChristoph Hellwig void __exit nvmet_exit_configfs(void) 1018a07b4970SChristoph Hellwig { 1019a07b4970SChristoph Hellwig configfs_unregister_subsystem(&nvmet_configfs_subsystem); 1020a07b4970SChristoph Hellwig } 1021