source: rtems-libbsd/freebsd/sbin/nvmecontrol/ns.c @ ddc8c35

5
Last change on this file since ddc8c35 was ddc8c35, checked in by Sebastian Huber <sebastian.huber@…>, on 11/13/19 at 11:57:55

NVMECONTROL(8): Import from FreeBSD

Update #3821.

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