blob: fee56b3a23bc7d57cb186ab54fb9b920c6f2e4bd [file] [log] [blame]
Christoph Hellwiga07b4972016-06-21 18:04:20 +02001/*
2 * Configfs interface for the NVMe target.
3 * Copyright (c) 2015-2016 HGST, a Western Digital Company.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 */
14#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
15#include <linux/kernel.h>
16#include <linux/module.h>
17#include <linux/slab.h>
18#include <linux/stat.h>
19#include <linux/ctype.h>
20
21#include "nvmet.h"
22
Bhumika Goyal66603a32017-10-16 17:18:47 +020023static const struct config_item_type nvmet_host_type;
24static const struct config_item_type nvmet_subsys_type;
Christoph Hellwiga07b4972016-06-21 18:04:20 +020025
Christoph Hellwiga5d18612018-03-20 20:41:34 +010026static const struct nvmet_transport_name {
27 u8 type;
28 const char *name;
29} nvmet_transport_names[] = {
30 { NVMF_TRTYPE_RDMA, "rdma" },
31 { NVMF_TRTYPE_FC, "fc" },
32 { NVMF_TRTYPE_LOOP, "loop" },
33};
34
Christoph Hellwiga07b4972016-06-21 18:04:20 +020035/*
36 * nvmet_port Generic ConfigFS definitions.
37 * Used in any place in the ConfigFS tree that refers to an address.
38 */
39static ssize_t nvmet_addr_adrfam_show(struct config_item *item,
40 char *page)
41{
42 switch (to_nvmet_port(item)->disc_addr.adrfam) {
43 case NVMF_ADDR_FAMILY_IP4:
44 return sprintf(page, "ipv4\n");
45 case NVMF_ADDR_FAMILY_IP6:
46 return sprintf(page, "ipv6\n");
47 case NVMF_ADDR_FAMILY_IB:
48 return sprintf(page, "ib\n");
James Smart885aa402016-10-21 23:32:51 +030049 case NVMF_ADDR_FAMILY_FC:
50 return sprintf(page, "fc\n");
Christoph Hellwiga07b4972016-06-21 18:04:20 +020051 default:
52 return sprintf(page, "\n");
53 }
54}
55
56static ssize_t nvmet_addr_adrfam_store(struct config_item *item,
57 const char *page, size_t count)
58{
59 struct nvmet_port *port = to_nvmet_port(item);
60
61 if (port->enabled) {
62 pr_err("Cannot modify address while enabled\n");
63 pr_err("Disable the address before modifying\n");
64 return -EACCES;
65 }
66
67 if (sysfs_streq(page, "ipv4")) {
68 port->disc_addr.adrfam = NVMF_ADDR_FAMILY_IP4;
69 } else if (sysfs_streq(page, "ipv6")) {
70 port->disc_addr.adrfam = NVMF_ADDR_FAMILY_IP6;
71 } else if (sysfs_streq(page, "ib")) {
72 port->disc_addr.adrfam = NVMF_ADDR_FAMILY_IB;
James Smart885aa402016-10-21 23:32:51 +030073 } else if (sysfs_streq(page, "fc")) {
74 port->disc_addr.adrfam = NVMF_ADDR_FAMILY_FC;
Christoph Hellwiga07b4972016-06-21 18:04:20 +020075 } else {
76 pr_err("Invalid value '%s' for adrfam\n", page);
77 return -EINVAL;
78 }
79
80 return count;
81}
82
83CONFIGFS_ATTR(nvmet_, addr_adrfam);
84
85static ssize_t nvmet_addr_portid_show(struct config_item *item,
86 char *page)
87{
88 struct nvmet_port *port = to_nvmet_port(item);
89
90 return snprintf(page, PAGE_SIZE, "%d\n",
91 le16_to_cpu(port->disc_addr.portid));
92}
93
94static ssize_t nvmet_addr_portid_store(struct config_item *item,
95 const char *page, size_t count)
96{
97 struct nvmet_port *port = to_nvmet_port(item);
98 u16 portid = 0;
99
100 if (kstrtou16(page, 0, &portid)) {
101 pr_err("Invalid value '%s' for portid\n", page);
102 return -EINVAL;
103 }
104
105 if (port->enabled) {
106 pr_err("Cannot modify address while enabled\n");
107 pr_err("Disable the address before modifying\n");
108 return -EACCES;
109 }
110 port->disc_addr.portid = cpu_to_le16(portid);
111 return count;
112}
113
114CONFIGFS_ATTR(nvmet_, addr_portid);
115
116static ssize_t nvmet_addr_traddr_show(struct config_item *item,
117 char *page)
118{
119 struct nvmet_port *port = to_nvmet_port(item);
120
121 return snprintf(page, PAGE_SIZE, "%s\n",
122 port->disc_addr.traddr);
123}
124
125static ssize_t nvmet_addr_traddr_store(struct config_item *item,
126 const char *page, size_t count)
127{
128 struct nvmet_port *port = to_nvmet_port(item);
129
130 if (count > NVMF_TRADDR_SIZE) {
131 pr_err("Invalid value '%s' for traddr\n", page);
132 return -EINVAL;
133 }
134
135 if (port->enabled) {
136 pr_err("Cannot modify address while enabled\n");
137 pr_err("Disable the address before modifying\n");
138 return -EACCES;
139 }
Sagi Grimberg9ba2a5c2018-06-06 15:27:48 +0300140
141 if (sscanf(page, "%s\n", port->disc_addr.traddr) != 1)
142 return -EINVAL;
143 return count;
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200144}
145
146CONFIGFS_ATTR(nvmet_, addr_traddr);
147
148static ssize_t nvmet_addr_treq_show(struct config_item *item,
149 char *page)
150{
151 switch (to_nvmet_port(item)->disc_addr.treq) {
152 case NVMF_TREQ_NOT_SPECIFIED:
153 return sprintf(page, "not specified\n");
154 case NVMF_TREQ_REQUIRED:
155 return sprintf(page, "required\n");
156 case NVMF_TREQ_NOT_REQUIRED:
157 return sprintf(page, "not required\n");
158 default:
159 return sprintf(page, "\n");
160 }
161}
162
163static ssize_t nvmet_addr_treq_store(struct config_item *item,
164 const char *page, size_t count)
165{
166 struct nvmet_port *port = to_nvmet_port(item);
167
168 if (port->enabled) {
169 pr_err("Cannot modify address while enabled\n");
170 pr_err("Disable the address before modifying\n");
171 return -EACCES;
172 }
173
174 if (sysfs_streq(page, "not specified")) {
175 port->disc_addr.treq = NVMF_TREQ_NOT_SPECIFIED;
176 } else if (sysfs_streq(page, "required")) {
177 port->disc_addr.treq = NVMF_TREQ_REQUIRED;
178 } else if (sysfs_streq(page, "not required")) {
179 port->disc_addr.treq = NVMF_TREQ_NOT_REQUIRED;
180 } else {
181 pr_err("Invalid value '%s' for treq\n", page);
182 return -EINVAL;
183 }
184
185 return count;
186}
187
188CONFIGFS_ATTR(nvmet_, addr_treq);
189
190static ssize_t nvmet_addr_trsvcid_show(struct config_item *item,
191 char *page)
192{
193 struct nvmet_port *port = to_nvmet_port(item);
194
195 return snprintf(page, PAGE_SIZE, "%s\n",
196 port->disc_addr.trsvcid);
197}
198
199static ssize_t nvmet_addr_trsvcid_store(struct config_item *item,
200 const char *page, size_t count)
201{
202 struct nvmet_port *port = to_nvmet_port(item);
203
204 if (count > NVMF_TRSVCID_SIZE) {
205 pr_err("Invalid value '%s' for trsvcid\n", page);
206 return -EINVAL;
207 }
208 if (port->enabled) {
209 pr_err("Cannot modify address while enabled\n");
210 pr_err("Disable the address before modifying\n");
211 return -EACCES;
212 }
Sagi Grimberg9ba2a5c2018-06-06 15:27:48 +0300213
214 if (sscanf(page, "%s\n", port->disc_addr.trsvcid) != 1)
215 return -EINVAL;
216 return count;
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200217}
218
219CONFIGFS_ATTR(nvmet_, addr_trsvcid);
220
221static ssize_t nvmet_addr_trtype_show(struct config_item *item,
222 char *page)
223{
Christoph Hellwiga5d18612018-03-20 20:41:34 +0100224 struct nvmet_port *port = to_nvmet_port(item);
225 int i;
226
227 for (i = 0; i < ARRAY_SIZE(nvmet_transport_names); i++) {
228 if (port->disc_addr.trtype != nvmet_transport_names[i].type)
229 continue;
230 return sprintf(page, "%s\n", nvmet_transport_names[i].name);
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200231 }
Christoph Hellwiga5d18612018-03-20 20:41:34 +0100232
233 return sprintf(page, "\n");
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200234}
235
236static void nvmet_port_init_tsas_rdma(struct nvmet_port *port)
237{
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200238 port->disc_addr.tsas.rdma.qptype = NVMF_RDMA_QPTYPE_CONNECTED;
239 port->disc_addr.tsas.rdma.prtype = NVMF_RDMA_PRTYPE_NOT_SPECIFIED;
240 port->disc_addr.tsas.rdma.cms = NVMF_RDMA_CMS_RDMA_CM;
241}
242
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200243static ssize_t nvmet_addr_trtype_store(struct config_item *item,
244 const char *page, size_t count)
245{
246 struct nvmet_port *port = to_nvmet_port(item);
Christoph Hellwiga5d18612018-03-20 20:41:34 +0100247 int i;
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200248
249 if (port->enabled) {
250 pr_err("Cannot modify address while enabled\n");
251 pr_err("Disable the address before modifying\n");
252 return -EACCES;
253 }
254
Christoph Hellwiga5d18612018-03-20 20:41:34 +0100255 for (i = 0; i < ARRAY_SIZE(nvmet_transport_names); i++) {
256 if (sysfs_streq(page, nvmet_transport_names[i].name))
257 goto found;
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200258 }
259
Christoph Hellwiga5d18612018-03-20 20:41:34 +0100260 pr_err("Invalid value '%s' for trtype\n", page);
261 return -EINVAL;
262found:
263 memset(&port->disc_addr.tsas, 0, NVMF_TSAS_SIZE);
264 port->disc_addr.trtype = nvmet_transport_names[i].type;
265 if (port->disc_addr.trtype == NVMF_TRTYPE_RDMA)
266 nvmet_port_init_tsas_rdma(port);
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200267 return count;
268}
269
270CONFIGFS_ATTR(nvmet_, addr_trtype);
271
272/*
273 * Namespace structures & file operation functions below
274 */
275static ssize_t nvmet_ns_device_path_show(struct config_item *item, char *page)
276{
277 return sprintf(page, "%s\n", to_nvmet_ns(item)->device_path);
278}
279
280static ssize_t nvmet_ns_device_path_store(struct config_item *item,
281 const char *page, size_t count)
282{
283 struct nvmet_ns *ns = to_nvmet_ns(item);
284 struct nvmet_subsys *subsys = ns->subsys;
285 int ret;
286
287 mutex_lock(&subsys->lock);
288 ret = -EBUSY;
Solganik Alexandere4fcf072016-10-30 10:35:15 +0200289 if (ns->enabled)
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200290 goto out_unlock;
291
292 kfree(ns->device_path);
293
294 ret = -ENOMEM;
Sagi Grimberg9ba2a5c2018-06-06 15:27:48 +0300295 ns->device_path = kstrndup(page, strcspn(page, "\n"), GFP_KERNEL);
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200296 if (!ns->device_path)
297 goto out_unlock;
298
299 mutex_unlock(&subsys->lock);
300 return count;
301
302out_unlock:
303 mutex_unlock(&subsys->lock);
304 return ret;
305}
306
307CONFIGFS_ATTR(nvmet_ns_, device_path);
308
Johannes Thumshirn430c7be2017-06-07 11:45:33 +0200309static ssize_t nvmet_ns_device_uuid_show(struct config_item *item, char *page)
310{
311 return sprintf(page, "%pUb\n", &to_nvmet_ns(item)->uuid);
312}
313
314static ssize_t nvmet_ns_device_uuid_store(struct config_item *item,
315 const char *page, size_t count)
316{
317 struct nvmet_ns *ns = to_nvmet_ns(item);
318 struct nvmet_subsys *subsys = ns->subsys;
319 int ret = 0;
320
321
322 mutex_lock(&subsys->lock);
323 if (ns->enabled) {
324 ret = -EBUSY;
325 goto out_unlock;
326 }
327
328
329 if (uuid_parse(page, &ns->uuid))
330 ret = -EINVAL;
331
332out_unlock:
333 mutex_unlock(&subsys->lock);
334 return ret ? ret : count;
335}
336
Max Gurtovoyf8717492018-03-20 14:20:41 +0200337CONFIGFS_ATTR(nvmet_ns_, device_uuid);
338
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200339static ssize_t nvmet_ns_device_nguid_show(struct config_item *item, char *page)
340{
341 return sprintf(page, "%pUb\n", &to_nvmet_ns(item)->nguid);
342}
343
344static ssize_t nvmet_ns_device_nguid_store(struct config_item *item,
345 const char *page, size_t count)
346{
347 struct nvmet_ns *ns = to_nvmet_ns(item);
348 struct nvmet_subsys *subsys = ns->subsys;
349 u8 nguid[16];
350 const char *p = page;
351 int i;
352 int ret = 0;
353
354 mutex_lock(&subsys->lock);
Solganik Alexandere4fcf072016-10-30 10:35:15 +0200355 if (ns->enabled) {
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200356 ret = -EBUSY;
357 goto out_unlock;
358 }
359
360 for (i = 0; i < 16; i++) {
361 if (p + 2 > page + count) {
362 ret = -EINVAL;
363 goto out_unlock;
364 }
365 if (!isxdigit(p[0]) || !isxdigit(p[1])) {
366 ret = -EINVAL;
367 goto out_unlock;
368 }
369
370 nguid[i] = (hex_to_bin(p[0]) << 4) | hex_to_bin(p[1]);
371 p += 2;
372
373 if (*p == '-' || *p == ':')
374 p++;
375 }
376
377 memcpy(&ns->nguid, nguid, sizeof(nguid));
378out_unlock:
379 mutex_unlock(&subsys->lock);
380 return ret ? ret : count;
381}
382
383CONFIGFS_ATTR(nvmet_ns_, device_nguid);
384
385static ssize_t nvmet_ns_enable_show(struct config_item *item, char *page)
386{
Solganik Alexandere4fcf072016-10-30 10:35:15 +0200387 return sprintf(page, "%d\n", to_nvmet_ns(item)->enabled);
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200388}
389
390static ssize_t nvmet_ns_enable_store(struct config_item *item,
391 const char *page, size_t count)
392{
393 struct nvmet_ns *ns = to_nvmet_ns(item);
394 bool enable;
395 int ret = 0;
396
397 if (strtobool(page, &enable))
398 return -EINVAL;
399
400 if (enable)
401 ret = nvmet_ns_enable(ns);
402 else
403 nvmet_ns_disable(ns);
404
405 return ret ? ret : count;
406}
407
408CONFIGFS_ATTR(nvmet_ns_, enable);
409
Chaitanya Kulkarni55eb942e2018-06-20 00:01:41 -0400410static ssize_t nvmet_ns_buffered_io_show(struct config_item *item, char *page)
411{
412 return sprintf(page, "%d\n", to_nvmet_ns(item)->buffered_io);
413}
414
415static ssize_t nvmet_ns_buffered_io_store(struct config_item *item,
416 const char *page, size_t count)
417{
418 struct nvmet_ns *ns = to_nvmet_ns(item);
419 bool val;
420
421 if (strtobool(page, &val))
422 return -EINVAL;
423
424 mutex_lock(&ns->subsys->lock);
425 if (ns->enabled) {
426 pr_err("disable ns before setting buffered_io value.\n");
427 mutex_unlock(&ns->subsys->lock);
428 return -EINVAL;
429 }
430
431 ns->buffered_io = val;
432 mutex_unlock(&ns->subsys->lock);
433 return count;
434}
435
436CONFIGFS_ATTR(nvmet_ns_, buffered_io);
437
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200438static struct configfs_attribute *nvmet_ns_attrs[] = {
439 &nvmet_ns_attr_device_path,
440 &nvmet_ns_attr_device_nguid,
Johannes Thumshirn430c7be2017-06-07 11:45:33 +0200441 &nvmet_ns_attr_device_uuid,
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200442 &nvmet_ns_attr_enable,
Chaitanya Kulkarni55eb942e2018-06-20 00:01:41 -0400443 &nvmet_ns_attr_buffered_io,
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200444 NULL,
445};
446
447static void nvmet_ns_release(struct config_item *item)
448{
449 struct nvmet_ns *ns = to_nvmet_ns(item);
450
451 nvmet_ns_free(ns);
452}
453
454static struct configfs_item_operations nvmet_ns_item_ops = {
455 .release = nvmet_ns_release,
456};
457
Bhumika Goyal66603a32017-10-16 17:18:47 +0200458static const struct config_item_type nvmet_ns_type = {
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200459 .ct_item_ops = &nvmet_ns_item_ops,
460 .ct_attrs = nvmet_ns_attrs,
461 .ct_owner = THIS_MODULE,
462};
463
464static struct config_group *nvmet_ns_make(struct config_group *group,
465 const char *name)
466{
467 struct nvmet_subsys *subsys = namespaces_to_subsys(&group->cg_item);
468 struct nvmet_ns *ns;
469 int ret;
470 u32 nsid;
471
472 ret = kstrtou32(name, 0, &nsid);
473 if (ret)
474 goto out;
475
476 ret = -EINVAL;
Christoph Hellwig1645d502017-07-18 19:46:36 +0200477 if (nsid == 0 || nsid == NVME_NSID_ALL)
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200478 goto out;
479
480 ret = -ENOMEM;
481 ns = nvmet_ns_alloc(subsys, nsid);
482 if (!ns)
483 goto out;
484 config_group_init_type_name(&ns->group, name, &nvmet_ns_type);
485
486 pr_info("adding nsid %d to subsystem %s\n", nsid, subsys->subsysnqn);
487
488 return &ns->group;
489out:
490 return ERR_PTR(ret);
491}
492
493static struct configfs_group_operations nvmet_namespaces_group_ops = {
494 .make_group = nvmet_ns_make,
495};
496
Bhumika Goyal66603a32017-10-16 17:18:47 +0200497static const struct config_item_type nvmet_namespaces_type = {
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200498 .ct_group_ops = &nvmet_namespaces_group_ops,
499 .ct_owner = THIS_MODULE,
500};
501
502static int nvmet_port_subsys_allow_link(struct config_item *parent,
503 struct config_item *target)
504{
505 struct nvmet_port *port = to_nvmet_port(parent->ci_parent);
506 struct nvmet_subsys *subsys;
507 struct nvmet_subsys_link *link, *p;
508 int ret;
509
510 if (target->ci_type != &nvmet_subsys_type) {
511 pr_err("can only link subsystems into the subsystems dir.!\n");
512 return -EINVAL;
513 }
514 subsys = to_subsys(target);
515 link = kmalloc(sizeof(*link), GFP_KERNEL);
516 if (!link)
517 return -ENOMEM;
518 link->subsys = subsys;
519
520 down_write(&nvmet_config_sem);
521 ret = -EEXIST;
522 list_for_each_entry(p, &port->subsystems, entry) {
523 if (p->subsys == subsys)
524 goto out_free_link;
525 }
526
527 if (list_empty(&port->subsystems)) {
528 ret = nvmet_enable_port(port);
529 if (ret)
530 goto out_free_link;
531 }
532
533 list_add_tail(&link->entry, &port->subsystems);
534 nvmet_genctr++;
535 up_write(&nvmet_config_sem);
536 return 0;
537
538out_free_link:
539 up_write(&nvmet_config_sem);
540 kfree(link);
541 return ret;
542}
543
Andrzej Pietrasiewicze16769d2016-11-28 13:22:42 +0100544static void nvmet_port_subsys_drop_link(struct config_item *parent,
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200545 struct config_item *target)
546{
547 struct nvmet_port *port = to_nvmet_port(parent->ci_parent);
548 struct nvmet_subsys *subsys = to_subsys(target);
549 struct nvmet_subsys_link *p;
550
551 down_write(&nvmet_config_sem);
552 list_for_each_entry(p, &port->subsystems, entry) {
553 if (p->subsys == subsys)
554 goto found;
555 }
556 up_write(&nvmet_config_sem);
Andrzej Pietrasiewicze16769d2016-11-28 13:22:42 +0100557 return;
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200558
559found:
560 list_del(&p->entry);
561 nvmet_genctr++;
562 if (list_empty(&port->subsystems))
563 nvmet_disable_port(port);
564 up_write(&nvmet_config_sem);
565 kfree(p);
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200566}
567
568static struct configfs_item_operations nvmet_port_subsys_item_ops = {
569 .allow_link = nvmet_port_subsys_allow_link,
570 .drop_link = nvmet_port_subsys_drop_link,
571};
572
Bhumika Goyal66603a32017-10-16 17:18:47 +0200573static const struct config_item_type nvmet_port_subsys_type = {
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200574 .ct_item_ops = &nvmet_port_subsys_item_ops,
575 .ct_owner = THIS_MODULE,
576};
577
578static int nvmet_allowed_hosts_allow_link(struct config_item *parent,
579 struct config_item *target)
580{
581 struct nvmet_subsys *subsys = to_subsys(parent->ci_parent);
582 struct nvmet_host *host;
583 struct nvmet_host_link *link, *p;
584 int ret;
585
586 if (target->ci_type != &nvmet_host_type) {
587 pr_err("can only link hosts into the allowed_hosts directory!\n");
588 return -EINVAL;
589 }
590
591 host = to_host(target);
592 link = kmalloc(sizeof(*link), GFP_KERNEL);
593 if (!link)
594 return -ENOMEM;
595 link->host = host;
596
597 down_write(&nvmet_config_sem);
598 ret = -EINVAL;
599 if (subsys->allow_any_host) {
600 pr_err("can't add hosts when allow_any_host is set!\n");
601 goto out_free_link;
602 }
603
604 ret = -EEXIST;
605 list_for_each_entry(p, &subsys->hosts, entry) {
606 if (!strcmp(nvmet_host_name(p->host), nvmet_host_name(host)))
607 goto out_free_link;
608 }
609 list_add_tail(&link->entry, &subsys->hosts);
610 nvmet_genctr++;
611 up_write(&nvmet_config_sem);
612 return 0;
613out_free_link:
614 up_write(&nvmet_config_sem);
615 kfree(link);
616 return ret;
617}
618
Andrzej Pietrasiewicze16769d2016-11-28 13:22:42 +0100619static void nvmet_allowed_hosts_drop_link(struct config_item *parent,
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200620 struct config_item *target)
621{
622 struct nvmet_subsys *subsys = to_subsys(parent->ci_parent);
623 struct nvmet_host *host = to_host(target);
624 struct nvmet_host_link *p;
625
626 down_write(&nvmet_config_sem);
627 list_for_each_entry(p, &subsys->hosts, entry) {
628 if (!strcmp(nvmet_host_name(p->host), nvmet_host_name(host)))
629 goto found;
630 }
631 up_write(&nvmet_config_sem);
Andrzej Pietrasiewicze16769d2016-11-28 13:22:42 +0100632 return;
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200633
634found:
635 list_del(&p->entry);
636 nvmet_genctr++;
637 up_write(&nvmet_config_sem);
638 kfree(p);
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200639}
640
641static struct configfs_item_operations nvmet_allowed_hosts_item_ops = {
642 .allow_link = nvmet_allowed_hosts_allow_link,
643 .drop_link = nvmet_allowed_hosts_drop_link,
644};
645
Bhumika Goyal66603a32017-10-16 17:18:47 +0200646static const struct config_item_type nvmet_allowed_hosts_type = {
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200647 .ct_item_ops = &nvmet_allowed_hosts_item_ops,
648 .ct_owner = THIS_MODULE,
649};
650
651static ssize_t nvmet_subsys_attr_allow_any_host_show(struct config_item *item,
652 char *page)
653{
654 return snprintf(page, PAGE_SIZE, "%d\n",
655 to_subsys(item)->allow_any_host);
656}
657
658static ssize_t nvmet_subsys_attr_allow_any_host_store(struct config_item *item,
659 const char *page, size_t count)
660{
661 struct nvmet_subsys *subsys = to_subsys(item);
662 bool allow_any_host;
663 int ret = 0;
664
665 if (strtobool(page, &allow_any_host))
666 return -EINVAL;
667
668 down_write(&nvmet_config_sem);
669 if (allow_any_host && !list_empty(&subsys->hosts)) {
670 pr_err("Can't set allow_any_host when explicit hosts are set!\n");
671 ret = -EINVAL;
672 goto out_unlock;
673 }
674
675 subsys->allow_any_host = allow_any_host;
676out_unlock:
677 up_write(&nvmet_config_sem);
678 return ret ? ret : count;
679}
680
681CONFIGFS_ATTR(nvmet_subsys_, attr_allow_any_host);
682
Johannes Thumshirn41528f82017-07-14 15:36:54 +0200683static ssize_t nvmet_subsys_attr_version_show(struct config_item *item,
Johannes Thumshirnc61d7882017-06-07 11:45:36 +0200684 char *page)
685{
686 struct nvmet_subsys *subsys = to_subsys(item);
687
688 if (NVME_TERTIARY(subsys->ver))
689 return snprintf(page, PAGE_SIZE, "%d.%d.%d\n",
690 (int)NVME_MAJOR(subsys->ver),
691 (int)NVME_MINOR(subsys->ver),
692 (int)NVME_TERTIARY(subsys->ver));
693 else
694 return snprintf(page, PAGE_SIZE, "%d.%d\n",
695 (int)NVME_MAJOR(subsys->ver),
696 (int)NVME_MINOR(subsys->ver));
697}
698
Johannes Thumshirn41528f82017-07-14 15:36:54 +0200699static ssize_t nvmet_subsys_attr_version_store(struct config_item *item,
Johannes Thumshirnc61d7882017-06-07 11:45:36 +0200700 const char *page, size_t count)
701{
702 struct nvmet_subsys *subsys = to_subsys(item);
703 int major, minor, tertiary = 0;
704 int ret;
705
706
707 ret = sscanf(page, "%d.%d.%d\n", &major, &minor, &tertiary);
708 if (ret != 2 && ret != 3)
709 return -EINVAL;
710
711 down_write(&nvmet_config_sem);
712 subsys->ver = NVME_VS(major, minor, tertiary);
713 up_write(&nvmet_config_sem);
714
715 return count;
716}
Johannes Thumshirn41528f82017-07-14 15:36:54 +0200717CONFIGFS_ATTR(nvmet_subsys_, attr_version);
Johannes Thumshirnc61d7882017-06-07 11:45:36 +0200718
Johannes Thumshirnfcbc5452017-07-14 15:36:56 +0200719static ssize_t nvmet_subsys_attr_serial_show(struct config_item *item,
720 char *page)
721{
722 struct nvmet_subsys *subsys = to_subsys(item);
723
724 return snprintf(page, PAGE_SIZE, "%llx\n", subsys->serial);
725}
726
727static ssize_t nvmet_subsys_attr_serial_store(struct config_item *item,
728 const char *page, size_t count)
729{
730 struct nvmet_subsys *subsys = to_subsys(item);
731
732 down_write(&nvmet_config_sem);
733 sscanf(page, "%llx\n", &subsys->serial);
734 up_write(&nvmet_config_sem);
735
736 return count;
737}
738CONFIGFS_ATTR(nvmet_subsys_, attr_serial);
739
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200740static struct configfs_attribute *nvmet_subsys_attrs[] = {
741 &nvmet_subsys_attr_attr_allow_any_host,
Johannes Thumshirn41528f82017-07-14 15:36:54 +0200742 &nvmet_subsys_attr_attr_version,
Johannes Thumshirnfcbc5452017-07-14 15:36:56 +0200743 &nvmet_subsys_attr_attr_serial,
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200744 NULL,
745};
746
747/*
748 * Subsystem structures & folder operation functions below
749 */
750static void nvmet_subsys_release(struct config_item *item)
751{
752 struct nvmet_subsys *subsys = to_subsys(item);
753
Sagi Grimberg344770b2016-11-27 22:29:17 +0200754 nvmet_subsys_del_ctrls(subsys);
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200755 nvmet_subsys_put(subsys);
756}
757
758static struct configfs_item_operations nvmet_subsys_item_ops = {
759 .release = nvmet_subsys_release,
760};
761
Bhumika Goyal66603a32017-10-16 17:18:47 +0200762static const struct config_item_type nvmet_subsys_type = {
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200763 .ct_item_ops = &nvmet_subsys_item_ops,
764 .ct_attrs = nvmet_subsys_attrs,
765 .ct_owner = THIS_MODULE,
766};
767
768static struct config_group *nvmet_subsys_make(struct config_group *group,
769 const char *name)
770{
771 struct nvmet_subsys *subsys;
772
773 if (sysfs_streq(name, NVME_DISC_SUBSYS_NAME)) {
774 pr_err("can't create discovery subsystem through configfs\n");
775 return ERR_PTR(-EINVAL);
776 }
777
778 subsys = nvmet_subsys_alloc(name, NVME_NQN_NVME);
779 if (!subsys)
780 return ERR_PTR(-ENOMEM);
781
782 config_group_init_type_name(&subsys->group, name, &nvmet_subsys_type);
783
784 config_group_init_type_name(&subsys->namespaces_group,
785 "namespaces", &nvmet_namespaces_type);
786 configfs_add_default_group(&subsys->namespaces_group, &subsys->group);
787
788 config_group_init_type_name(&subsys->allowed_hosts_group,
789 "allowed_hosts", &nvmet_allowed_hosts_type);
790 configfs_add_default_group(&subsys->allowed_hosts_group,
791 &subsys->group);
792
793 return &subsys->group;
794}
795
796static struct configfs_group_operations nvmet_subsystems_group_ops = {
797 .make_group = nvmet_subsys_make,
798};
799
Bhumika Goyal66603a32017-10-16 17:18:47 +0200800static const struct config_item_type nvmet_subsystems_type = {
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200801 .ct_group_ops = &nvmet_subsystems_group_ops,
802 .ct_owner = THIS_MODULE,
803};
804
805static ssize_t nvmet_referral_enable_show(struct config_item *item,
806 char *page)
807{
808 return snprintf(page, PAGE_SIZE, "%d\n", to_nvmet_port(item)->enabled);
809}
810
811static ssize_t nvmet_referral_enable_store(struct config_item *item,
812 const char *page, size_t count)
813{
814 struct nvmet_port *parent = to_nvmet_port(item->ci_parent->ci_parent);
815 struct nvmet_port *port = to_nvmet_port(item);
816 bool enable;
817
818 if (strtobool(page, &enable))
819 goto inval;
820
821 if (enable)
822 nvmet_referral_enable(parent, port);
823 else
824 nvmet_referral_disable(port);
825
826 return count;
827inval:
828 pr_err("Invalid value '%s' for enable\n", page);
829 return -EINVAL;
830}
831
832CONFIGFS_ATTR(nvmet_referral_, enable);
833
834/*
835 * Discovery Service subsystem definitions
836 */
837static struct configfs_attribute *nvmet_referral_attrs[] = {
838 &nvmet_attr_addr_adrfam,
839 &nvmet_attr_addr_portid,
840 &nvmet_attr_addr_treq,
841 &nvmet_attr_addr_traddr,
842 &nvmet_attr_addr_trsvcid,
843 &nvmet_attr_addr_trtype,
844 &nvmet_referral_attr_enable,
845 NULL,
846};
847
848static void nvmet_referral_release(struct config_item *item)
849{
850 struct nvmet_port *port = to_nvmet_port(item);
851
852 nvmet_referral_disable(port);
853 kfree(port);
854}
855
856static struct configfs_item_operations nvmet_referral_item_ops = {
857 .release = nvmet_referral_release,
858};
859
Bhumika Goyal66603a32017-10-16 17:18:47 +0200860static const struct config_item_type nvmet_referral_type = {
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200861 .ct_owner = THIS_MODULE,
862 .ct_attrs = nvmet_referral_attrs,
863 .ct_item_ops = &nvmet_referral_item_ops,
864};
865
866static struct config_group *nvmet_referral_make(
867 struct config_group *group, const char *name)
868{
869 struct nvmet_port *port;
870
871 port = kzalloc(sizeof(*port), GFP_KERNEL);
872 if (!port)
Dan Carpenterf98d9ca2016-07-07 11:15:26 +0300873 return ERR_PTR(-ENOMEM);
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200874
875 INIT_LIST_HEAD(&port->entry);
876 config_group_init_type_name(&port->group, name, &nvmet_referral_type);
877
878 return &port->group;
879}
880
881static struct configfs_group_operations nvmet_referral_group_ops = {
882 .make_group = nvmet_referral_make,
883};
884
Bhumika Goyal66603a32017-10-16 17:18:47 +0200885static const struct config_item_type nvmet_referrals_type = {
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200886 .ct_owner = THIS_MODULE,
887 .ct_group_ops = &nvmet_referral_group_ops,
888};
889
890/*
891 * Ports definitions.
892 */
893static void nvmet_port_release(struct config_item *item)
894{
895 struct nvmet_port *port = to_nvmet_port(item);
896
897 kfree(port);
898}
899
900static struct configfs_attribute *nvmet_port_attrs[] = {
901 &nvmet_attr_addr_adrfam,
902 &nvmet_attr_addr_treq,
903 &nvmet_attr_addr_traddr,
904 &nvmet_attr_addr_trsvcid,
905 &nvmet_attr_addr_trtype,
906 NULL,
907};
908
909static struct configfs_item_operations nvmet_port_item_ops = {
910 .release = nvmet_port_release,
911};
912
Bhumika Goyal66603a32017-10-16 17:18:47 +0200913static const struct config_item_type nvmet_port_type = {
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200914 .ct_attrs = nvmet_port_attrs,
915 .ct_item_ops = &nvmet_port_item_ops,
916 .ct_owner = THIS_MODULE,
917};
918
919static struct config_group *nvmet_ports_make(struct config_group *group,
920 const char *name)
921{
922 struct nvmet_port *port;
923 u16 portid;
924
925 if (kstrtou16(name, 0, &portid))
926 return ERR_PTR(-EINVAL);
927
928 port = kzalloc(sizeof(*port), GFP_KERNEL);
929 if (!port)
Dan Carpenterf98d9ca2016-07-07 11:15:26 +0300930 return ERR_PTR(-ENOMEM);
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200931
932 INIT_LIST_HEAD(&port->entry);
933 INIT_LIST_HEAD(&port->subsystems);
934 INIT_LIST_HEAD(&port->referrals);
935
936 port->disc_addr.portid = cpu_to_le16(portid);
937 config_group_init_type_name(&port->group, name, &nvmet_port_type);
938
939 config_group_init_type_name(&port->subsys_group,
940 "subsystems", &nvmet_port_subsys_type);
941 configfs_add_default_group(&port->subsys_group, &port->group);
942
943 config_group_init_type_name(&port->referrals_group,
944 "referrals", &nvmet_referrals_type);
945 configfs_add_default_group(&port->referrals_group, &port->group);
946
947 return &port->group;
948}
949
950static struct configfs_group_operations nvmet_ports_group_ops = {
951 .make_group = nvmet_ports_make,
952};
953
Bhumika Goyal66603a32017-10-16 17:18:47 +0200954static const struct config_item_type nvmet_ports_type = {
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200955 .ct_group_ops = &nvmet_ports_group_ops,
956 .ct_owner = THIS_MODULE,
957};
958
959static struct config_group nvmet_subsystems_group;
960static struct config_group nvmet_ports_group;
961
962static void nvmet_host_release(struct config_item *item)
963{
964 struct nvmet_host *host = to_host(item);
965
966 kfree(host);
967}
968
969static struct configfs_item_operations nvmet_host_item_ops = {
970 .release = nvmet_host_release,
971};
972
Bhumika Goyal66603a32017-10-16 17:18:47 +0200973static const struct config_item_type nvmet_host_type = {
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200974 .ct_item_ops = &nvmet_host_item_ops,
975 .ct_owner = THIS_MODULE,
976};
977
978static struct config_group *nvmet_hosts_make_group(struct config_group *group,
979 const char *name)
980{
981 struct nvmet_host *host;
982
983 host = kzalloc(sizeof(*host), GFP_KERNEL);
984 if (!host)
985 return ERR_PTR(-ENOMEM);
986
987 config_group_init_type_name(&host->group, name, &nvmet_host_type);
988
989 return &host->group;
990}
991
992static struct configfs_group_operations nvmet_hosts_group_ops = {
993 .make_group = nvmet_hosts_make_group,
994};
995
Bhumika Goyal66603a32017-10-16 17:18:47 +0200996static const struct config_item_type nvmet_hosts_type = {
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200997 .ct_group_ops = &nvmet_hosts_group_ops,
998 .ct_owner = THIS_MODULE,
999};
1000
1001static struct config_group nvmet_hosts_group;
1002
Bhumika Goyal66603a32017-10-16 17:18:47 +02001003static const struct config_item_type nvmet_root_type = {
Christoph Hellwiga07b4972016-06-21 18:04:20 +02001004 .ct_owner = THIS_MODULE,
1005};
1006
1007static struct configfs_subsystem nvmet_configfs_subsystem = {
1008 .su_group = {
1009 .cg_item = {
1010 .ci_namebuf = "nvmet",
1011 .ci_type = &nvmet_root_type,
1012 },
1013 },
1014};
1015
1016int __init nvmet_init_configfs(void)
1017{
1018 int ret;
1019
1020 config_group_init(&nvmet_configfs_subsystem.su_group);
1021 mutex_init(&nvmet_configfs_subsystem.su_mutex);
1022
1023 config_group_init_type_name(&nvmet_subsystems_group,
1024 "subsystems", &nvmet_subsystems_type);
1025 configfs_add_default_group(&nvmet_subsystems_group,
1026 &nvmet_configfs_subsystem.su_group);
1027
1028 config_group_init_type_name(&nvmet_ports_group,
1029 "ports", &nvmet_ports_type);
1030 configfs_add_default_group(&nvmet_ports_group,
1031 &nvmet_configfs_subsystem.su_group);
1032
1033 config_group_init_type_name(&nvmet_hosts_group,
1034 "hosts", &nvmet_hosts_type);
1035 configfs_add_default_group(&nvmet_hosts_group,
1036 &nvmet_configfs_subsystem.su_group);
1037
1038 ret = configfs_register_subsystem(&nvmet_configfs_subsystem);
1039 if (ret) {
1040 pr_err("configfs_register_subsystem: %d\n", ret);
1041 return ret;
1042 }
1043
1044 return 0;
1045}
1046
1047void __exit nvmet_exit_configfs(void)
1048{
1049 configfs_unregister_subsystem(&nvmet_configfs_subsystem);
1050}