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