xref: /openbmc/linux/drivers/nvme/target/configfs.c (revision 9b95d2fb)
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>
20c6925093SLogan Gunthorpe #include <linux/pci.h>
21c6925093SLogan Gunthorpe #include <linux/pci-p2pdma.h>
22a07b4970SChristoph Hellwig 
23a07b4970SChristoph Hellwig #include "nvmet.h"
24a07b4970SChristoph Hellwig 
2566603a31SBhumika Goyal static const struct config_item_type nvmet_host_type;
2666603a31SBhumika Goyal static const struct config_item_type nvmet_subsys_type;
27a07b4970SChristoph Hellwig 
28b662a078SJay Sternberg static LIST_HEAD(nvmet_ports_list);
29b662a078SJay Sternberg struct list_head *nvmet_ports = &nvmet_ports_list;
30b662a078SJay Sternberg 
31a5d18612SChristoph Hellwig static const struct nvmet_transport_name {
32a5d18612SChristoph Hellwig 	u8		type;
33a5d18612SChristoph Hellwig 	const char	*name;
34a5d18612SChristoph Hellwig } nvmet_transport_names[] = {
35a5d18612SChristoph Hellwig 	{ NVMF_TRTYPE_RDMA,	"rdma" },
36a5d18612SChristoph Hellwig 	{ NVMF_TRTYPE_FC,	"fc" },
37a5d18612SChristoph Hellwig 	{ NVMF_TRTYPE_LOOP,	"loop" },
38a5d18612SChristoph Hellwig };
39a5d18612SChristoph Hellwig 
40a07b4970SChristoph Hellwig /*
41a07b4970SChristoph Hellwig  * nvmet_port Generic ConfigFS definitions.
42a07b4970SChristoph Hellwig  * Used in any place in the ConfigFS tree that refers to an address.
43a07b4970SChristoph Hellwig  */
44a07b4970SChristoph Hellwig static ssize_t nvmet_addr_adrfam_show(struct config_item *item,
45a07b4970SChristoph Hellwig 		char *page)
46a07b4970SChristoph Hellwig {
47a07b4970SChristoph Hellwig 	switch (to_nvmet_port(item)->disc_addr.adrfam) {
48a07b4970SChristoph Hellwig 	case NVMF_ADDR_FAMILY_IP4:
49a07b4970SChristoph Hellwig 		return sprintf(page, "ipv4\n");
50a07b4970SChristoph Hellwig 	case NVMF_ADDR_FAMILY_IP6:
51a07b4970SChristoph Hellwig 		return sprintf(page, "ipv6\n");
52a07b4970SChristoph Hellwig 	case NVMF_ADDR_FAMILY_IB:
53a07b4970SChristoph Hellwig 		return sprintf(page, "ib\n");
54885aa401SJames Smart 	case NVMF_ADDR_FAMILY_FC:
55885aa401SJames Smart 		return sprintf(page, "fc\n");
56a07b4970SChristoph Hellwig 	default:
57a07b4970SChristoph Hellwig 		return sprintf(page, "\n");
58a07b4970SChristoph Hellwig 	}
59a07b4970SChristoph Hellwig }
60a07b4970SChristoph Hellwig 
61a07b4970SChristoph Hellwig static ssize_t nvmet_addr_adrfam_store(struct config_item *item,
62a07b4970SChristoph Hellwig 		const char *page, size_t count)
63a07b4970SChristoph Hellwig {
64a07b4970SChristoph Hellwig 	struct nvmet_port *port = to_nvmet_port(item);
65a07b4970SChristoph Hellwig 
66a07b4970SChristoph Hellwig 	if (port->enabled) {
67a07b4970SChristoph Hellwig 		pr_err("Cannot modify address while enabled\n");
68a07b4970SChristoph Hellwig 		pr_err("Disable the address before modifying\n");
69a07b4970SChristoph Hellwig 		return -EACCES;
70a07b4970SChristoph Hellwig 	}
71a07b4970SChristoph Hellwig 
72a07b4970SChristoph Hellwig 	if (sysfs_streq(page, "ipv4")) {
73a07b4970SChristoph Hellwig 		port->disc_addr.adrfam = NVMF_ADDR_FAMILY_IP4;
74a07b4970SChristoph Hellwig 	} else if (sysfs_streq(page, "ipv6")) {
75a07b4970SChristoph Hellwig 		port->disc_addr.adrfam = NVMF_ADDR_FAMILY_IP6;
76a07b4970SChristoph Hellwig 	} else if (sysfs_streq(page, "ib")) {
77a07b4970SChristoph Hellwig 		port->disc_addr.adrfam = NVMF_ADDR_FAMILY_IB;
78885aa401SJames Smart 	} else if (sysfs_streq(page, "fc")) {
79885aa401SJames Smart 		port->disc_addr.adrfam = NVMF_ADDR_FAMILY_FC;
80a07b4970SChristoph Hellwig 	} else {
81a07b4970SChristoph Hellwig 		pr_err("Invalid value '%s' for adrfam\n", page);
82a07b4970SChristoph Hellwig 		return -EINVAL;
83a07b4970SChristoph Hellwig 	}
84a07b4970SChristoph Hellwig 
85a07b4970SChristoph Hellwig 	return count;
86a07b4970SChristoph Hellwig }
87a07b4970SChristoph Hellwig 
88a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_, addr_adrfam);
89a07b4970SChristoph Hellwig 
90a07b4970SChristoph Hellwig static ssize_t nvmet_addr_portid_show(struct config_item *item,
91a07b4970SChristoph Hellwig 		char *page)
92a07b4970SChristoph Hellwig {
93a07b4970SChristoph Hellwig 	struct nvmet_port *port = to_nvmet_port(item);
94a07b4970SChristoph Hellwig 
95a07b4970SChristoph Hellwig 	return snprintf(page, PAGE_SIZE, "%d\n",
96a07b4970SChristoph Hellwig 			le16_to_cpu(port->disc_addr.portid));
97a07b4970SChristoph Hellwig }
98a07b4970SChristoph Hellwig 
99a07b4970SChristoph Hellwig static ssize_t nvmet_addr_portid_store(struct config_item *item,
100a07b4970SChristoph Hellwig 		const char *page, size_t count)
101a07b4970SChristoph Hellwig {
102a07b4970SChristoph Hellwig 	struct nvmet_port *port = to_nvmet_port(item);
103a07b4970SChristoph Hellwig 	u16 portid = 0;
104a07b4970SChristoph Hellwig 
105a07b4970SChristoph Hellwig 	if (kstrtou16(page, 0, &portid)) {
106a07b4970SChristoph Hellwig 		pr_err("Invalid value '%s' for portid\n", page);
107a07b4970SChristoph Hellwig 		return -EINVAL;
108a07b4970SChristoph Hellwig 	}
109a07b4970SChristoph Hellwig 
110a07b4970SChristoph Hellwig 	if (port->enabled) {
111a07b4970SChristoph Hellwig 		pr_err("Cannot modify address while enabled\n");
112a07b4970SChristoph Hellwig 		pr_err("Disable the address before modifying\n");
113a07b4970SChristoph Hellwig 		return -EACCES;
114a07b4970SChristoph Hellwig 	}
115a07b4970SChristoph Hellwig 	port->disc_addr.portid = cpu_to_le16(portid);
116a07b4970SChristoph Hellwig 	return count;
117a07b4970SChristoph Hellwig }
118a07b4970SChristoph Hellwig 
119a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_, addr_portid);
120a07b4970SChristoph Hellwig 
121a07b4970SChristoph Hellwig static ssize_t nvmet_addr_traddr_show(struct config_item *item,
122a07b4970SChristoph Hellwig 		char *page)
123a07b4970SChristoph Hellwig {
124a07b4970SChristoph Hellwig 	struct nvmet_port *port = to_nvmet_port(item);
125a07b4970SChristoph Hellwig 
126a07b4970SChristoph Hellwig 	return snprintf(page, PAGE_SIZE, "%s\n",
127a07b4970SChristoph Hellwig 			port->disc_addr.traddr);
128a07b4970SChristoph Hellwig }
129a07b4970SChristoph Hellwig 
130a07b4970SChristoph Hellwig static ssize_t nvmet_addr_traddr_store(struct config_item *item,
131a07b4970SChristoph Hellwig 		const char *page, size_t count)
132a07b4970SChristoph Hellwig {
133a07b4970SChristoph Hellwig 	struct nvmet_port *port = to_nvmet_port(item);
134a07b4970SChristoph Hellwig 
135a07b4970SChristoph Hellwig 	if (count > NVMF_TRADDR_SIZE) {
136a07b4970SChristoph Hellwig 		pr_err("Invalid value '%s' for traddr\n", page);
137a07b4970SChristoph Hellwig 		return -EINVAL;
138a07b4970SChristoph Hellwig 	}
139a07b4970SChristoph Hellwig 
140a07b4970SChristoph Hellwig 	if (port->enabled) {
141a07b4970SChristoph Hellwig 		pr_err("Cannot modify address while enabled\n");
142a07b4970SChristoph Hellwig 		pr_err("Disable the address before modifying\n");
143a07b4970SChristoph Hellwig 		return -EACCES;
144a07b4970SChristoph Hellwig 	}
1459ba2a5cbSSagi Grimberg 
1469ba2a5cbSSagi Grimberg 	if (sscanf(page, "%s\n", port->disc_addr.traddr) != 1)
1479ba2a5cbSSagi Grimberg 		return -EINVAL;
1489ba2a5cbSSagi Grimberg 	return count;
149a07b4970SChristoph Hellwig }
150a07b4970SChristoph Hellwig 
151a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_, addr_traddr);
152a07b4970SChristoph Hellwig 
153a07b4970SChristoph Hellwig static ssize_t nvmet_addr_treq_show(struct config_item *item,
154a07b4970SChristoph Hellwig 		char *page)
155a07b4970SChristoph Hellwig {
1560445e1b5SSagi Grimberg 	switch (to_nvmet_port(item)->disc_addr.treq &
1570445e1b5SSagi Grimberg 		NVME_TREQ_SECURE_CHANNEL_MASK) {
158a07b4970SChristoph Hellwig 	case NVMF_TREQ_NOT_SPECIFIED:
159a07b4970SChristoph Hellwig 		return sprintf(page, "not specified\n");
160a07b4970SChristoph Hellwig 	case NVMF_TREQ_REQUIRED:
161a07b4970SChristoph Hellwig 		return sprintf(page, "required\n");
162a07b4970SChristoph Hellwig 	case NVMF_TREQ_NOT_REQUIRED:
163a07b4970SChristoph Hellwig 		return sprintf(page, "not required\n");
164a07b4970SChristoph Hellwig 	default:
165a07b4970SChristoph Hellwig 		return sprintf(page, "\n");
166a07b4970SChristoph Hellwig 	}
167a07b4970SChristoph Hellwig }
168a07b4970SChristoph Hellwig 
169a07b4970SChristoph Hellwig static ssize_t nvmet_addr_treq_store(struct config_item *item,
170a07b4970SChristoph Hellwig 		const char *page, size_t count)
171a07b4970SChristoph Hellwig {
172a07b4970SChristoph Hellwig 	struct nvmet_port *port = to_nvmet_port(item);
1730445e1b5SSagi Grimberg 	u8 treq = port->disc_addr.treq & ~NVME_TREQ_SECURE_CHANNEL_MASK;
174a07b4970SChristoph Hellwig 
175a07b4970SChristoph Hellwig 	if (port->enabled) {
176a07b4970SChristoph Hellwig 		pr_err("Cannot modify address while enabled\n");
177a07b4970SChristoph Hellwig 		pr_err("Disable the address before modifying\n");
178a07b4970SChristoph Hellwig 		return -EACCES;
179a07b4970SChristoph Hellwig 	}
180a07b4970SChristoph Hellwig 
181a07b4970SChristoph Hellwig 	if (sysfs_streq(page, "not specified")) {
1820445e1b5SSagi Grimberg 		treq |= NVMF_TREQ_NOT_SPECIFIED;
183a07b4970SChristoph Hellwig 	} else if (sysfs_streq(page, "required")) {
1840445e1b5SSagi Grimberg 		treq |= NVMF_TREQ_REQUIRED;
185a07b4970SChristoph Hellwig 	} else if (sysfs_streq(page, "not required")) {
1860445e1b5SSagi Grimberg 		treq |= NVMF_TREQ_NOT_REQUIRED;
187a07b4970SChristoph Hellwig 	} else {
188a07b4970SChristoph Hellwig 		pr_err("Invalid value '%s' for treq\n", page);
189a07b4970SChristoph Hellwig 		return -EINVAL;
190a07b4970SChristoph Hellwig 	}
1910445e1b5SSagi Grimberg 	port->disc_addr.treq = treq;
192a07b4970SChristoph Hellwig 
193a07b4970SChristoph Hellwig 	return count;
194a07b4970SChristoph Hellwig }
195a07b4970SChristoph Hellwig 
196a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_, addr_treq);
197a07b4970SChristoph Hellwig 
198a07b4970SChristoph Hellwig static ssize_t nvmet_addr_trsvcid_show(struct config_item *item,
199a07b4970SChristoph Hellwig 		char *page)
200a07b4970SChristoph Hellwig {
201a07b4970SChristoph Hellwig 	struct nvmet_port *port = to_nvmet_port(item);
202a07b4970SChristoph Hellwig 
203a07b4970SChristoph Hellwig 	return snprintf(page, PAGE_SIZE, "%s\n",
204a07b4970SChristoph Hellwig 			port->disc_addr.trsvcid);
205a07b4970SChristoph Hellwig }
206a07b4970SChristoph Hellwig 
207a07b4970SChristoph Hellwig static ssize_t nvmet_addr_trsvcid_store(struct config_item *item,
208a07b4970SChristoph Hellwig 		const char *page, size_t count)
209a07b4970SChristoph Hellwig {
210a07b4970SChristoph Hellwig 	struct nvmet_port *port = to_nvmet_port(item);
211a07b4970SChristoph Hellwig 
212a07b4970SChristoph Hellwig 	if (count > NVMF_TRSVCID_SIZE) {
213a07b4970SChristoph Hellwig 		pr_err("Invalid value '%s' for trsvcid\n", page);
214a07b4970SChristoph Hellwig 		return -EINVAL;
215a07b4970SChristoph Hellwig 	}
216a07b4970SChristoph Hellwig 	if (port->enabled) {
217a07b4970SChristoph Hellwig 		pr_err("Cannot modify address while enabled\n");
218a07b4970SChristoph Hellwig 		pr_err("Disable the address before modifying\n");
219a07b4970SChristoph Hellwig 		return -EACCES;
220a07b4970SChristoph Hellwig 	}
2219ba2a5cbSSagi Grimberg 
2229ba2a5cbSSagi Grimberg 	if (sscanf(page, "%s\n", port->disc_addr.trsvcid) != 1)
2239ba2a5cbSSagi Grimberg 		return -EINVAL;
2249ba2a5cbSSagi Grimberg 	return count;
225a07b4970SChristoph Hellwig }
226a07b4970SChristoph Hellwig 
227a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_, addr_trsvcid);
228a07b4970SChristoph Hellwig 
2290d5ee2b2SSteve Wise static ssize_t nvmet_param_inline_data_size_show(struct config_item *item,
2300d5ee2b2SSteve Wise 		char *page)
2310d5ee2b2SSteve Wise {
2320d5ee2b2SSteve Wise 	struct nvmet_port *port = to_nvmet_port(item);
2330d5ee2b2SSteve Wise 
2340d5ee2b2SSteve Wise 	return snprintf(page, PAGE_SIZE, "%d\n", port->inline_data_size);
2350d5ee2b2SSteve Wise }
2360d5ee2b2SSteve Wise 
2370d5ee2b2SSteve Wise static ssize_t nvmet_param_inline_data_size_store(struct config_item *item,
2380d5ee2b2SSteve Wise 		const char *page, size_t count)
2390d5ee2b2SSteve Wise {
2400d5ee2b2SSteve Wise 	struct nvmet_port *port = to_nvmet_port(item);
2410d5ee2b2SSteve Wise 	int ret;
2420d5ee2b2SSteve Wise 
2430d5ee2b2SSteve Wise 	if (port->enabled) {
2440d5ee2b2SSteve Wise 		pr_err("Cannot modify inline_data_size while port enabled\n");
2450d5ee2b2SSteve Wise 		pr_err("Disable the port before modifying\n");
2460d5ee2b2SSteve Wise 		return -EACCES;
2470d5ee2b2SSteve Wise 	}
2480d5ee2b2SSteve Wise 	ret = kstrtoint(page, 0, &port->inline_data_size);
2490d5ee2b2SSteve Wise 	if (ret) {
2500d5ee2b2SSteve Wise 		pr_err("Invalid value '%s' for inline_data_size\n", page);
2510d5ee2b2SSteve Wise 		return -EINVAL;
2520d5ee2b2SSteve Wise 	}
2530d5ee2b2SSteve Wise 	return count;
2540d5ee2b2SSteve Wise }
2550d5ee2b2SSteve Wise 
2560d5ee2b2SSteve Wise CONFIGFS_ATTR(nvmet_, param_inline_data_size);
2570d5ee2b2SSteve Wise 
258a07b4970SChristoph Hellwig static ssize_t nvmet_addr_trtype_show(struct config_item *item,
259a07b4970SChristoph Hellwig 		char *page)
260a07b4970SChristoph Hellwig {
261a5d18612SChristoph Hellwig 	struct nvmet_port *port = to_nvmet_port(item);
262a5d18612SChristoph Hellwig 	int i;
263a5d18612SChristoph Hellwig 
264a5d18612SChristoph Hellwig 	for (i = 0; i < ARRAY_SIZE(nvmet_transport_names); i++) {
265a5d18612SChristoph Hellwig 		if (port->disc_addr.trtype != nvmet_transport_names[i].type)
266a5d18612SChristoph Hellwig 			continue;
267a5d18612SChristoph Hellwig 		return sprintf(page, "%s\n", nvmet_transport_names[i].name);
268a07b4970SChristoph Hellwig 	}
269a5d18612SChristoph Hellwig 
270a5d18612SChristoph Hellwig 	return sprintf(page, "\n");
271a07b4970SChristoph Hellwig }
272a07b4970SChristoph Hellwig 
273a07b4970SChristoph Hellwig static void nvmet_port_init_tsas_rdma(struct nvmet_port *port)
274a07b4970SChristoph Hellwig {
275a07b4970SChristoph Hellwig 	port->disc_addr.tsas.rdma.qptype = NVMF_RDMA_QPTYPE_CONNECTED;
276a07b4970SChristoph Hellwig 	port->disc_addr.tsas.rdma.prtype = NVMF_RDMA_PRTYPE_NOT_SPECIFIED;
277a07b4970SChristoph Hellwig 	port->disc_addr.tsas.rdma.cms = NVMF_RDMA_CMS_RDMA_CM;
278a07b4970SChristoph Hellwig }
279a07b4970SChristoph Hellwig 
280a07b4970SChristoph Hellwig static ssize_t nvmet_addr_trtype_store(struct config_item *item,
281a07b4970SChristoph Hellwig 		const char *page, size_t count)
282a07b4970SChristoph Hellwig {
283a07b4970SChristoph Hellwig 	struct nvmet_port *port = to_nvmet_port(item);
284a5d18612SChristoph Hellwig 	int i;
285a07b4970SChristoph Hellwig 
286a07b4970SChristoph Hellwig 	if (port->enabled) {
287a07b4970SChristoph Hellwig 		pr_err("Cannot modify address while enabled\n");
288a07b4970SChristoph Hellwig 		pr_err("Disable the address before modifying\n");
289a07b4970SChristoph Hellwig 		return -EACCES;
290a07b4970SChristoph Hellwig 	}
291a07b4970SChristoph Hellwig 
292a5d18612SChristoph Hellwig 	for (i = 0; i < ARRAY_SIZE(nvmet_transport_names); i++) {
293a5d18612SChristoph Hellwig 		if (sysfs_streq(page, nvmet_transport_names[i].name))
294a5d18612SChristoph Hellwig 			goto found;
295a07b4970SChristoph Hellwig 	}
296a07b4970SChristoph Hellwig 
297a5d18612SChristoph Hellwig 	pr_err("Invalid value '%s' for trtype\n", page);
298a5d18612SChristoph Hellwig 	return -EINVAL;
299a5d18612SChristoph Hellwig found:
300a5d18612SChristoph Hellwig 	memset(&port->disc_addr.tsas, 0, NVMF_TSAS_SIZE);
301a5d18612SChristoph Hellwig 	port->disc_addr.trtype = nvmet_transport_names[i].type;
302a5d18612SChristoph Hellwig 	if (port->disc_addr.trtype == NVMF_TRTYPE_RDMA)
303a5d18612SChristoph Hellwig 		nvmet_port_init_tsas_rdma(port);
304a07b4970SChristoph Hellwig 	return count;
305a07b4970SChristoph Hellwig }
306a07b4970SChristoph Hellwig 
307a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_, addr_trtype);
308a07b4970SChristoph Hellwig 
309a07b4970SChristoph Hellwig /*
310a07b4970SChristoph Hellwig  * Namespace structures & file operation functions below
311a07b4970SChristoph Hellwig  */
312a07b4970SChristoph Hellwig static ssize_t nvmet_ns_device_path_show(struct config_item *item, char *page)
313a07b4970SChristoph Hellwig {
314a07b4970SChristoph Hellwig 	return sprintf(page, "%s\n", to_nvmet_ns(item)->device_path);
315a07b4970SChristoph Hellwig }
316a07b4970SChristoph Hellwig 
317a07b4970SChristoph Hellwig static ssize_t nvmet_ns_device_path_store(struct config_item *item,
318a07b4970SChristoph Hellwig 		const char *page, size_t count)
319a07b4970SChristoph Hellwig {
320a07b4970SChristoph Hellwig 	struct nvmet_ns *ns = to_nvmet_ns(item);
321a07b4970SChristoph Hellwig 	struct nvmet_subsys *subsys = ns->subsys;
3225613d312SHannes Reinecke 	size_t len;
323a07b4970SChristoph Hellwig 	int ret;
324a07b4970SChristoph Hellwig 
325a07b4970SChristoph Hellwig 	mutex_lock(&subsys->lock);
326a07b4970SChristoph Hellwig 	ret = -EBUSY;
327e4fcf07cSSolganik Alexander 	if (ns->enabled)
328a07b4970SChristoph Hellwig 		goto out_unlock;
329a07b4970SChristoph Hellwig 
3305613d312SHannes Reinecke 	ret = -EINVAL;
3315613d312SHannes Reinecke 	len = strcspn(page, "\n");
3325613d312SHannes Reinecke 	if (!len)
3335613d312SHannes Reinecke 		goto out_unlock;
334a07b4970SChristoph Hellwig 
3355613d312SHannes Reinecke 	kfree(ns->device_path);
336a07b4970SChristoph Hellwig 	ret = -ENOMEM;
3375613d312SHannes Reinecke 	ns->device_path = kstrndup(page, len, GFP_KERNEL);
338a07b4970SChristoph Hellwig 	if (!ns->device_path)
339a07b4970SChristoph Hellwig 		goto out_unlock;
340a07b4970SChristoph Hellwig 
341a07b4970SChristoph Hellwig 	mutex_unlock(&subsys->lock);
342a07b4970SChristoph Hellwig 	return count;
343a07b4970SChristoph Hellwig 
344a07b4970SChristoph Hellwig out_unlock:
345a07b4970SChristoph Hellwig 	mutex_unlock(&subsys->lock);
346a07b4970SChristoph Hellwig 	return ret;
347a07b4970SChristoph Hellwig }
348a07b4970SChristoph Hellwig 
349a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_ns_, device_path);
350a07b4970SChristoph Hellwig 
351c6925093SLogan Gunthorpe #ifdef CONFIG_PCI_P2PDMA
352c6925093SLogan Gunthorpe static ssize_t nvmet_ns_p2pmem_show(struct config_item *item, char *page)
353c6925093SLogan Gunthorpe {
354c6925093SLogan Gunthorpe 	struct nvmet_ns *ns = to_nvmet_ns(item);
355c6925093SLogan Gunthorpe 
356c6925093SLogan Gunthorpe 	return pci_p2pdma_enable_show(page, ns->p2p_dev, ns->use_p2pmem);
357c6925093SLogan Gunthorpe }
358c6925093SLogan Gunthorpe 
359c6925093SLogan Gunthorpe static ssize_t nvmet_ns_p2pmem_store(struct config_item *item,
360c6925093SLogan Gunthorpe 		const char *page, size_t count)
361c6925093SLogan Gunthorpe {
362c6925093SLogan Gunthorpe 	struct nvmet_ns *ns = to_nvmet_ns(item);
363c6925093SLogan Gunthorpe 	struct pci_dev *p2p_dev = NULL;
364c6925093SLogan Gunthorpe 	bool use_p2pmem;
365c6925093SLogan Gunthorpe 	int ret = count;
366c6925093SLogan Gunthorpe 	int error;
367c6925093SLogan Gunthorpe 
368c6925093SLogan Gunthorpe 	mutex_lock(&ns->subsys->lock);
369c6925093SLogan Gunthorpe 	if (ns->enabled) {
370c6925093SLogan Gunthorpe 		ret = -EBUSY;
371c6925093SLogan Gunthorpe 		goto out_unlock;
372c6925093SLogan Gunthorpe 	}
373c6925093SLogan Gunthorpe 
374c6925093SLogan Gunthorpe 	error = pci_p2pdma_enable_store(page, &p2p_dev, &use_p2pmem);
375c6925093SLogan Gunthorpe 	if (error) {
376c6925093SLogan Gunthorpe 		ret = error;
377c6925093SLogan Gunthorpe 		goto out_unlock;
378c6925093SLogan Gunthorpe 	}
379c6925093SLogan Gunthorpe 
380c6925093SLogan Gunthorpe 	ns->use_p2pmem = use_p2pmem;
381c6925093SLogan Gunthorpe 	pci_dev_put(ns->p2p_dev);
382c6925093SLogan Gunthorpe 	ns->p2p_dev = p2p_dev;
383c6925093SLogan Gunthorpe 
384c6925093SLogan Gunthorpe out_unlock:
385c6925093SLogan Gunthorpe 	mutex_unlock(&ns->subsys->lock);
386c6925093SLogan Gunthorpe 
387c6925093SLogan Gunthorpe 	return ret;
388c6925093SLogan Gunthorpe }
389c6925093SLogan Gunthorpe 
390c6925093SLogan Gunthorpe CONFIGFS_ATTR(nvmet_ns_, p2pmem);
391c6925093SLogan Gunthorpe #endif /* CONFIG_PCI_P2PDMA */
392c6925093SLogan Gunthorpe 
393430c7befSJohannes Thumshirn static ssize_t nvmet_ns_device_uuid_show(struct config_item *item, char *page)
394430c7befSJohannes Thumshirn {
395430c7befSJohannes Thumshirn 	return sprintf(page, "%pUb\n", &to_nvmet_ns(item)->uuid);
396430c7befSJohannes Thumshirn }
397430c7befSJohannes Thumshirn 
398430c7befSJohannes Thumshirn static ssize_t nvmet_ns_device_uuid_store(struct config_item *item,
399430c7befSJohannes Thumshirn 					  const char *page, size_t count)
400430c7befSJohannes Thumshirn {
401430c7befSJohannes Thumshirn 	struct nvmet_ns *ns = to_nvmet_ns(item);
402430c7befSJohannes Thumshirn 	struct nvmet_subsys *subsys = ns->subsys;
403430c7befSJohannes Thumshirn 	int ret = 0;
404430c7befSJohannes Thumshirn 
405430c7befSJohannes Thumshirn 
406430c7befSJohannes Thumshirn 	mutex_lock(&subsys->lock);
407430c7befSJohannes Thumshirn 	if (ns->enabled) {
408430c7befSJohannes Thumshirn 		ret = -EBUSY;
409430c7befSJohannes Thumshirn 		goto out_unlock;
410430c7befSJohannes Thumshirn 	}
411430c7befSJohannes Thumshirn 
412430c7befSJohannes Thumshirn 
413430c7befSJohannes Thumshirn 	if (uuid_parse(page, &ns->uuid))
414430c7befSJohannes Thumshirn 		ret = -EINVAL;
415430c7befSJohannes Thumshirn 
416430c7befSJohannes Thumshirn out_unlock:
417430c7befSJohannes Thumshirn 	mutex_unlock(&subsys->lock);
418430c7befSJohannes Thumshirn 	return ret ? ret : count;
419430c7befSJohannes Thumshirn }
420430c7befSJohannes Thumshirn 
421f871749aSMax Gurtovoy CONFIGFS_ATTR(nvmet_ns_, device_uuid);
422f871749aSMax Gurtovoy 
423a07b4970SChristoph Hellwig static ssize_t nvmet_ns_device_nguid_show(struct config_item *item, char *page)
424a07b4970SChristoph Hellwig {
425a07b4970SChristoph Hellwig 	return sprintf(page, "%pUb\n", &to_nvmet_ns(item)->nguid);
426a07b4970SChristoph Hellwig }
427a07b4970SChristoph Hellwig 
428a07b4970SChristoph Hellwig static ssize_t nvmet_ns_device_nguid_store(struct config_item *item,
429a07b4970SChristoph Hellwig 		const char *page, size_t count)
430a07b4970SChristoph Hellwig {
431a07b4970SChristoph Hellwig 	struct nvmet_ns *ns = to_nvmet_ns(item);
432a07b4970SChristoph Hellwig 	struct nvmet_subsys *subsys = ns->subsys;
433a07b4970SChristoph Hellwig 	u8 nguid[16];
434a07b4970SChristoph Hellwig 	const char *p = page;
435a07b4970SChristoph Hellwig 	int i;
436a07b4970SChristoph Hellwig 	int ret = 0;
437a07b4970SChristoph Hellwig 
438a07b4970SChristoph Hellwig 	mutex_lock(&subsys->lock);
439e4fcf07cSSolganik Alexander 	if (ns->enabled) {
440a07b4970SChristoph Hellwig 		ret = -EBUSY;
441a07b4970SChristoph Hellwig 		goto out_unlock;
442a07b4970SChristoph Hellwig 	}
443a07b4970SChristoph Hellwig 
444a07b4970SChristoph Hellwig 	for (i = 0; i < 16; i++) {
445a07b4970SChristoph Hellwig 		if (p + 2 > page + count) {
446a07b4970SChristoph Hellwig 			ret = -EINVAL;
447a07b4970SChristoph Hellwig 			goto out_unlock;
448a07b4970SChristoph Hellwig 		}
449a07b4970SChristoph Hellwig 		if (!isxdigit(p[0]) || !isxdigit(p[1])) {
450a07b4970SChristoph Hellwig 			ret = -EINVAL;
451a07b4970SChristoph Hellwig 			goto out_unlock;
452a07b4970SChristoph Hellwig 		}
453a07b4970SChristoph Hellwig 
454a07b4970SChristoph Hellwig 		nguid[i] = (hex_to_bin(p[0]) << 4) | hex_to_bin(p[1]);
455a07b4970SChristoph Hellwig 		p += 2;
456a07b4970SChristoph Hellwig 
457a07b4970SChristoph Hellwig 		if (*p == '-' || *p == ':')
458a07b4970SChristoph Hellwig 			p++;
459a07b4970SChristoph Hellwig 	}
460a07b4970SChristoph Hellwig 
461a07b4970SChristoph Hellwig 	memcpy(&ns->nguid, nguid, sizeof(nguid));
462a07b4970SChristoph Hellwig out_unlock:
463a07b4970SChristoph Hellwig 	mutex_unlock(&subsys->lock);
464a07b4970SChristoph Hellwig 	return ret ? ret : count;
465a07b4970SChristoph Hellwig }
466a07b4970SChristoph Hellwig 
467a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_ns_, device_nguid);
468a07b4970SChristoph Hellwig 
46962ac0d32SChristoph Hellwig static ssize_t nvmet_ns_ana_grpid_show(struct config_item *item, char *page)
47062ac0d32SChristoph Hellwig {
47162ac0d32SChristoph Hellwig 	return sprintf(page, "%u\n", to_nvmet_ns(item)->anagrpid);
47262ac0d32SChristoph Hellwig }
47362ac0d32SChristoph Hellwig 
47462ac0d32SChristoph Hellwig static ssize_t nvmet_ns_ana_grpid_store(struct config_item *item,
47562ac0d32SChristoph Hellwig 		const char *page, size_t count)
47662ac0d32SChristoph Hellwig {
47762ac0d32SChristoph Hellwig 	struct nvmet_ns *ns = to_nvmet_ns(item);
47862ac0d32SChristoph Hellwig 	u32 oldgrpid, newgrpid;
47962ac0d32SChristoph Hellwig 	int ret;
48062ac0d32SChristoph Hellwig 
48162ac0d32SChristoph Hellwig 	ret = kstrtou32(page, 0, &newgrpid);
48262ac0d32SChristoph Hellwig 	if (ret)
48362ac0d32SChristoph Hellwig 		return ret;
48462ac0d32SChristoph Hellwig 
48562ac0d32SChristoph Hellwig 	if (newgrpid < 1 || newgrpid > NVMET_MAX_ANAGRPS)
48662ac0d32SChristoph Hellwig 		return -EINVAL;
48762ac0d32SChristoph Hellwig 
48862ac0d32SChristoph Hellwig 	down_write(&nvmet_ana_sem);
48962ac0d32SChristoph Hellwig 	oldgrpid = ns->anagrpid;
49062ac0d32SChristoph Hellwig 	nvmet_ana_group_enabled[newgrpid]++;
49162ac0d32SChristoph Hellwig 	ns->anagrpid = newgrpid;
49262ac0d32SChristoph Hellwig 	nvmet_ana_group_enabled[oldgrpid]--;
49362ac0d32SChristoph Hellwig 	nvmet_ana_chgcnt++;
49462ac0d32SChristoph Hellwig 	up_write(&nvmet_ana_sem);
49562ac0d32SChristoph Hellwig 
49662ac0d32SChristoph Hellwig 	nvmet_send_ana_event(ns->subsys, NULL);
49762ac0d32SChristoph Hellwig 	return count;
49862ac0d32SChristoph Hellwig }
49962ac0d32SChristoph Hellwig 
50062ac0d32SChristoph Hellwig CONFIGFS_ATTR(nvmet_ns_, ana_grpid);
50162ac0d32SChristoph Hellwig 
502a07b4970SChristoph Hellwig static ssize_t nvmet_ns_enable_show(struct config_item *item, char *page)
503a07b4970SChristoph Hellwig {
504e4fcf07cSSolganik Alexander 	return sprintf(page, "%d\n", to_nvmet_ns(item)->enabled);
505a07b4970SChristoph Hellwig }
506a07b4970SChristoph Hellwig 
507a07b4970SChristoph Hellwig static ssize_t nvmet_ns_enable_store(struct config_item *item,
508a07b4970SChristoph Hellwig 		const char *page, size_t count)
509a07b4970SChristoph Hellwig {
510a07b4970SChristoph Hellwig 	struct nvmet_ns *ns = to_nvmet_ns(item);
511a07b4970SChristoph Hellwig 	bool enable;
512a07b4970SChristoph Hellwig 	int ret = 0;
513a07b4970SChristoph Hellwig 
514a07b4970SChristoph Hellwig 	if (strtobool(page, &enable))
515a07b4970SChristoph Hellwig 		return -EINVAL;
516a07b4970SChristoph Hellwig 
517a07b4970SChristoph Hellwig 	if (enable)
518a07b4970SChristoph Hellwig 		ret = nvmet_ns_enable(ns);
519a07b4970SChristoph Hellwig 	else
520a07b4970SChristoph Hellwig 		nvmet_ns_disable(ns);
521a07b4970SChristoph Hellwig 
522a07b4970SChristoph Hellwig 	return ret ? ret : count;
523a07b4970SChristoph Hellwig }
524a07b4970SChristoph Hellwig 
525a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_ns_, enable);
526a07b4970SChristoph Hellwig 
52755eb942eSChaitanya Kulkarni static ssize_t nvmet_ns_buffered_io_show(struct config_item *item, char *page)
52855eb942eSChaitanya Kulkarni {
52955eb942eSChaitanya Kulkarni 	return sprintf(page, "%d\n", to_nvmet_ns(item)->buffered_io);
53055eb942eSChaitanya Kulkarni }
53155eb942eSChaitanya Kulkarni 
53255eb942eSChaitanya Kulkarni static ssize_t nvmet_ns_buffered_io_store(struct config_item *item,
53355eb942eSChaitanya Kulkarni 		const char *page, size_t count)
53455eb942eSChaitanya Kulkarni {
53555eb942eSChaitanya Kulkarni 	struct nvmet_ns *ns = to_nvmet_ns(item);
53655eb942eSChaitanya Kulkarni 	bool val;
53755eb942eSChaitanya Kulkarni 
53855eb942eSChaitanya Kulkarni 	if (strtobool(page, &val))
53955eb942eSChaitanya Kulkarni 		return -EINVAL;
54055eb942eSChaitanya Kulkarni 
54155eb942eSChaitanya Kulkarni 	mutex_lock(&ns->subsys->lock);
54255eb942eSChaitanya Kulkarni 	if (ns->enabled) {
54355eb942eSChaitanya Kulkarni 		pr_err("disable ns before setting buffered_io value.\n");
54455eb942eSChaitanya Kulkarni 		mutex_unlock(&ns->subsys->lock);
54555eb942eSChaitanya Kulkarni 		return -EINVAL;
54655eb942eSChaitanya Kulkarni 	}
54755eb942eSChaitanya Kulkarni 
54855eb942eSChaitanya Kulkarni 	ns->buffered_io = val;
54955eb942eSChaitanya Kulkarni 	mutex_unlock(&ns->subsys->lock);
55055eb942eSChaitanya Kulkarni 	return count;
55155eb942eSChaitanya Kulkarni }
55255eb942eSChaitanya Kulkarni 
55355eb942eSChaitanya Kulkarni CONFIGFS_ATTR(nvmet_ns_, buffered_io);
55455eb942eSChaitanya Kulkarni 
555a07b4970SChristoph Hellwig static struct configfs_attribute *nvmet_ns_attrs[] = {
556a07b4970SChristoph Hellwig 	&nvmet_ns_attr_device_path,
557a07b4970SChristoph Hellwig 	&nvmet_ns_attr_device_nguid,
558430c7befSJohannes Thumshirn 	&nvmet_ns_attr_device_uuid,
55962ac0d32SChristoph Hellwig 	&nvmet_ns_attr_ana_grpid,
560a07b4970SChristoph Hellwig 	&nvmet_ns_attr_enable,
56155eb942eSChaitanya Kulkarni 	&nvmet_ns_attr_buffered_io,
562c6925093SLogan Gunthorpe #ifdef CONFIG_PCI_P2PDMA
563c6925093SLogan Gunthorpe 	&nvmet_ns_attr_p2pmem,
564c6925093SLogan Gunthorpe #endif
565a07b4970SChristoph Hellwig 	NULL,
566a07b4970SChristoph Hellwig };
567a07b4970SChristoph Hellwig 
568a07b4970SChristoph Hellwig static void nvmet_ns_release(struct config_item *item)
569a07b4970SChristoph Hellwig {
570a07b4970SChristoph Hellwig 	struct nvmet_ns *ns = to_nvmet_ns(item);
571a07b4970SChristoph Hellwig 
572a07b4970SChristoph Hellwig 	nvmet_ns_free(ns);
573a07b4970SChristoph Hellwig }
574a07b4970SChristoph Hellwig 
575a07b4970SChristoph Hellwig static struct configfs_item_operations nvmet_ns_item_ops = {
576a07b4970SChristoph Hellwig 	.release		= nvmet_ns_release,
577a07b4970SChristoph Hellwig };
578a07b4970SChristoph Hellwig 
57966603a31SBhumika Goyal static const struct config_item_type nvmet_ns_type = {
580a07b4970SChristoph Hellwig 	.ct_item_ops		= &nvmet_ns_item_ops,
581a07b4970SChristoph Hellwig 	.ct_attrs		= nvmet_ns_attrs,
582a07b4970SChristoph Hellwig 	.ct_owner		= THIS_MODULE,
583a07b4970SChristoph Hellwig };
584a07b4970SChristoph Hellwig 
585a07b4970SChristoph Hellwig static struct config_group *nvmet_ns_make(struct config_group *group,
586a07b4970SChristoph Hellwig 		const char *name)
587a07b4970SChristoph Hellwig {
588a07b4970SChristoph Hellwig 	struct nvmet_subsys *subsys = namespaces_to_subsys(&group->cg_item);
589a07b4970SChristoph Hellwig 	struct nvmet_ns *ns;
590a07b4970SChristoph Hellwig 	int ret;
591a07b4970SChristoph Hellwig 	u32 nsid;
592a07b4970SChristoph Hellwig 
593a07b4970SChristoph Hellwig 	ret = kstrtou32(name, 0, &nsid);
594a07b4970SChristoph Hellwig 	if (ret)
595a07b4970SChristoph Hellwig 		goto out;
596a07b4970SChristoph Hellwig 
597a07b4970SChristoph Hellwig 	ret = -EINVAL;
5981645d503SChristoph Hellwig 	if (nsid == 0 || nsid == NVME_NSID_ALL)
599a07b4970SChristoph Hellwig 		goto out;
600a07b4970SChristoph Hellwig 
601a07b4970SChristoph Hellwig 	ret = -ENOMEM;
602a07b4970SChristoph Hellwig 	ns = nvmet_ns_alloc(subsys, nsid);
603a07b4970SChristoph Hellwig 	if (!ns)
604a07b4970SChristoph Hellwig 		goto out;
605a07b4970SChristoph Hellwig 	config_group_init_type_name(&ns->group, name, &nvmet_ns_type);
606a07b4970SChristoph Hellwig 
607a07b4970SChristoph Hellwig 	pr_info("adding nsid %d to subsystem %s\n", nsid, subsys->subsysnqn);
608a07b4970SChristoph Hellwig 
609a07b4970SChristoph Hellwig 	return &ns->group;
610a07b4970SChristoph Hellwig out:
611a07b4970SChristoph Hellwig 	return ERR_PTR(ret);
612a07b4970SChristoph Hellwig }
613a07b4970SChristoph Hellwig 
614a07b4970SChristoph Hellwig static struct configfs_group_operations nvmet_namespaces_group_ops = {
615a07b4970SChristoph Hellwig 	.make_group		= nvmet_ns_make,
616a07b4970SChristoph Hellwig };
617a07b4970SChristoph Hellwig 
61866603a31SBhumika Goyal static const struct config_item_type nvmet_namespaces_type = {
619a07b4970SChristoph Hellwig 	.ct_group_ops		= &nvmet_namespaces_group_ops,
620a07b4970SChristoph Hellwig 	.ct_owner		= THIS_MODULE,
621a07b4970SChristoph Hellwig };
622a07b4970SChristoph Hellwig 
623a07b4970SChristoph Hellwig static int nvmet_port_subsys_allow_link(struct config_item *parent,
624a07b4970SChristoph Hellwig 		struct config_item *target)
625a07b4970SChristoph Hellwig {
626a07b4970SChristoph Hellwig 	struct nvmet_port *port = to_nvmet_port(parent->ci_parent);
627a07b4970SChristoph Hellwig 	struct nvmet_subsys *subsys;
628a07b4970SChristoph Hellwig 	struct nvmet_subsys_link *link, *p;
629a07b4970SChristoph Hellwig 	int ret;
630a07b4970SChristoph Hellwig 
631a07b4970SChristoph Hellwig 	if (target->ci_type != &nvmet_subsys_type) {
632a07b4970SChristoph Hellwig 		pr_err("can only link subsystems into the subsystems dir.!\n");
633a07b4970SChristoph Hellwig 		return -EINVAL;
634a07b4970SChristoph Hellwig 	}
635a07b4970SChristoph Hellwig 	subsys = to_subsys(target);
636a07b4970SChristoph Hellwig 	link = kmalloc(sizeof(*link), GFP_KERNEL);
637a07b4970SChristoph Hellwig 	if (!link)
638a07b4970SChristoph Hellwig 		return -ENOMEM;
639a07b4970SChristoph Hellwig 	link->subsys = subsys;
640a07b4970SChristoph Hellwig 
641a07b4970SChristoph Hellwig 	down_write(&nvmet_config_sem);
642a07b4970SChristoph Hellwig 	ret = -EEXIST;
643a07b4970SChristoph Hellwig 	list_for_each_entry(p, &port->subsystems, entry) {
644a07b4970SChristoph Hellwig 		if (p->subsys == subsys)
645a07b4970SChristoph Hellwig 			goto out_free_link;
646a07b4970SChristoph Hellwig 	}
647a07b4970SChristoph Hellwig 
648a07b4970SChristoph Hellwig 	if (list_empty(&port->subsystems)) {
649a07b4970SChristoph Hellwig 		ret = nvmet_enable_port(port);
650a07b4970SChristoph Hellwig 		if (ret)
651a07b4970SChristoph Hellwig 			goto out_free_link;
652a07b4970SChristoph Hellwig 	}
653a07b4970SChristoph Hellwig 
654a07b4970SChristoph Hellwig 	list_add_tail(&link->entry, &port->subsystems);
655b662a078SJay Sternberg 	nvmet_port_disc_changed(port, subsys);
656b662a078SJay Sternberg 
657a07b4970SChristoph Hellwig 	up_write(&nvmet_config_sem);
658a07b4970SChristoph Hellwig 	return 0;
659a07b4970SChristoph Hellwig 
660a07b4970SChristoph Hellwig out_free_link:
661a07b4970SChristoph Hellwig 	up_write(&nvmet_config_sem);
662a07b4970SChristoph Hellwig 	kfree(link);
663a07b4970SChristoph Hellwig 	return ret;
664a07b4970SChristoph Hellwig }
665a07b4970SChristoph Hellwig 
666e16769d4SAndrzej Pietrasiewicz static void nvmet_port_subsys_drop_link(struct config_item *parent,
667a07b4970SChristoph Hellwig 		struct config_item *target)
668a07b4970SChristoph Hellwig {
669a07b4970SChristoph Hellwig 	struct nvmet_port *port = to_nvmet_port(parent->ci_parent);
670a07b4970SChristoph Hellwig 	struct nvmet_subsys *subsys = to_subsys(target);
671a07b4970SChristoph Hellwig 	struct nvmet_subsys_link *p;
672a07b4970SChristoph Hellwig 
673a07b4970SChristoph Hellwig 	down_write(&nvmet_config_sem);
674a07b4970SChristoph Hellwig 	list_for_each_entry(p, &port->subsystems, entry) {
675a07b4970SChristoph Hellwig 		if (p->subsys == subsys)
676a07b4970SChristoph Hellwig 			goto found;
677a07b4970SChristoph Hellwig 	}
678a07b4970SChristoph Hellwig 	up_write(&nvmet_config_sem);
679e16769d4SAndrzej Pietrasiewicz 	return;
680a07b4970SChristoph Hellwig 
681a07b4970SChristoph Hellwig found:
682a07b4970SChristoph Hellwig 	list_del(&p->entry);
683b662a078SJay Sternberg 	nvmet_port_disc_changed(port, subsys);
684b662a078SJay Sternberg 
685a07b4970SChristoph Hellwig 	if (list_empty(&port->subsystems))
686a07b4970SChristoph Hellwig 		nvmet_disable_port(port);
687a07b4970SChristoph Hellwig 	up_write(&nvmet_config_sem);
688a07b4970SChristoph Hellwig 	kfree(p);
689a07b4970SChristoph Hellwig }
690a07b4970SChristoph Hellwig 
691a07b4970SChristoph Hellwig static struct configfs_item_operations nvmet_port_subsys_item_ops = {
692a07b4970SChristoph Hellwig 	.allow_link		= nvmet_port_subsys_allow_link,
693a07b4970SChristoph Hellwig 	.drop_link		= nvmet_port_subsys_drop_link,
694a07b4970SChristoph Hellwig };
695a07b4970SChristoph Hellwig 
69666603a31SBhumika Goyal static const struct config_item_type nvmet_port_subsys_type = {
697a07b4970SChristoph Hellwig 	.ct_item_ops		= &nvmet_port_subsys_item_ops,
698a07b4970SChristoph Hellwig 	.ct_owner		= THIS_MODULE,
699a07b4970SChristoph Hellwig };
700a07b4970SChristoph Hellwig 
701a07b4970SChristoph Hellwig static int nvmet_allowed_hosts_allow_link(struct config_item *parent,
702a07b4970SChristoph Hellwig 		struct config_item *target)
703a07b4970SChristoph Hellwig {
704a07b4970SChristoph Hellwig 	struct nvmet_subsys *subsys = to_subsys(parent->ci_parent);
705a07b4970SChristoph Hellwig 	struct nvmet_host *host;
706a07b4970SChristoph Hellwig 	struct nvmet_host_link *link, *p;
707a07b4970SChristoph Hellwig 	int ret;
708a07b4970SChristoph Hellwig 
709a07b4970SChristoph Hellwig 	if (target->ci_type != &nvmet_host_type) {
710a07b4970SChristoph Hellwig 		pr_err("can only link hosts into the allowed_hosts directory!\n");
711a07b4970SChristoph Hellwig 		return -EINVAL;
712a07b4970SChristoph Hellwig 	}
713a07b4970SChristoph Hellwig 
714a07b4970SChristoph Hellwig 	host = to_host(target);
715a07b4970SChristoph Hellwig 	link = kmalloc(sizeof(*link), GFP_KERNEL);
716a07b4970SChristoph Hellwig 	if (!link)
717a07b4970SChristoph Hellwig 		return -ENOMEM;
718a07b4970SChristoph Hellwig 	link->host = host;
719a07b4970SChristoph Hellwig 
720a07b4970SChristoph Hellwig 	down_write(&nvmet_config_sem);
721a07b4970SChristoph Hellwig 	ret = -EINVAL;
722a07b4970SChristoph Hellwig 	if (subsys->allow_any_host) {
723a07b4970SChristoph Hellwig 		pr_err("can't add hosts when allow_any_host is set!\n");
724a07b4970SChristoph Hellwig 		goto out_free_link;
725a07b4970SChristoph Hellwig 	}
726a07b4970SChristoph Hellwig 
727a07b4970SChristoph Hellwig 	ret = -EEXIST;
728a07b4970SChristoph Hellwig 	list_for_each_entry(p, &subsys->hosts, entry) {
729a07b4970SChristoph Hellwig 		if (!strcmp(nvmet_host_name(p->host), nvmet_host_name(host)))
730a07b4970SChristoph Hellwig 			goto out_free_link;
731a07b4970SChristoph Hellwig 	}
732a07b4970SChristoph Hellwig 	list_add_tail(&link->entry, &subsys->hosts);
733b662a078SJay Sternberg 	nvmet_subsys_disc_changed(subsys, host);
734b662a078SJay Sternberg 
735a07b4970SChristoph Hellwig 	up_write(&nvmet_config_sem);
736a07b4970SChristoph Hellwig 	return 0;
737a07b4970SChristoph Hellwig out_free_link:
738a07b4970SChristoph Hellwig 	up_write(&nvmet_config_sem);
739a07b4970SChristoph Hellwig 	kfree(link);
740a07b4970SChristoph Hellwig 	return ret;
741a07b4970SChristoph Hellwig }
742a07b4970SChristoph Hellwig 
743e16769d4SAndrzej Pietrasiewicz static void nvmet_allowed_hosts_drop_link(struct config_item *parent,
744a07b4970SChristoph Hellwig 		struct config_item *target)
745a07b4970SChristoph Hellwig {
746a07b4970SChristoph Hellwig 	struct nvmet_subsys *subsys = to_subsys(parent->ci_parent);
747a07b4970SChristoph Hellwig 	struct nvmet_host *host = to_host(target);
748a07b4970SChristoph Hellwig 	struct nvmet_host_link *p;
749a07b4970SChristoph Hellwig 
750a07b4970SChristoph Hellwig 	down_write(&nvmet_config_sem);
751a07b4970SChristoph Hellwig 	list_for_each_entry(p, &subsys->hosts, entry) {
752a07b4970SChristoph Hellwig 		if (!strcmp(nvmet_host_name(p->host), nvmet_host_name(host)))
753a07b4970SChristoph Hellwig 			goto found;
754a07b4970SChristoph Hellwig 	}
755a07b4970SChristoph Hellwig 	up_write(&nvmet_config_sem);
756e16769d4SAndrzej Pietrasiewicz 	return;
757a07b4970SChristoph Hellwig 
758a07b4970SChristoph Hellwig found:
759a07b4970SChristoph Hellwig 	list_del(&p->entry);
760b662a078SJay Sternberg 	nvmet_subsys_disc_changed(subsys, host);
761b662a078SJay Sternberg 
762a07b4970SChristoph Hellwig 	up_write(&nvmet_config_sem);
763a07b4970SChristoph Hellwig 	kfree(p);
764a07b4970SChristoph Hellwig }
765a07b4970SChristoph Hellwig 
766a07b4970SChristoph Hellwig static struct configfs_item_operations nvmet_allowed_hosts_item_ops = {
767a07b4970SChristoph Hellwig 	.allow_link		= nvmet_allowed_hosts_allow_link,
768a07b4970SChristoph Hellwig 	.drop_link		= nvmet_allowed_hosts_drop_link,
769a07b4970SChristoph Hellwig };
770a07b4970SChristoph Hellwig 
77166603a31SBhumika Goyal static const struct config_item_type nvmet_allowed_hosts_type = {
772a07b4970SChristoph Hellwig 	.ct_item_ops		= &nvmet_allowed_hosts_item_ops,
773a07b4970SChristoph Hellwig 	.ct_owner		= THIS_MODULE,
774a07b4970SChristoph Hellwig };
775a07b4970SChristoph Hellwig 
776a07b4970SChristoph Hellwig static ssize_t nvmet_subsys_attr_allow_any_host_show(struct config_item *item,
777a07b4970SChristoph Hellwig 		char *page)
778a07b4970SChristoph Hellwig {
779a07b4970SChristoph Hellwig 	return snprintf(page, PAGE_SIZE, "%d\n",
780a07b4970SChristoph Hellwig 		to_subsys(item)->allow_any_host);
781a07b4970SChristoph Hellwig }
782a07b4970SChristoph Hellwig 
783a07b4970SChristoph Hellwig static ssize_t nvmet_subsys_attr_allow_any_host_store(struct config_item *item,
784a07b4970SChristoph Hellwig 		const char *page, size_t count)
785a07b4970SChristoph Hellwig {
786a07b4970SChristoph Hellwig 	struct nvmet_subsys *subsys = to_subsys(item);
787a07b4970SChristoph Hellwig 	bool allow_any_host;
788a07b4970SChristoph Hellwig 	int ret = 0;
789a07b4970SChristoph Hellwig 
790a07b4970SChristoph Hellwig 	if (strtobool(page, &allow_any_host))
791a07b4970SChristoph Hellwig 		return -EINVAL;
792a07b4970SChristoph Hellwig 
793a07b4970SChristoph Hellwig 	down_write(&nvmet_config_sem);
794a07b4970SChristoph Hellwig 	if (allow_any_host && !list_empty(&subsys->hosts)) {
795a07b4970SChristoph Hellwig 		pr_err("Can't set allow_any_host when explicit hosts are set!\n");
796a07b4970SChristoph Hellwig 		ret = -EINVAL;
797a07b4970SChristoph Hellwig 		goto out_unlock;
798a07b4970SChristoph Hellwig 	}
799a07b4970SChristoph Hellwig 
800b662a078SJay Sternberg 	if (subsys->allow_any_host != allow_any_host) {
801a07b4970SChristoph Hellwig 		subsys->allow_any_host = allow_any_host;
802b662a078SJay Sternberg 		nvmet_subsys_disc_changed(subsys, NULL);
803b662a078SJay Sternberg 	}
804b662a078SJay Sternberg 
805a07b4970SChristoph Hellwig out_unlock:
806a07b4970SChristoph Hellwig 	up_write(&nvmet_config_sem);
807a07b4970SChristoph Hellwig 	return ret ? ret : count;
808a07b4970SChristoph Hellwig }
809a07b4970SChristoph Hellwig 
810a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_subsys_, attr_allow_any_host);
811a07b4970SChristoph Hellwig 
81241528f80SJohannes Thumshirn static ssize_t nvmet_subsys_attr_version_show(struct config_item *item,
813c61d788bSJohannes Thumshirn 					      char *page)
814c61d788bSJohannes Thumshirn {
815c61d788bSJohannes Thumshirn 	struct nvmet_subsys *subsys = to_subsys(item);
816c61d788bSJohannes Thumshirn 
817c61d788bSJohannes Thumshirn 	if (NVME_TERTIARY(subsys->ver))
818c61d788bSJohannes Thumshirn 		return snprintf(page, PAGE_SIZE, "%d.%d.%d\n",
819c61d788bSJohannes Thumshirn 				(int)NVME_MAJOR(subsys->ver),
820c61d788bSJohannes Thumshirn 				(int)NVME_MINOR(subsys->ver),
821c61d788bSJohannes Thumshirn 				(int)NVME_TERTIARY(subsys->ver));
822c61d788bSJohannes Thumshirn 	else
823c61d788bSJohannes Thumshirn 		return snprintf(page, PAGE_SIZE, "%d.%d\n",
824c61d788bSJohannes Thumshirn 				(int)NVME_MAJOR(subsys->ver),
825c61d788bSJohannes Thumshirn 				(int)NVME_MINOR(subsys->ver));
826c61d788bSJohannes Thumshirn }
827c61d788bSJohannes Thumshirn 
82841528f80SJohannes Thumshirn static ssize_t nvmet_subsys_attr_version_store(struct config_item *item,
829c61d788bSJohannes Thumshirn 					       const char *page, size_t count)
830c61d788bSJohannes Thumshirn {
831c61d788bSJohannes Thumshirn 	struct nvmet_subsys *subsys = to_subsys(item);
832c61d788bSJohannes Thumshirn 	int major, minor, tertiary = 0;
833c61d788bSJohannes Thumshirn 	int ret;
834c61d788bSJohannes Thumshirn 
835c61d788bSJohannes Thumshirn 
836c61d788bSJohannes Thumshirn 	ret = sscanf(page, "%d.%d.%d\n", &major, &minor, &tertiary);
837c61d788bSJohannes Thumshirn 	if (ret != 2 && ret != 3)
838c61d788bSJohannes Thumshirn 		return -EINVAL;
839c61d788bSJohannes Thumshirn 
840c61d788bSJohannes Thumshirn 	down_write(&nvmet_config_sem);
841c61d788bSJohannes Thumshirn 	subsys->ver = NVME_VS(major, minor, tertiary);
842c61d788bSJohannes Thumshirn 	up_write(&nvmet_config_sem);
843c61d788bSJohannes Thumshirn 
844c61d788bSJohannes Thumshirn 	return count;
845c61d788bSJohannes Thumshirn }
84641528f80SJohannes Thumshirn CONFIGFS_ATTR(nvmet_subsys_, attr_version);
847c61d788bSJohannes Thumshirn 
848fcbc5459SJohannes Thumshirn static ssize_t nvmet_subsys_attr_serial_show(struct config_item *item,
849fcbc5459SJohannes Thumshirn 					     char *page)
850fcbc5459SJohannes Thumshirn {
851fcbc5459SJohannes Thumshirn 	struct nvmet_subsys *subsys = to_subsys(item);
852fcbc5459SJohannes Thumshirn 
853fcbc5459SJohannes Thumshirn 	return snprintf(page, PAGE_SIZE, "%llx\n", subsys->serial);
854fcbc5459SJohannes Thumshirn }
855fcbc5459SJohannes Thumshirn 
856fcbc5459SJohannes Thumshirn static ssize_t nvmet_subsys_attr_serial_store(struct config_item *item,
857fcbc5459SJohannes Thumshirn 					      const char *page, size_t count)
858fcbc5459SJohannes Thumshirn {
859fcbc5459SJohannes Thumshirn 	struct nvmet_subsys *subsys = to_subsys(item);
860fcbc5459SJohannes Thumshirn 
861fcbc5459SJohannes Thumshirn 	down_write(&nvmet_config_sem);
862fcbc5459SJohannes Thumshirn 	sscanf(page, "%llx\n", &subsys->serial);
863fcbc5459SJohannes Thumshirn 	up_write(&nvmet_config_sem);
864fcbc5459SJohannes Thumshirn 
865fcbc5459SJohannes Thumshirn 	return count;
866fcbc5459SJohannes Thumshirn }
867fcbc5459SJohannes Thumshirn CONFIGFS_ATTR(nvmet_subsys_, attr_serial);
868fcbc5459SJohannes Thumshirn 
869a07b4970SChristoph Hellwig static struct configfs_attribute *nvmet_subsys_attrs[] = {
870a07b4970SChristoph Hellwig 	&nvmet_subsys_attr_attr_allow_any_host,
87141528f80SJohannes Thumshirn 	&nvmet_subsys_attr_attr_version,
872fcbc5459SJohannes Thumshirn 	&nvmet_subsys_attr_attr_serial,
873a07b4970SChristoph Hellwig 	NULL,
874a07b4970SChristoph Hellwig };
875a07b4970SChristoph Hellwig 
876a07b4970SChristoph Hellwig /*
877a07b4970SChristoph Hellwig  * Subsystem structures & folder operation functions below
878a07b4970SChristoph Hellwig  */
879a07b4970SChristoph Hellwig static void nvmet_subsys_release(struct config_item *item)
880a07b4970SChristoph Hellwig {
881a07b4970SChristoph Hellwig 	struct nvmet_subsys *subsys = to_subsys(item);
882a07b4970SChristoph Hellwig 
883344770b0SSagi Grimberg 	nvmet_subsys_del_ctrls(subsys);
884a07b4970SChristoph Hellwig 	nvmet_subsys_put(subsys);
885a07b4970SChristoph Hellwig }
886a07b4970SChristoph Hellwig 
887a07b4970SChristoph Hellwig static struct configfs_item_operations nvmet_subsys_item_ops = {
888a07b4970SChristoph Hellwig 	.release		= nvmet_subsys_release,
889a07b4970SChristoph Hellwig };
890a07b4970SChristoph Hellwig 
89166603a31SBhumika Goyal static const struct config_item_type nvmet_subsys_type = {
892a07b4970SChristoph Hellwig 	.ct_item_ops		= &nvmet_subsys_item_ops,
893a07b4970SChristoph Hellwig 	.ct_attrs		= nvmet_subsys_attrs,
894a07b4970SChristoph Hellwig 	.ct_owner		= THIS_MODULE,
895a07b4970SChristoph Hellwig };
896a07b4970SChristoph Hellwig 
897a07b4970SChristoph Hellwig static struct config_group *nvmet_subsys_make(struct config_group *group,
898a07b4970SChristoph Hellwig 		const char *name)
899a07b4970SChristoph Hellwig {
900a07b4970SChristoph Hellwig 	struct nvmet_subsys *subsys;
901a07b4970SChristoph Hellwig 
902a07b4970SChristoph Hellwig 	if (sysfs_streq(name, NVME_DISC_SUBSYS_NAME)) {
903a07b4970SChristoph Hellwig 		pr_err("can't create discovery subsystem through configfs\n");
904a07b4970SChristoph Hellwig 		return ERR_PTR(-EINVAL);
905a07b4970SChristoph Hellwig 	}
906a07b4970SChristoph Hellwig 
907a07b4970SChristoph Hellwig 	subsys = nvmet_subsys_alloc(name, NVME_NQN_NVME);
908a07b4970SChristoph Hellwig 	if (!subsys)
909a07b4970SChristoph Hellwig 		return ERR_PTR(-ENOMEM);
910a07b4970SChristoph Hellwig 
911a07b4970SChristoph Hellwig 	config_group_init_type_name(&subsys->group, name, &nvmet_subsys_type);
912a07b4970SChristoph Hellwig 
913a07b4970SChristoph Hellwig 	config_group_init_type_name(&subsys->namespaces_group,
914a07b4970SChristoph Hellwig 			"namespaces", &nvmet_namespaces_type);
915a07b4970SChristoph Hellwig 	configfs_add_default_group(&subsys->namespaces_group, &subsys->group);
916a07b4970SChristoph Hellwig 
917a07b4970SChristoph Hellwig 	config_group_init_type_name(&subsys->allowed_hosts_group,
918a07b4970SChristoph Hellwig 			"allowed_hosts", &nvmet_allowed_hosts_type);
919a07b4970SChristoph Hellwig 	configfs_add_default_group(&subsys->allowed_hosts_group,
920a07b4970SChristoph Hellwig 			&subsys->group);
921a07b4970SChristoph Hellwig 
922a07b4970SChristoph Hellwig 	return &subsys->group;
923a07b4970SChristoph Hellwig }
924a07b4970SChristoph Hellwig 
925a07b4970SChristoph Hellwig static struct configfs_group_operations nvmet_subsystems_group_ops = {
926a07b4970SChristoph Hellwig 	.make_group		= nvmet_subsys_make,
927a07b4970SChristoph Hellwig };
928a07b4970SChristoph Hellwig 
92966603a31SBhumika Goyal static const struct config_item_type nvmet_subsystems_type = {
930a07b4970SChristoph Hellwig 	.ct_group_ops		= &nvmet_subsystems_group_ops,
931a07b4970SChristoph Hellwig 	.ct_owner		= THIS_MODULE,
932a07b4970SChristoph Hellwig };
933a07b4970SChristoph Hellwig 
934a07b4970SChristoph Hellwig static ssize_t nvmet_referral_enable_show(struct config_item *item,
935a07b4970SChristoph Hellwig 		char *page)
936a07b4970SChristoph Hellwig {
937a07b4970SChristoph Hellwig 	return snprintf(page, PAGE_SIZE, "%d\n", to_nvmet_port(item)->enabled);
938a07b4970SChristoph Hellwig }
939a07b4970SChristoph Hellwig 
940a07b4970SChristoph Hellwig static ssize_t nvmet_referral_enable_store(struct config_item *item,
941a07b4970SChristoph Hellwig 		const char *page, size_t count)
942a07b4970SChristoph Hellwig {
943a07b4970SChristoph Hellwig 	struct nvmet_port *parent = to_nvmet_port(item->ci_parent->ci_parent);
944a07b4970SChristoph Hellwig 	struct nvmet_port *port = to_nvmet_port(item);
945a07b4970SChristoph Hellwig 	bool enable;
946a07b4970SChristoph Hellwig 
947a07b4970SChristoph Hellwig 	if (strtobool(page, &enable))
948a07b4970SChristoph Hellwig 		goto inval;
949a07b4970SChristoph Hellwig 
950a07b4970SChristoph Hellwig 	if (enable)
951a07b4970SChristoph Hellwig 		nvmet_referral_enable(parent, port);
952a07b4970SChristoph Hellwig 	else
953b662a078SJay Sternberg 		nvmet_referral_disable(parent, port);
954a07b4970SChristoph Hellwig 
955a07b4970SChristoph Hellwig 	return count;
956a07b4970SChristoph Hellwig inval:
957a07b4970SChristoph Hellwig 	pr_err("Invalid value '%s' for enable\n", page);
958a07b4970SChristoph Hellwig 	return -EINVAL;
959a07b4970SChristoph Hellwig }
960a07b4970SChristoph Hellwig 
961a07b4970SChristoph Hellwig CONFIGFS_ATTR(nvmet_referral_, enable);
962a07b4970SChristoph Hellwig 
963a07b4970SChristoph Hellwig /*
964a07b4970SChristoph Hellwig  * Discovery Service subsystem definitions
965a07b4970SChristoph Hellwig  */
966a07b4970SChristoph Hellwig static struct configfs_attribute *nvmet_referral_attrs[] = {
967a07b4970SChristoph Hellwig 	&nvmet_attr_addr_adrfam,
968a07b4970SChristoph Hellwig 	&nvmet_attr_addr_portid,
969a07b4970SChristoph Hellwig 	&nvmet_attr_addr_treq,
970a07b4970SChristoph Hellwig 	&nvmet_attr_addr_traddr,
971a07b4970SChristoph Hellwig 	&nvmet_attr_addr_trsvcid,
972a07b4970SChristoph Hellwig 	&nvmet_attr_addr_trtype,
973a07b4970SChristoph Hellwig 	&nvmet_referral_attr_enable,
974a07b4970SChristoph Hellwig 	NULL,
975a07b4970SChristoph Hellwig };
976a07b4970SChristoph Hellwig 
977a07b4970SChristoph Hellwig static void nvmet_referral_release(struct config_item *item)
978a07b4970SChristoph Hellwig {
979b662a078SJay Sternberg 	struct nvmet_port *parent = to_nvmet_port(item->ci_parent->ci_parent);
980a07b4970SChristoph Hellwig 	struct nvmet_port *port = to_nvmet_port(item);
981a07b4970SChristoph Hellwig 
982b662a078SJay Sternberg 	nvmet_referral_disable(parent, port);
983a07b4970SChristoph Hellwig 	kfree(port);
984a07b4970SChristoph Hellwig }
985a07b4970SChristoph Hellwig 
986a07b4970SChristoph Hellwig static struct configfs_item_operations nvmet_referral_item_ops = {
987a07b4970SChristoph Hellwig 	.release	= nvmet_referral_release,
988a07b4970SChristoph Hellwig };
989a07b4970SChristoph Hellwig 
99066603a31SBhumika Goyal static const struct config_item_type nvmet_referral_type = {
991a07b4970SChristoph Hellwig 	.ct_owner	= THIS_MODULE,
992a07b4970SChristoph Hellwig 	.ct_attrs	= nvmet_referral_attrs,
993a07b4970SChristoph Hellwig 	.ct_item_ops	= &nvmet_referral_item_ops,
994a07b4970SChristoph Hellwig };
995a07b4970SChristoph Hellwig 
996a07b4970SChristoph Hellwig static struct config_group *nvmet_referral_make(
997a07b4970SChristoph Hellwig 		struct config_group *group, const char *name)
998a07b4970SChristoph Hellwig {
999a07b4970SChristoph Hellwig 	struct nvmet_port *port;
1000a07b4970SChristoph Hellwig 
1001a07b4970SChristoph Hellwig 	port = kzalloc(sizeof(*port), GFP_KERNEL);
1002a07b4970SChristoph Hellwig 	if (!port)
1003f98d9ca1SDan Carpenter 		return ERR_PTR(-ENOMEM);
1004a07b4970SChristoph Hellwig 
1005a07b4970SChristoph Hellwig 	INIT_LIST_HEAD(&port->entry);
1006a07b4970SChristoph Hellwig 	config_group_init_type_name(&port->group, name, &nvmet_referral_type);
1007a07b4970SChristoph Hellwig 
1008a07b4970SChristoph Hellwig 	return &port->group;
1009a07b4970SChristoph Hellwig }
1010a07b4970SChristoph Hellwig 
1011a07b4970SChristoph Hellwig static struct configfs_group_operations nvmet_referral_group_ops = {
1012a07b4970SChristoph Hellwig 	.make_group		= nvmet_referral_make,
1013a07b4970SChristoph Hellwig };
1014a07b4970SChristoph Hellwig 
101566603a31SBhumika Goyal static const struct config_item_type nvmet_referrals_type = {
1016a07b4970SChristoph Hellwig 	.ct_owner	= THIS_MODULE,
1017a07b4970SChristoph Hellwig 	.ct_group_ops	= &nvmet_referral_group_ops,
1018a07b4970SChristoph Hellwig };
1019a07b4970SChristoph Hellwig 
102062ac0d32SChristoph Hellwig static struct {
102162ac0d32SChristoph Hellwig 	enum nvme_ana_state	state;
102262ac0d32SChristoph Hellwig 	const char		*name;
102362ac0d32SChristoph Hellwig } nvmet_ana_state_names[] = {
102462ac0d32SChristoph Hellwig 	{ NVME_ANA_OPTIMIZED,		"optimized" },
102562ac0d32SChristoph Hellwig 	{ NVME_ANA_NONOPTIMIZED,	"non-optimized" },
102662ac0d32SChristoph Hellwig 	{ NVME_ANA_INACCESSIBLE,	"inaccessible" },
102762ac0d32SChristoph Hellwig 	{ NVME_ANA_PERSISTENT_LOSS,	"persistent-loss" },
102862ac0d32SChristoph Hellwig 	{ NVME_ANA_CHANGE,		"change" },
102962ac0d32SChristoph Hellwig };
103062ac0d32SChristoph Hellwig 
103162ac0d32SChristoph Hellwig static ssize_t nvmet_ana_group_ana_state_show(struct config_item *item,
103262ac0d32SChristoph Hellwig 		char *page)
103362ac0d32SChristoph Hellwig {
103462ac0d32SChristoph Hellwig 	struct nvmet_ana_group *grp = to_ana_group(item);
103562ac0d32SChristoph Hellwig 	enum nvme_ana_state state = grp->port->ana_state[grp->grpid];
103662ac0d32SChristoph Hellwig 	int i;
103762ac0d32SChristoph Hellwig 
103862ac0d32SChristoph Hellwig 	for (i = 0; i < ARRAY_SIZE(nvmet_ana_state_names); i++) {
103962ac0d32SChristoph Hellwig 		if (state != nvmet_ana_state_names[i].state)
104062ac0d32SChristoph Hellwig 			continue;
104162ac0d32SChristoph Hellwig 		return sprintf(page, "%s\n", nvmet_ana_state_names[i].name);
104262ac0d32SChristoph Hellwig 	}
104362ac0d32SChristoph Hellwig 
104462ac0d32SChristoph Hellwig 	return sprintf(page, "\n");
104562ac0d32SChristoph Hellwig }
104662ac0d32SChristoph Hellwig 
104762ac0d32SChristoph Hellwig static ssize_t nvmet_ana_group_ana_state_store(struct config_item *item,
104862ac0d32SChristoph Hellwig 		const char *page, size_t count)
104962ac0d32SChristoph Hellwig {
105062ac0d32SChristoph Hellwig 	struct nvmet_ana_group *grp = to_ana_group(item);
105162ac0d32SChristoph Hellwig 	int i;
105262ac0d32SChristoph Hellwig 
105362ac0d32SChristoph Hellwig 	for (i = 0; i < ARRAY_SIZE(nvmet_ana_state_names); i++) {
105462ac0d32SChristoph Hellwig 		if (sysfs_streq(page, nvmet_ana_state_names[i].name))
105562ac0d32SChristoph Hellwig 			goto found;
105662ac0d32SChristoph Hellwig 	}
105762ac0d32SChristoph Hellwig 
105862ac0d32SChristoph Hellwig 	pr_err("Invalid value '%s' for ana_state\n", page);
105962ac0d32SChristoph Hellwig 	return -EINVAL;
106062ac0d32SChristoph Hellwig 
106162ac0d32SChristoph Hellwig found:
106262ac0d32SChristoph Hellwig 	down_write(&nvmet_ana_sem);
106362ac0d32SChristoph Hellwig 	grp->port->ana_state[grp->grpid] = nvmet_ana_state_names[i].state;
106462ac0d32SChristoph Hellwig 	nvmet_ana_chgcnt++;
106562ac0d32SChristoph Hellwig 	up_write(&nvmet_ana_sem);
106662ac0d32SChristoph Hellwig 
106762ac0d32SChristoph Hellwig 	nvmet_port_send_ana_event(grp->port);
106862ac0d32SChristoph Hellwig 	return count;
106962ac0d32SChristoph Hellwig }
107062ac0d32SChristoph Hellwig 
107162ac0d32SChristoph Hellwig CONFIGFS_ATTR(nvmet_ana_group_, ana_state);
107262ac0d32SChristoph Hellwig 
107362ac0d32SChristoph Hellwig static struct configfs_attribute *nvmet_ana_group_attrs[] = {
107462ac0d32SChristoph Hellwig 	&nvmet_ana_group_attr_ana_state,
107562ac0d32SChristoph Hellwig 	NULL,
107662ac0d32SChristoph Hellwig };
107762ac0d32SChristoph Hellwig 
107862ac0d32SChristoph Hellwig static void nvmet_ana_group_release(struct config_item *item)
107962ac0d32SChristoph Hellwig {
108062ac0d32SChristoph Hellwig 	struct nvmet_ana_group *grp = to_ana_group(item);
108162ac0d32SChristoph Hellwig 
108262ac0d32SChristoph Hellwig 	if (grp == &grp->port->ana_default_group)
108362ac0d32SChristoph Hellwig 		return;
108462ac0d32SChristoph Hellwig 
108562ac0d32SChristoph Hellwig 	down_write(&nvmet_ana_sem);
108662ac0d32SChristoph Hellwig 	grp->port->ana_state[grp->grpid] = NVME_ANA_INACCESSIBLE;
108762ac0d32SChristoph Hellwig 	nvmet_ana_group_enabled[grp->grpid]--;
108862ac0d32SChristoph Hellwig 	up_write(&nvmet_ana_sem);
108962ac0d32SChristoph Hellwig 
109062ac0d32SChristoph Hellwig 	nvmet_port_send_ana_event(grp->port);
109162ac0d32SChristoph Hellwig 	kfree(grp);
109262ac0d32SChristoph Hellwig }
109362ac0d32SChristoph Hellwig 
109462ac0d32SChristoph Hellwig static struct configfs_item_operations nvmet_ana_group_item_ops = {
109562ac0d32SChristoph Hellwig 	.release		= nvmet_ana_group_release,
109662ac0d32SChristoph Hellwig };
109762ac0d32SChristoph Hellwig 
109862ac0d32SChristoph Hellwig static const struct config_item_type nvmet_ana_group_type = {
109962ac0d32SChristoph Hellwig 	.ct_item_ops		= &nvmet_ana_group_item_ops,
110062ac0d32SChristoph Hellwig 	.ct_attrs		= nvmet_ana_group_attrs,
110162ac0d32SChristoph Hellwig 	.ct_owner		= THIS_MODULE,
110262ac0d32SChristoph Hellwig };
110362ac0d32SChristoph Hellwig 
110462ac0d32SChristoph Hellwig static struct config_group *nvmet_ana_groups_make_group(
110562ac0d32SChristoph Hellwig 		struct config_group *group, const char *name)
110662ac0d32SChristoph Hellwig {
110762ac0d32SChristoph Hellwig 	struct nvmet_port *port = ana_groups_to_port(&group->cg_item);
110862ac0d32SChristoph Hellwig 	struct nvmet_ana_group *grp;
110962ac0d32SChristoph Hellwig 	u32 grpid;
111062ac0d32SChristoph Hellwig 	int ret;
111162ac0d32SChristoph Hellwig 
111262ac0d32SChristoph Hellwig 	ret = kstrtou32(name, 0, &grpid);
111362ac0d32SChristoph Hellwig 	if (ret)
111462ac0d32SChristoph Hellwig 		goto out;
111562ac0d32SChristoph Hellwig 
111662ac0d32SChristoph Hellwig 	ret = -EINVAL;
111762ac0d32SChristoph Hellwig 	if (grpid <= 1 || grpid > NVMET_MAX_ANAGRPS)
111862ac0d32SChristoph Hellwig 		goto out;
111962ac0d32SChristoph Hellwig 
112062ac0d32SChristoph Hellwig 	ret = -ENOMEM;
112162ac0d32SChristoph Hellwig 	grp = kzalloc(sizeof(*grp), GFP_KERNEL);
112262ac0d32SChristoph Hellwig 	if (!grp)
112362ac0d32SChristoph Hellwig 		goto out;
112462ac0d32SChristoph Hellwig 	grp->port = port;
112562ac0d32SChristoph Hellwig 	grp->grpid = grpid;
112662ac0d32SChristoph Hellwig 
112762ac0d32SChristoph Hellwig 	down_write(&nvmet_ana_sem);
112862ac0d32SChristoph Hellwig 	nvmet_ana_group_enabled[grpid]++;
112962ac0d32SChristoph Hellwig 	up_write(&nvmet_ana_sem);
113062ac0d32SChristoph Hellwig 
113162ac0d32SChristoph Hellwig 	nvmet_port_send_ana_event(grp->port);
113262ac0d32SChristoph Hellwig 
113362ac0d32SChristoph Hellwig 	config_group_init_type_name(&grp->group, name, &nvmet_ana_group_type);
113462ac0d32SChristoph Hellwig 	return &grp->group;
113562ac0d32SChristoph Hellwig out:
113662ac0d32SChristoph Hellwig 	return ERR_PTR(ret);
113762ac0d32SChristoph Hellwig }
113862ac0d32SChristoph Hellwig 
113962ac0d32SChristoph Hellwig static struct configfs_group_operations nvmet_ana_groups_group_ops = {
114062ac0d32SChristoph Hellwig 	.make_group		= nvmet_ana_groups_make_group,
114162ac0d32SChristoph Hellwig };
114262ac0d32SChristoph Hellwig 
114362ac0d32SChristoph Hellwig static const struct config_item_type nvmet_ana_groups_type = {
114462ac0d32SChristoph Hellwig 	.ct_group_ops		= &nvmet_ana_groups_group_ops,
114562ac0d32SChristoph Hellwig 	.ct_owner		= THIS_MODULE,
114662ac0d32SChristoph Hellwig };
114762ac0d32SChristoph Hellwig 
1148a07b4970SChristoph Hellwig /*
1149a07b4970SChristoph Hellwig  * Ports definitions.
1150a07b4970SChristoph Hellwig  */
1151a07b4970SChristoph Hellwig static void nvmet_port_release(struct config_item *item)
1152a07b4970SChristoph Hellwig {
1153a07b4970SChristoph Hellwig 	struct nvmet_port *port = to_nvmet_port(item);
1154a07b4970SChristoph Hellwig 
1155b662a078SJay Sternberg 	list_del(&port->global_entry);
1156b662a078SJay Sternberg 
115772efd25dSChristoph Hellwig 	kfree(port->ana_state);
1158a07b4970SChristoph Hellwig 	kfree(port);
1159a07b4970SChristoph Hellwig }
1160a07b4970SChristoph Hellwig 
1161a07b4970SChristoph Hellwig static struct configfs_attribute *nvmet_port_attrs[] = {
1162a07b4970SChristoph Hellwig 	&nvmet_attr_addr_adrfam,
1163a07b4970SChristoph Hellwig 	&nvmet_attr_addr_treq,
1164a07b4970SChristoph Hellwig 	&nvmet_attr_addr_traddr,
1165a07b4970SChristoph Hellwig 	&nvmet_attr_addr_trsvcid,
1166a07b4970SChristoph Hellwig 	&nvmet_attr_addr_trtype,
11670d5ee2b2SSteve Wise 	&nvmet_attr_param_inline_data_size,
1168a07b4970SChristoph Hellwig 	NULL,
1169a07b4970SChristoph Hellwig };
1170a07b4970SChristoph Hellwig 
1171a07b4970SChristoph Hellwig static struct configfs_item_operations nvmet_port_item_ops = {
1172a07b4970SChristoph Hellwig 	.release		= nvmet_port_release,
1173a07b4970SChristoph Hellwig };
1174a07b4970SChristoph Hellwig 
117566603a31SBhumika Goyal static const struct config_item_type nvmet_port_type = {
1176a07b4970SChristoph Hellwig 	.ct_attrs		= nvmet_port_attrs,
1177a07b4970SChristoph Hellwig 	.ct_item_ops		= &nvmet_port_item_ops,
1178a07b4970SChristoph Hellwig 	.ct_owner		= THIS_MODULE,
1179a07b4970SChristoph Hellwig };
1180a07b4970SChristoph Hellwig 
1181a07b4970SChristoph Hellwig static struct config_group *nvmet_ports_make(struct config_group *group,
1182a07b4970SChristoph Hellwig 		const char *name)
1183a07b4970SChristoph Hellwig {
1184a07b4970SChristoph Hellwig 	struct nvmet_port *port;
1185a07b4970SChristoph Hellwig 	u16 portid;
118662ac0d32SChristoph Hellwig 	u32 i;
1187a07b4970SChristoph Hellwig 
1188a07b4970SChristoph Hellwig 	if (kstrtou16(name, 0, &portid))
1189a07b4970SChristoph Hellwig 		return ERR_PTR(-EINVAL);
1190a07b4970SChristoph Hellwig 
1191a07b4970SChristoph Hellwig 	port = kzalloc(sizeof(*port), GFP_KERNEL);
1192a07b4970SChristoph Hellwig 	if (!port)
1193f98d9ca1SDan Carpenter 		return ERR_PTR(-ENOMEM);
1194a07b4970SChristoph Hellwig 
119572efd25dSChristoph Hellwig 	port->ana_state = kcalloc(NVMET_MAX_ANAGRPS + 1,
119672efd25dSChristoph Hellwig 			sizeof(*port->ana_state), GFP_KERNEL);
119772efd25dSChristoph Hellwig 	if (!port->ana_state) {
119872efd25dSChristoph Hellwig 		kfree(port);
119972efd25dSChristoph Hellwig 		return ERR_PTR(-ENOMEM);
120072efd25dSChristoph Hellwig 	}
120172efd25dSChristoph Hellwig 
120262ac0d32SChristoph Hellwig 	for (i = 1; i <= NVMET_MAX_ANAGRPS; i++) {
120362ac0d32SChristoph Hellwig 		if (i == NVMET_DEFAULT_ANA_GRPID)
120462ac0d32SChristoph Hellwig 			port->ana_state[1] = NVME_ANA_OPTIMIZED;
120562ac0d32SChristoph Hellwig 		else
120662ac0d32SChristoph Hellwig 			port->ana_state[i] = NVME_ANA_INACCESSIBLE;
120762ac0d32SChristoph Hellwig 	}
120872efd25dSChristoph Hellwig 
1209b662a078SJay Sternberg 	list_add(&port->global_entry, &nvmet_ports_list);
1210b662a078SJay Sternberg 
1211a07b4970SChristoph Hellwig 	INIT_LIST_HEAD(&port->entry);
1212a07b4970SChristoph Hellwig 	INIT_LIST_HEAD(&port->subsystems);
1213a07b4970SChristoph Hellwig 	INIT_LIST_HEAD(&port->referrals);
12140d5ee2b2SSteve Wise 	port->inline_data_size = -1;	/* < 0 == let the transport choose */
1215a07b4970SChristoph Hellwig 
1216a07b4970SChristoph Hellwig 	port->disc_addr.portid = cpu_to_le16(portid);
12179b95d2fbSSagi Grimberg 	port->disc_addr.treq = NVMF_TREQ_DISABLE_SQFLOW;
1218a07b4970SChristoph Hellwig 	config_group_init_type_name(&port->group, name, &nvmet_port_type);
1219a07b4970SChristoph Hellwig 
1220a07b4970SChristoph Hellwig 	config_group_init_type_name(&port->subsys_group,
1221a07b4970SChristoph Hellwig 			"subsystems", &nvmet_port_subsys_type);
1222a07b4970SChristoph Hellwig 	configfs_add_default_group(&port->subsys_group, &port->group);
1223a07b4970SChristoph Hellwig 
1224a07b4970SChristoph Hellwig 	config_group_init_type_name(&port->referrals_group,
1225a07b4970SChristoph Hellwig 			"referrals", &nvmet_referrals_type);
1226a07b4970SChristoph Hellwig 	configfs_add_default_group(&port->referrals_group, &port->group);
1227a07b4970SChristoph Hellwig 
122862ac0d32SChristoph Hellwig 	config_group_init_type_name(&port->ana_groups_group,
122962ac0d32SChristoph Hellwig 			"ana_groups", &nvmet_ana_groups_type);
123062ac0d32SChristoph Hellwig 	configfs_add_default_group(&port->ana_groups_group, &port->group);
123162ac0d32SChristoph Hellwig 
123262ac0d32SChristoph Hellwig 	port->ana_default_group.port = port;
123362ac0d32SChristoph Hellwig 	port->ana_default_group.grpid = NVMET_DEFAULT_ANA_GRPID;
123462ac0d32SChristoph Hellwig 	config_group_init_type_name(&port->ana_default_group.group,
123562ac0d32SChristoph Hellwig 			__stringify(NVMET_DEFAULT_ANA_GRPID),
123662ac0d32SChristoph Hellwig 			&nvmet_ana_group_type);
123762ac0d32SChristoph Hellwig 	configfs_add_default_group(&port->ana_default_group.group,
123862ac0d32SChristoph Hellwig 			&port->ana_groups_group);
123962ac0d32SChristoph Hellwig 
1240a07b4970SChristoph Hellwig 	return &port->group;
1241a07b4970SChristoph Hellwig }
1242a07b4970SChristoph Hellwig 
1243a07b4970SChristoph Hellwig static struct configfs_group_operations nvmet_ports_group_ops = {
1244a07b4970SChristoph Hellwig 	.make_group		= nvmet_ports_make,
1245a07b4970SChristoph Hellwig };
1246a07b4970SChristoph Hellwig 
124766603a31SBhumika Goyal static const struct config_item_type nvmet_ports_type = {
1248a07b4970SChristoph Hellwig 	.ct_group_ops		= &nvmet_ports_group_ops,
1249a07b4970SChristoph Hellwig 	.ct_owner		= THIS_MODULE,
1250a07b4970SChristoph Hellwig };
1251a07b4970SChristoph Hellwig 
1252a07b4970SChristoph Hellwig static struct config_group nvmet_subsystems_group;
1253a07b4970SChristoph Hellwig static struct config_group nvmet_ports_group;
1254a07b4970SChristoph Hellwig 
1255a07b4970SChristoph Hellwig static void nvmet_host_release(struct config_item *item)
1256a07b4970SChristoph Hellwig {
1257a07b4970SChristoph Hellwig 	struct nvmet_host *host = to_host(item);
1258a07b4970SChristoph Hellwig 
1259a07b4970SChristoph Hellwig 	kfree(host);
1260a07b4970SChristoph Hellwig }
1261a07b4970SChristoph Hellwig 
1262a07b4970SChristoph Hellwig static struct configfs_item_operations nvmet_host_item_ops = {
1263a07b4970SChristoph Hellwig 	.release		= nvmet_host_release,
1264a07b4970SChristoph Hellwig };
1265a07b4970SChristoph Hellwig 
126666603a31SBhumika Goyal static const struct config_item_type nvmet_host_type = {
1267a07b4970SChristoph Hellwig 	.ct_item_ops		= &nvmet_host_item_ops,
1268a07b4970SChristoph Hellwig 	.ct_owner		= THIS_MODULE,
1269a07b4970SChristoph Hellwig };
1270a07b4970SChristoph Hellwig 
1271a07b4970SChristoph Hellwig static struct config_group *nvmet_hosts_make_group(struct config_group *group,
1272a07b4970SChristoph Hellwig 		const char *name)
1273a07b4970SChristoph Hellwig {
1274a07b4970SChristoph Hellwig 	struct nvmet_host *host;
1275a07b4970SChristoph Hellwig 
1276a07b4970SChristoph Hellwig 	host = kzalloc(sizeof(*host), GFP_KERNEL);
1277a07b4970SChristoph Hellwig 	if (!host)
1278a07b4970SChristoph Hellwig 		return ERR_PTR(-ENOMEM);
1279a07b4970SChristoph Hellwig 
1280a07b4970SChristoph Hellwig 	config_group_init_type_name(&host->group, name, &nvmet_host_type);
1281a07b4970SChristoph Hellwig 
1282a07b4970SChristoph Hellwig 	return &host->group;
1283a07b4970SChristoph Hellwig }
1284a07b4970SChristoph Hellwig 
1285a07b4970SChristoph Hellwig static struct configfs_group_operations nvmet_hosts_group_ops = {
1286a07b4970SChristoph Hellwig 	.make_group		= nvmet_hosts_make_group,
1287a07b4970SChristoph Hellwig };
1288a07b4970SChristoph Hellwig 
128966603a31SBhumika Goyal static const struct config_item_type nvmet_hosts_type = {
1290a07b4970SChristoph Hellwig 	.ct_group_ops		= &nvmet_hosts_group_ops,
1291a07b4970SChristoph Hellwig 	.ct_owner		= THIS_MODULE,
1292a07b4970SChristoph Hellwig };
1293a07b4970SChristoph Hellwig 
1294a07b4970SChristoph Hellwig static struct config_group nvmet_hosts_group;
1295a07b4970SChristoph Hellwig 
129666603a31SBhumika Goyal static const struct config_item_type nvmet_root_type = {
1297a07b4970SChristoph Hellwig 	.ct_owner		= THIS_MODULE,
1298a07b4970SChristoph Hellwig };
1299a07b4970SChristoph Hellwig 
1300a07b4970SChristoph Hellwig static struct configfs_subsystem nvmet_configfs_subsystem = {
1301a07b4970SChristoph Hellwig 	.su_group = {
1302a07b4970SChristoph Hellwig 		.cg_item = {
1303a07b4970SChristoph Hellwig 			.ci_namebuf	= "nvmet",
1304a07b4970SChristoph Hellwig 			.ci_type	= &nvmet_root_type,
1305a07b4970SChristoph Hellwig 		},
1306a07b4970SChristoph Hellwig 	},
1307a07b4970SChristoph Hellwig };
1308a07b4970SChristoph Hellwig 
1309a07b4970SChristoph Hellwig int __init nvmet_init_configfs(void)
1310a07b4970SChristoph Hellwig {
1311a07b4970SChristoph Hellwig 	int ret;
1312a07b4970SChristoph Hellwig 
1313a07b4970SChristoph Hellwig 	config_group_init(&nvmet_configfs_subsystem.su_group);
1314a07b4970SChristoph Hellwig 	mutex_init(&nvmet_configfs_subsystem.su_mutex);
1315a07b4970SChristoph Hellwig 
1316a07b4970SChristoph Hellwig 	config_group_init_type_name(&nvmet_subsystems_group,
1317a07b4970SChristoph Hellwig 			"subsystems", &nvmet_subsystems_type);
1318a07b4970SChristoph Hellwig 	configfs_add_default_group(&nvmet_subsystems_group,
1319a07b4970SChristoph Hellwig 			&nvmet_configfs_subsystem.su_group);
1320a07b4970SChristoph Hellwig 
1321a07b4970SChristoph Hellwig 	config_group_init_type_name(&nvmet_ports_group,
1322a07b4970SChristoph Hellwig 			"ports", &nvmet_ports_type);
1323a07b4970SChristoph Hellwig 	configfs_add_default_group(&nvmet_ports_group,
1324a07b4970SChristoph Hellwig 			&nvmet_configfs_subsystem.su_group);
1325a07b4970SChristoph Hellwig 
1326a07b4970SChristoph Hellwig 	config_group_init_type_name(&nvmet_hosts_group,
1327a07b4970SChristoph Hellwig 			"hosts", &nvmet_hosts_type);
1328a07b4970SChristoph Hellwig 	configfs_add_default_group(&nvmet_hosts_group,
1329a07b4970SChristoph Hellwig 			&nvmet_configfs_subsystem.su_group);
1330a07b4970SChristoph Hellwig 
1331a07b4970SChristoph Hellwig 	ret = configfs_register_subsystem(&nvmet_configfs_subsystem);
1332a07b4970SChristoph Hellwig 	if (ret) {
1333a07b4970SChristoph Hellwig 		pr_err("configfs_register_subsystem: %d\n", ret);
1334a07b4970SChristoph Hellwig 		return ret;
1335a07b4970SChristoph Hellwig 	}
1336a07b4970SChristoph Hellwig 
1337a07b4970SChristoph Hellwig 	return 0;
1338a07b4970SChristoph Hellwig }
1339a07b4970SChristoph Hellwig 
1340a07b4970SChristoph Hellwig void __exit nvmet_exit_configfs(void)
1341a07b4970SChristoph Hellwig {
1342a07b4970SChristoph Hellwig 	configfs_unregister_subsystem(&nvmet_configfs_subsystem);
1343a07b4970SChristoph Hellwig }
1344