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