xref: /openbmc/linux/drivers/nvme/target/configfs.c (revision 1f357548)
177141dc6SChristoph Hellwig // SPDX-License-Identifier: GPL-2.0
2a07b4970SChristoph Hellwig /*
3a07b4970SChristoph Hellwig  * Configfs interface for the NVMe target.
4a07b4970SChristoph Hellwig  * Copyright (c) 2015-2016 HGST, a Western Digital Company.
5a07b4970SChristoph Hellwig  */
6a07b4970SChristoph Hellwig #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
7a07b4970SChristoph Hellwig #include <linux/kernel.h>
8a07b4970SChristoph Hellwig #include <linux/module.h>
9a07b4970SChristoph Hellwig #include <linux/slab.h>
10a07b4970SChristoph Hellwig #include <linux/stat.h>
11a07b4970SChristoph Hellwig #include <linux/ctype.h>
12c6925093SLogan Gunthorpe #include <linux/pci.h>
13c6925093SLogan Gunthorpe #include <linux/pci-p2pdma.h>
14a07b4970SChristoph Hellwig 
15a07b4970SChristoph Hellwig #include "nvmet.h"
16a07b4970SChristoph Hellwig 
1766603a31SBhumika Goyal static const struct config_item_type nvmet_host_type;
1866603a31SBhumika Goyal static const struct config_item_type nvmet_subsys_type;
19a07b4970SChristoph Hellwig 
20b662a078SJay Sternberg static LIST_HEAD(nvmet_ports_list);
21b662a078SJay Sternberg struct list_head *nvmet_ports = &nvmet_ports_list;
22b662a078SJay Sternberg 
2345e2f3c2SChaitanya Kulkarni struct nvmet_type_name_map {
24a5d18612SChristoph Hellwig 	u8		type;
25a5d18612SChristoph Hellwig 	const char	*name;
2645e2f3c2SChaitanya Kulkarni };
2745e2f3c2SChaitanya Kulkarni 
2845e2f3c2SChaitanya Kulkarni static struct nvmet_type_name_map nvmet_transport[] = {
29a5d18612SChristoph Hellwig 	{ NVMF_TRTYPE_RDMA,	"rdma" },
30a5d18612SChristoph Hellwig 	{ NVMF_TRTYPE_FC,	"fc" },
31ad4f530eSSagi Grimberg 	{ NVMF_TRTYPE_TCP,	"tcp" },
32a5d18612SChristoph Hellwig 	{ NVMF_TRTYPE_LOOP,	"loop" },
33a5d18612SChristoph Hellwig };
34a5d18612SChristoph Hellwig 
357e764179SChaitanya Kulkarni static const struct nvmet_type_name_map nvmet_addr_family[] = {
367e764179SChaitanya Kulkarni 	{ NVMF_ADDR_FAMILY_PCI,		"pcie" },
377e764179SChaitanya Kulkarni 	{ NVMF_ADDR_FAMILY_IP4,		"ipv4" },
387e764179SChaitanya Kulkarni 	{ NVMF_ADDR_FAMILY_IP6,		"ipv6" },
397e764179SChaitanya Kulkarni 	{ NVMF_ADDR_FAMILY_IB,		"ib" },
407e764179SChaitanya Kulkarni 	{ NVMF_ADDR_FAMILY_FC,		"fc" },
41d02abd19SChaitanya Kulkarni 	{ NVMF_ADDR_FAMILY_LOOP,	"loop" },
427e764179SChaitanya Kulkarni };
437e764179SChaitanya Kulkarni 
443ecb5faaSChaitanya Kulkarni static bool nvmet_is_port_enabled(struct nvmet_port *p, const char *caller)
453ecb5faaSChaitanya Kulkarni {
463ecb5faaSChaitanya Kulkarni 	if (p->enabled)
473ecb5faaSChaitanya Kulkarni 		pr_err("Disable port '%u' before changing attribute in %s\n",
483ecb5faaSChaitanya Kulkarni 				le16_to_cpu(p->disc_addr.portid), caller);
493ecb5faaSChaitanya Kulkarni 	return p->enabled;
503ecb5faaSChaitanya Kulkarni }
513ecb5faaSChaitanya Kulkarni 
52a07b4970SChristoph Hellwig /*
53a07b4970SChristoph Hellwig  * nvmet_port Generic ConfigFS definitions.
54a07b4970SChristoph Hellwig  * Used in any place in the ConfigFS tree that refers to an address.
55a07b4970SChristoph Hellwig  */
567e764179SChaitanya Kulkarni static ssize_t nvmet_addr_adrfam_show(struct config_item *item, char *page)
57a07b4970SChristoph Hellwig {
587e764179SChaitanya Kulkarni 	u8 adrfam = to_nvmet_port(item)->disc_addr.adrfam;
597e764179SChaitanya Kulkarni 	int i;
607e764179SChaitanya Kulkarni 
617e764179SChaitanya Kulkarni 	for (i = 1; i < ARRAY_SIZE(nvmet_addr_family); i++) {
627e764179SChaitanya Kulkarni 		if (nvmet_addr_family[i].type == adrfam)
637e764179SChaitanya Kulkarni 			return sprintf(page, "%s\n", nvmet_addr_family[i].name);
64a07b4970SChristoph Hellwig 	}
657e764179SChaitanya Kulkarni 
667e764179SChaitanya Kulkarni 	return sprintf(page, "\n");
67a07b4970SChristoph Hellwig }
68a07b4970SChristoph Hellwig 
69a07b4970SChristoph Hellwig static ssize_t nvmet_addr_adrfam_store(struct config_item *item,
70a07b4970SChristoph Hellwig 		const char *page, size_t count)
71a07b4970SChristoph Hellwig {
72a07b4970SChristoph Hellwig 	struct nvmet_port *port = to_nvmet_port(item);
737e764179SChaitanya Kulkarni 	int i;
74a07b4970SChristoph Hellwig 
753ecb5faaSChaitanya Kulkarni 	if (nvmet_is_port_enabled(port, __func__))
76a07b4970SChristoph Hellwig 		return -EACCES;
77a07b4970SChristoph Hellwig 
787e764179SChaitanya Kulkarni 	for (i = 1; i < ARRAY_SIZE(nvmet_addr_family); i++) {
797e764179SChaitanya Kulkarni 		if (sysfs_streq(page, nvmet_addr_family[i].name))
807e764179SChaitanya Kulkarni 			goto found;
81a07b4970SChristoph Hellwig 	}
82a07b4970SChristoph Hellwig 
837e764179SChaitanya Kulkarni 	pr_err("Invalid value '%s' for adrfam\n", page);
847e764179SChaitanya Kulkarni 	return -EINVAL;
857e764179SChaitanya Kulkarni 
867e764179SChaitanya Kulkarni found:
87d02abd19SChaitanya Kulkarni 	port->disc_addr.adrfam = nvmet_addr_family[i].type;
88a07b4970SChristoph Hellwig 	return count;
89a07b4970SChristoph Hellwig }
90a07b4970SChristoph Hellwig 
91a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_, addr_adrfam);
92a07b4970SChristoph Hellwig 
93a07b4970SChristoph Hellwig static ssize_t nvmet_addr_portid_show(struct config_item *item,
94a07b4970SChristoph Hellwig 		char *page)
95a07b4970SChristoph Hellwig {
96a07b4970SChristoph Hellwig 	struct nvmet_port *port = to_nvmet_port(item);
97a07b4970SChristoph Hellwig 
98a07b4970SChristoph Hellwig 	return snprintf(page, PAGE_SIZE, "%d\n",
99a07b4970SChristoph Hellwig 			le16_to_cpu(port->disc_addr.portid));
100a07b4970SChristoph Hellwig }
101a07b4970SChristoph Hellwig 
102a07b4970SChristoph Hellwig static ssize_t nvmet_addr_portid_store(struct config_item *item,
103a07b4970SChristoph Hellwig 		const char *page, size_t count)
104a07b4970SChristoph Hellwig {
105a07b4970SChristoph Hellwig 	struct nvmet_port *port = to_nvmet_port(item);
106a07b4970SChristoph Hellwig 	u16 portid = 0;
107a07b4970SChristoph Hellwig 
108a07b4970SChristoph Hellwig 	if (kstrtou16(page, 0, &portid)) {
109a07b4970SChristoph Hellwig 		pr_err("Invalid value '%s' for portid\n", page);
110a07b4970SChristoph Hellwig 		return -EINVAL;
111a07b4970SChristoph Hellwig 	}
112a07b4970SChristoph Hellwig 
1133ecb5faaSChaitanya Kulkarni 	if (nvmet_is_port_enabled(port, __func__))
114a07b4970SChristoph Hellwig 		return -EACCES;
1153ecb5faaSChaitanya Kulkarni 
116a07b4970SChristoph Hellwig 	port->disc_addr.portid = cpu_to_le16(portid);
117a07b4970SChristoph Hellwig 	return count;
118a07b4970SChristoph Hellwig }
119a07b4970SChristoph Hellwig 
120a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_, addr_portid);
121a07b4970SChristoph Hellwig 
122a07b4970SChristoph Hellwig static ssize_t nvmet_addr_traddr_show(struct config_item *item,
123a07b4970SChristoph Hellwig 		char *page)
124a07b4970SChristoph Hellwig {
125a07b4970SChristoph Hellwig 	struct nvmet_port *port = to_nvmet_port(item);
126a07b4970SChristoph Hellwig 
127a07b4970SChristoph Hellwig 	return snprintf(page, PAGE_SIZE, "%s\n",
128a07b4970SChristoph Hellwig 			port->disc_addr.traddr);
129a07b4970SChristoph Hellwig }
130a07b4970SChristoph Hellwig 
131a07b4970SChristoph Hellwig static ssize_t nvmet_addr_traddr_store(struct config_item *item,
132a07b4970SChristoph Hellwig 		const char *page, size_t count)
133a07b4970SChristoph Hellwig {
134a07b4970SChristoph Hellwig 	struct nvmet_port *port = to_nvmet_port(item);
135a07b4970SChristoph Hellwig 
136a07b4970SChristoph Hellwig 	if (count > NVMF_TRADDR_SIZE) {
137a07b4970SChristoph Hellwig 		pr_err("Invalid value '%s' for traddr\n", page);
138a07b4970SChristoph Hellwig 		return -EINVAL;
139a07b4970SChristoph Hellwig 	}
140a07b4970SChristoph Hellwig 
1413ecb5faaSChaitanya Kulkarni 	if (nvmet_is_port_enabled(port, __func__))
142a07b4970SChristoph Hellwig 		return -EACCES;
1439ba2a5cbSSagi Grimberg 
1449ba2a5cbSSagi Grimberg 	if (sscanf(page, "%s\n", port->disc_addr.traddr) != 1)
1459ba2a5cbSSagi Grimberg 		return -EINVAL;
1469ba2a5cbSSagi Grimberg 	return count;
147a07b4970SChristoph Hellwig }
148a07b4970SChristoph Hellwig 
149a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_, addr_traddr);
150a07b4970SChristoph Hellwig 
15187628e28SChaitanya Kulkarni static const struct nvmet_type_name_map nvmet_addr_treq[] = {
15287628e28SChaitanya Kulkarni 	{ NVMF_TREQ_NOT_SPECIFIED,	"not specified" },
15387628e28SChaitanya Kulkarni 	{ NVMF_TREQ_REQUIRED,		"required" },
15487628e28SChaitanya Kulkarni 	{ NVMF_TREQ_NOT_REQUIRED,	"not required" },
15587628e28SChaitanya Kulkarni };
15687628e28SChaitanya Kulkarni 
15787628e28SChaitanya Kulkarni static ssize_t nvmet_addr_treq_show(struct config_item *item, char *page)
158a07b4970SChristoph Hellwig {
15987628e28SChaitanya Kulkarni 	u8 treq = to_nvmet_port(item)->disc_addr.treq &
16087628e28SChaitanya Kulkarni 		NVME_TREQ_SECURE_CHANNEL_MASK;
16187628e28SChaitanya Kulkarni 	int i;
16287628e28SChaitanya Kulkarni 
16387628e28SChaitanya Kulkarni 	for (i = 0; i < ARRAY_SIZE(nvmet_addr_treq); i++) {
16487628e28SChaitanya Kulkarni 		if (treq == nvmet_addr_treq[i].type)
16587628e28SChaitanya Kulkarni 			return sprintf(page, "%s\n", nvmet_addr_treq[i].name);
166a07b4970SChristoph Hellwig 	}
16787628e28SChaitanya Kulkarni 
16887628e28SChaitanya Kulkarni 	return sprintf(page, "\n");
169a07b4970SChristoph Hellwig }
170a07b4970SChristoph Hellwig 
171a07b4970SChristoph Hellwig static ssize_t nvmet_addr_treq_store(struct config_item *item,
172a07b4970SChristoph Hellwig 		const char *page, size_t count)
173a07b4970SChristoph Hellwig {
174a07b4970SChristoph Hellwig 	struct nvmet_port *port = to_nvmet_port(item);
1750445e1b5SSagi Grimberg 	u8 treq = port->disc_addr.treq & ~NVME_TREQ_SECURE_CHANNEL_MASK;
17687628e28SChaitanya Kulkarni 	int i;
177a07b4970SChristoph Hellwig 
1783ecb5faaSChaitanya Kulkarni 	if (nvmet_is_port_enabled(port, __func__))
179a07b4970SChristoph Hellwig 		return -EACCES;
180a07b4970SChristoph Hellwig 
18187628e28SChaitanya Kulkarni 	for (i = 0; i < ARRAY_SIZE(nvmet_addr_treq); i++) {
18287628e28SChaitanya Kulkarni 		if (sysfs_streq(page, nvmet_addr_treq[i].name))
18387628e28SChaitanya Kulkarni 			goto found;
18487628e28SChaitanya Kulkarni 	}
18587628e28SChaitanya Kulkarni 
186a07b4970SChristoph Hellwig 	pr_err("Invalid value '%s' for treq\n", page);
187a07b4970SChristoph Hellwig 	return -EINVAL;
188a07b4970SChristoph Hellwig 
18987628e28SChaitanya Kulkarni found:
19087628e28SChaitanya Kulkarni 	treq |= nvmet_addr_treq[i].type;
19187628e28SChaitanya Kulkarni 	port->disc_addr.treq = treq;
192a07b4970SChristoph Hellwig 	return count;
193a07b4970SChristoph Hellwig }
194a07b4970SChristoph Hellwig 
195a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_, addr_treq);
196a07b4970SChristoph Hellwig 
197a07b4970SChristoph Hellwig static ssize_t nvmet_addr_trsvcid_show(struct config_item *item,
198a07b4970SChristoph Hellwig 		char *page)
199a07b4970SChristoph Hellwig {
200a07b4970SChristoph Hellwig 	struct nvmet_port *port = to_nvmet_port(item);
201a07b4970SChristoph Hellwig 
202a07b4970SChristoph Hellwig 	return snprintf(page, PAGE_SIZE, "%s\n",
203a07b4970SChristoph Hellwig 			port->disc_addr.trsvcid);
204a07b4970SChristoph Hellwig }
205a07b4970SChristoph Hellwig 
206a07b4970SChristoph Hellwig static ssize_t nvmet_addr_trsvcid_store(struct config_item *item,
207a07b4970SChristoph Hellwig 		const char *page, size_t count)
208a07b4970SChristoph Hellwig {
209a07b4970SChristoph Hellwig 	struct nvmet_port *port = to_nvmet_port(item);
210a07b4970SChristoph Hellwig 
211a07b4970SChristoph Hellwig 	if (count > NVMF_TRSVCID_SIZE) {
212a07b4970SChristoph Hellwig 		pr_err("Invalid value '%s' for trsvcid\n", page);
213a07b4970SChristoph Hellwig 		return -EINVAL;
214a07b4970SChristoph Hellwig 	}
2153ecb5faaSChaitanya Kulkarni 	if (nvmet_is_port_enabled(port, __func__))
216a07b4970SChristoph Hellwig 		return -EACCES;
2179ba2a5cbSSagi Grimberg 
2189ba2a5cbSSagi Grimberg 	if (sscanf(page, "%s\n", port->disc_addr.trsvcid) != 1)
2199ba2a5cbSSagi Grimberg 		return -EINVAL;
2209ba2a5cbSSagi Grimberg 	return count;
221a07b4970SChristoph Hellwig }
222a07b4970SChristoph Hellwig 
223a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_, addr_trsvcid);
224a07b4970SChristoph Hellwig 
2250d5ee2b2SSteve Wise static ssize_t nvmet_param_inline_data_size_show(struct config_item *item,
2260d5ee2b2SSteve Wise 		char *page)
2270d5ee2b2SSteve Wise {
2280d5ee2b2SSteve Wise 	struct nvmet_port *port = to_nvmet_port(item);
2290d5ee2b2SSteve Wise 
2300d5ee2b2SSteve Wise 	return snprintf(page, PAGE_SIZE, "%d\n", port->inline_data_size);
2310d5ee2b2SSteve Wise }
2320d5ee2b2SSteve Wise 
2330d5ee2b2SSteve Wise static ssize_t nvmet_param_inline_data_size_store(struct config_item *item,
2340d5ee2b2SSteve Wise 		const char *page, size_t count)
2350d5ee2b2SSteve Wise {
2360d5ee2b2SSteve Wise 	struct nvmet_port *port = to_nvmet_port(item);
2370d5ee2b2SSteve Wise 	int ret;
2380d5ee2b2SSteve Wise 
2393ecb5faaSChaitanya Kulkarni 	if (nvmet_is_port_enabled(port, __func__))
2400d5ee2b2SSteve Wise 		return -EACCES;
2410d5ee2b2SSteve Wise 	ret = kstrtoint(page, 0, &port->inline_data_size);
2420d5ee2b2SSteve Wise 	if (ret) {
2430d5ee2b2SSteve Wise 		pr_err("Invalid value '%s' for inline_data_size\n", page);
2440d5ee2b2SSteve Wise 		return -EINVAL;
2450d5ee2b2SSteve Wise 	}
2460d5ee2b2SSteve Wise 	return count;
2470d5ee2b2SSteve Wise }
2480d5ee2b2SSteve Wise 
2490d5ee2b2SSteve Wise CONFIGFS_ATTR(nvmet_, param_inline_data_size);
2500d5ee2b2SSteve Wise 
251a07b4970SChristoph Hellwig static ssize_t nvmet_addr_trtype_show(struct config_item *item,
252a07b4970SChristoph Hellwig 		char *page)
253a07b4970SChristoph Hellwig {
254a5d18612SChristoph Hellwig 	struct nvmet_port *port = to_nvmet_port(item);
255a5d18612SChristoph Hellwig 	int i;
256a5d18612SChristoph Hellwig 
25745e2f3c2SChaitanya Kulkarni 	for (i = 0; i < ARRAY_SIZE(nvmet_transport); i++) {
25845e2f3c2SChaitanya Kulkarni 		if (port->disc_addr.trtype == nvmet_transport[i].type)
25945e2f3c2SChaitanya Kulkarni 			return sprintf(page, "%s\n", nvmet_transport[i].name);
260a07b4970SChristoph Hellwig 	}
261a5d18612SChristoph Hellwig 
262a5d18612SChristoph Hellwig 	return sprintf(page, "\n");
263a07b4970SChristoph Hellwig }
264a07b4970SChristoph Hellwig 
265a07b4970SChristoph Hellwig static void nvmet_port_init_tsas_rdma(struct nvmet_port *port)
266a07b4970SChristoph Hellwig {
267a07b4970SChristoph Hellwig 	port->disc_addr.tsas.rdma.qptype = NVMF_RDMA_QPTYPE_CONNECTED;
268a07b4970SChristoph Hellwig 	port->disc_addr.tsas.rdma.prtype = NVMF_RDMA_PRTYPE_NOT_SPECIFIED;
269a07b4970SChristoph Hellwig 	port->disc_addr.tsas.rdma.cms = NVMF_RDMA_CMS_RDMA_CM;
270a07b4970SChristoph Hellwig }
271a07b4970SChristoph Hellwig 
272a07b4970SChristoph Hellwig static ssize_t nvmet_addr_trtype_store(struct config_item *item,
273a07b4970SChristoph Hellwig 		const char *page, size_t count)
274a07b4970SChristoph Hellwig {
275a07b4970SChristoph Hellwig 	struct nvmet_port *port = to_nvmet_port(item);
276a5d18612SChristoph Hellwig 	int i;
277a07b4970SChristoph Hellwig 
2783ecb5faaSChaitanya Kulkarni 	if (nvmet_is_port_enabled(port, __func__))
279a07b4970SChristoph Hellwig 		return -EACCES;
280a07b4970SChristoph Hellwig 
28145e2f3c2SChaitanya Kulkarni 	for (i = 0; i < ARRAY_SIZE(nvmet_transport); i++) {
28245e2f3c2SChaitanya Kulkarni 		if (sysfs_streq(page, nvmet_transport[i].name))
283a5d18612SChristoph Hellwig 			goto found;
284a07b4970SChristoph Hellwig 	}
285a07b4970SChristoph Hellwig 
286a5d18612SChristoph Hellwig 	pr_err("Invalid value '%s' for trtype\n", page);
287a5d18612SChristoph Hellwig 	return -EINVAL;
2887e764179SChaitanya Kulkarni 
289a5d18612SChristoph Hellwig found:
290a5d18612SChristoph Hellwig 	memset(&port->disc_addr.tsas, 0, NVMF_TSAS_SIZE);
29145e2f3c2SChaitanya Kulkarni 	port->disc_addr.trtype = nvmet_transport[i].type;
292a5d18612SChristoph Hellwig 	if (port->disc_addr.trtype == NVMF_TRTYPE_RDMA)
293a5d18612SChristoph Hellwig 		nvmet_port_init_tsas_rdma(port);
294a07b4970SChristoph Hellwig 	return count;
295a07b4970SChristoph Hellwig }
296a07b4970SChristoph Hellwig 
297a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_, addr_trtype);
298a07b4970SChristoph Hellwig 
299a07b4970SChristoph Hellwig /*
300a07b4970SChristoph Hellwig  * Namespace structures & file operation functions below
301a07b4970SChristoph Hellwig  */
302a07b4970SChristoph Hellwig static ssize_t nvmet_ns_device_path_show(struct config_item *item, char *page)
303a07b4970SChristoph Hellwig {
304a07b4970SChristoph Hellwig 	return sprintf(page, "%s\n", to_nvmet_ns(item)->device_path);
305a07b4970SChristoph Hellwig }
306a07b4970SChristoph Hellwig 
307a07b4970SChristoph Hellwig static ssize_t nvmet_ns_device_path_store(struct config_item *item,
308a07b4970SChristoph Hellwig 		const char *page, size_t count)
309a07b4970SChristoph Hellwig {
310a07b4970SChristoph Hellwig 	struct nvmet_ns *ns = to_nvmet_ns(item);
311a07b4970SChristoph Hellwig 	struct nvmet_subsys *subsys = ns->subsys;
3125613d312SHannes Reinecke 	size_t len;
313a07b4970SChristoph Hellwig 	int ret;
314a07b4970SChristoph Hellwig 
315a07b4970SChristoph Hellwig 	mutex_lock(&subsys->lock);
316a07b4970SChristoph Hellwig 	ret = -EBUSY;
317e4fcf07cSSolganik Alexander 	if (ns->enabled)
318a07b4970SChristoph Hellwig 		goto out_unlock;
319a07b4970SChristoph Hellwig 
3205613d312SHannes Reinecke 	ret = -EINVAL;
3215613d312SHannes Reinecke 	len = strcspn(page, "\n");
3225613d312SHannes Reinecke 	if (!len)
3235613d312SHannes Reinecke 		goto out_unlock;
324a07b4970SChristoph Hellwig 
3255613d312SHannes Reinecke 	kfree(ns->device_path);
326a07b4970SChristoph Hellwig 	ret = -ENOMEM;
32709bb8986SChen Zhou 	ns->device_path = kmemdup_nul(page, len, GFP_KERNEL);
328a07b4970SChristoph Hellwig 	if (!ns->device_path)
329a07b4970SChristoph Hellwig 		goto out_unlock;
330a07b4970SChristoph Hellwig 
331a07b4970SChristoph Hellwig 	mutex_unlock(&subsys->lock);
332a07b4970SChristoph Hellwig 	return count;
333a07b4970SChristoph Hellwig 
334a07b4970SChristoph Hellwig out_unlock:
335a07b4970SChristoph Hellwig 	mutex_unlock(&subsys->lock);
336a07b4970SChristoph Hellwig 	return ret;
337a07b4970SChristoph Hellwig }
338a07b4970SChristoph Hellwig 
339a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_ns_, device_path);
340a07b4970SChristoph Hellwig 
341c6925093SLogan Gunthorpe #ifdef CONFIG_PCI_P2PDMA
342c6925093SLogan Gunthorpe static ssize_t nvmet_ns_p2pmem_show(struct config_item *item, char *page)
343c6925093SLogan Gunthorpe {
344c6925093SLogan Gunthorpe 	struct nvmet_ns *ns = to_nvmet_ns(item);
345c6925093SLogan Gunthorpe 
346c6925093SLogan Gunthorpe 	return pci_p2pdma_enable_show(page, ns->p2p_dev, ns->use_p2pmem);
347c6925093SLogan Gunthorpe }
348c6925093SLogan Gunthorpe 
349c6925093SLogan Gunthorpe static ssize_t nvmet_ns_p2pmem_store(struct config_item *item,
350c6925093SLogan Gunthorpe 		const char *page, size_t count)
351c6925093SLogan Gunthorpe {
352c6925093SLogan Gunthorpe 	struct nvmet_ns *ns = to_nvmet_ns(item);
353c6925093SLogan Gunthorpe 	struct pci_dev *p2p_dev = NULL;
354c6925093SLogan Gunthorpe 	bool use_p2pmem;
355c6925093SLogan Gunthorpe 	int ret = count;
356c6925093SLogan Gunthorpe 	int error;
357c6925093SLogan Gunthorpe 
358c6925093SLogan Gunthorpe 	mutex_lock(&ns->subsys->lock);
359c6925093SLogan Gunthorpe 	if (ns->enabled) {
360c6925093SLogan Gunthorpe 		ret = -EBUSY;
361c6925093SLogan Gunthorpe 		goto out_unlock;
362c6925093SLogan Gunthorpe 	}
363c6925093SLogan Gunthorpe 
364c6925093SLogan Gunthorpe 	error = pci_p2pdma_enable_store(page, &p2p_dev, &use_p2pmem);
365c6925093SLogan Gunthorpe 	if (error) {
366c6925093SLogan Gunthorpe 		ret = error;
367c6925093SLogan Gunthorpe 		goto out_unlock;
368c6925093SLogan Gunthorpe 	}
369c6925093SLogan Gunthorpe 
370c6925093SLogan Gunthorpe 	ns->use_p2pmem = use_p2pmem;
371c6925093SLogan Gunthorpe 	pci_dev_put(ns->p2p_dev);
372c6925093SLogan Gunthorpe 	ns->p2p_dev = p2p_dev;
373c6925093SLogan Gunthorpe 
374c6925093SLogan Gunthorpe out_unlock:
375c6925093SLogan Gunthorpe 	mutex_unlock(&ns->subsys->lock);
376c6925093SLogan Gunthorpe 
377c6925093SLogan Gunthorpe 	return ret;
378c6925093SLogan Gunthorpe }
379c6925093SLogan Gunthorpe 
380c6925093SLogan Gunthorpe CONFIGFS_ATTR(nvmet_ns_, p2pmem);
381c6925093SLogan Gunthorpe #endif /* CONFIG_PCI_P2PDMA */
382c6925093SLogan Gunthorpe 
383430c7befSJohannes Thumshirn static ssize_t nvmet_ns_device_uuid_show(struct config_item *item, char *page)
384430c7befSJohannes Thumshirn {
385430c7befSJohannes Thumshirn 	return sprintf(page, "%pUb\n", &to_nvmet_ns(item)->uuid);
386430c7befSJohannes Thumshirn }
387430c7befSJohannes Thumshirn 
388430c7befSJohannes Thumshirn static ssize_t nvmet_ns_device_uuid_store(struct config_item *item,
389430c7befSJohannes Thumshirn 					  const char *page, size_t count)
390430c7befSJohannes Thumshirn {
391430c7befSJohannes Thumshirn 	struct nvmet_ns *ns = to_nvmet_ns(item);
392430c7befSJohannes Thumshirn 	struct nvmet_subsys *subsys = ns->subsys;
393430c7befSJohannes Thumshirn 	int ret = 0;
394430c7befSJohannes Thumshirn 
395430c7befSJohannes Thumshirn 	mutex_lock(&subsys->lock);
396430c7befSJohannes Thumshirn 	if (ns->enabled) {
397430c7befSJohannes Thumshirn 		ret = -EBUSY;
398430c7befSJohannes Thumshirn 		goto out_unlock;
399430c7befSJohannes Thumshirn 	}
400430c7befSJohannes Thumshirn 
401430c7befSJohannes Thumshirn 	if (uuid_parse(page, &ns->uuid))
402430c7befSJohannes Thumshirn 		ret = -EINVAL;
403430c7befSJohannes Thumshirn 
404430c7befSJohannes Thumshirn out_unlock:
405430c7befSJohannes Thumshirn 	mutex_unlock(&subsys->lock);
406430c7befSJohannes Thumshirn 	return ret ? ret : count;
407430c7befSJohannes Thumshirn }
408430c7befSJohannes Thumshirn 
409f871749aSMax Gurtovoy CONFIGFS_ATTR(nvmet_ns_, device_uuid);
410f871749aSMax Gurtovoy 
411a07b4970SChristoph Hellwig static ssize_t nvmet_ns_device_nguid_show(struct config_item *item, char *page)
412a07b4970SChristoph Hellwig {
413a07b4970SChristoph Hellwig 	return sprintf(page, "%pUb\n", &to_nvmet_ns(item)->nguid);
414a07b4970SChristoph Hellwig }
415a07b4970SChristoph Hellwig 
416a07b4970SChristoph Hellwig static ssize_t nvmet_ns_device_nguid_store(struct config_item *item,
417a07b4970SChristoph Hellwig 		const char *page, size_t count)
418a07b4970SChristoph Hellwig {
419a07b4970SChristoph Hellwig 	struct nvmet_ns *ns = to_nvmet_ns(item);
420a07b4970SChristoph Hellwig 	struct nvmet_subsys *subsys = ns->subsys;
421a07b4970SChristoph Hellwig 	u8 nguid[16];
422a07b4970SChristoph Hellwig 	const char *p = page;
423a07b4970SChristoph Hellwig 	int i;
424a07b4970SChristoph Hellwig 	int ret = 0;
425a07b4970SChristoph Hellwig 
426a07b4970SChristoph Hellwig 	mutex_lock(&subsys->lock);
427e4fcf07cSSolganik Alexander 	if (ns->enabled) {
428a07b4970SChristoph Hellwig 		ret = -EBUSY;
429a07b4970SChristoph Hellwig 		goto out_unlock;
430a07b4970SChristoph Hellwig 	}
431a07b4970SChristoph Hellwig 
432a07b4970SChristoph Hellwig 	for (i = 0; i < 16; i++) {
433a07b4970SChristoph Hellwig 		if (p + 2 > page + count) {
434a07b4970SChristoph Hellwig 			ret = -EINVAL;
435a07b4970SChristoph Hellwig 			goto out_unlock;
436a07b4970SChristoph Hellwig 		}
437a07b4970SChristoph Hellwig 		if (!isxdigit(p[0]) || !isxdigit(p[1])) {
438a07b4970SChristoph Hellwig 			ret = -EINVAL;
439a07b4970SChristoph Hellwig 			goto out_unlock;
440a07b4970SChristoph Hellwig 		}
441a07b4970SChristoph Hellwig 
442a07b4970SChristoph Hellwig 		nguid[i] = (hex_to_bin(p[0]) << 4) | hex_to_bin(p[1]);
443a07b4970SChristoph Hellwig 		p += 2;
444a07b4970SChristoph Hellwig 
445a07b4970SChristoph Hellwig 		if (*p == '-' || *p == ':')
446a07b4970SChristoph Hellwig 			p++;
447a07b4970SChristoph Hellwig 	}
448a07b4970SChristoph Hellwig 
449a07b4970SChristoph Hellwig 	memcpy(&ns->nguid, nguid, sizeof(nguid));
450a07b4970SChristoph Hellwig out_unlock:
451a07b4970SChristoph Hellwig 	mutex_unlock(&subsys->lock);
452a07b4970SChristoph Hellwig 	return ret ? ret : count;
453a07b4970SChristoph Hellwig }
454a07b4970SChristoph Hellwig 
455a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_ns_, device_nguid);
456a07b4970SChristoph Hellwig 
45762ac0d32SChristoph Hellwig static ssize_t nvmet_ns_ana_grpid_show(struct config_item *item, char *page)
45862ac0d32SChristoph Hellwig {
45962ac0d32SChristoph Hellwig 	return sprintf(page, "%u\n", to_nvmet_ns(item)->anagrpid);
46062ac0d32SChristoph Hellwig }
46162ac0d32SChristoph Hellwig 
46262ac0d32SChristoph Hellwig static ssize_t nvmet_ns_ana_grpid_store(struct config_item *item,
46362ac0d32SChristoph Hellwig 		const char *page, size_t count)
46462ac0d32SChristoph Hellwig {
46562ac0d32SChristoph Hellwig 	struct nvmet_ns *ns = to_nvmet_ns(item);
46662ac0d32SChristoph Hellwig 	u32 oldgrpid, newgrpid;
46762ac0d32SChristoph Hellwig 	int ret;
46862ac0d32SChristoph Hellwig 
46962ac0d32SChristoph Hellwig 	ret = kstrtou32(page, 0, &newgrpid);
47062ac0d32SChristoph Hellwig 	if (ret)
47162ac0d32SChristoph Hellwig 		return ret;
47262ac0d32SChristoph Hellwig 
47362ac0d32SChristoph Hellwig 	if (newgrpid < 1 || newgrpid > NVMET_MAX_ANAGRPS)
47462ac0d32SChristoph Hellwig 		return -EINVAL;
47562ac0d32SChristoph Hellwig 
47662ac0d32SChristoph Hellwig 	down_write(&nvmet_ana_sem);
47762ac0d32SChristoph Hellwig 	oldgrpid = ns->anagrpid;
47862ac0d32SChristoph Hellwig 	nvmet_ana_group_enabled[newgrpid]++;
47962ac0d32SChristoph Hellwig 	ns->anagrpid = newgrpid;
48062ac0d32SChristoph Hellwig 	nvmet_ana_group_enabled[oldgrpid]--;
48162ac0d32SChristoph Hellwig 	nvmet_ana_chgcnt++;
48262ac0d32SChristoph Hellwig 	up_write(&nvmet_ana_sem);
48362ac0d32SChristoph Hellwig 
48462ac0d32SChristoph Hellwig 	nvmet_send_ana_event(ns->subsys, NULL);
48562ac0d32SChristoph Hellwig 	return count;
48662ac0d32SChristoph Hellwig }
48762ac0d32SChristoph Hellwig 
48862ac0d32SChristoph Hellwig CONFIGFS_ATTR(nvmet_ns_, ana_grpid);
48962ac0d32SChristoph Hellwig 
490a07b4970SChristoph Hellwig static ssize_t nvmet_ns_enable_show(struct config_item *item, char *page)
491a07b4970SChristoph Hellwig {
492e4fcf07cSSolganik Alexander 	return sprintf(page, "%d\n", to_nvmet_ns(item)->enabled);
493a07b4970SChristoph Hellwig }
494a07b4970SChristoph Hellwig 
495a07b4970SChristoph Hellwig static ssize_t nvmet_ns_enable_store(struct config_item *item,
496a07b4970SChristoph Hellwig 		const char *page, size_t count)
497a07b4970SChristoph Hellwig {
498a07b4970SChristoph Hellwig 	struct nvmet_ns *ns = to_nvmet_ns(item);
499a07b4970SChristoph Hellwig 	bool enable;
500a07b4970SChristoph Hellwig 	int ret = 0;
501a07b4970SChristoph Hellwig 
502a07b4970SChristoph Hellwig 	if (strtobool(page, &enable))
503a07b4970SChristoph Hellwig 		return -EINVAL;
504a07b4970SChristoph Hellwig 
505a07b4970SChristoph Hellwig 	if (enable)
506a07b4970SChristoph Hellwig 		ret = nvmet_ns_enable(ns);
507a07b4970SChristoph Hellwig 	else
508a07b4970SChristoph Hellwig 		nvmet_ns_disable(ns);
509a07b4970SChristoph Hellwig 
510a07b4970SChristoph Hellwig 	return ret ? ret : count;
511a07b4970SChristoph Hellwig }
512a07b4970SChristoph Hellwig 
513a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_ns_, enable);
514a07b4970SChristoph Hellwig 
51555eb942eSChaitanya Kulkarni static ssize_t nvmet_ns_buffered_io_show(struct config_item *item, char *page)
51655eb942eSChaitanya Kulkarni {
51755eb942eSChaitanya Kulkarni 	return sprintf(page, "%d\n", to_nvmet_ns(item)->buffered_io);
51855eb942eSChaitanya Kulkarni }
51955eb942eSChaitanya Kulkarni 
52055eb942eSChaitanya Kulkarni static ssize_t nvmet_ns_buffered_io_store(struct config_item *item,
52155eb942eSChaitanya Kulkarni 		const char *page, size_t count)
52255eb942eSChaitanya Kulkarni {
52355eb942eSChaitanya Kulkarni 	struct nvmet_ns *ns = to_nvmet_ns(item);
52455eb942eSChaitanya Kulkarni 	bool val;
52555eb942eSChaitanya Kulkarni 
52655eb942eSChaitanya Kulkarni 	if (strtobool(page, &val))
52755eb942eSChaitanya Kulkarni 		return -EINVAL;
52855eb942eSChaitanya Kulkarni 
52955eb942eSChaitanya Kulkarni 	mutex_lock(&ns->subsys->lock);
53055eb942eSChaitanya Kulkarni 	if (ns->enabled) {
53155eb942eSChaitanya Kulkarni 		pr_err("disable ns before setting buffered_io value.\n");
53255eb942eSChaitanya Kulkarni 		mutex_unlock(&ns->subsys->lock);
53355eb942eSChaitanya Kulkarni 		return -EINVAL;
53455eb942eSChaitanya Kulkarni 	}
53555eb942eSChaitanya Kulkarni 
53655eb942eSChaitanya Kulkarni 	ns->buffered_io = val;
53755eb942eSChaitanya Kulkarni 	mutex_unlock(&ns->subsys->lock);
53855eb942eSChaitanya Kulkarni 	return count;
53955eb942eSChaitanya Kulkarni }
54055eb942eSChaitanya Kulkarni 
54155eb942eSChaitanya Kulkarni CONFIGFS_ATTR(nvmet_ns_, buffered_io);
54255eb942eSChaitanya Kulkarni 
5431f357548SChaitanya Kulkarni static ssize_t nvmet_ns_revalidate_size_store(struct config_item *item,
5441f357548SChaitanya Kulkarni 		const char *page, size_t count)
5451f357548SChaitanya Kulkarni {
5461f357548SChaitanya Kulkarni 	struct nvmet_ns *ns = to_nvmet_ns(item);
5471f357548SChaitanya Kulkarni 	bool val;
5481f357548SChaitanya Kulkarni 
5491f357548SChaitanya Kulkarni 	if (strtobool(page, &val))
5501f357548SChaitanya Kulkarni 		return -EINVAL;
5511f357548SChaitanya Kulkarni 
5521f357548SChaitanya Kulkarni 	if (!val)
5531f357548SChaitanya Kulkarni 		return -EINVAL;
5541f357548SChaitanya Kulkarni 
5551f357548SChaitanya Kulkarni 	mutex_lock(&ns->subsys->lock);
5561f357548SChaitanya Kulkarni 	if (!ns->enabled) {
5571f357548SChaitanya Kulkarni 		pr_err("enable ns before revalidate.\n");
5581f357548SChaitanya Kulkarni 		mutex_unlock(&ns->subsys->lock);
5591f357548SChaitanya Kulkarni 		return -EINVAL;
5601f357548SChaitanya Kulkarni 	}
5611f357548SChaitanya Kulkarni 	nvmet_ns_revalidate(ns);
5621f357548SChaitanya Kulkarni 	mutex_unlock(&ns->subsys->lock);
5631f357548SChaitanya Kulkarni 	return count;
5641f357548SChaitanya Kulkarni }
5651f357548SChaitanya Kulkarni 
5661f357548SChaitanya Kulkarni CONFIGFS_ATTR_WO(nvmet_ns_, revalidate_size);
5671f357548SChaitanya Kulkarni 
568a07b4970SChristoph Hellwig static struct configfs_attribute *nvmet_ns_attrs[] = {
569a07b4970SChristoph Hellwig 	&nvmet_ns_attr_device_path,
570a07b4970SChristoph Hellwig 	&nvmet_ns_attr_device_nguid,
571430c7befSJohannes Thumshirn 	&nvmet_ns_attr_device_uuid,
57262ac0d32SChristoph Hellwig 	&nvmet_ns_attr_ana_grpid,
573a07b4970SChristoph Hellwig 	&nvmet_ns_attr_enable,
57455eb942eSChaitanya Kulkarni 	&nvmet_ns_attr_buffered_io,
5751f357548SChaitanya Kulkarni 	&nvmet_ns_attr_revalidate_size,
576c6925093SLogan Gunthorpe #ifdef CONFIG_PCI_P2PDMA
577c6925093SLogan Gunthorpe 	&nvmet_ns_attr_p2pmem,
578c6925093SLogan Gunthorpe #endif
579a07b4970SChristoph Hellwig 	NULL,
580a07b4970SChristoph Hellwig };
581a07b4970SChristoph Hellwig 
582a07b4970SChristoph Hellwig static void nvmet_ns_release(struct config_item *item)
583a07b4970SChristoph Hellwig {
584a07b4970SChristoph Hellwig 	struct nvmet_ns *ns = to_nvmet_ns(item);
585a07b4970SChristoph Hellwig 
586a07b4970SChristoph Hellwig 	nvmet_ns_free(ns);
587a07b4970SChristoph Hellwig }
588a07b4970SChristoph Hellwig 
589a07b4970SChristoph Hellwig static struct configfs_item_operations nvmet_ns_item_ops = {
590a07b4970SChristoph Hellwig 	.release		= nvmet_ns_release,
591a07b4970SChristoph Hellwig };
592a07b4970SChristoph Hellwig 
59366603a31SBhumika Goyal static const struct config_item_type nvmet_ns_type = {
594a07b4970SChristoph Hellwig 	.ct_item_ops		= &nvmet_ns_item_ops,
595a07b4970SChristoph Hellwig 	.ct_attrs		= nvmet_ns_attrs,
596a07b4970SChristoph Hellwig 	.ct_owner		= THIS_MODULE,
597a07b4970SChristoph Hellwig };
598a07b4970SChristoph Hellwig 
599a07b4970SChristoph Hellwig static struct config_group *nvmet_ns_make(struct config_group *group,
600a07b4970SChristoph Hellwig 		const char *name)
601a07b4970SChristoph Hellwig {
602a07b4970SChristoph Hellwig 	struct nvmet_subsys *subsys = namespaces_to_subsys(&group->cg_item);
603a07b4970SChristoph Hellwig 	struct nvmet_ns *ns;
604a07b4970SChristoph Hellwig 	int ret;
605a07b4970SChristoph Hellwig 	u32 nsid;
606a07b4970SChristoph Hellwig 
607a07b4970SChristoph Hellwig 	ret = kstrtou32(name, 0, &nsid);
608a07b4970SChristoph Hellwig 	if (ret)
609a07b4970SChristoph Hellwig 		goto out;
610a07b4970SChristoph Hellwig 
611a07b4970SChristoph Hellwig 	ret = -EINVAL;
6125ba89503SMikhail Skorzhinskii 	if (nsid == 0 || nsid == NVME_NSID_ALL) {
6135ba89503SMikhail Skorzhinskii 		pr_err("invalid nsid %#x", nsid);
614a07b4970SChristoph Hellwig 		goto out;
6155ba89503SMikhail Skorzhinskii 	}
616a07b4970SChristoph Hellwig 
617a07b4970SChristoph Hellwig 	ret = -ENOMEM;
618a07b4970SChristoph Hellwig 	ns = nvmet_ns_alloc(subsys, nsid);
619a07b4970SChristoph Hellwig 	if (!ns)
620a07b4970SChristoph Hellwig 		goto out;
621a07b4970SChristoph Hellwig 	config_group_init_type_name(&ns->group, name, &nvmet_ns_type);
622a07b4970SChristoph Hellwig 
623a07b4970SChristoph Hellwig 	pr_info("adding nsid %d to subsystem %s\n", nsid, subsys->subsysnqn);
624a07b4970SChristoph Hellwig 
625a07b4970SChristoph Hellwig 	return &ns->group;
626a07b4970SChristoph Hellwig out:
627a07b4970SChristoph Hellwig 	return ERR_PTR(ret);
628a07b4970SChristoph Hellwig }
629a07b4970SChristoph Hellwig 
630a07b4970SChristoph Hellwig static struct configfs_group_operations nvmet_namespaces_group_ops = {
631a07b4970SChristoph Hellwig 	.make_group		= nvmet_ns_make,
632a07b4970SChristoph Hellwig };
633a07b4970SChristoph Hellwig 
63466603a31SBhumika Goyal static const struct config_item_type nvmet_namespaces_type = {
635a07b4970SChristoph Hellwig 	.ct_group_ops		= &nvmet_namespaces_group_ops,
636a07b4970SChristoph Hellwig 	.ct_owner		= THIS_MODULE,
637a07b4970SChristoph Hellwig };
638a07b4970SChristoph Hellwig 
639a07b4970SChristoph Hellwig static int nvmet_port_subsys_allow_link(struct config_item *parent,
640a07b4970SChristoph Hellwig 		struct config_item *target)
641a07b4970SChristoph Hellwig {
642a07b4970SChristoph Hellwig 	struct nvmet_port *port = to_nvmet_port(parent->ci_parent);
643a07b4970SChristoph Hellwig 	struct nvmet_subsys *subsys;
644a07b4970SChristoph Hellwig 	struct nvmet_subsys_link *link, *p;
645a07b4970SChristoph Hellwig 	int ret;
646a07b4970SChristoph Hellwig 
647a07b4970SChristoph Hellwig 	if (target->ci_type != &nvmet_subsys_type) {
648a07b4970SChristoph Hellwig 		pr_err("can only link subsystems into the subsystems dir.!\n");
649a07b4970SChristoph Hellwig 		return -EINVAL;
650a07b4970SChristoph Hellwig 	}
651a07b4970SChristoph Hellwig 	subsys = to_subsys(target);
652a07b4970SChristoph Hellwig 	link = kmalloc(sizeof(*link), GFP_KERNEL);
653a07b4970SChristoph Hellwig 	if (!link)
654a07b4970SChristoph Hellwig 		return -ENOMEM;
655a07b4970SChristoph Hellwig 	link->subsys = subsys;
656a07b4970SChristoph Hellwig 
657a07b4970SChristoph Hellwig 	down_write(&nvmet_config_sem);
658a07b4970SChristoph Hellwig 	ret = -EEXIST;
659a07b4970SChristoph Hellwig 	list_for_each_entry(p, &port->subsystems, entry) {
660a07b4970SChristoph Hellwig 		if (p->subsys == subsys)
661a07b4970SChristoph Hellwig 			goto out_free_link;
662a07b4970SChristoph Hellwig 	}
663a07b4970SChristoph Hellwig 
664a07b4970SChristoph Hellwig 	if (list_empty(&port->subsystems)) {
665a07b4970SChristoph Hellwig 		ret = nvmet_enable_port(port);
666a07b4970SChristoph Hellwig 		if (ret)
667a07b4970SChristoph Hellwig 			goto out_free_link;
668a07b4970SChristoph Hellwig 	}
669a07b4970SChristoph Hellwig 
670a07b4970SChristoph Hellwig 	list_add_tail(&link->entry, &port->subsystems);
671b662a078SJay Sternberg 	nvmet_port_disc_changed(port, subsys);
672b662a078SJay Sternberg 
673a07b4970SChristoph Hellwig 	up_write(&nvmet_config_sem);
674a07b4970SChristoph Hellwig 	return 0;
675a07b4970SChristoph Hellwig 
676a07b4970SChristoph Hellwig out_free_link:
677a07b4970SChristoph Hellwig 	up_write(&nvmet_config_sem);
678a07b4970SChristoph Hellwig 	kfree(link);
679a07b4970SChristoph Hellwig 	return ret;
680a07b4970SChristoph Hellwig }
681a07b4970SChristoph Hellwig 
682e16769d4SAndrzej Pietrasiewicz static void nvmet_port_subsys_drop_link(struct config_item *parent,
683a07b4970SChristoph Hellwig 		struct config_item *target)
684a07b4970SChristoph Hellwig {
685a07b4970SChristoph Hellwig 	struct nvmet_port *port = to_nvmet_port(parent->ci_parent);
686a07b4970SChristoph Hellwig 	struct nvmet_subsys *subsys = to_subsys(target);
687a07b4970SChristoph Hellwig 	struct nvmet_subsys_link *p;
688a07b4970SChristoph Hellwig 
689a07b4970SChristoph Hellwig 	down_write(&nvmet_config_sem);
690a07b4970SChristoph Hellwig 	list_for_each_entry(p, &port->subsystems, entry) {
691a07b4970SChristoph Hellwig 		if (p->subsys == subsys)
692a07b4970SChristoph Hellwig 			goto found;
693a07b4970SChristoph Hellwig 	}
694a07b4970SChristoph Hellwig 	up_write(&nvmet_config_sem);
695e16769d4SAndrzej Pietrasiewicz 	return;
696a07b4970SChristoph Hellwig 
697a07b4970SChristoph Hellwig found:
698a07b4970SChristoph Hellwig 	list_del(&p->entry);
6993aed8673SLogan Gunthorpe 	nvmet_port_del_ctrls(port, subsys);
700b662a078SJay Sternberg 	nvmet_port_disc_changed(port, subsys);
701b662a078SJay Sternberg 
702a07b4970SChristoph Hellwig 	if (list_empty(&port->subsystems))
703a07b4970SChristoph Hellwig 		nvmet_disable_port(port);
704a07b4970SChristoph Hellwig 	up_write(&nvmet_config_sem);
705a07b4970SChristoph Hellwig 	kfree(p);
706a07b4970SChristoph Hellwig }
707a07b4970SChristoph Hellwig 
708a07b4970SChristoph Hellwig static struct configfs_item_operations nvmet_port_subsys_item_ops = {
709a07b4970SChristoph Hellwig 	.allow_link		= nvmet_port_subsys_allow_link,
710a07b4970SChristoph Hellwig 	.drop_link		= nvmet_port_subsys_drop_link,
711a07b4970SChristoph Hellwig };
712a07b4970SChristoph Hellwig 
71366603a31SBhumika Goyal static const struct config_item_type nvmet_port_subsys_type = {
714a07b4970SChristoph Hellwig 	.ct_item_ops		= &nvmet_port_subsys_item_ops,
715a07b4970SChristoph Hellwig 	.ct_owner		= THIS_MODULE,
716a07b4970SChristoph Hellwig };
717a07b4970SChristoph Hellwig 
718a07b4970SChristoph Hellwig static int nvmet_allowed_hosts_allow_link(struct config_item *parent,
719a07b4970SChristoph Hellwig 		struct config_item *target)
720a07b4970SChristoph Hellwig {
721a07b4970SChristoph Hellwig 	struct nvmet_subsys *subsys = to_subsys(parent->ci_parent);
722a07b4970SChristoph Hellwig 	struct nvmet_host *host;
723a07b4970SChristoph Hellwig 	struct nvmet_host_link *link, *p;
724a07b4970SChristoph Hellwig 	int ret;
725a07b4970SChristoph Hellwig 
726a07b4970SChristoph Hellwig 	if (target->ci_type != &nvmet_host_type) {
727a07b4970SChristoph Hellwig 		pr_err("can only link hosts into the allowed_hosts directory!\n");
728a07b4970SChristoph Hellwig 		return -EINVAL;
729a07b4970SChristoph Hellwig 	}
730a07b4970SChristoph Hellwig 
731a07b4970SChristoph Hellwig 	host = to_host(target);
732a07b4970SChristoph Hellwig 	link = kmalloc(sizeof(*link), GFP_KERNEL);
733a07b4970SChristoph Hellwig 	if (!link)
734a07b4970SChristoph Hellwig 		return -ENOMEM;
735a07b4970SChristoph Hellwig 	link->host = host;
736a07b4970SChristoph Hellwig 
737a07b4970SChristoph Hellwig 	down_write(&nvmet_config_sem);
738a07b4970SChristoph Hellwig 	ret = -EINVAL;
739a07b4970SChristoph Hellwig 	if (subsys->allow_any_host) {
740a07b4970SChristoph Hellwig 		pr_err("can't add hosts when allow_any_host is set!\n");
741a07b4970SChristoph Hellwig 		goto out_free_link;
742a07b4970SChristoph Hellwig 	}
743a07b4970SChristoph Hellwig 
744a07b4970SChristoph Hellwig 	ret = -EEXIST;
745a07b4970SChristoph Hellwig 	list_for_each_entry(p, &subsys->hosts, entry) {
746a07b4970SChristoph Hellwig 		if (!strcmp(nvmet_host_name(p->host), nvmet_host_name(host)))
747a07b4970SChristoph Hellwig 			goto out_free_link;
748a07b4970SChristoph Hellwig 	}
749a07b4970SChristoph Hellwig 	list_add_tail(&link->entry, &subsys->hosts);
750b662a078SJay Sternberg 	nvmet_subsys_disc_changed(subsys, host);
751b662a078SJay Sternberg 
752a07b4970SChristoph Hellwig 	up_write(&nvmet_config_sem);
753a07b4970SChristoph Hellwig 	return 0;
754a07b4970SChristoph Hellwig out_free_link:
755a07b4970SChristoph Hellwig 	up_write(&nvmet_config_sem);
756a07b4970SChristoph Hellwig 	kfree(link);
757a07b4970SChristoph Hellwig 	return ret;
758a07b4970SChristoph Hellwig }
759a07b4970SChristoph Hellwig 
760e16769d4SAndrzej Pietrasiewicz static void nvmet_allowed_hosts_drop_link(struct config_item *parent,
761a07b4970SChristoph Hellwig 		struct config_item *target)
762a07b4970SChristoph Hellwig {
763a07b4970SChristoph Hellwig 	struct nvmet_subsys *subsys = to_subsys(parent->ci_parent);
764a07b4970SChristoph Hellwig 	struct nvmet_host *host = to_host(target);
765a07b4970SChristoph Hellwig 	struct nvmet_host_link *p;
766a07b4970SChristoph Hellwig 
767a07b4970SChristoph Hellwig 	down_write(&nvmet_config_sem);
768a07b4970SChristoph Hellwig 	list_for_each_entry(p, &subsys->hosts, entry) {
769a07b4970SChristoph Hellwig 		if (!strcmp(nvmet_host_name(p->host), nvmet_host_name(host)))
770a07b4970SChristoph Hellwig 			goto found;
771a07b4970SChristoph Hellwig 	}
772a07b4970SChristoph Hellwig 	up_write(&nvmet_config_sem);
773e16769d4SAndrzej Pietrasiewicz 	return;
774a07b4970SChristoph Hellwig 
775a07b4970SChristoph Hellwig found:
776a07b4970SChristoph Hellwig 	list_del(&p->entry);
777b662a078SJay Sternberg 	nvmet_subsys_disc_changed(subsys, host);
778b662a078SJay Sternberg 
779a07b4970SChristoph Hellwig 	up_write(&nvmet_config_sem);
780a07b4970SChristoph Hellwig 	kfree(p);
781a07b4970SChristoph Hellwig }
782a07b4970SChristoph Hellwig 
783a07b4970SChristoph Hellwig static struct configfs_item_operations nvmet_allowed_hosts_item_ops = {
784a07b4970SChristoph Hellwig 	.allow_link		= nvmet_allowed_hosts_allow_link,
785a07b4970SChristoph Hellwig 	.drop_link		= nvmet_allowed_hosts_drop_link,
786a07b4970SChristoph Hellwig };
787a07b4970SChristoph Hellwig 
78866603a31SBhumika Goyal static const struct config_item_type nvmet_allowed_hosts_type = {
789a07b4970SChristoph Hellwig 	.ct_item_ops		= &nvmet_allowed_hosts_item_ops,
790a07b4970SChristoph Hellwig 	.ct_owner		= THIS_MODULE,
791a07b4970SChristoph Hellwig };
792a07b4970SChristoph Hellwig 
793a07b4970SChristoph Hellwig static ssize_t nvmet_subsys_attr_allow_any_host_show(struct config_item *item,
794a07b4970SChristoph Hellwig 		char *page)
795a07b4970SChristoph Hellwig {
796a07b4970SChristoph Hellwig 	return snprintf(page, PAGE_SIZE, "%d\n",
797a07b4970SChristoph Hellwig 		to_subsys(item)->allow_any_host);
798a07b4970SChristoph Hellwig }
799a07b4970SChristoph Hellwig 
800a07b4970SChristoph Hellwig static ssize_t nvmet_subsys_attr_allow_any_host_store(struct config_item *item,
801a07b4970SChristoph Hellwig 		const char *page, size_t count)
802a07b4970SChristoph Hellwig {
803a07b4970SChristoph Hellwig 	struct nvmet_subsys *subsys = to_subsys(item);
804a07b4970SChristoph Hellwig 	bool allow_any_host;
805a07b4970SChristoph Hellwig 	int ret = 0;
806a07b4970SChristoph Hellwig 
807a07b4970SChristoph Hellwig 	if (strtobool(page, &allow_any_host))
808a07b4970SChristoph Hellwig 		return -EINVAL;
809a07b4970SChristoph Hellwig 
810a07b4970SChristoph Hellwig 	down_write(&nvmet_config_sem);
811a07b4970SChristoph Hellwig 	if (allow_any_host && !list_empty(&subsys->hosts)) {
812a07b4970SChristoph Hellwig 		pr_err("Can't set allow_any_host when explicit hosts are set!\n");
813a07b4970SChristoph Hellwig 		ret = -EINVAL;
814a07b4970SChristoph Hellwig 		goto out_unlock;
815a07b4970SChristoph Hellwig 	}
816a07b4970SChristoph Hellwig 
817b662a078SJay Sternberg 	if (subsys->allow_any_host != allow_any_host) {
818a07b4970SChristoph Hellwig 		subsys->allow_any_host = allow_any_host;
819b662a078SJay Sternberg 		nvmet_subsys_disc_changed(subsys, NULL);
820b662a078SJay Sternberg 	}
821b662a078SJay Sternberg 
822a07b4970SChristoph Hellwig out_unlock:
823a07b4970SChristoph Hellwig 	up_write(&nvmet_config_sem);
824a07b4970SChristoph Hellwig 	return ret ? ret : count;
825a07b4970SChristoph Hellwig }
826a07b4970SChristoph Hellwig 
827a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_subsys_, attr_allow_any_host);
828a07b4970SChristoph Hellwig 
82941528f80SJohannes Thumshirn static ssize_t nvmet_subsys_attr_version_show(struct config_item *item,
830c61d788bSJohannes Thumshirn 					      char *page)
831c61d788bSJohannes Thumshirn {
832c61d788bSJohannes Thumshirn 	struct nvmet_subsys *subsys = to_subsys(item);
833c61d788bSJohannes Thumshirn 
834c61d788bSJohannes Thumshirn 	if (NVME_TERTIARY(subsys->ver))
835c61d788bSJohannes Thumshirn 		return snprintf(page, PAGE_SIZE, "%d.%d.%d\n",
836c61d788bSJohannes Thumshirn 				(int)NVME_MAJOR(subsys->ver),
837c61d788bSJohannes Thumshirn 				(int)NVME_MINOR(subsys->ver),
838c61d788bSJohannes Thumshirn 				(int)NVME_TERTIARY(subsys->ver));
839527123c7SChaitanya Kulkarni 
840c61d788bSJohannes Thumshirn 	return snprintf(page, PAGE_SIZE, "%d.%d\n",
841c61d788bSJohannes Thumshirn 			(int)NVME_MAJOR(subsys->ver),
842c61d788bSJohannes Thumshirn 			(int)NVME_MINOR(subsys->ver));
843c61d788bSJohannes Thumshirn }
844c61d788bSJohannes Thumshirn 
84541528f80SJohannes Thumshirn static ssize_t nvmet_subsys_attr_version_store(struct config_item *item,
846c61d788bSJohannes Thumshirn 					       const char *page, size_t count)
847c61d788bSJohannes Thumshirn {
848c61d788bSJohannes Thumshirn 	struct nvmet_subsys *subsys = to_subsys(item);
849c61d788bSJohannes Thumshirn 	int major, minor, tertiary = 0;
850c61d788bSJohannes Thumshirn 	int ret;
851c61d788bSJohannes Thumshirn 
852c61d788bSJohannes Thumshirn 	ret = sscanf(page, "%d.%d.%d\n", &major, &minor, &tertiary);
853c61d788bSJohannes Thumshirn 	if (ret != 2 && ret != 3)
854c61d788bSJohannes Thumshirn 		return -EINVAL;
855c61d788bSJohannes Thumshirn 
856c61d788bSJohannes Thumshirn 	down_write(&nvmet_config_sem);
857c61d788bSJohannes Thumshirn 	subsys->ver = NVME_VS(major, minor, tertiary);
858c61d788bSJohannes Thumshirn 	up_write(&nvmet_config_sem);
859c61d788bSJohannes Thumshirn 
860c61d788bSJohannes Thumshirn 	return count;
861c61d788bSJohannes Thumshirn }
86241528f80SJohannes Thumshirn CONFIGFS_ATTR(nvmet_subsys_, attr_version);
863c61d788bSJohannes Thumshirn 
864fcbc5459SJohannes Thumshirn static ssize_t nvmet_subsys_attr_serial_show(struct config_item *item,
865fcbc5459SJohannes Thumshirn 					     char *page)
866fcbc5459SJohannes Thumshirn {
867fcbc5459SJohannes Thumshirn 	struct nvmet_subsys *subsys = to_subsys(item);
868fcbc5459SJohannes Thumshirn 
869fcbc5459SJohannes Thumshirn 	return snprintf(page, PAGE_SIZE, "%llx\n", subsys->serial);
870fcbc5459SJohannes Thumshirn }
871fcbc5459SJohannes Thumshirn 
872fcbc5459SJohannes Thumshirn static ssize_t nvmet_subsys_attr_serial_store(struct config_item *item,
873fcbc5459SJohannes Thumshirn 					      const char *page, size_t count)
874fcbc5459SJohannes Thumshirn {
875d3a9b0caSChaitanya Kulkarni 	u64 serial;
876d3a9b0caSChaitanya Kulkarni 
877d3a9b0caSChaitanya Kulkarni 	if (sscanf(page, "%llx\n", &serial) != 1)
878d3a9b0caSChaitanya Kulkarni 		return -EINVAL;
879fcbc5459SJohannes Thumshirn 
880fcbc5459SJohannes Thumshirn 	down_write(&nvmet_config_sem);
881d3a9b0caSChaitanya Kulkarni 	to_subsys(item)->serial = serial;
882fcbc5459SJohannes Thumshirn 	up_write(&nvmet_config_sem);
883fcbc5459SJohannes Thumshirn 
884fcbc5459SJohannes Thumshirn 	return count;
885fcbc5459SJohannes Thumshirn }
886fcbc5459SJohannes Thumshirn CONFIGFS_ATTR(nvmet_subsys_, attr_serial);
887fcbc5459SJohannes Thumshirn 
88894a39d61SChaitanya Kulkarni static ssize_t nvmet_subsys_attr_cntlid_min_show(struct config_item *item,
88994a39d61SChaitanya Kulkarni 						 char *page)
89094a39d61SChaitanya Kulkarni {
89194a39d61SChaitanya Kulkarni 	return snprintf(page, PAGE_SIZE, "%u\n", to_subsys(item)->cntlid_min);
89294a39d61SChaitanya Kulkarni }
89394a39d61SChaitanya Kulkarni 
89494a39d61SChaitanya Kulkarni static ssize_t nvmet_subsys_attr_cntlid_min_store(struct config_item *item,
89594a39d61SChaitanya Kulkarni 						  const char *page, size_t cnt)
89694a39d61SChaitanya Kulkarni {
89794a39d61SChaitanya Kulkarni 	u16 cntlid_min;
89894a39d61SChaitanya Kulkarni 
89994a39d61SChaitanya Kulkarni 	if (sscanf(page, "%hu\n", &cntlid_min) != 1)
90094a39d61SChaitanya Kulkarni 		return -EINVAL;
90194a39d61SChaitanya Kulkarni 
90294a39d61SChaitanya Kulkarni 	if (cntlid_min == 0)
90394a39d61SChaitanya Kulkarni 		return -EINVAL;
90494a39d61SChaitanya Kulkarni 
90594a39d61SChaitanya Kulkarni 	down_write(&nvmet_config_sem);
90694a39d61SChaitanya Kulkarni 	if (cntlid_min >= to_subsys(item)->cntlid_max)
90794a39d61SChaitanya Kulkarni 		goto out_unlock;
90894a39d61SChaitanya Kulkarni 	to_subsys(item)->cntlid_min = cntlid_min;
90994a39d61SChaitanya Kulkarni 	up_write(&nvmet_config_sem);
91094a39d61SChaitanya Kulkarni 	return cnt;
91194a39d61SChaitanya Kulkarni 
91294a39d61SChaitanya Kulkarni out_unlock:
91394a39d61SChaitanya Kulkarni 	up_write(&nvmet_config_sem);
91494a39d61SChaitanya Kulkarni 	return -EINVAL;
91594a39d61SChaitanya Kulkarni }
91694a39d61SChaitanya Kulkarni CONFIGFS_ATTR(nvmet_subsys_, attr_cntlid_min);
91794a39d61SChaitanya Kulkarni 
91894a39d61SChaitanya Kulkarni static ssize_t nvmet_subsys_attr_cntlid_max_show(struct config_item *item,
91994a39d61SChaitanya Kulkarni 						 char *page)
92094a39d61SChaitanya Kulkarni {
92194a39d61SChaitanya Kulkarni 	return snprintf(page, PAGE_SIZE, "%u\n", to_subsys(item)->cntlid_max);
92294a39d61SChaitanya Kulkarni }
92394a39d61SChaitanya Kulkarni 
92494a39d61SChaitanya Kulkarni static ssize_t nvmet_subsys_attr_cntlid_max_store(struct config_item *item,
92594a39d61SChaitanya Kulkarni 						  const char *page, size_t cnt)
92694a39d61SChaitanya Kulkarni {
92794a39d61SChaitanya Kulkarni 	u16 cntlid_max;
92894a39d61SChaitanya Kulkarni 
92994a39d61SChaitanya Kulkarni 	if (sscanf(page, "%hu\n", &cntlid_max) != 1)
93094a39d61SChaitanya Kulkarni 		return -EINVAL;
93194a39d61SChaitanya Kulkarni 
93294a39d61SChaitanya Kulkarni 	if (cntlid_max == 0)
93394a39d61SChaitanya Kulkarni 		return -EINVAL;
93494a39d61SChaitanya Kulkarni 
93594a39d61SChaitanya Kulkarni 	down_write(&nvmet_config_sem);
93694a39d61SChaitanya Kulkarni 	if (cntlid_max <= to_subsys(item)->cntlid_min)
93794a39d61SChaitanya Kulkarni 		goto out_unlock;
93894a39d61SChaitanya Kulkarni 	to_subsys(item)->cntlid_max = cntlid_max;
93994a39d61SChaitanya Kulkarni 	up_write(&nvmet_config_sem);
94094a39d61SChaitanya Kulkarni 	return cnt;
94194a39d61SChaitanya Kulkarni 
94294a39d61SChaitanya Kulkarni out_unlock:
94394a39d61SChaitanya Kulkarni 	up_write(&nvmet_config_sem);
94494a39d61SChaitanya Kulkarni 	return -EINVAL;
94594a39d61SChaitanya Kulkarni }
94694a39d61SChaitanya Kulkarni CONFIGFS_ATTR(nvmet_subsys_, attr_cntlid_max);
94794a39d61SChaitanya Kulkarni 
948013b7ebeSMark Ruijter static ssize_t nvmet_subsys_attr_model_show(struct config_item *item,
949013b7ebeSMark Ruijter 					    char *page)
950013b7ebeSMark Ruijter {
951013b7ebeSMark Ruijter 	struct nvmet_subsys *subsys = to_subsys(item);
952013b7ebeSMark Ruijter 	struct nvmet_subsys_model *subsys_model;
953013b7ebeSMark Ruijter 	char *model = NVMET_DEFAULT_CTRL_MODEL;
954013b7ebeSMark Ruijter 	int ret;
955013b7ebeSMark Ruijter 
956013b7ebeSMark Ruijter 	rcu_read_lock();
957013b7ebeSMark Ruijter 	subsys_model = rcu_dereference(subsys->model);
958013b7ebeSMark Ruijter 	if (subsys_model)
959013b7ebeSMark Ruijter 		model = subsys_model->number;
960013b7ebeSMark Ruijter 	ret = snprintf(page, PAGE_SIZE, "%s\n", model);
961013b7ebeSMark Ruijter 	rcu_read_unlock();
962013b7ebeSMark Ruijter 
963013b7ebeSMark Ruijter 	return ret;
964013b7ebeSMark Ruijter }
965013b7ebeSMark Ruijter 
966013b7ebeSMark Ruijter /* See Section 1.5 of NVMe 1.4 */
967013b7ebeSMark Ruijter static bool nvmet_is_ascii(const char c)
968013b7ebeSMark Ruijter {
969013b7ebeSMark Ruijter 	return c >= 0x20 && c <= 0x7e;
970013b7ebeSMark Ruijter }
971013b7ebeSMark Ruijter 
972013b7ebeSMark Ruijter static ssize_t nvmet_subsys_attr_model_store(struct config_item *item,
973013b7ebeSMark Ruijter 					     const char *page, size_t count)
974013b7ebeSMark Ruijter {
975013b7ebeSMark Ruijter 	struct nvmet_subsys *subsys = to_subsys(item);
976013b7ebeSMark Ruijter 	struct nvmet_subsys_model *new_model;
977013b7ebeSMark Ruijter 	char *new_model_number;
978013b7ebeSMark Ruijter 	int pos = 0, len;
979013b7ebeSMark Ruijter 
980013b7ebeSMark Ruijter 	len = strcspn(page, "\n");
981013b7ebeSMark Ruijter 	if (!len)
982013b7ebeSMark Ruijter 		return -EINVAL;
983013b7ebeSMark Ruijter 
984013b7ebeSMark Ruijter 	for (pos = 0; pos < len; pos++) {
985013b7ebeSMark Ruijter 		if (!nvmet_is_ascii(page[pos]))
986013b7ebeSMark Ruijter 			return -EINVAL;
987013b7ebeSMark Ruijter 	}
988013b7ebeSMark Ruijter 
98909bb8986SChen Zhou 	new_model_number = kmemdup_nul(page, len, GFP_KERNEL);
990013b7ebeSMark Ruijter 	if (!new_model_number)
991013b7ebeSMark Ruijter 		return -ENOMEM;
992013b7ebeSMark Ruijter 
993013b7ebeSMark Ruijter 	new_model = kzalloc(sizeof(*new_model) + len + 1, GFP_KERNEL);
994013b7ebeSMark Ruijter 	if (!new_model) {
995013b7ebeSMark Ruijter 		kfree(new_model_number);
996013b7ebeSMark Ruijter 		return -ENOMEM;
997013b7ebeSMark Ruijter 	}
998013b7ebeSMark Ruijter 	memcpy(new_model->number, new_model_number, len);
999013b7ebeSMark Ruijter 
1000013b7ebeSMark Ruijter 	down_write(&nvmet_config_sem);
1001013b7ebeSMark Ruijter 	mutex_lock(&subsys->lock);
1002013b7ebeSMark Ruijter 	new_model = rcu_replace_pointer(subsys->model, new_model,
1003013b7ebeSMark Ruijter 					mutex_is_locked(&subsys->lock));
1004013b7ebeSMark Ruijter 	mutex_unlock(&subsys->lock);
1005013b7ebeSMark Ruijter 	up_write(&nvmet_config_sem);
1006013b7ebeSMark Ruijter 
1007013b7ebeSMark Ruijter 	kfree_rcu(new_model, rcuhead);
1008013b7ebeSMark Ruijter 
1009013b7ebeSMark Ruijter 	return count;
1010013b7ebeSMark Ruijter }
1011013b7ebeSMark Ruijter CONFIGFS_ATTR(nvmet_subsys_, attr_model);
1012013b7ebeSMark Ruijter 
1013a07b4970SChristoph Hellwig static struct configfs_attribute *nvmet_subsys_attrs[] = {
1014a07b4970SChristoph Hellwig 	&nvmet_subsys_attr_attr_allow_any_host,
101541528f80SJohannes Thumshirn 	&nvmet_subsys_attr_attr_version,
1016fcbc5459SJohannes Thumshirn 	&nvmet_subsys_attr_attr_serial,
101794a39d61SChaitanya Kulkarni 	&nvmet_subsys_attr_attr_cntlid_min,
101894a39d61SChaitanya Kulkarni 	&nvmet_subsys_attr_attr_cntlid_max,
1019013b7ebeSMark Ruijter 	&nvmet_subsys_attr_attr_model,
1020a07b4970SChristoph Hellwig 	NULL,
1021a07b4970SChristoph Hellwig };
1022a07b4970SChristoph Hellwig 
1023a07b4970SChristoph Hellwig /*
1024a07b4970SChristoph Hellwig  * Subsystem structures & folder operation functions below
1025a07b4970SChristoph Hellwig  */
1026a07b4970SChristoph Hellwig static void nvmet_subsys_release(struct config_item *item)
1027a07b4970SChristoph Hellwig {
1028a07b4970SChristoph Hellwig 	struct nvmet_subsys *subsys = to_subsys(item);
1029a07b4970SChristoph Hellwig 
1030344770b0SSagi Grimberg 	nvmet_subsys_del_ctrls(subsys);
1031a07b4970SChristoph Hellwig 	nvmet_subsys_put(subsys);
1032a07b4970SChristoph Hellwig }
1033a07b4970SChristoph Hellwig 
1034a07b4970SChristoph Hellwig static struct configfs_item_operations nvmet_subsys_item_ops = {
1035a07b4970SChristoph Hellwig 	.release		= nvmet_subsys_release,
1036a07b4970SChristoph Hellwig };
1037a07b4970SChristoph Hellwig 
103866603a31SBhumika Goyal static const struct config_item_type nvmet_subsys_type = {
1039a07b4970SChristoph Hellwig 	.ct_item_ops		= &nvmet_subsys_item_ops,
1040a07b4970SChristoph Hellwig 	.ct_attrs		= nvmet_subsys_attrs,
1041a07b4970SChristoph Hellwig 	.ct_owner		= THIS_MODULE,
1042a07b4970SChristoph Hellwig };
1043a07b4970SChristoph Hellwig 
1044a07b4970SChristoph Hellwig static struct config_group *nvmet_subsys_make(struct config_group *group,
1045a07b4970SChristoph Hellwig 		const char *name)
1046a07b4970SChristoph Hellwig {
1047a07b4970SChristoph Hellwig 	struct nvmet_subsys *subsys;
1048a07b4970SChristoph Hellwig 
1049a07b4970SChristoph Hellwig 	if (sysfs_streq(name, NVME_DISC_SUBSYS_NAME)) {
1050a07b4970SChristoph Hellwig 		pr_err("can't create discovery subsystem through configfs\n");
1051a07b4970SChristoph Hellwig 		return ERR_PTR(-EINVAL);
1052a07b4970SChristoph Hellwig 	}
1053a07b4970SChristoph Hellwig 
1054a07b4970SChristoph Hellwig 	subsys = nvmet_subsys_alloc(name, NVME_NQN_NVME);
10556b7e631bSMinwoo Im 	if (IS_ERR(subsys))
10566b7e631bSMinwoo Im 		return ERR_CAST(subsys);
1057a07b4970SChristoph Hellwig 
1058a07b4970SChristoph Hellwig 	config_group_init_type_name(&subsys->group, name, &nvmet_subsys_type);
1059a07b4970SChristoph Hellwig 
1060a07b4970SChristoph Hellwig 	config_group_init_type_name(&subsys->namespaces_group,
1061a07b4970SChristoph Hellwig 			"namespaces", &nvmet_namespaces_type);
1062a07b4970SChristoph Hellwig 	configfs_add_default_group(&subsys->namespaces_group, &subsys->group);
1063a07b4970SChristoph Hellwig 
1064a07b4970SChristoph Hellwig 	config_group_init_type_name(&subsys->allowed_hosts_group,
1065a07b4970SChristoph Hellwig 			"allowed_hosts", &nvmet_allowed_hosts_type);
1066a07b4970SChristoph Hellwig 	configfs_add_default_group(&subsys->allowed_hosts_group,
1067a07b4970SChristoph Hellwig 			&subsys->group);
1068a07b4970SChristoph Hellwig 
1069a07b4970SChristoph Hellwig 	return &subsys->group;
1070a07b4970SChristoph Hellwig }
1071a07b4970SChristoph Hellwig 
1072a07b4970SChristoph Hellwig static struct configfs_group_operations nvmet_subsystems_group_ops = {
1073a07b4970SChristoph Hellwig 	.make_group		= nvmet_subsys_make,
1074a07b4970SChristoph Hellwig };
1075a07b4970SChristoph Hellwig 
107666603a31SBhumika Goyal static const struct config_item_type nvmet_subsystems_type = {
1077a07b4970SChristoph Hellwig 	.ct_group_ops		= &nvmet_subsystems_group_ops,
1078a07b4970SChristoph Hellwig 	.ct_owner		= THIS_MODULE,
1079a07b4970SChristoph Hellwig };
1080a07b4970SChristoph Hellwig 
1081a07b4970SChristoph Hellwig static ssize_t nvmet_referral_enable_show(struct config_item *item,
1082a07b4970SChristoph Hellwig 		char *page)
1083a07b4970SChristoph Hellwig {
1084a07b4970SChristoph Hellwig 	return snprintf(page, PAGE_SIZE, "%d\n", to_nvmet_port(item)->enabled);
1085a07b4970SChristoph Hellwig }
1086a07b4970SChristoph Hellwig 
1087a07b4970SChristoph Hellwig static ssize_t nvmet_referral_enable_store(struct config_item *item,
1088a07b4970SChristoph Hellwig 		const char *page, size_t count)
1089a07b4970SChristoph Hellwig {
1090a07b4970SChristoph Hellwig 	struct nvmet_port *parent = to_nvmet_port(item->ci_parent->ci_parent);
1091a07b4970SChristoph Hellwig 	struct nvmet_port *port = to_nvmet_port(item);
1092a07b4970SChristoph Hellwig 	bool enable;
1093a07b4970SChristoph Hellwig 
1094a07b4970SChristoph Hellwig 	if (strtobool(page, &enable))
1095a07b4970SChristoph Hellwig 		goto inval;
1096a07b4970SChristoph Hellwig 
1097a07b4970SChristoph Hellwig 	if (enable)
1098a07b4970SChristoph Hellwig 		nvmet_referral_enable(parent, port);
1099a07b4970SChristoph Hellwig 	else
1100b662a078SJay Sternberg 		nvmet_referral_disable(parent, port);
1101a07b4970SChristoph Hellwig 
1102a07b4970SChristoph Hellwig 	return count;
1103a07b4970SChristoph Hellwig inval:
1104a07b4970SChristoph Hellwig 	pr_err("Invalid value '%s' for enable\n", page);
1105a07b4970SChristoph Hellwig 	return -EINVAL;
1106a07b4970SChristoph Hellwig }
1107a07b4970SChristoph Hellwig 
1108a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_referral_, enable);
1109a07b4970SChristoph Hellwig 
1110a07b4970SChristoph Hellwig /*
1111a07b4970SChristoph Hellwig  * Discovery Service subsystem definitions
1112a07b4970SChristoph Hellwig  */
1113a07b4970SChristoph Hellwig static struct configfs_attribute *nvmet_referral_attrs[] = {
1114a07b4970SChristoph Hellwig 	&nvmet_attr_addr_adrfam,
1115a07b4970SChristoph Hellwig 	&nvmet_attr_addr_portid,
1116a07b4970SChristoph Hellwig 	&nvmet_attr_addr_treq,
1117a07b4970SChristoph Hellwig 	&nvmet_attr_addr_traddr,
1118a07b4970SChristoph Hellwig 	&nvmet_attr_addr_trsvcid,
1119a07b4970SChristoph Hellwig 	&nvmet_attr_addr_trtype,
1120a07b4970SChristoph Hellwig 	&nvmet_referral_attr_enable,
1121a07b4970SChristoph Hellwig 	NULL,
1122a07b4970SChristoph Hellwig };
1123a07b4970SChristoph Hellwig 
1124f0e656e4SSagi Grimberg static void nvmet_referral_notify(struct config_group *group,
1125f0e656e4SSagi Grimberg 		struct config_item *item)
1126a07b4970SChristoph Hellwig {
1127b662a078SJay Sternberg 	struct nvmet_port *parent = to_nvmet_port(item->ci_parent->ci_parent);
1128a07b4970SChristoph Hellwig 	struct nvmet_port *port = to_nvmet_port(item);
1129a07b4970SChristoph Hellwig 
1130b662a078SJay Sternberg 	nvmet_referral_disable(parent, port);
1131f0e656e4SSagi Grimberg }
1132f0e656e4SSagi Grimberg 
1133f0e656e4SSagi Grimberg static void nvmet_referral_release(struct config_item *item)
1134f0e656e4SSagi Grimberg {
1135f0e656e4SSagi Grimberg 	struct nvmet_port *port = to_nvmet_port(item);
1136f0e656e4SSagi Grimberg 
1137a07b4970SChristoph Hellwig 	kfree(port);
1138a07b4970SChristoph Hellwig }
1139a07b4970SChristoph Hellwig 
1140a07b4970SChristoph Hellwig static struct configfs_item_operations nvmet_referral_item_ops = {
1141a07b4970SChristoph Hellwig 	.release	= nvmet_referral_release,
1142a07b4970SChristoph Hellwig };
1143a07b4970SChristoph Hellwig 
114466603a31SBhumika Goyal static const struct config_item_type nvmet_referral_type = {
1145a07b4970SChristoph Hellwig 	.ct_owner	= THIS_MODULE,
1146a07b4970SChristoph Hellwig 	.ct_attrs	= nvmet_referral_attrs,
1147a07b4970SChristoph Hellwig 	.ct_item_ops	= &nvmet_referral_item_ops,
1148a07b4970SChristoph Hellwig };
1149a07b4970SChristoph Hellwig 
1150a07b4970SChristoph Hellwig static struct config_group *nvmet_referral_make(
1151a07b4970SChristoph Hellwig 		struct config_group *group, const char *name)
1152a07b4970SChristoph Hellwig {
1153a07b4970SChristoph Hellwig 	struct nvmet_port *port;
1154a07b4970SChristoph Hellwig 
1155a07b4970SChristoph Hellwig 	port = kzalloc(sizeof(*port), GFP_KERNEL);
1156a07b4970SChristoph Hellwig 	if (!port)
1157f98d9ca1SDan Carpenter 		return ERR_PTR(-ENOMEM);
1158a07b4970SChristoph Hellwig 
1159a07b4970SChristoph Hellwig 	INIT_LIST_HEAD(&port->entry);
1160a07b4970SChristoph Hellwig 	config_group_init_type_name(&port->group, name, &nvmet_referral_type);
1161a07b4970SChristoph Hellwig 
1162a07b4970SChristoph Hellwig 	return &port->group;
1163a07b4970SChristoph Hellwig }
1164a07b4970SChristoph Hellwig 
1165a07b4970SChristoph Hellwig static struct configfs_group_operations nvmet_referral_group_ops = {
1166a07b4970SChristoph Hellwig 	.make_group		= nvmet_referral_make,
1167f0e656e4SSagi Grimberg 	.disconnect_notify	= nvmet_referral_notify,
1168a07b4970SChristoph Hellwig };
1169a07b4970SChristoph Hellwig 
117066603a31SBhumika Goyal static const struct config_item_type nvmet_referrals_type = {
1171a07b4970SChristoph Hellwig 	.ct_owner	= THIS_MODULE,
1172a07b4970SChristoph Hellwig 	.ct_group_ops	= &nvmet_referral_group_ops,
1173a07b4970SChristoph Hellwig };
1174a07b4970SChristoph Hellwig 
117574255969SChristoph Hellwig static struct nvmet_type_name_map nvmet_ana_state[] = {
117662ac0d32SChristoph Hellwig 	{ NVME_ANA_OPTIMIZED,		"optimized" },
117762ac0d32SChristoph Hellwig 	{ NVME_ANA_NONOPTIMIZED,	"non-optimized" },
117862ac0d32SChristoph Hellwig 	{ NVME_ANA_INACCESSIBLE,	"inaccessible" },
117962ac0d32SChristoph Hellwig 	{ NVME_ANA_PERSISTENT_LOSS,	"persistent-loss" },
118062ac0d32SChristoph Hellwig 	{ NVME_ANA_CHANGE,		"change" },
118162ac0d32SChristoph Hellwig };
118262ac0d32SChristoph Hellwig 
118362ac0d32SChristoph Hellwig static ssize_t nvmet_ana_group_ana_state_show(struct config_item *item,
118462ac0d32SChristoph Hellwig 		char *page)
118562ac0d32SChristoph Hellwig {
118662ac0d32SChristoph Hellwig 	struct nvmet_ana_group *grp = to_ana_group(item);
118762ac0d32SChristoph Hellwig 	enum nvme_ana_state state = grp->port->ana_state[grp->grpid];
118862ac0d32SChristoph Hellwig 	int i;
118962ac0d32SChristoph Hellwig 
119084b8d0d7SChaitanya Kulkarni 	for (i = 0; i < ARRAY_SIZE(nvmet_ana_state); i++) {
119184b8d0d7SChaitanya Kulkarni 		if (state == nvmet_ana_state[i].type)
119284b8d0d7SChaitanya Kulkarni 			return sprintf(page, "%s\n", nvmet_ana_state[i].name);
119362ac0d32SChristoph Hellwig 	}
119462ac0d32SChristoph Hellwig 
119562ac0d32SChristoph Hellwig 	return sprintf(page, "\n");
119662ac0d32SChristoph Hellwig }
119762ac0d32SChristoph Hellwig 
119862ac0d32SChristoph Hellwig static ssize_t nvmet_ana_group_ana_state_store(struct config_item *item,
119962ac0d32SChristoph Hellwig 		const char *page, size_t count)
120062ac0d32SChristoph Hellwig {
120162ac0d32SChristoph Hellwig 	struct nvmet_ana_group *grp = to_ana_group(item);
120284b8d0d7SChaitanya Kulkarni 	enum nvme_ana_state *ana_state = grp->port->ana_state;
120362ac0d32SChristoph Hellwig 	int i;
120462ac0d32SChristoph Hellwig 
120584b8d0d7SChaitanya Kulkarni 	for (i = 0; i < ARRAY_SIZE(nvmet_ana_state); i++) {
120684b8d0d7SChaitanya Kulkarni 		if (sysfs_streq(page, nvmet_ana_state[i].name))
120762ac0d32SChristoph Hellwig 			goto found;
120862ac0d32SChristoph Hellwig 	}
120962ac0d32SChristoph Hellwig 
121062ac0d32SChristoph Hellwig 	pr_err("Invalid value '%s' for ana_state\n", page);
121162ac0d32SChristoph Hellwig 	return -EINVAL;
121262ac0d32SChristoph Hellwig 
121362ac0d32SChristoph Hellwig found:
121462ac0d32SChristoph Hellwig 	down_write(&nvmet_ana_sem);
121584b8d0d7SChaitanya Kulkarni 	ana_state[grp->grpid] = (enum nvme_ana_state) nvmet_ana_state[i].type;
121662ac0d32SChristoph Hellwig 	nvmet_ana_chgcnt++;
121762ac0d32SChristoph Hellwig 	up_write(&nvmet_ana_sem);
121862ac0d32SChristoph Hellwig 	nvmet_port_send_ana_event(grp->port);
121962ac0d32SChristoph Hellwig 	return count;
122062ac0d32SChristoph Hellwig }
122162ac0d32SChristoph Hellwig 
122262ac0d32SChristoph Hellwig CONFIGFS_ATTR(nvmet_ana_group_, ana_state);
122362ac0d32SChristoph Hellwig 
122462ac0d32SChristoph Hellwig static struct configfs_attribute *nvmet_ana_group_attrs[] = {
122562ac0d32SChristoph Hellwig 	&nvmet_ana_group_attr_ana_state,
122662ac0d32SChristoph Hellwig 	NULL,
122762ac0d32SChristoph Hellwig };
122862ac0d32SChristoph Hellwig 
122962ac0d32SChristoph Hellwig static void nvmet_ana_group_release(struct config_item *item)
123062ac0d32SChristoph Hellwig {
123162ac0d32SChristoph Hellwig 	struct nvmet_ana_group *grp = to_ana_group(item);
123262ac0d32SChristoph Hellwig 
123362ac0d32SChristoph Hellwig 	if (grp == &grp->port->ana_default_group)
123462ac0d32SChristoph Hellwig 		return;
123562ac0d32SChristoph Hellwig 
123662ac0d32SChristoph Hellwig 	down_write(&nvmet_ana_sem);
123762ac0d32SChristoph Hellwig 	grp->port->ana_state[grp->grpid] = NVME_ANA_INACCESSIBLE;
123862ac0d32SChristoph Hellwig 	nvmet_ana_group_enabled[grp->grpid]--;
123962ac0d32SChristoph Hellwig 	up_write(&nvmet_ana_sem);
124062ac0d32SChristoph Hellwig 
124162ac0d32SChristoph Hellwig 	nvmet_port_send_ana_event(grp->port);
124262ac0d32SChristoph Hellwig 	kfree(grp);
124362ac0d32SChristoph Hellwig }
124462ac0d32SChristoph Hellwig 
124562ac0d32SChristoph Hellwig static struct configfs_item_operations nvmet_ana_group_item_ops = {
124662ac0d32SChristoph Hellwig 	.release		= nvmet_ana_group_release,
124762ac0d32SChristoph Hellwig };
124862ac0d32SChristoph Hellwig 
124962ac0d32SChristoph Hellwig static const struct config_item_type nvmet_ana_group_type = {
125062ac0d32SChristoph Hellwig 	.ct_item_ops		= &nvmet_ana_group_item_ops,
125162ac0d32SChristoph Hellwig 	.ct_attrs		= nvmet_ana_group_attrs,
125262ac0d32SChristoph Hellwig 	.ct_owner		= THIS_MODULE,
125362ac0d32SChristoph Hellwig };
125462ac0d32SChristoph Hellwig 
125562ac0d32SChristoph Hellwig static struct config_group *nvmet_ana_groups_make_group(
125662ac0d32SChristoph Hellwig 		struct config_group *group, const char *name)
125762ac0d32SChristoph Hellwig {
125862ac0d32SChristoph Hellwig 	struct nvmet_port *port = ana_groups_to_port(&group->cg_item);
125962ac0d32SChristoph Hellwig 	struct nvmet_ana_group *grp;
126062ac0d32SChristoph Hellwig 	u32 grpid;
126162ac0d32SChristoph Hellwig 	int ret;
126262ac0d32SChristoph Hellwig 
126362ac0d32SChristoph Hellwig 	ret = kstrtou32(name, 0, &grpid);
126462ac0d32SChristoph Hellwig 	if (ret)
126562ac0d32SChristoph Hellwig 		goto out;
126662ac0d32SChristoph Hellwig 
126762ac0d32SChristoph Hellwig 	ret = -EINVAL;
126862ac0d32SChristoph Hellwig 	if (grpid <= 1 || grpid > NVMET_MAX_ANAGRPS)
126962ac0d32SChristoph Hellwig 		goto out;
127062ac0d32SChristoph Hellwig 
127162ac0d32SChristoph Hellwig 	ret = -ENOMEM;
127262ac0d32SChristoph Hellwig 	grp = kzalloc(sizeof(*grp), GFP_KERNEL);
127362ac0d32SChristoph Hellwig 	if (!grp)
127462ac0d32SChristoph Hellwig 		goto out;
127562ac0d32SChristoph Hellwig 	grp->port = port;
127662ac0d32SChristoph Hellwig 	grp->grpid = grpid;
127762ac0d32SChristoph Hellwig 
127862ac0d32SChristoph Hellwig 	down_write(&nvmet_ana_sem);
127962ac0d32SChristoph Hellwig 	nvmet_ana_group_enabled[grpid]++;
128062ac0d32SChristoph Hellwig 	up_write(&nvmet_ana_sem);
128162ac0d32SChristoph Hellwig 
128262ac0d32SChristoph Hellwig 	nvmet_port_send_ana_event(grp->port);
128362ac0d32SChristoph Hellwig 
128462ac0d32SChristoph Hellwig 	config_group_init_type_name(&grp->group, name, &nvmet_ana_group_type);
128562ac0d32SChristoph Hellwig 	return &grp->group;
128662ac0d32SChristoph Hellwig out:
128762ac0d32SChristoph Hellwig 	return ERR_PTR(ret);
128862ac0d32SChristoph Hellwig }
128962ac0d32SChristoph Hellwig 
129062ac0d32SChristoph Hellwig static struct configfs_group_operations nvmet_ana_groups_group_ops = {
129162ac0d32SChristoph Hellwig 	.make_group		= nvmet_ana_groups_make_group,
129262ac0d32SChristoph Hellwig };
129362ac0d32SChristoph Hellwig 
129462ac0d32SChristoph Hellwig static const struct config_item_type nvmet_ana_groups_type = {
129562ac0d32SChristoph Hellwig 	.ct_group_ops		= &nvmet_ana_groups_group_ops,
129662ac0d32SChristoph Hellwig 	.ct_owner		= THIS_MODULE,
129762ac0d32SChristoph Hellwig };
129862ac0d32SChristoph Hellwig 
1299a07b4970SChristoph Hellwig /*
1300a07b4970SChristoph Hellwig  * Ports definitions.
1301a07b4970SChristoph Hellwig  */
1302a07b4970SChristoph Hellwig static void nvmet_port_release(struct config_item *item)
1303a07b4970SChristoph Hellwig {
1304a07b4970SChristoph Hellwig 	struct nvmet_port *port = to_nvmet_port(item);
1305a07b4970SChristoph Hellwig 
1306b662a078SJay Sternberg 	list_del(&port->global_entry);
1307b662a078SJay Sternberg 
130872efd25dSChristoph Hellwig 	kfree(port->ana_state);
1309a07b4970SChristoph Hellwig 	kfree(port);
1310a07b4970SChristoph Hellwig }
1311a07b4970SChristoph Hellwig 
1312a07b4970SChristoph Hellwig static struct configfs_attribute *nvmet_port_attrs[] = {
1313a07b4970SChristoph Hellwig 	&nvmet_attr_addr_adrfam,
1314a07b4970SChristoph Hellwig 	&nvmet_attr_addr_treq,
1315a07b4970SChristoph Hellwig 	&nvmet_attr_addr_traddr,
1316a07b4970SChristoph Hellwig 	&nvmet_attr_addr_trsvcid,
1317a07b4970SChristoph Hellwig 	&nvmet_attr_addr_trtype,
13180d5ee2b2SSteve Wise 	&nvmet_attr_param_inline_data_size,
1319a07b4970SChristoph Hellwig 	NULL,
1320a07b4970SChristoph Hellwig };
1321a07b4970SChristoph Hellwig 
1322a07b4970SChristoph Hellwig static struct configfs_item_operations nvmet_port_item_ops = {
1323a07b4970SChristoph Hellwig 	.release		= nvmet_port_release,
1324a07b4970SChristoph Hellwig };
1325a07b4970SChristoph Hellwig 
132666603a31SBhumika Goyal static const struct config_item_type nvmet_port_type = {
1327a07b4970SChristoph Hellwig 	.ct_attrs		= nvmet_port_attrs,
1328a07b4970SChristoph Hellwig 	.ct_item_ops		= &nvmet_port_item_ops,
1329a07b4970SChristoph Hellwig 	.ct_owner		= THIS_MODULE,
1330a07b4970SChristoph Hellwig };
1331a07b4970SChristoph Hellwig 
1332a07b4970SChristoph Hellwig static struct config_group *nvmet_ports_make(struct config_group *group,
1333a07b4970SChristoph Hellwig 		const char *name)
1334a07b4970SChristoph Hellwig {
1335a07b4970SChristoph Hellwig 	struct nvmet_port *port;
1336a07b4970SChristoph Hellwig 	u16 portid;
133762ac0d32SChristoph Hellwig 	u32 i;
1338a07b4970SChristoph Hellwig 
1339a07b4970SChristoph Hellwig 	if (kstrtou16(name, 0, &portid))
1340a07b4970SChristoph Hellwig 		return ERR_PTR(-EINVAL);
1341a07b4970SChristoph Hellwig 
1342a07b4970SChristoph Hellwig 	port = kzalloc(sizeof(*port), GFP_KERNEL);
1343a07b4970SChristoph Hellwig 	if (!port)
1344f98d9ca1SDan Carpenter 		return ERR_PTR(-ENOMEM);
1345a07b4970SChristoph Hellwig 
134672efd25dSChristoph Hellwig 	port->ana_state = kcalloc(NVMET_MAX_ANAGRPS + 1,
134772efd25dSChristoph Hellwig 			sizeof(*port->ana_state), GFP_KERNEL);
134872efd25dSChristoph Hellwig 	if (!port->ana_state) {
134972efd25dSChristoph Hellwig 		kfree(port);
135072efd25dSChristoph Hellwig 		return ERR_PTR(-ENOMEM);
135172efd25dSChristoph Hellwig 	}
135272efd25dSChristoph Hellwig 
135362ac0d32SChristoph Hellwig 	for (i = 1; i <= NVMET_MAX_ANAGRPS; i++) {
135462ac0d32SChristoph Hellwig 		if (i == NVMET_DEFAULT_ANA_GRPID)
135562ac0d32SChristoph Hellwig 			port->ana_state[1] = NVME_ANA_OPTIMIZED;
135662ac0d32SChristoph Hellwig 		else
135762ac0d32SChristoph Hellwig 			port->ana_state[i] = NVME_ANA_INACCESSIBLE;
135862ac0d32SChristoph Hellwig 	}
135972efd25dSChristoph Hellwig 
1360b662a078SJay Sternberg 	list_add(&port->global_entry, &nvmet_ports_list);
1361b662a078SJay Sternberg 
1362a07b4970SChristoph Hellwig 	INIT_LIST_HEAD(&port->entry);
1363a07b4970SChristoph Hellwig 	INIT_LIST_HEAD(&port->subsystems);
1364a07b4970SChristoph Hellwig 	INIT_LIST_HEAD(&port->referrals);
13650d5ee2b2SSteve Wise 	port->inline_data_size = -1;	/* < 0 == let the transport choose */
1366a07b4970SChristoph Hellwig 
1367a07b4970SChristoph Hellwig 	port->disc_addr.portid = cpu_to_le16(portid);
1368d02abd19SChaitanya Kulkarni 	port->disc_addr.adrfam = NVMF_ADDR_FAMILY_MAX;
13699b95d2fbSSagi Grimberg 	port->disc_addr.treq = NVMF_TREQ_DISABLE_SQFLOW;
1370a07b4970SChristoph Hellwig 	config_group_init_type_name(&port->group, name, &nvmet_port_type);
1371a07b4970SChristoph Hellwig 
1372a07b4970SChristoph Hellwig 	config_group_init_type_name(&port->subsys_group,
1373a07b4970SChristoph Hellwig 			"subsystems", &nvmet_port_subsys_type);
1374a07b4970SChristoph Hellwig 	configfs_add_default_group(&port->subsys_group, &port->group);
1375a07b4970SChristoph Hellwig 
1376a07b4970SChristoph Hellwig 	config_group_init_type_name(&port->referrals_group,
1377a07b4970SChristoph Hellwig 			"referrals", &nvmet_referrals_type);
1378a07b4970SChristoph Hellwig 	configfs_add_default_group(&port->referrals_group, &port->group);
1379a07b4970SChristoph Hellwig 
138062ac0d32SChristoph Hellwig 	config_group_init_type_name(&port->ana_groups_group,
138162ac0d32SChristoph Hellwig 			"ana_groups", &nvmet_ana_groups_type);
138262ac0d32SChristoph Hellwig 	configfs_add_default_group(&port->ana_groups_group, &port->group);
138362ac0d32SChristoph Hellwig 
138462ac0d32SChristoph Hellwig 	port->ana_default_group.port = port;
138562ac0d32SChristoph Hellwig 	port->ana_default_group.grpid = NVMET_DEFAULT_ANA_GRPID;
138662ac0d32SChristoph Hellwig 	config_group_init_type_name(&port->ana_default_group.group,
138762ac0d32SChristoph Hellwig 			__stringify(NVMET_DEFAULT_ANA_GRPID),
138862ac0d32SChristoph Hellwig 			&nvmet_ana_group_type);
138962ac0d32SChristoph Hellwig 	configfs_add_default_group(&port->ana_default_group.group,
139062ac0d32SChristoph Hellwig 			&port->ana_groups_group);
139162ac0d32SChristoph Hellwig 
1392a07b4970SChristoph Hellwig 	return &port->group;
1393a07b4970SChristoph Hellwig }
1394a07b4970SChristoph Hellwig 
1395a07b4970SChristoph Hellwig static struct configfs_group_operations nvmet_ports_group_ops = {
1396a07b4970SChristoph Hellwig 	.make_group		= nvmet_ports_make,
1397a07b4970SChristoph Hellwig };
1398a07b4970SChristoph Hellwig 
139966603a31SBhumika Goyal static const struct config_item_type nvmet_ports_type = {
1400a07b4970SChristoph Hellwig 	.ct_group_ops		= &nvmet_ports_group_ops,
1401a07b4970SChristoph Hellwig 	.ct_owner		= THIS_MODULE,
1402a07b4970SChristoph Hellwig };
1403a07b4970SChristoph Hellwig 
1404a07b4970SChristoph Hellwig static struct config_group nvmet_subsystems_group;
1405a07b4970SChristoph Hellwig static struct config_group nvmet_ports_group;
1406a07b4970SChristoph Hellwig 
1407a07b4970SChristoph Hellwig static void nvmet_host_release(struct config_item *item)
1408a07b4970SChristoph Hellwig {
1409a07b4970SChristoph Hellwig 	struct nvmet_host *host = to_host(item);
1410a07b4970SChristoph Hellwig 
1411a07b4970SChristoph Hellwig 	kfree(host);
1412a07b4970SChristoph Hellwig }
1413a07b4970SChristoph Hellwig 
1414a07b4970SChristoph Hellwig static struct configfs_item_operations nvmet_host_item_ops = {
1415a07b4970SChristoph Hellwig 	.release		= nvmet_host_release,
1416a07b4970SChristoph Hellwig };
1417a07b4970SChristoph Hellwig 
141866603a31SBhumika Goyal static const struct config_item_type nvmet_host_type = {
1419a07b4970SChristoph Hellwig 	.ct_item_ops		= &nvmet_host_item_ops,
1420a07b4970SChristoph Hellwig 	.ct_owner		= THIS_MODULE,
1421a07b4970SChristoph Hellwig };
1422a07b4970SChristoph Hellwig 
1423a07b4970SChristoph Hellwig static struct config_group *nvmet_hosts_make_group(struct config_group *group,
1424a07b4970SChristoph Hellwig 		const char *name)
1425a07b4970SChristoph Hellwig {
1426a07b4970SChristoph Hellwig 	struct nvmet_host *host;
1427a07b4970SChristoph Hellwig 
1428a07b4970SChristoph Hellwig 	host = kzalloc(sizeof(*host), GFP_KERNEL);
1429a07b4970SChristoph Hellwig 	if (!host)
1430a07b4970SChristoph Hellwig 		return ERR_PTR(-ENOMEM);
1431a07b4970SChristoph Hellwig 
1432a07b4970SChristoph Hellwig 	config_group_init_type_name(&host->group, name, &nvmet_host_type);
1433a07b4970SChristoph Hellwig 
1434a07b4970SChristoph Hellwig 	return &host->group;
1435a07b4970SChristoph Hellwig }
1436a07b4970SChristoph Hellwig 
1437a07b4970SChristoph Hellwig static struct configfs_group_operations nvmet_hosts_group_ops = {
1438a07b4970SChristoph Hellwig 	.make_group		= nvmet_hosts_make_group,
1439a07b4970SChristoph Hellwig };
1440a07b4970SChristoph Hellwig 
144166603a31SBhumika Goyal static const struct config_item_type nvmet_hosts_type = {
1442a07b4970SChristoph Hellwig 	.ct_group_ops		= &nvmet_hosts_group_ops,
1443a07b4970SChristoph Hellwig 	.ct_owner		= THIS_MODULE,
1444a07b4970SChristoph Hellwig };
1445a07b4970SChristoph Hellwig 
1446a07b4970SChristoph Hellwig static struct config_group nvmet_hosts_group;
1447a07b4970SChristoph Hellwig 
144866603a31SBhumika Goyal static const struct config_item_type nvmet_root_type = {
1449a07b4970SChristoph Hellwig 	.ct_owner		= THIS_MODULE,
1450a07b4970SChristoph Hellwig };
1451a07b4970SChristoph Hellwig 
1452a07b4970SChristoph Hellwig static struct configfs_subsystem nvmet_configfs_subsystem = {
1453a07b4970SChristoph Hellwig 	.su_group = {
1454a07b4970SChristoph Hellwig 		.cg_item = {
1455a07b4970SChristoph Hellwig 			.ci_namebuf	= "nvmet",
1456a07b4970SChristoph Hellwig 			.ci_type	= &nvmet_root_type,
1457a07b4970SChristoph Hellwig 		},
1458a07b4970SChristoph Hellwig 	},
1459a07b4970SChristoph Hellwig };
1460a07b4970SChristoph Hellwig 
1461a07b4970SChristoph Hellwig int __init nvmet_init_configfs(void)
1462a07b4970SChristoph Hellwig {
1463a07b4970SChristoph Hellwig 	int ret;
1464a07b4970SChristoph Hellwig 
1465a07b4970SChristoph Hellwig 	config_group_init(&nvmet_configfs_subsystem.su_group);
1466a07b4970SChristoph Hellwig 	mutex_init(&nvmet_configfs_subsystem.su_mutex);
1467a07b4970SChristoph Hellwig 
1468a07b4970SChristoph Hellwig 	config_group_init_type_name(&nvmet_subsystems_group,
1469a07b4970SChristoph Hellwig 			"subsystems", &nvmet_subsystems_type);
1470a07b4970SChristoph Hellwig 	configfs_add_default_group(&nvmet_subsystems_group,
1471a07b4970SChristoph Hellwig 			&nvmet_configfs_subsystem.su_group);
1472a07b4970SChristoph Hellwig 
1473a07b4970SChristoph Hellwig 	config_group_init_type_name(&nvmet_ports_group,
1474a07b4970SChristoph Hellwig 			"ports", &nvmet_ports_type);
1475a07b4970SChristoph Hellwig 	configfs_add_default_group(&nvmet_ports_group,
1476a07b4970SChristoph Hellwig 			&nvmet_configfs_subsystem.su_group);
1477a07b4970SChristoph Hellwig 
1478a07b4970SChristoph Hellwig 	config_group_init_type_name(&nvmet_hosts_group,
1479a07b4970SChristoph Hellwig 			"hosts", &nvmet_hosts_type);
1480a07b4970SChristoph Hellwig 	configfs_add_default_group(&nvmet_hosts_group,
1481a07b4970SChristoph Hellwig 			&nvmet_configfs_subsystem.su_group);
1482a07b4970SChristoph Hellwig 
1483a07b4970SChristoph Hellwig 	ret = configfs_register_subsystem(&nvmet_configfs_subsystem);
1484a07b4970SChristoph Hellwig 	if (ret) {
1485a07b4970SChristoph Hellwig 		pr_err("configfs_register_subsystem: %d\n", ret);
1486a07b4970SChristoph Hellwig 		return ret;
1487a07b4970SChristoph Hellwig 	}
1488a07b4970SChristoph Hellwig 
1489a07b4970SChristoph Hellwig 	return 0;
1490a07b4970SChristoph Hellwig }
1491a07b4970SChristoph Hellwig 
1492a07b4970SChristoph Hellwig void __exit nvmet_exit_configfs(void)
1493a07b4970SChristoph Hellwig {
1494a07b4970SChristoph Hellwig 	configfs_unregister_subsystem(&nvmet_configfs_subsystem);
1495a07b4970SChristoph Hellwig }
1496