blob: cd52b9f153766602036eb9e7322f845551fff855 [file] [log] [blame]
Christoph Hellwig77141dc2019-02-18 11:36:11 +01001// SPDX-License-Identifier: GPL-2.0
Christoph Hellwiga07b4972016-06-21 18:04:20 +02002/*
3 * Configfs interface for the NVMe target.
4 * Copyright (c) 2015-2016 HGST, a Western Digital Company.
Christoph Hellwiga07b4972016-06-21 18:04:20 +02005 */
6#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
7#include <linux/kernel.h>
8#include <linux/module.h>
9#include <linux/slab.h>
10#include <linux/stat.h>
11#include <linux/ctype.h>
Logan Gunthorpec6925092018-10-04 15:27:47 -060012#include <linux/pci.h>
13#include <linux/pci-p2pdma.h>
Christoph Hellwiga07b4972016-06-21 18:04:20 +020014
15#include "nvmet.h"
16
Bhumika Goyal66603a32017-10-16 17:18:47 +020017static const struct config_item_type nvmet_host_type;
18static const struct config_item_type nvmet_subsys_type;
Christoph Hellwiga07b4972016-06-21 18:04:20 +020019
Jay Sternbergb662a072018-11-12 13:56:40 -080020static LIST_HEAD(nvmet_ports_list);
21struct list_head *nvmet_ports = &nvmet_ports_list;
22
Christoph Hellwiga5d18612018-03-20 20:41:34 +010023static const struct nvmet_transport_name {
24 u8 type;
25 const char *name;
26} nvmet_transport_names[] = {
27 { NVMF_TRTYPE_RDMA, "rdma" },
28 { NVMF_TRTYPE_FC, "fc" },
Sagi Grimbergad4f5302018-12-03 17:52:16 -080029 { NVMF_TRTYPE_TCP, "tcp" },
Christoph Hellwiga5d18612018-03-20 20:41:34 +010030 { NVMF_TRTYPE_LOOP, "loop" },
31};
32
Christoph Hellwiga07b4972016-06-21 18:04:20 +020033/*
34 * nvmet_port Generic ConfigFS definitions.
35 * Used in any place in the ConfigFS tree that refers to an address.
36 */
37static ssize_t nvmet_addr_adrfam_show(struct config_item *item,
38 char *page)
39{
40 switch (to_nvmet_port(item)->disc_addr.adrfam) {
41 case NVMF_ADDR_FAMILY_IP4:
42 return sprintf(page, "ipv4\n");
43 case NVMF_ADDR_FAMILY_IP6:
44 return sprintf(page, "ipv6\n");
45 case NVMF_ADDR_FAMILY_IB:
46 return sprintf(page, "ib\n");
James Smart885aa402016-10-21 23:32:51 +030047 case NVMF_ADDR_FAMILY_FC:
48 return sprintf(page, "fc\n");
Christoph Hellwiga07b4972016-06-21 18:04:20 +020049 default:
50 return sprintf(page, "\n");
51 }
52}
53
54static ssize_t nvmet_addr_adrfam_store(struct config_item *item,
55 const char *page, size_t count)
56{
57 struct nvmet_port *port = to_nvmet_port(item);
58
59 if (port->enabled) {
60 pr_err("Cannot modify address while enabled\n");
61 pr_err("Disable the address before modifying\n");
62 return -EACCES;
63 }
64
65 if (sysfs_streq(page, "ipv4")) {
66 port->disc_addr.adrfam = NVMF_ADDR_FAMILY_IP4;
67 } else if (sysfs_streq(page, "ipv6")) {
68 port->disc_addr.adrfam = NVMF_ADDR_FAMILY_IP6;
69 } else if (sysfs_streq(page, "ib")) {
70 port->disc_addr.adrfam = NVMF_ADDR_FAMILY_IB;
James Smart885aa402016-10-21 23:32:51 +030071 } else if (sysfs_streq(page, "fc")) {
72 port->disc_addr.adrfam = NVMF_ADDR_FAMILY_FC;
Christoph Hellwiga07b4972016-06-21 18:04:20 +020073 } else {
74 pr_err("Invalid value '%s' for adrfam\n", page);
75 return -EINVAL;
76 }
77
78 return count;
79}
80
81CONFIGFS_ATTR(nvmet_, addr_adrfam);
82
83static ssize_t nvmet_addr_portid_show(struct config_item *item,
84 char *page)
85{
86 struct nvmet_port *port = to_nvmet_port(item);
87
88 return snprintf(page, PAGE_SIZE, "%d\n",
89 le16_to_cpu(port->disc_addr.portid));
90}
91
92static ssize_t nvmet_addr_portid_store(struct config_item *item,
93 const char *page, size_t count)
94{
95 struct nvmet_port *port = to_nvmet_port(item);
96 u16 portid = 0;
97
98 if (kstrtou16(page, 0, &portid)) {
99 pr_err("Invalid value '%s' for portid\n", page);
100 return -EINVAL;
101 }
102
103 if (port->enabled) {
104 pr_err("Cannot modify address while enabled\n");
105 pr_err("Disable the address before modifying\n");
106 return -EACCES;
107 }
108 port->disc_addr.portid = cpu_to_le16(portid);
109 return count;
110}
111
112CONFIGFS_ATTR(nvmet_, addr_portid);
113
114static ssize_t nvmet_addr_traddr_show(struct config_item *item,
115 char *page)
116{
117 struct nvmet_port *port = to_nvmet_port(item);
118
119 return snprintf(page, PAGE_SIZE, "%s\n",
120 port->disc_addr.traddr);
121}
122
123static ssize_t nvmet_addr_traddr_store(struct config_item *item,
124 const char *page, size_t count)
125{
126 struct nvmet_port *port = to_nvmet_port(item);
127
128 if (count > NVMF_TRADDR_SIZE) {
129 pr_err("Invalid value '%s' for traddr\n", page);
130 return -EINVAL;
131 }
132
133 if (port->enabled) {
134 pr_err("Cannot modify address while enabled\n");
135 pr_err("Disable the address before modifying\n");
136 return -EACCES;
137 }
Sagi Grimberg9ba2a5c2018-06-06 15:27:48 +0300138
139 if (sscanf(page, "%s\n", port->disc_addr.traddr) != 1)
140 return -EINVAL;
141 return count;
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200142}
143
144CONFIGFS_ATTR(nvmet_, addr_traddr);
145
146static ssize_t nvmet_addr_treq_show(struct config_item *item,
147 char *page)
148{
Sagi Grimberg0445e1b52018-11-19 14:11:13 -0800149 switch (to_nvmet_port(item)->disc_addr.treq &
150 NVME_TREQ_SECURE_CHANNEL_MASK) {
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200151 case NVMF_TREQ_NOT_SPECIFIED:
152 return sprintf(page, "not specified\n");
153 case NVMF_TREQ_REQUIRED:
154 return sprintf(page, "required\n");
155 case NVMF_TREQ_NOT_REQUIRED:
156 return sprintf(page, "not required\n");
157 default:
158 return sprintf(page, "\n");
159 }
160}
161
162static ssize_t nvmet_addr_treq_store(struct config_item *item,
163 const char *page, size_t count)
164{
165 struct nvmet_port *port = to_nvmet_port(item);
Sagi Grimberg0445e1b52018-11-19 14:11:13 -0800166 u8 treq = port->disc_addr.treq & ~NVME_TREQ_SECURE_CHANNEL_MASK;
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200167
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")) {
Sagi Grimberg0445e1b52018-11-19 14:11:13 -0800175 treq |= NVMF_TREQ_NOT_SPECIFIED;
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200176 } else if (sysfs_streq(page, "required")) {
Sagi Grimberg0445e1b52018-11-19 14:11:13 -0800177 treq |= NVMF_TREQ_REQUIRED;
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200178 } else if (sysfs_streq(page, "not required")) {
Sagi Grimberg0445e1b52018-11-19 14:11:13 -0800179 treq |= NVMF_TREQ_NOT_REQUIRED;
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200180 } else {
181 pr_err("Invalid value '%s' for treq\n", page);
182 return -EINVAL;
183 }
Sagi Grimberg0445e1b52018-11-19 14:11:13 -0800184 port->disc_addr.treq = treq;
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200185
186 return count;
187}
188
189CONFIGFS_ATTR(nvmet_, addr_treq);
190
191static ssize_t nvmet_addr_trsvcid_show(struct config_item *item,
192 char *page)
193{
194 struct nvmet_port *port = to_nvmet_port(item);
195
196 return snprintf(page, PAGE_SIZE, "%s\n",
197 port->disc_addr.trsvcid);
198}
199
200static ssize_t nvmet_addr_trsvcid_store(struct config_item *item,
201 const char *page, size_t count)
202{
203 struct nvmet_port *port = to_nvmet_port(item);
204
205 if (count > NVMF_TRSVCID_SIZE) {
206 pr_err("Invalid value '%s' for trsvcid\n", page);
207 return -EINVAL;
208 }
209 if (port->enabled) {
210 pr_err("Cannot modify address while enabled\n");
211 pr_err("Disable the address before modifying\n");
212 return -EACCES;
213 }
Sagi Grimberg9ba2a5c2018-06-06 15:27:48 +0300214
215 if (sscanf(page, "%s\n", port->disc_addr.trsvcid) != 1)
216 return -EINVAL;
217 return count;
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200218}
219
220CONFIGFS_ATTR(nvmet_, addr_trsvcid);
221
Steve Wise0d5ee2b2018-06-20 07:15:10 -0700222static ssize_t nvmet_param_inline_data_size_show(struct config_item *item,
223 char *page)
224{
225 struct nvmet_port *port = to_nvmet_port(item);
226
227 return snprintf(page, PAGE_SIZE, "%d\n", port->inline_data_size);
228}
229
230static ssize_t nvmet_param_inline_data_size_store(struct config_item *item,
231 const char *page, size_t count)
232{
233 struct nvmet_port *port = to_nvmet_port(item);
234 int ret;
235
236 if (port->enabled) {
237 pr_err("Cannot modify inline_data_size while port enabled\n");
238 pr_err("Disable the port before modifying\n");
239 return -EACCES;
240 }
241 ret = kstrtoint(page, 0, &port->inline_data_size);
242 if (ret) {
243 pr_err("Invalid value '%s' for inline_data_size\n", page);
244 return -EINVAL;
245 }
246 return count;
247}
248
249CONFIGFS_ATTR(nvmet_, param_inline_data_size);
250
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200251static ssize_t nvmet_addr_trtype_show(struct config_item *item,
252 char *page)
253{
Christoph Hellwiga5d18612018-03-20 20:41:34 +0100254 struct nvmet_port *port = to_nvmet_port(item);
255 int i;
256
257 for (i = 0; i < ARRAY_SIZE(nvmet_transport_names); i++) {
258 if (port->disc_addr.trtype != nvmet_transport_names[i].type)
259 continue;
260 return sprintf(page, "%s\n", nvmet_transport_names[i].name);
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200261 }
Christoph Hellwiga5d18612018-03-20 20:41:34 +0100262
263 return sprintf(page, "\n");
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200264}
265
266static void nvmet_port_init_tsas_rdma(struct nvmet_port *port)
267{
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200268 port->disc_addr.tsas.rdma.qptype = NVMF_RDMA_QPTYPE_CONNECTED;
269 port->disc_addr.tsas.rdma.prtype = NVMF_RDMA_PRTYPE_NOT_SPECIFIED;
270 port->disc_addr.tsas.rdma.cms = NVMF_RDMA_CMS_RDMA_CM;
271}
272
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200273static ssize_t nvmet_addr_trtype_store(struct config_item *item,
274 const char *page, size_t count)
275{
276 struct nvmet_port *port = to_nvmet_port(item);
Christoph Hellwiga5d18612018-03-20 20:41:34 +0100277 int i;
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200278
279 if (port->enabled) {
280 pr_err("Cannot modify address while enabled\n");
281 pr_err("Disable the address before modifying\n");
282 return -EACCES;
283 }
284
Christoph Hellwiga5d18612018-03-20 20:41:34 +0100285 for (i = 0; i < ARRAY_SIZE(nvmet_transport_names); i++) {
286 if (sysfs_streq(page, nvmet_transport_names[i].name))
287 goto found;
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200288 }
289
Christoph Hellwiga5d18612018-03-20 20:41:34 +0100290 pr_err("Invalid value '%s' for trtype\n", page);
291 return -EINVAL;
292found:
293 memset(&port->disc_addr.tsas, 0, NVMF_TSAS_SIZE);
294 port->disc_addr.trtype = nvmet_transport_names[i].type;
295 if (port->disc_addr.trtype == NVMF_TRTYPE_RDMA)
296 nvmet_port_init_tsas_rdma(port);
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200297 return count;
298}
299
300CONFIGFS_ATTR(nvmet_, addr_trtype);
301
302/*
303 * Namespace structures & file operation functions below
304 */
305static ssize_t nvmet_ns_device_path_show(struct config_item *item, char *page)
306{
307 return sprintf(page, "%s\n", to_nvmet_ns(item)->device_path);
308}
309
310static ssize_t nvmet_ns_device_path_store(struct config_item *item,
311 const char *page, size_t count)
312{
313 struct nvmet_ns *ns = to_nvmet_ns(item);
314 struct nvmet_subsys *subsys = ns->subsys;
Hannes Reinecke5613d312018-07-25 08:35:17 +0200315 size_t len;
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200316 int ret;
317
318 mutex_lock(&subsys->lock);
319 ret = -EBUSY;
Solganik Alexandere4fcf072016-10-30 10:35:15 +0200320 if (ns->enabled)
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200321 goto out_unlock;
322
Hannes Reinecke5613d312018-07-25 08:35:17 +0200323 ret = -EINVAL;
324 len = strcspn(page, "\n");
325 if (!len)
326 goto out_unlock;
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200327
Hannes Reinecke5613d312018-07-25 08:35:17 +0200328 kfree(ns->device_path);
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200329 ret = -ENOMEM;
Hannes Reinecke5613d312018-07-25 08:35:17 +0200330 ns->device_path = kstrndup(page, len, GFP_KERNEL);
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200331 if (!ns->device_path)
332 goto out_unlock;
333
334 mutex_unlock(&subsys->lock);
335 return count;
336
337out_unlock:
338 mutex_unlock(&subsys->lock);
339 return ret;
340}
341
342CONFIGFS_ATTR(nvmet_ns_, device_path);
343
Logan Gunthorpec6925092018-10-04 15:27:47 -0600344#ifdef CONFIG_PCI_P2PDMA
345static ssize_t nvmet_ns_p2pmem_show(struct config_item *item, char *page)
346{
347 struct nvmet_ns *ns = to_nvmet_ns(item);
348
349 return pci_p2pdma_enable_show(page, ns->p2p_dev, ns->use_p2pmem);
350}
351
352static ssize_t nvmet_ns_p2pmem_store(struct config_item *item,
353 const char *page, size_t count)
354{
355 struct nvmet_ns *ns = to_nvmet_ns(item);
356 struct pci_dev *p2p_dev = NULL;
357 bool use_p2pmem;
358 int ret = count;
359 int error;
360
361 mutex_lock(&ns->subsys->lock);
362 if (ns->enabled) {
363 ret = -EBUSY;
364 goto out_unlock;
365 }
366
367 error = pci_p2pdma_enable_store(page, &p2p_dev, &use_p2pmem);
368 if (error) {
369 ret = error;
370 goto out_unlock;
371 }
372
373 ns->use_p2pmem = use_p2pmem;
374 pci_dev_put(ns->p2p_dev);
375 ns->p2p_dev = p2p_dev;
376
377out_unlock:
378 mutex_unlock(&ns->subsys->lock);
379
380 return ret;
381}
382
383CONFIGFS_ATTR(nvmet_ns_, p2pmem);
384#endif /* CONFIG_PCI_P2PDMA */
385
Johannes Thumshirn430c7be2017-06-07 11:45:33 +0200386static ssize_t nvmet_ns_device_uuid_show(struct config_item *item, char *page)
387{
388 return sprintf(page, "%pUb\n", &to_nvmet_ns(item)->uuid);
389}
390
391static ssize_t nvmet_ns_device_uuid_store(struct config_item *item,
392 const char *page, size_t count)
393{
394 struct nvmet_ns *ns = to_nvmet_ns(item);
395 struct nvmet_subsys *subsys = ns->subsys;
396 int ret = 0;
397
398
399 mutex_lock(&subsys->lock);
400 if (ns->enabled) {
401 ret = -EBUSY;
402 goto out_unlock;
403 }
404
405
406 if (uuid_parse(page, &ns->uuid))
407 ret = -EINVAL;
408
409out_unlock:
410 mutex_unlock(&subsys->lock);
411 return ret ? ret : count;
412}
413
Max Gurtovoyf8717492018-03-20 14:20:41 +0200414CONFIGFS_ATTR(nvmet_ns_, device_uuid);
415
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200416static ssize_t nvmet_ns_device_nguid_show(struct config_item *item, char *page)
417{
418 return sprintf(page, "%pUb\n", &to_nvmet_ns(item)->nguid);
419}
420
421static ssize_t nvmet_ns_device_nguid_store(struct config_item *item,
422 const char *page, size_t count)
423{
424 struct nvmet_ns *ns = to_nvmet_ns(item);
425 struct nvmet_subsys *subsys = ns->subsys;
426 u8 nguid[16];
427 const char *p = page;
428 int i;
429 int ret = 0;
430
431 mutex_lock(&subsys->lock);
Solganik Alexandere4fcf072016-10-30 10:35:15 +0200432 if (ns->enabled) {
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200433 ret = -EBUSY;
434 goto out_unlock;
435 }
436
437 for (i = 0; i < 16; i++) {
438 if (p + 2 > page + count) {
439 ret = -EINVAL;
440 goto out_unlock;
441 }
442 if (!isxdigit(p[0]) || !isxdigit(p[1])) {
443 ret = -EINVAL;
444 goto out_unlock;
445 }
446
447 nguid[i] = (hex_to_bin(p[0]) << 4) | hex_to_bin(p[1]);
448 p += 2;
449
450 if (*p == '-' || *p == ':')
451 p++;
452 }
453
454 memcpy(&ns->nguid, nguid, sizeof(nguid));
455out_unlock:
456 mutex_unlock(&subsys->lock);
457 return ret ? ret : count;
458}
459
460CONFIGFS_ATTR(nvmet_ns_, device_nguid);
461
Christoph Hellwig62ac0d32018-06-01 08:59:25 +0200462static ssize_t nvmet_ns_ana_grpid_show(struct config_item *item, char *page)
463{
464 return sprintf(page, "%u\n", to_nvmet_ns(item)->anagrpid);
465}
466
467static ssize_t nvmet_ns_ana_grpid_store(struct config_item *item,
468 const char *page, size_t count)
469{
470 struct nvmet_ns *ns = to_nvmet_ns(item);
471 u32 oldgrpid, newgrpid;
472 int ret;
473
474 ret = kstrtou32(page, 0, &newgrpid);
475 if (ret)
476 return ret;
477
478 if (newgrpid < 1 || newgrpid > NVMET_MAX_ANAGRPS)
479 return -EINVAL;
480
481 down_write(&nvmet_ana_sem);
482 oldgrpid = ns->anagrpid;
483 nvmet_ana_group_enabled[newgrpid]++;
484 ns->anagrpid = newgrpid;
485 nvmet_ana_group_enabled[oldgrpid]--;
486 nvmet_ana_chgcnt++;
487 up_write(&nvmet_ana_sem);
488
489 nvmet_send_ana_event(ns->subsys, NULL);
490 return count;
491}
492
493CONFIGFS_ATTR(nvmet_ns_, ana_grpid);
494
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200495static ssize_t nvmet_ns_enable_show(struct config_item *item, char *page)
496{
Solganik Alexandere4fcf072016-10-30 10:35:15 +0200497 return sprintf(page, "%d\n", to_nvmet_ns(item)->enabled);
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200498}
499
500static ssize_t nvmet_ns_enable_store(struct config_item *item,
501 const char *page, size_t count)
502{
503 struct nvmet_ns *ns = to_nvmet_ns(item);
504 bool enable;
505 int ret = 0;
506
507 if (strtobool(page, &enable))
508 return -EINVAL;
509
510 if (enable)
511 ret = nvmet_ns_enable(ns);
512 else
513 nvmet_ns_disable(ns);
514
515 return ret ? ret : count;
516}
517
518CONFIGFS_ATTR(nvmet_ns_, enable);
519
Chaitanya Kulkarni55eb942e2018-06-20 00:01:41 -0400520static ssize_t nvmet_ns_buffered_io_show(struct config_item *item, char *page)
521{
522 return sprintf(page, "%d\n", to_nvmet_ns(item)->buffered_io);
523}
524
525static ssize_t nvmet_ns_buffered_io_store(struct config_item *item,
526 const char *page, size_t count)
527{
528 struct nvmet_ns *ns = to_nvmet_ns(item);
529 bool val;
530
531 if (strtobool(page, &val))
532 return -EINVAL;
533
534 mutex_lock(&ns->subsys->lock);
535 if (ns->enabled) {
536 pr_err("disable ns before setting buffered_io value.\n");
537 mutex_unlock(&ns->subsys->lock);
538 return -EINVAL;
539 }
540
541 ns->buffered_io = val;
542 mutex_unlock(&ns->subsys->lock);
543 return count;
544}
545
546CONFIGFS_ATTR(nvmet_ns_, buffered_io);
547
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200548static struct configfs_attribute *nvmet_ns_attrs[] = {
549 &nvmet_ns_attr_device_path,
550 &nvmet_ns_attr_device_nguid,
Johannes Thumshirn430c7be2017-06-07 11:45:33 +0200551 &nvmet_ns_attr_device_uuid,
Christoph Hellwig62ac0d32018-06-01 08:59:25 +0200552 &nvmet_ns_attr_ana_grpid,
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200553 &nvmet_ns_attr_enable,
Chaitanya Kulkarni55eb942e2018-06-20 00:01:41 -0400554 &nvmet_ns_attr_buffered_io,
Logan Gunthorpec6925092018-10-04 15:27:47 -0600555#ifdef CONFIG_PCI_P2PDMA
556 &nvmet_ns_attr_p2pmem,
557#endif
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200558 NULL,
559};
560
561static void nvmet_ns_release(struct config_item *item)
562{
563 struct nvmet_ns *ns = to_nvmet_ns(item);
564
565 nvmet_ns_free(ns);
566}
567
568static struct configfs_item_operations nvmet_ns_item_ops = {
569 .release = nvmet_ns_release,
570};
571
Bhumika Goyal66603a32017-10-16 17:18:47 +0200572static const struct config_item_type nvmet_ns_type = {
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200573 .ct_item_ops = &nvmet_ns_item_ops,
574 .ct_attrs = nvmet_ns_attrs,
575 .ct_owner = THIS_MODULE,
576};
577
578static struct config_group *nvmet_ns_make(struct config_group *group,
579 const char *name)
580{
581 struct nvmet_subsys *subsys = namespaces_to_subsys(&group->cg_item);
582 struct nvmet_ns *ns;
583 int ret;
584 u32 nsid;
585
586 ret = kstrtou32(name, 0, &nsid);
587 if (ret)
588 goto out;
589
590 ret = -EINVAL;
Mikhail Skorzhinskii5ba89502019-07-04 10:01:48 +0200591 if (nsid == 0 || nsid == NVME_NSID_ALL) {
592 pr_err("invalid nsid %#x", nsid);
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200593 goto out;
Mikhail Skorzhinskii5ba89502019-07-04 10:01:48 +0200594 }
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200595
596 ret = -ENOMEM;
597 ns = nvmet_ns_alloc(subsys, nsid);
598 if (!ns)
599 goto out;
600 config_group_init_type_name(&ns->group, name, &nvmet_ns_type);
601
602 pr_info("adding nsid %d to subsystem %s\n", nsid, subsys->subsysnqn);
603
604 return &ns->group;
605out:
606 return ERR_PTR(ret);
607}
608
609static struct configfs_group_operations nvmet_namespaces_group_ops = {
610 .make_group = nvmet_ns_make,
611};
612
Bhumika Goyal66603a32017-10-16 17:18:47 +0200613static const struct config_item_type nvmet_namespaces_type = {
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200614 .ct_group_ops = &nvmet_namespaces_group_ops,
615 .ct_owner = THIS_MODULE,
616};
617
618static int nvmet_port_subsys_allow_link(struct config_item *parent,
619 struct config_item *target)
620{
621 struct nvmet_port *port = to_nvmet_port(parent->ci_parent);
622 struct nvmet_subsys *subsys;
623 struct nvmet_subsys_link *link, *p;
624 int ret;
625
626 if (target->ci_type != &nvmet_subsys_type) {
627 pr_err("can only link subsystems into the subsystems dir.!\n");
628 return -EINVAL;
629 }
630 subsys = to_subsys(target);
631 link = kmalloc(sizeof(*link), GFP_KERNEL);
632 if (!link)
633 return -ENOMEM;
634 link->subsys = subsys;
635
636 down_write(&nvmet_config_sem);
637 ret = -EEXIST;
638 list_for_each_entry(p, &port->subsystems, entry) {
639 if (p->subsys == subsys)
640 goto out_free_link;
641 }
642
643 if (list_empty(&port->subsystems)) {
644 ret = nvmet_enable_port(port);
645 if (ret)
646 goto out_free_link;
647 }
648
649 list_add_tail(&link->entry, &port->subsystems);
Jay Sternbergb662a072018-11-12 13:56:40 -0800650 nvmet_port_disc_changed(port, subsys);
651
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200652 up_write(&nvmet_config_sem);
653 return 0;
654
655out_free_link:
656 up_write(&nvmet_config_sem);
657 kfree(link);
658 return ret;
659}
660
Andrzej Pietrasiewicze16769d2016-11-28 13:22:42 +0100661static void nvmet_port_subsys_drop_link(struct config_item *parent,
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200662 struct config_item *target)
663{
664 struct nvmet_port *port = to_nvmet_port(parent->ci_parent);
665 struct nvmet_subsys *subsys = to_subsys(target);
666 struct nvmet_subsys_link *p;
667
668 down_write(&nvmet_config_sem);
669 list_for_each_entry(p, &port->subsystems, entry) {
670 if (p->subsys == subsys)
671 goto found;
672 }
673 up_write(&nvmet_config_sem);
Andrzej Pietrasiewicze16769d2016-11-28 13:22:42 +0100674 return;
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200675
676found:
677 list_del(&p->entry);
Jay Sternbergb662a072018-11-12 13:56:40 -0800678 nvmet_port_disc_changed(port, subsys);
679
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200680 if (list_empty(&port->subsystems))
681 nvmet_disable_port(port);
682 up_write(&nvmet_config_sem);
683 kfree(p);
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200684}
685
686static struct configfs_item_operations nvmet_port_subsys_item_ops = {
687 .allow_link = nvmet_port_subsys_allow_link,
688 .drop_link = nvmet_port_subsys_drop_link,
689};
690
Bhumika Goyal66603a32017-10-16 17:18:47 +0200691static const struct config_item_type nvmet_port_subsys_type = {
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200692 .ct_item_ops = &nvmet_port_subsys_item_ops,
693 .ct_owner = THIS_MODULE,
694};
695
696static int nvmet_allowed_hosts_allow_link(struct config_item *parent,
697 struct config_item *target)
698{
699 struct nvmet_subsys *subsys = to_subsys(parent->ci_parent);
700 struct nvmet_host *host;
701 struct nvmet_host_link *link, *p;
702 int ret;
703
704 if (target->ci_type != &nvmet_host_type) {
705 pr_err("can only link hosts into the allowed_hosts directory!\n");
706 return -EINVAL;
707 }
708
709 host = to_host(target);
710 link = kmalloc(sizeof(*link), GFP_KERNEL);
711 if (!link)
712 return -ENOMEM;
713 link->host = host;
714
715 down_write(&nvmet_config_sem);
716 ret = -EINVAL;
717 if (subsys->allow_any_host) {
718 pr_err("can't add hosts when allow_any_host is set!\n");
719 goto out_free_link;
720 }
721
722 ret = -EEXIST;
723 list_for_each_entry(p, &subsys->hosts, entry) {
724 if (!strcmp(nvmet_host_name(p->host), nvmet_host_name(host)))
725 goto out_free_link;
726 }
727 list_add_tail(&link->entry, &subsys->hosts);
Jay Sternbergb662a072018-11-12 13:56:40 -0800728 nvmet_subsys_disc_changed(subsys, host);
729
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200730 up_write(&nvmet_config_sem);
731 return 0;
732out_free_link:
733 up_write(&nvmet_config_sem);
734 kfree(link);
735 return ret;
736}
737
Andrzej Pietrasiewicze16769d2016-11-28 13:22:42 +0100738static void nvmet_allowed_hosts_drop_link(struct config_item *parent,
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200739 struct config_item *target)
740{
741 struct nvmet_subsys *subsys = to_subsys(parent->ci_parent);
742 struct nvmet_host *host = to_host(target);
743 struct nvmet_host_link *p;
744
745 down_write(&nvmet_config_sem);
746 list_for_each_entry(p, &subsys->hosts, entry) {
747 if (!strcmp(nvmet_host_name(p->host), nvmet_host_name(host)))
748 goto found;
749 }
750 up_write(&nvmet_config_sem);
Andrzej Pietrasiewicze16769d2016-11-28 13:22:42 +0100751 return;
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200752
753found:
754 list_del(&p->entry);
Jay Sternbergb662a072018-11-12 13:56:40 -0800755 nvmet_subsys_disc_changed(subsys, host);
756
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200757 up_write(&nvmet_config_sem);
758 kfree(p);
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200759}
760
761static struct configfs_item_operations nvmet_allowed_hosts_item_ops = {
762 .allow_link = nvmet_allowed_hosts_allow_link,
763 .drop_link = nvmet_allowed_hosts_drop_link,
764};
765
Bhumika Goyal66603a32017-10-16 17:18:47 +0200766static const struct config_item_type nvmet_allowed_hosts_type = {
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200767 .ct_item_ops = &nvmet_allowed_hosts_item_ops,
768 .ct_owner = THIS_MODULE,
769};
770
771static ssize_t nvmet_subsys_attr_allow_any_host_show(struct config_item *item,
772 char *page)
773{
774 return snprintf(page, PAGE_SIZE, "%d\n",
775 to_subsys(item)->allow_any_host);
776}
777
778static ssize_t nvmet_subsys_attr_allow_any_host_store(struct config_item *item,
779 const char *page, size_t count)
780{
781 struct nvmet_subsys *subsys = to_subsys(item);
782 bool allow_any_host;
783 int ret = 0;
784
785 if (strtobool(page, &allow_any_host))
786 return -EINVAL;
787
788 down_write(&nvmet_config_sem);
789 if (allow_any_host && !list_empty(&subsys->hosts)) {
790 pr_err("Can't set allow_any_host when explicit hosts are set!\n");
791 ret = -EINVAL;
792 goto out_unlock;
793 }
794
Jay Sternbergb662a072018-11-12 13:56:40 -0800795 if (subsys->allow_any_host != allow_any_host) {
796 subsys->allow_any_host = allow_any_host;
797 nvmet_subsys_disc_changed(subsys, NULL);
798 }
799
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200800out_unlock:
801 up_write(&nvmet_config_sem);
802 return ret ? ret : count;
803}
804
805CONFIGFS_ATTR(nvmet_subsys_, attr_allow_any_host);
806
Johannes Thumshirn41528f82017-07-14 15:36:54 +0200807static ssize_t nvmet_subsys_attr_version_show(struct config_item *item,
Johannes Thumshirnc61d7882017-06-07 11:45:36 +0200808 char *page)
809{
810 struct nvmet_subsys *subsys = to_subsys(item);
811
812 if (NVME_TERTIARY(subsys->ver))
813 return snprintf(page, PAGE_SIZE, "%d.%d.%d\n",
814 (int)NVME_MAJOR(subsys->ver),
815 (int)NVME_MINOR(subsys->ver),
816 (int)NVME_TERTIARY(subsys->ver));
817 else
818 return snprintf(page, PAGE_SIZE, "%d.%d\n",
819 (int)NVME_MAJOR(subsys->ver),
820 (int)NVME_MINOR(subsys->ver));
821}
822
Johannes Thumshirn41528f82017-07-14 15:36:54 +0200823static ssize_t nvmet_subsys_attr_version_store(struct config_item *item,
Johannes Thumshirnc61d7882017-06-07 11:45:36 +0200824 const char *page, size_t count)
825{
826 struct nvmet_subsys *subsys = to_subsys(item);
827 int major, minor, tertiary = 0;
828 int ret;
829
830
831 ret = sscanf(page, "%d.%d.%d\n", &major, &minor, &tertiary);
832 if (ret != 2 && ret != 3)
833 return -EINVAL;
834
835 down_write(&nvmet_config_sem);
836 subsys->ver = NVME_VS(major, minor, tertiary);
837 up_write(&nvmet_config_sem);
838
839 return count;
840}
Johannes Thumshirn41528f82017-07-14 15:36:54 +0200841CONFIGFS_ATTR(nvmet_subsys_, attr_version);
Johannes Thumshirnc61d7882017-06-07 11:45:36 +0200842
Johannes Thumshirnfcbc5452017-07-14 15:36:56 +0200843static ssize_t nvmet_subsys_attr_serial_show(struct config_item *item,
844 char *page)
845{
846 struct nvmet_subsys *subsys = to_subsys(item);
847
848 return snprintf(page, PAGE_SIZE, "%llx\n", subsys->serial);
849}
850
851static ssize_t nvmet_subsys_attr_serial_store(struct config_item *item,
852 const char *page, size_t count)
853{
854 struct nvmet_subsys *subsys = to_subsys(item);
855
856 down_write(&nvmet_config_sem);
857 sscanf(page, "%llx\n", &subsys->serial);
858 up_write(&nvmet_config_sem);
859
860 return count;
861}
862CONFIGFS_ATTR(nvmet_subsys_, attr_serial);
863
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200864static struct configfs_attribute *nvmet_subsys_attrs[] = {
865 &nvmet_subsys_attr_attr_allow_any_host,
Johannes Thumshirn41528f82017-07-14 15:36:54 +0200866 &nvmet_subsys_attr_attr_version,
Johannes Thumshirnfcbc5452017-07-14 15:36:56 +0200867 &nvmet_subsys_attr_attr_serial,
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200868 NULL,
869};
870
871/*
872 * Subsystem structures & folder operation functions below
873 */
874static void nvmet_subsys_release(struct config_item *item)
875{
876 struct nvmet_subsys *subsys = to_subsys(item);
877
Sagi Grimberg344770b2016-11-27 22:29:17 +0200878 nvmet_subsys_del_ctrls(subsys);
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200879 nvmet_subsys_put(subsys);
880}
881
882static struct configfs_item_operations nvmet_subsys_item_ops = {
883 .release = nvmet_subsys_release,
884};
885
Bhumika Goyal66603a32017-10-16 17:18:47 +0200886static const struct config_item_type nvmet_subsys_type = {
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200887 .ct_item_ops = &nvmet_subsys_item_ops,
888 .ct_attrs = nvmet_subsys_attrs,
889 .ct_owner = THIS_MODULE,
890};
891
892static struct config_group *nvmet_subsys_make(struct config_group *group,
893 const char *name)
894{
895 struct nvmet_subsys *subsys;
896
897 if (sysfs_streq(name, NVME_DISC_SUBSYS_NAME)) {
898 pr_err("can't create discovery subsystem through configfs\n");
899 return ERR_PTR(-EINVAL);
900 }
901
902 subsys = nvmet_subsys_alloc(name, NVME_NQN_NVME);
Minwoo Im6b7e6312019-04-07 15:28:06 +0900903 if (IS_ERR(subsys))
904 return ERR_CAST(subsys);
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200905
906 config_group_init_type_name(&subsys->group, name, &nvmet_subsys_type);
907
908 config_group_init_type_name(&subsys->namespaces_group,
909 "namespaces", &nvmet_namespaces_type);
910 configfs_add_default_group(&subsys->namespaces_group, &subsys->group);
911
912 config_group_init_type_name(&subsys->allowed_hosts_group,
913 "allowed_hosts", &nvmet_allowed_hosts_type);
914 configfs_add_default_group(&subsys->allowed_hosts_group,
915 &subsys->group);
916
917 return &subsys->group;
918}
919
920static struct configfs_group_operations nvmet_subsystems_group_ops = {
921 .make_group = nvmet_subsys_make,
922};
923
Bhumika Goyal66603a32017-10-16 17:18:47 +0200924static const struct config_item_type nvmet_subsystems_type = {
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200925 .ct_group_ops = &nvmet_subsystems_group_ops,
926 .ct_owner = THIS_MODULE,
927};
928
929static ssize_t nvmet_referral_enable_show(struct config_item *item,
930 char *page)
931{
932 return snprintf(page, PAGE_SIZE, "%d\n", to_nvmet_port(item)->enabled);
933}
934
935static ssize_t nvmet_referral_enable_store(struct config_item *item,
936 const char *page, size_t count)
937{
938 struct nvmet_port *parent = to_nvmet_port(item->ci_parent->ci_parent);
939 struct nvmet_port *port = to_nvmet_port(item);
940 bool enable;
941
942 if (strtobool(page, &enable))
943 goto inval;
944
945 if (enable)
946 nvmet_referral_enable(parent, port);
947 else
Jay Sternbergb662a072018-11-12 13:56:40 -0800948 nvmet_referral_disable(parent, port);
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200949
950 return count;
951inval:
952 pr_err("Invalid value '%s' for enable\n", page);
953 return -EINVAL;
954}
955
956CONFIGFS_ATTR(nvmet_referral_, enable);
957
958/*
959 * Discovery Service subsystem definitions
960 */
961static struct configfs_attribute *nvmet_referral_attrs[] = {
962 &nvmet_attr_addr_adrfam,
963 &nvmet_attr_addr_portid,
964 &nvmet_attr_addr_treq,
965 &nvmet_attr_addr_traddr,
966 &nvmet_attr_addr_trsvcid,
967 &nvmet_attr_addr_trtype,
968 &nvmet_referral_attr_enable,
969 NULL,
970};
971
972static void nvmet_referral_release(struct config_item *item)
973{
Jay Sternbergb662a072018-11-12 13:56:40 -0800974 struct nvmet_port *parent = to_nvmet_port(item->ci_parent->ci_parent);
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200975 struct nvmet_port *port = to_nvmet_port(item);
976
Jay Sternbergb662a072018-11-12 13:56:40 -0800977 nvmet_referral_disable(parent, port);
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200978 kfree(port);
979}
980
981static struct configfs_item_operations nvmet_referral_item_ops = {
982 .release = nvmet_referral_release,
983};
984
Bhumika Goyal66603a32017-10-16 17:18:47 +0200985static const struct config_item_type nvmet_referral_type = {
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200986 .ct_owner = THIS_MODULE,
987 .ct_attrs = nvmet_referral_attrs,
988 .ct_item_ops = &nvmet_referral_item_ops,
989};
990
991static struct config_group *nvmet_referral_make(
992 struct config_group *group, const char *name)
993{
994 struct nvmet_port *port;
995
996 port = kzalloc(sizeof(*port), GFP_KERNEL);
997 if (!port)
Dan Carpenterf98d9ca2016-07-07 11:15:26 +0300998 return ERR_PTR(-ENOMEM);
Christoph Hellwiga07b4972016-06-21 18:04:20 +0200999
1000 INIT_LIST_HEAD(&port->entry);
1001 config_group_init_type_name(&port->group, name, &nvmet_referral_type);
1002
1003 return &port->group;
1004}
1005
1006static struct configfs_group_operations nvmet_referral_group_ops = {
1007 .make_group = nvmet_referral_make,
1008};
1009
Bhumika Goyal66603a32017-10-16 17:18:47 +02001010static const struct config_item_type nvmet_referrals_type = {
Christoph Hellwiga07b4972016-06-21 18:04:20 +02001011 .ct_owner = THIS_MODULE,
1012 .ct_group_ops = &nvmet_referral_group_ops,
1013};
1014
Christoph Hellwig62ac0d32018-06-01 08:59:25 +02001015static struct {
1016 enum nvme_ana_state state;
1017 const char *name;
1018} nvmet_ana_state_names[] = {
1019 { NVME_ANA_OPTIMIZED, "optimized" },
1020 { NVME_ANA_NONOPTIMIZED, "non-optimized" },
1021 { NVME_ANA_INACCESSIBLE, "inaccessible" },
1022 { NVME_ANA_PERSISTENT_LOSS, "persistent-loss" },
1023 { NVME_ANA_CHANGE, "change" },
1024};
1025
1026static ssize_t nvmet_ana_group_ana_state_show(struct config_item *item,
1027 char *page)
1028{
1029 struct nvmet_ana_group *grp = to_ana_group(item);
1030 enum nvme_ana_state state = grp->port->ana_state[grp->grpid];
1031 int i;
1032
1033 for (i = 0; i < ARRAY_SIZE(nvmet_ana_state_names); i++) {
1034 if (state != nvmet_ana_state_names[i].state)
1035 continue;
1036 return sprintf(page, "%s\n", nvmet_ana_state_names[i].name);
1037 }
1038
1039 return sprintf(page, "\n");
1040}
1041
1042static ssize_t nvmet_ana_group_ana_state_store(struct config_item *item,
1043 const char *page, size_t count)
1044{
1045 struct nvmet_ana_group *grp = to_ana_group(item);
1046 int i;
1047
1048 for (i = 0; i < ARRAY_SIZE(nvmet_ana_state_names); i++) {
1049 if (sysfs_streq(page, nvmet_ana_state_names[i].name))
1050 goto found;
1051 }
1052
1053 pr_err("Invalid value '%s' for ana_state\n", page);
1054 return -EINVAL;
1055
1056found:
1057 down_write(&nvmet_ana_sem);
1058 grp->port->ana_state[grp->grpid] = nvmet_ana_state_names[i].state;
1059 nvmet_ana_chgcnt++;
1060 up_write(&nvmet_ana_sem);
1061
1062 nvmet_port_send_ana_event(grp->port);
1063 return count;
1064}
1065
1066CONFIGFS_ATTR(nvmet_ana_group_, ana_state);
1067
1068static struct configfs_attribute *nvmet_ana_group_attrs[] = {
1069 &nvmet_ana_group_attr_ana_state,
1070 NULL,
1071};
1072
1073static void nvmet_ana_group_release(struct config_item *item)
1074{
1075 struct nvmet_ana_group *grp = to_ana_group(item);
1076
1077 if (grp == &grp->port->ana_default_group)
1078 return;
1079
1080 down_write(&nvmet_ana_sem);
1081 grp->port->ana_state[grp->grpid] = NVME_ANA_INACCESSIBLE;
1082 nvmet_ana_group_enabled[grp->grpid]--;
1083 up_write(&nvmet_ana_sem);
1084
1085 nvmet_port_send_ana_event(grp->port);
1086 kfree(grp);
1087}
1088
1089static struct configfs_item_operations nvmet_ana_group_item_ops = {
1090 .release = nvmet_ana_group_release,
1091};
1092
1093static const struct config_item_type nvmet_ana_group_type = {
1094 .ct_item_ops = &nvmet_ana_group_item_ops,
1095 .ct_attrs = nvmet_ana_group_attrs,
1096 .ct_owner = THIS_MODULE,
1097};
1098
1099static struct config_group *nvmet_ana_groups_make_group(
1100 struct config_group *group, const char *name)
1101{
1102 struct nvmet_port *port = ana_groups_to_port(&group->cg_item);
1103 struct nvmet_ana_group *grp;
1104 u32 grpid;
1105 int ret;
1106
1107 ret = kstrtou32(name, 0, &grpid);
1108 if (ret)
1109 goto out;
1110
1111 ret = -EINVAL;
1112 if (grpid <= 1 || grpid > NVMET_MAX_ANAGRPS)
1113 goto out;
1114
1115 ret = -ENOMEM;
1116 grp = kzalloc(sizeof(*grp), GFP_KERNEL);
1117 if (!grp)
1118 goto out;
1119 grp->port = port;
1120 grp->grpid = grpid;
1121
1122 down_write(&nvmet_ana_sem);
1123 nvmet_ana_group_enabled[grpid]++;
1124 up_write(&nvmet_ana_sem);
1125
1126 nvmet_port_send_ana_event(grp->port);
1127
1128 config_group_init_type_name(&grp->group, name, &nvmet_ana_group_type);
1129 return &grp->group;
1130out:
1131 return ERR_PTR(ret);
1132}
1133
1134static struct configfs_group_operations nvmet_ana_groups_group_ops = {
1135 .make_group = nvmet_ana_groups_make_group,
1136};
1137
1138static const struct config_item_type nvmet_ana_groups_type = {
1139 .ct_group_ops = &nvmet_ana_groups_group_ops,
1140 .ct_owner = THIS_MODULE,
1141};
1142
Christoph Hellwiga07b4972016-06-21 18:04:20 +02001143/*
1144 * Ports definitions.
1145 */
1146static void nvmet_port_release(struct config_item *item)
1147{
1148 struct nvmet_port *port = to_nvmet_port(item);
1149
Jay Sternbergb662a072018-11-12 13:56:40 -08001150 list_del(&port->global_entry);
1151
Christoph Hellwig72efd252018-07-19 07:35:20 -07001152 kfree(port->ana_state);
Christoph Hellwiga07b4972016-06-21 18:04:20 +02001153 kfree(port);
1154}
1155
1156static struct configfs_attribute *nvmet_port_attrs[] = {
1157 &nvmet_attr_addr_adrfam,
1158 &nvmet_attr_addr_treq,
1159 &nvmet_attr_addr_traddr,
1160 &nvmet_attr_addr_trsvcid,
1161 &nvmet_attr_addr_trtype,
Steve Wise0d5ee2b2018-06-20 07:15:10 -07001162 &nvmet_attr_param_inline_data_size,
Christoph Hellwiga07b4972016-06-21 18:04:20 +02001163 NULL,
1164};
1165
1166static struct configfs_item_operations nvmet_port_item_ops = {
1167 .release = nvmet_port_release,
1168};
1169
Bhumika Goyal66603a32017-10-16 17:18:47 +02001170static const struct config_item_type nvmet_port_type = {
Christoph Hellwiga07b4972016-06-21 18:04:20 +02001171 .ct_attrs = nvmet_port_attrs,
1172 .ct_item_ops = &nvmet_port_item_ops,
1173 .ct_owner = THIS_MODULE,
1174};
1175
1176static struct config_group *nvmet_ports_make(struct config_group *group,
1177 const char *name)
1178{
1179 struct nvmet_port *port;
1180 u16 portid;
Christoph Hellwig62ac0d32018-06-01 08:59:25 +02001181 u32 i;
Christoph Hellwiga07b4972016-06-21 18:04:20 +02001182
1183 if (kstrtou16(name, 0, &portid))
1184 return ERR_PTR(-EINVAL);
1185
1186 port = kzalloc(sizeof(*port), GFP_KERNEL);
1187 if (!port)
Dan Carpenterf98d9ca2016-07-07 11:15:26 +03001188 return ERR_PTR(-ENOMEM);
Christoph Hellwiga07b4972016-06-21 18:04:20 +02001189
Christoph Hellwig72efd252018-07-19 07:35:20 -07001190 port->ana_state = kcalloc(NVMET_MAX_ANAGRPS + 1,
1191 sizeof(*port->ana_state), GFP_KERNEL);
1192 if (!port->ana_state) {
1193 kfree(port);
1194 return ERR_PTR(-ENOMEM);
1195 }
1196
Christoph Hellwig62ac0d32018-06-01 08:59:25 +02001197 for (i = 1; i <= NVMET_MAX_ANAGRPS; i++) {
1198 if (i == NVMET_DEFAULT_ANA_GRPID)
1199 port->ana_state[1] = NVME_ANA_OPTIMIZED;
1200 else
1201 port->ana_state[i] = NVME_ANA_INACCESSIBLE;
1202 }
Christoph Hellwig72efd252018-07-19 07:35:20 -07001203
Jay Sternbergb662a072018-11-12 13:56:40 -08001204 list_add(&port->global_entry, &nvmet_ports_list);
1205
Christoph Hellwiga07b4972016-06-21 18:04:20 +02001206 INIT_LIST_HEAD(&port->entry);
1207 INIT_LIST_HEAD(&port->subsystems);
1208 INIT_LIST_HEAD(&port->referrals);
Steve Wise0d5ee2b2018-06-20 07:15:10 -07001209 port->inline_data_size = -1; /* < 0 == let the transport choose */
Christoph Hellwiga07b4972016-06-21 18:04:20 +02001210
1211 port->disc_addr.portid = cpu_to_le16(portid);
Sagi Grimberg9b95d2f2018-11-20 10:34:19 +01001212 port->disc_addr.treq = NVMF_TREQ_DISABLE_SQFLOW;
Christoph Hellwiga07b4972016-06-21 18:04:20 +02001213 config_group_init_type_name(&port->group, name, &nvmet_port_type);
1214
1215 config_group_init_type_name(&port->subsys_group,
1216 "subsystems", &nvmet_port_subsys_type);
1217 configfs_add_default_group(&port->subsys_group, &port->group);
1218
1219 config_group_init_type_name(&port->referrals_group,
1220 "referrals", &nvmet_referrals_type);
1221 configfs_add_default_group(&port->referrals_group, &port->group);
1222
Christoph Hellwig62ac0d32018-06-01 08:59:25 +02001223 config_group_init_type_name(&port->ana_groups_group,
1224 "ana_groups", &nvmet_ana_groups_type);
1225 configfs_add_default_group(&port->ana_groups_group, &port->group);
1226
1227 port->ana_default_group.port = port;
1228 port->ana_default_group.grpid = NVMET_DEFAULT_ANA_GRPID;
1229 config_group_init_type_name(&port->ana_default_group.group,
1230 __stringify(NVMET_DEFAULT_ANA_GRPID),
1231 &nvmet_ana_group_type);
1232 configfs_add_default_group(&port->ana_default_group.group,
1233 &port->ana_groups_group);
1234
Christoph Hellwiga07b4972016-06-21 18:04:20 +02001235 return &port->group;
1236}
1237
1238static struct configfs_group_operations nvmet_ports_group_ops = {
1239 .make_group = nvmet_ports_make,
1240};
1241
Bhumika Goyal66603a32017-10-16 17:18:47 +02001242static const struct config_item_type nvmet_ports_type = {
Christoph Hellwiga07b4972016-06-21 18:04:20 +02001243 .ct_group_ops = &nvmet_ports_group_ops,
1244 .ct_owner = THIS_MODULE,
1245};
1246
1247static struct config_group nvmet_subsystems_group;
1248static struct config_group nvmet_ports_group;
1249
1250static void nvmet_host_release(struct config_item *item)
1251{
1252 struct nvmet_host *host = to_host(item);
1253
1254 kfree(host);
1255}
1256
1257static struct configfs_item_operations nvmet_host_item_ops = {
1258 .release = nvmet_host_release,
1259};
1260
Bhumika Goyal66603a32017-10-16 17:18:47 +02001261static const struct config_item_type nvmet_host_type = {
Christoph Hellwiga07b4972016-06-21 18:04:20 +02001262 .ct_item_ops = &nvmet_host_item_ops,
1263 .ct_owner = THIS_MODULE,
1264};
1265
1266static struct config_group *nvmet_hosts_make_group(struct config_group *group,
1267 const char *name)
1268{
1269 struct nvmet_host *host;
1270
1271 host = kzalloc(sizeof(*host), GFP_KERNEL);
1272 if (!host)
1273 return ERR_PTR(-ENOMEM);
1274
1275 config_group_init_type_name(&host->group, name, &nvmet_host_type);
1276
1277 return &host->group;
1278}
1279
1280static struct configfs_group_operations nvmet_hosts_group_ops = {
1281 .make_group = nvmet_hosts_make_group,
1282};
1283
Bhumika Goyal66603a32017-10-16 17:18:47 +02001284static const struct config_item_type nvmet_hosts_type = {
Christoph Hellwiga07b4972016-06-21 18:04:20 +02001285 .ct_group_ops = &nvmet_hosts_group_ops,
1286 .ct_owner = THIS_MODULE,
1287};
1288
1289static struct config_group nvmet_hosts_group;
1290
Bhumika Goyal66603a32017-10-16 17:18:47 +02001291static const struct config_item_type nvmet_root_type = {
Christoph Hellwiga07b4972016-06-21 18:04:20 +02001292 .ct_owner = THIS_MODULE,
1293};
1294
1295static struct configfs_subsystem nvmet_configfs_subsystem = {
1296 .su_group = {
1297 .cg_item = {
1298 .ci_namebuf = "nvmet",
1299 .ci_type = &nvmet_root_type,
1300 },
1301 },
1302};
1303
1304int __init nvmet_init_configfs(void)
1305{
1306 int ret;
1307
1308 config_group_init(&nvmet_configfs_subsystem.su_group);
1309 mutex_init(&nvmet_configfs_subsystem.su_mutex);
1310
1311 config_group_init_type_name(&nvmet_subsystems_group,
1312 "subsystems", &nvmet_subsystems_type);
1313 configfs_add_default_group(&nvmet_subsystems_group,
1314 &nvmet_configfs_subsystem.su_group);
1315
1316 config_group_init_type_name(&nvmet_ports_group,
1317 "ports", &nvmet_ports_type);
1318 configfs_add_default_group(&nvmet_ports_group,
1319 &nvmet_configfs_subsystem.su_group);
1320
1321 config_group_init_type_name(&nvmet_hosts_group,
1322 "hosts", &nvmet_hosts_type);
1323 configfs_add_default_group(&nvmet_hosts_group,
1324 &nvmet_configfs_subsystem.su_group);
1325
1326 ret = configfs_register_subsystem(&nvmet_configfs_subsystem);
1327 if (ret) {
1328 pr_err("configfs_register_subsystem: %d\n", ret);
1329 return ret;
1330 }
1331
1332 return 0;
1333}
1334
1335void __exit nvmet_exit_configfs(void)
1336{
1337 configfs_unregister_subsystem(&nvmet_configfs_subsystem);
1338}