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