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