]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/nvmecontrol/ns.c
Update Subversion to 1.14.0 LTS. See contrib/subversion/CHANGES for a
[FreeBSD/FreeBSD.git] / sbin / nvmecontrol / ns.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2017 Netflix, Inc.
5  * Copyright (C) 2018-2019 Alexander Motin <mav@FreeBSD.org>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer,
12  *    without modification, immediately at the beginning of the file.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/param.h>
33 #include <sys/ioccom.h>
34
35 #include <err.h>
36 #include <fcntl.h>
37 #include <stdbool.h>
38 #include <stddef.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <unistd.h>
43
44 #include "nvmecontrol.h"
45
46 /* Tables for command line parsing */
47
48 static cmd_fn_t ns;
49 static cmd_fn_t nsactive;
50 static cmd_fn_t nsallocated;
51 static cmd_fn_t nscontrollers;
52 static cmd_fn_t nscreate;
53 static cmd_fn_t nsdelete;
54 static cmd_fn_t nsattach;
55 static cmd_fn_t nsdetach;
56 static cmd_fn_t nsattached;
57 static cmd_fn_t nsidentify;
58
59 #define NONE 0xffffffffu
60 #define NONE64 0xffffffffffffffffull
61 #define OPT(l, s, t, opt, addr, desc) { l, s, t, &opt.addr, desc }
62 #define OPT_END { NULL, 0, arg_none, NULL, NULL }
63
64 static struct cmd ns_cmd = {
65         .name = "ns",
66         .fn = ns,
67         .descr = "Namespace management commands",
68         .ctx_size = 0,
69         .opts = NULL,
70         .args = NULL,
71 };
72
73 CMD_COMMAND(ns_cmd);
74
75 static struct active_options {
76         const char      *dev;
77 } active_opt = {
78         .dev = NULL,
79 };
80
81 static const struct args active_args[] = {
82         { arg_string, &active_opt.dev, "controller-id|namespace-id" },
83         { arg_none, NULL, NULL },
84 };
85
86 static struct cmd active_cmd = {
87         .name = "active",
88         .fn = nsactive,
89         .descr = "List active (attached) namespaces",
90         .ctx_size = sizeof(active_opt),
91         .opts = NULL,
92         .args = active_args,
93 };
94
95 CMD_SUBCOMMAND(ns_cmd, active_cmd);
96
97 static struct cmd allocated_cmd = {
98         .name = "allocated",
99         .fn = nsallocated,
100         .descr = "List allocated (created) namespaces",
101         .ctx_size = sizeof(active_opt),
102         .opts = NULL,
103         .args = active_args,
104 };
105
106 CMD_SUBCOMMAND(ns_cmd, allocated_cmd);
107
108 static struct controllers_options {
109         const char      *dev;
110 } controllers_opt = {
111         .dev = NULL,
112 };
113
114 static const struct args controllers_args[] = {
115         { arg_string, &controllers_opt.dev, "controller-id|namespace-id" },
116         { arg_none, NULL, NULL },
117 };
118
119 static struct cmd controllers_cmd = {
120         .name = "controllers",
121         .fn = nscontrollers,
122         .descr = "List all controllers in NVM subsystem",
123         .ctx_size = sizeof(controllers_opt),
124         .opts = NULL,
125         .args = controllers_args,
126 };
127
128 CMD_SUBCOMMAND(ns_cmd, controllers_cmd);
129
130 static struct create_options {
131         uint64_t nsze;
132         uint64_t cap;
133         uint32_t lbaf;
134         uint32_t mset;
135         uint32_t nmic;
136         uint32_t pi;
137         uint32_t pil;
138         uint32_t flbas;
139         uint32_t dps;
140 //      uint32_t block_size;
141         const char *dev;
142 } create_opt = {
143         .nsze = NONE64,
144         .cap = NONE64,
145         .lbaf = NONE,
146         .mset = NONE,
147         .nmic = NONE,
148         .pi = NONE,
149         .pil = NONE,
150         .flbas = NONE,
151         .dps = NONE,
152         .dev = NULL,
153 //      .block_size = NONE,
154 };
155
156 static const struct opts create_opts[] = {
157         OPT("nsze", 's', arg_uint64, create_opt, nsze,
158             "The namespace size"),
159         OPT("ncap", 'c', arg_uint64, create_opt, cap,
160             "The capacity of the namespace (<= ns size)"),
161         OPT("lbaf", 'f', arg_uint32, create_opt, lbaf,
162             "The FMT field of the FLBAS"),
163         OPT("mset", 'm', arg_uint32, create_opt, mset,
164             "The MSET field of the FLBAS"),
165         OPT("nmic", 'n', arg_uint32, create_opt, nmic,
166             "Namespace multipath and sharing capabilities"),
167         OPT("pi", 'p', arg_uint32, create_opt, pi,
168             "PI field of FLBAS"),
169         OPT("pil", 'l', arg_uint32, create_opt, pil,
170             "PIL field of FLBAS"),
171         OPT("flbas", 'L', arg_uint32, create_opt, flbas,
172             "Namespace formatted logical block size setting"),
173         OPT("dps", 'd', arg_uint32, create_opt, dps,
174             "Data protection settings"),
175 //      OPT("block-size", 'b', arg_uint32, create_opt, block_size,
176 //          "Blocksize of the namespace"),
177         OPT_END
178 };
179
180 static const struct args create_args[] = {
181         { arg_string, &create_opt.dev, "controller-id|namespace-id" },
182         { arg_none, NULL, NULL },
183 };
184
185 static struct cmd create_cmd = {
186         .name = "create",
187         .fn = nscreate,
188         .descr = "Create a namespace",
189         .ctx_size = sizeof(create_opt),
190         .opts = create_opts,
191         .args = create_args,
192 };
193
194 CMD_SUBCOMMAND(ns_cmd, create_cmd);
195
196 static struct delete_options {
197         uint32_t        nsid;
198         const char      *dev;
199 } delete_opt = {
200         .nsid = NONE,
201         .dev = NULL,
202 };
203
204 static const struct opts delete_opts[] = {
205         OPT("namespace-id", 'n', arg_uint32, delete_opt, nsid,
206             "The namespace ID to delete"),
207         OPT_END
208 };
209
210 static const struct args delete_args[] = {
211         { arg_string, &delete_opt.dev, "controller-id|namespace-id" },
212         { arg_none, NULL, NULL },
213 };
214
215 static struct cmd delete_cmd = {
216         .name = "delete",
217         .fn = nsdelete,
218         .descr = "Delete a namespace",
219         .ctx_size = sizeof(delete_opt),
220         .opts = delete_opts,
221         .args = delete_args,
222 };
223
224 CMD_SUBCOMMAND(ns_cmd, delete_cmd);
225
226 static struct attach_options {
227         uint32_t        nsid;
228         uint32_t        ctrlrid;
229         const char      *dev;
230 } attach_opt = {
231         .nsid = NONE,
232         .ctrlrid = NONE - 1,
233         .dev = NULL,
234 };
235
236 static const struct opts attach_opts[] = {
237         OPT("namespace-id", 'n', arg_uint32, attach_opt, nsid,
238             "The namespace ID to attach"),
239         OPT("controller", 'c', arg_uint32, attach_opt, ctrlrid,
240             "The controller ID to attach"),
241         OPT_END
242 };
243
244 static const struct args attach_args[] = {
245         { arg_string, &attach_opt.dev, "controller-id|namespace-id" },
246         { arg_none, NULL, NULL },
247 };
248
249 static struct cmd attach_cmd = {
250         .name = "attach",
251         .fn = nsattach,
252         .descr = "Attach a controller to a namespace",
253         .ctx_size = sizeof(attach_opt),
254         .opts = attach_opts,
255         .args = attach_args,
256 };
257
258 CMD_SUBCOMMAND(ns_cmd, attach_cmd);
259
260 static struct attached_options {
261         uint32_t        nsid;
262         const char      *dev;
263 } attached_opt = {
264         .nsid = NONE,
265         .dev = NULL,
266 };
267
268 static const struct opts attached_opts[] = {
269         OPT("namespace-id", 'n', arg_uint32, attached_opt, nsid,
270             "The namespace ID to request attached controllers"),
271         OPT_END
272 };
273
274 static const struct args attached_args[] = {
275         { arg_string, &attached_opt.dev, "controller-id|namespace-id" },
276         { arg_none, NULL, NULL },
277 };
278
279 static struct cmd attached_cmd = {
280         .name = "attached",
281         .fn = nsattached,
282         .descr = "List controllers attached to a namespace",
283         .ctx_size = sizeof(attached_opt),
284         .opts = attached_opts,
285         .args = attached_args,
286 };
287
288 CMD_SUBCOMMAND(ns_cmd, attached_cmd);
289
290 static struct detach_options {
291         uint32_t        nsid;
292         uint32_t        ctrlrid;
293         const char      *dev;
294 } detach_opt = {
295         .nsid = NONE,
296         .ctrlrid = NONE - 1,
297         .dev = NULL,
298 };
299
300 static const struct opts detach_opts[] = {
301         OPT("namespace-id", 'n', arg_uint32, detach_opt, nsid,
302             "The namespace ID to detach"),
303         OPT("controller", 'c', arg_uint32, detach_opt, ctrlrid,
304             "The controller ID to detach"),
305         OPT_END
306 };
307
308 static const struct args detach_args[] = {
309         { arg_string, &detach_opt.dev, "controller-id|namespace-id" },
310         { arg_none, NULL, NULL },
311 };
312
313 static struct cmd detach_cmd = {
314         .name = "detach",
315         .fn = nsdetach,
316         .descr = "Detach a controller from a namespace",
317         .ctx_size = sizeof(detach_opt),
318         .opts = detach_opts,
319         .args = detach_args,
320 };
321
322 CMD_SUBCOMMAND(ns_cmd, detach_cmd);
323
324 static struct identify_options {
325         bool            hex;
326         bool            verbose;
327         const char      *dev;
328         uint32_t        nsid;
329 } identify_opt = {
330         .hex = false,
331         .verbose = false,
332         .dev = NULL,
333         .nsid = NONE,
334 };
335
336 static const struct opts identify_opts[] = {
337         OPT("hex", 'x', arg_none, identify_opt, hex,
338             "Print identiy information in hex"),
339         OPT("verbose", 'v', arg_none, identify_opt, verbose,
340             "More verbosity: print entire identify table"),
341         OPT("nsid", 'n', arg_uint32, identify_opt, nsid,
342             "The namespace ID to print IDENTIFY for"),
343         { NULL, 0, arg_none, NULL, NULL }
344 };
345
346 static const struct args identify_args[] = {
347         { arg_string, &identify_opt.dev, "controller-id|namespace-id" },
348         { arg_none, NULL, NULL },
349 };
350
351 static struct cmd identify_cmd = {
352         .name = "identify",
353         .fn = nsidentify,
354         .descr = "Print IDENTIFY for allocated namespace",
355         .ctx_size = sizeof(identify_opt),
356         .opts = identify_opts,
357         .args = identify_args,
358 };
359
360 CMD_SUBCOMMAND(ns_cmd, identify_cmd);
361
362 /* handles NVME_OPC_NAMESPACE_MANAGEMENT and ATTACHMENT admin cmds */
363
364 struct ns_result_str {
365         uint16_t res;
366         const char * str;
367 };
368
369 static struct ns_result_str ns_result[] = {
370         { 0x2,  "Invalid Field"},
371         { 0xa,  "Invalid Format"},
372         { 0xb,  "Invalid Namespace or format"},
373         { 0x15, "Namespace insufficent capacity"},
374         { 0x16, "Namespace ID unavaliable"},
375         { 0x18, "Namespace already attached"},
376         { 0x19, "Namespace is private"},
377         { 0x1a, "Namespace is not attached"},
378         { 0x1b, "Thin provisioning not supported"},
379         { 0x1c, "Controller list invalid"},
380         { 0x24, "ANA Group Identifier Invalid"},
381         { 0x25, "ANA Attach Failed"},
382         { 0xFFFF, "Unknown"}
383 };
384
385 static const char *
386 get_res_str(uint16_t res)
387 {
388         struct ns_result_str *t = ns_result;
389
390         while (t->res != 0xFFFF) {
391                 if (t->res == res)
392                         return (t->str);
393                 t++;
394         }
395         return t->str;
396 }
397
398 static void
399 nsactive(const struct cmd *f, int argc, char *argv[])
400 {
401         struct nvme_pt_command  pt;
402         struct nvme_controller_data cd;
403         int     fd, i;
404         char    *path;
405         uint32_t nsid;
406         uint32_t list[1024];
407
408         if (arg_parse(argc, argv, f))
409                 return;
410         open_dev(active_opt.dev, &fd, 0, 1);
411         get_nsid(fd, &path, &nsid);
412         if (nsid != 0) {
413                 close(fd);
414                 open_dev(path, &fd, 0, 1);
415         }
416         free(path);
417         read_controller_data(fd, &cd);
418
419         /* Check that controller can execute this command. */
420         if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
421             NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
422                 errx(1, "controller does not support namespace management");
423
424         memset(&pt, 0, sizeof(pt));
425         pt.cmd.opc = NVME_OPC_IDENTIFY;
426         pt.cmd.nsid = htole32(0);
427         pt.cmd.cdw10 = htole32(0x02);
428         pt.buf = list;
429         pt.len = sizeof(list);
430         pt.is_read = 1;
431         if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
432                 err(1, "identify request failed");
433         if (nvme_completion_is_error(&pt.cpl))
434                 errx(1, "identify request returned error");
435
436         printf("Active namespaces:\n");
437         for (i = 0; list[i] != 0; i++)
438                 printf("%10d\n", le32toh(list[i]));
439
440         exit(0);
441 }
442
443 static void
444 nsallocated(const struct cmd *f, int argc, char *argv[])
445 {
446         struct nvme_pt_command  pt;
447         struct nvme_controller_data cd;
448         int     fd, i;
449         char    *path;
450         uint32_t nsid;
451         uint32_t list[1024];
452
453         if (arg_parse(argc, argv, f))
454                 return;
455         open_dev(active_opt.dev, &fd, 0, 1);
456         get_nsid(fd, &path, &nsid);
457         if (nsid != 0) {
458                 close(fd);
459                 open_dev(path, &fd, 0, 1);
460         }
461         free(path);
462         read_controller_data(fd, &cd);
463
464         /* Check that controller can execute this command. */
465         if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
466             NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
467                 errx(1, "controller does not support namespace management");
468
469         memset(&pt, 0, sizeof(pt));
470         pt.cmd.opc = NVME_OPC_IDENTIFY;
471         pt.cmd.nsid = htole32(0);
472         pt.cmd.cdw10 = htole32(0x10);
473         pt.buf = list;
474         pt.len = sizeof(list);
475         pt.is_read = 1;
476         if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
477                 err(1, "identify request failed");
478         if (nvme_completion_is_error(&pt.cpl))
479                 errx(1, "identify request returned error");
480
481         printf("Allocated namespaces:\n");
482         for (i = 0; list[i] != 0; i++)
483                 printf("%10d\n", le32toh(list[i]));
484
485         exit(0);
486 }
487
488 static void
489 nscontrollers(const struct cmd *f, int argc, char *argv[])
490 {
491         struct nvme_pt_command  pt;
492         struct nvme_controller_data cd;
493         int     fd, i, n;
494         char    *path;
495         uint32_t nsid;
496         uint16_t clist[2048];
497
498         if (arg_parse(argc, argv, f))
499                 return;
500         open_dev(controllers_opt.dev, &fd, 0, 1);
501         get_nsid(fd, &path, &nsid);
502         if (nsid != 0) {
503                 close(fd);
504                 open_dev(path, &fd, 0, 1);
505         }
506         free(path);
507         read_controller_data(fd, &cd);
508
509         /* Check that controller can execute this command. */
510         if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
511             NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
512                 errx(1, "controller does not support namespace management");
513
514         memset(&pt, 0, sizeof(pt));
515         pt.cmd.opc = NVME_OPC_IDENTIFY;
516         pt.cmd.cdw10 = htole32(0x13);
517         pt.buf = clist;
518         pt.len = sizeof(clist);
519         pt.is_read = 1;
520         if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
521                 err(1, "identify request failed");
522         if (nvme_completion_is_error(&pt.cpl))
523                 errx(1, "identify request returned error");
524
525         n = le16toh(clist[0]);
526         printf("NVM subsystem includes %d controller(s):\n", n);
527         for (i = 0; i < n; i++)
528                 printf("  0x%04x\n", le16toh(clist[i + 1]));
529
530         exit(0);
531 }
532
533 /*
534  * NS MGMT Command specific status values:
535  * 0xa = Invalid Format
536  * 0x15 = Namespace Insuffience capacity
537  * 0x16 = Namespace ID  unavailable (number namespaces exceeded)
538  * 0xb = Thin Provisioning Not supported
539  */
540 static void
541 nscreate(const struct cmd *f, int argc, char *argv[])
542 {
543         struct nvme_pt_command  pt;
544         struct nvme_controller_data cd;
545         struct nvme_namespace_data nsdata;
546         int     fd, result;
547         char    *path;
548         uint32_t nsid;
549
550         if (arg_parse(argc, argv, f))
551                 return;
552
553         if (create_opt.cap == NONE64)
554                 create_opt.cap = create_opt.nsze;
555         if (create_opt.nsze == NONE64) {
556                 fprintf(stderr,
557                     "Size not specified\n");
558                 arg_help(argc, argv, f);
559         }
560
561         open_dev(create_opt.dev, &fd, 1, 1);
562         get_nsid(fd, &path, &nsid);
563         if (nsid != 0) {
564                 close(fd);
565                 open_dev(path, &fd, 1, 1);
566         }
567         free(path);
568         read_controller_data(fd, &cd);
569
570         /* Check that controller can execute this command. */
571         if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
572             NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
573                 errx(1, "controller does not support namespace management");
574
575         /* Allow namespaces sharing if Multi-Path I/O is supported. */
576         if (create_opt.nmic == NONE) {
577                 create_opt.nmic = cd.mic ? (NVME_NS_DATA_NMIC_MAY_BE_SHARED_MASK <<
578                      NVME_NS_DATA_NMIC_MAY_BE_SHARED_SHIFT) : 0;
579         }
580
581         memset(&nsdata, 0, sizeof(nsdata));
582         nsdata.nsze = create_opt.nsze;
583         nsdata.ncap = create_opt.cap;
584         if (create_opt.flbas == NONE)
585                 nsdata.flbas = ((create_opt.lbaf & NVME_NS_DATA_FLBAS_FORMAT_MASK)
586                     << NVME_NS_DATA_FLBAS_FORMAT_SHIFT) |
587                     ((create_opt.mset & NVME_NS_DATA_FLBAS_EXTENDED_MASK)
588                         << NVME_NS_DATA_FLBAS_EXTENDED_SHIFT);
589         else
590                 nsdata.flbas = create_opt.flbas;
591         if (create_opt.dps == NONE)
592                 nsdata.dps = ((create_opt.pi & NVME_NS_DATA_DPS_MD_START_MASK)
593                     << NVME_NS_DATA_DPS_MD_START_SHIFT) |
594                     ((create_opt.pil & NVME_NS_DATA_DPS_PIT_MASK)
595                         << NVME_NS_DATA_DPS_PIT_SHIFT);
596         else
597                 nsdata.dps = create_opt.dps;
598         nsdata.nmic = create_opt.nmic;
599         nvme_namespace_data_swapbytes(&nsdata);
600
601         memset(&pt, 0, sizeof(pt));
602         pt.cmd.opc = NVME_OPC_NAMESPACE_MANAGEMENT;
603         pt.cmd.cdw10 = htole32(0); /* create */
604         pt.buf = &nsdata;
605         pt.len = sizeof(struct nvme_namespace_data);
606         pt.is_read = 0; /* passthrough writes data to ctrlr */
607         if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0)
608                 errx(1, "ioctl request to %s failed: %d", argv[optind], result);
609
610         if (nvme_completion_is_error(&pt.cpl)) {
611                 errx(1, "namespace creation failed: %s",
612                     get_res_str((pt.cpl.status >> NVME_STATUS_SC_SHIFT) &
613                     NVME_STATUS_SC_MASK));
614         }
615         printf("namespace %d created\n", pt.cpl.cdw0);
616         exit(0);
617 }
618
619 static void
620 nsdelete(const struct cmd *f, int argc, char *argv[])
621 {
622         struct nvme_pt_command  pt;
623         struct nvme_controller_data cd;
624         int     fd, result;
625         char    *path;
626         uint32_t nsid;
627         char buf[2];
628
629         if (arg_parse(argc, argv, f))
630                 return;
631
632         open_dev(delete_opt.dev, &fd, 1, 1);
633         get_nsid(fd, &path, &nsid);
634         if (nsid != 0) {
635                 close(fd);
636                 open_dev(path, &fd, 1, 1);
637         } else if (delete_opt.nsid == NONE) {
638                 close(fd);
639                 fprintf(stderr, "No NSID specified");
640                 arg_help(argc, argv, f);
641         }
642         if (delete_opt.nsid != NONE)
643                 nsid = delete_opt.nsid;
644         free(path);
645         read_controller_data(fd, &cd);
646
647         /* Check that controller can execute this command. */
648         if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
649             NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
650                 errx(1, "controller does not support namespace management");
651
652         memset(&pt, 0, sizeof(pt));
653         pt.cmd.opc = NVME_OPC_NAMESPACE_MANAGEMENT;
654         pt.cmd.cdw10 = htole32(1); /* delete */
655         pt.buf = buf;
656         pt.len = sizeof(buf);
657         pt.is_read = 1;
658         pt.cmd.nsid = nsid;
659
660         if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0)
661                 errx(1, "ioctl request to %s failed: %d", delete_opt.dev, result);
662
663         if (nvme_completion_is_error(&pt.cpl)) {
664                 errx(1, "namespace deletion failed: %s",
665                     get_res_str((pt.cpl.status >> NVME_STATUS_SC_SHIFT) &
666                     NVME_STATUS_SC_MASK));
667         }
668         printf("namespace %d deleted\n", nsid);
669         exit(0);
670 }
671
672 /*
673  * Attach and Detach use Dword 10, and a controller list (section 4.9)
674  * This struct is 4096 bytes in size.
675  * 0h = attach
676  * 1h = detach
677  *
678  * Result values for both attach/detach:
679  *
680  * Completion 18h = Already attached
681  *            19h = NS is private and already attached to a controller
682  *            1Ah = Not attached, request could not be completed
683  *            1Ch = Controller list invalid.
684  *
685  * 0x2 Invalid Field can occur if ctrlrid d.n.e in system.
686  */
687 static void
688 nsattach(const struct cmd *f, int argc, char *argv[])
689 {
690         struct nvme_pt_command  pt;
691         struct nvme_controller_data cd;
692         int     fd, result;
693         char    *path;
694         uint32_t nsid;
695         uint16_t clist[2048];
696
697         if (arg_parse(argc, argv, f))
698                 return;
699         open_dev(attach_opt.dev, &fd, 1, 1);
700         get_nsid(fd, &path, &nsid);
701         if (nsid != 0) {
702                 close(fd);
703                 open_dev(path, &fd, 1, 1);
704         } else if (attach_opt.nsid == NONE) {
705                 close(fd);
706                 fprintf(stderr, "No NSID specified");
707                 arg_help(argc, argv, f);
708         }
709         if (attach_opt.nsid != NONE)
710                 nsid = attach_opt.nsid;
711         read_controller_data(fd, &cd);
712
713         /* Check that controller can execute this command. */
714         if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
715             NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
716                 errx(1, "controller does not support namespace management");
717
718         if (attach_opt.ctrlrid == NONE) {
719                 /* Get full list of controllers to attach to. */
720                 memset(&pt, 0, sizeof(pt));
721                 pt.cmd.opc = NVME_OPC_IDENTIFY;
722                 pt.cmd.cdw10 = htole32(0x13);
723                 pt.buf = clist;
724                 pt.len = sizeof(clist);
725                 pt.is_read = 1;
726                 if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
727                         err(1, "identify request failed");
728                 if (nvme_completion_is_error(&pt.cpl))
729                         errx(1, "identify request returned error");
730         } else {
731                 /* By default attach to this controller. */
732                 if (attach_opt.ctrlrid == NONE - 1)
733                         attach_opt.ctrlrid = cd.ctrlr_id;
734                 memset(&clist, 0, sizeof(clist));
735                 clist[0] = htole16(1);
736                 clist[1] = htole16(attach_opt.ctrlrid);
737         }
738
739         memset(&pt, 0, sizeof(pt));
740         pt.cmd.opc = NVME_OPC_NAMESPACE_ATTACHMENT;
741         pt.cmd.cdw10 = htole32(0); /* attach */
742         pt.cmd.nsid = nsid;
743         pt.buf = &clist;
744         pt.len = sizeof(clist);
745
746         if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0)
747                 errx(1, "ioctl request to %s failed: %d", attach_opt.dev, result);
748
749         if (nvme_completion_is_error(&pt.cpl)) {
750                 errx(1, "namespace attach failed: %s",
751                     get_res_str((pt.cpl.status >> NVME_STATUS_SC_SHIFT) &
752                     NVME_STATUS_SC_MASK));
753         }
754         printf("namespace %d attached\n", nsid);
755         exit(0);
756 }
757
758 static void
759 nsdetach(const struct cmd *f, int argc, char *argv[])
760 {
761         struct nvme_pt_command  pt;
762         struct nvme_controller_data cd;
763         int     fd, result;
764         char    *path;
765         uint32_t nsid;
766         uint16_t clist[2048];
767
768         if (arg_parse(argc, argv, f))
769                 return;
770         open_dev(detach_opt.dev, &fd, 1, 1);
771         get_nsid(fd, &path, &nsid);
772         if (nsid != 0) {
773                 close(fd);
774                 open_dev(path, &fd, 1, 1);
775         } else if (detach_opt.nsid == NONE) {
776                 close(fd);
777                 fprintf(stderr, "No NSID specified");
778                 arg_help(argc, argv, f);
779         }
780         if (detach_opt.nsid != NONE)
781                 nsid = detach_opt.nsid;
782         read_controller_data(fd, &cd);
783
784         /* Check that controller can execute this command. */
785         if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
786             NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
787                 errx(1, "controller does not support namespace management");
788
789         if (detach_opt.ctrlrid == NONE) {
790                 /* Get list of controllers this namespace attached to. */
791                 memset(&pt, 0, sizeof(pt));
792                 pt.cmd.opc = NVME_OPC_IDENTIFY;
793                 pt.cmd.nsid = htole32(nsid);
794                 pt.cmd.cdw10 = htole32(0x12);
795                 pt.buf = clist;
796                 pt.len = sizeof(clist);
797                 pt.is_read = 1;
798                 if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
799                         err(1, "identify request failed");
800                 if (nvme_completion_is_error(&pt.cpl))
801                         errx(1, "identify request returned error");
802                 if (clist[0] == 0) {
803                         detach_opt.ctrlrid = cd.ctrlr_id;
804                         memset(&clist, 0, sizeof(clist));
805                         clist[0] = htole16(1);
806                         clist[1] = htole16(detach_opt.ctrlrid);
807                 }
808         } else {
809                 /* By default detach from this controller. */
810                 if (detach_opt.ctrlrid == NONE - 1)
811                         detach_opt.ctrlrid = cd.ctrlr_id;
812                 memset(&clist, 0, sizeof(clist));
813                 clist[0] = htole16(1);
814                 clist[1] = htole16(detach_opt.ctrlrid);
815         }
816
817         memset(&pt, 0, sizeof(pt));
818         pt.cmd.opc = NVME_OPC_NAMESPACE_ATTACHMENT;
819         pt.cmd.cdw10 = htole32(1); /* detach */
820         pt.cmd.nsid = nsid;
821         pt.buf = &clist;
822         pt.len = sizeof(clist);
823
824         if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0)
825                 errx(1, "ioctl request to %s failed: %d", argv[optind], result);
826
827         if (nvme_completion_is_error(&pt.cpl)) {
828                 errx(1, "namespace detach failed: %s",
829                     get_res_str((pt.cpl.status >> NVME_STATUS_SC_SHIFT) &
830                     NVME_STATUS_SC_MASK));
831         }
832         printf("namespace %d detached\n", nsid);
833         exit(0);
834 }
835
836 static void
837 nsattached(const struct cmd *f, int argc, char *argv[])
838 {
839         struct nvme_pt_command  pt;
840         struct nvme_controller_data cd;
841         int     fd, i, n;
842         char    *path;
843         uint32_t nsid;
844         uint16_t clist[2048];
845
846         if (arg_parse(argc, argv, f))
847                 return;
848         open_dev(attached_opt.dev, &fd, 0, 1);
849         get_nsid(fd, &path, &nsid);
850         if (nsid != 0) {
851                 close(fd);
852                 open_dev(path, &fd, 1, 1);
853         } else if (attached_opt.nsid == NONE) {
854                 close(fd);
855                 fprintf(stderr, "No NSID specified");
856                 arg_help(argc, argv, f);
857         }
858         if (attached_opt.nsid != NONE)
859                 nsid = attached_opt.nsid;
860         read_controller_data(fd, &cd);
861
862         /* Check that controller can execute this command. */
863         if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
864             NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
865                 errx(1, "controller does not support namespace management");
866
867         memset(&pt, 0, sizeof(pt));
868         pt.cmd.opc = NVME_OPC_IDENTIFY;
869         pt.cmd.nsid = htole32(nsid);
870         pt.cmd.cdw10 = htole32(0x12);
871         pt.buf = clist;
872         pt.len = sizeof(clist);
873         pt.is_read = 1;
874         if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
875                 err(1, "identify request failed");
876         if (nvme_completion_is_error(&pt.cpl))
877                 errx(1, "identify request returned error");
878
879         n = le16toh(clist[0]);
880         printf("Attached %d controller(s):\n", n);
881         for (i = 0; i < n; i++)
882                 printf("  0x%04x\n", le16toh(clist[i + 1]));
883
884         exit(0);
885 }
886
887 static void
888 nsidentify(const struct cmd *f, int argc, char *argv[])
889 {
890         struct nvme_pt_command  pt;
891         struct nvme_controller_data cd;
892         struct nvme_namespace_data nsdata;
893         uint8_t *data;
894         int     fd;
895         char    *path;
896         uint32_t nsid;
897         u_int   i;
898
899         if (arg_parse(argc, argv, f))
900                 return;
901         open_dev(identify_opt.dev, &fd, 0, 1);
902         get_nsid(fd, &path, &nsid);
903         if (nsid != 0) {
904                 close(fd);
905                 open_dev(path, &fd, 1, 1);
906         } else if (identify_opt.nsid == NONE) {
907                 close(fd);
908                 fprintf(stderr, "No NSID specified");
909                 arg_help(argc, argv, f);
910         }
911         if (identify_opt.nsid != NONE)
912                 nsid = identify_opt.nsid;
913         read_controller_data(fd, &cd);
914
915         /* Check that controller can execute this command. */
916         if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
917             NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
918                 errx(1, "controller does not support namespace management");
919
920         memset(&pt, 0, sizeof(pt));
921         pt.cmd.opc = NVME_OPC_IDENTIFY;
922         pt.cmd.nsid = htole32(nsid);
923         pt.cmd.cdw10 = htole32(0x11);
924         pt.buf = &nsdata;
925         pt.len = sizeof(nsdata);
926         pt.is_read = 1;
927
928         if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
929                 err(1, "identify request failed");
930
931         if (nvme_completion_is_error(&pt.cpl))
932                 errx(1, "identify request returned error");
933
934         close(fd);
935
936         data = (uint8_t *)&nsdata;
937         for (i = 0; i < sizeof(nsdata); i++) {
938                 if (data[i] != 0)
939                         break;
940         }
941         if (i == sizeof(nsdata))
942                 errx(1, "namespace %d is not allocated", nsid);
943
944         /* Convert data to host endian */
945         nvme_namespace_data_swapbytes(&nsdata);
946
947         if (identify_opt.hex) {
948                 i = sizeof(struct nvme_namespace_data);
949                 if (!identify_opt.verbose) {
950                         for (; i > 384; i--) {
951                                 if (data[i - 1] != 0)
952                                         break;
953                         }
954                 }
955                 print_hex(&nsdata, i);
956                 exit(0);
957         }
958
959         print_namespace(&nsdata);
960         exit(0);
961 }
962
963 static void
964 ns(const struct cmd *nf __unused, int argc, char *argv[])
965 {
966
967         cmd_dispatch(argc, argv, &ns_cmd);
968 }