xref: /freebsd/sbin/nvmecontrol/ns.c (revision a7bf63be698c377070e5e7cc6e9315b958811529)
1ba405bc8SAlexander Motin /*-
2ba405bc8SAlexander Motin  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3ba405bc8SAlexander Motin  *
452467047SWarner Losh  * Copyright (c) 2017 Netflix, Inc.
5*a7bf63beSAlexander Motin  * Copyright (C) 2018-2019 Alexander Motin <mav@FreeBSD.org>
6ba405bc8SAlexander Motin  *
7ba405bc8SAlexander Motin  * Redistribution and use in source and binary forms, with or without
8ba405bc8SAlexander Motin  * modification, are permitted provided that the following conditions
9ba405bc8SAlexander Motin  * are met:
10ba405bc8SAlexander Motin  * 1. Redistributions of source code must retain the above copyright
11ba405bc8SAlexander Motin  *    notice, this list of conditions and the following disclaimer,
12ba405bc8SAlexander Motin  *    without modification, immediately at the beginning of the file.
13ba405bc8SAlexander Motin  * 2. Redistributions in binary form must reproduce the above copyright
14ba405bc8SAlexander Motin  *    notice, this list of conditions and the following disclaimer in the
15ba405bc8SAlexander Motin  *    documentation and/or other materials provided with the distribution.
16ba405bc8SAlexander Motin  *
17ba405bc8SAlexander Motin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18ba405bc8SAlexander Motin  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19ba405bc8SAlexander Motin  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20ba405bc8SAlexander Motin  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21ba405bc8SAlexander Motin  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22ba405bc8SAlexander Motin  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23ba405bc8SAlexander Motin  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24ba405bc8SAlexander Motin  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25ba405bc8SAlexander Motin  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26ba405bc8SAlexander Motin  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27ba405bc8SAlexander Motin  */
28ba405bc8SAlexander Motin 
29ba405bc8SAlexander Motin #include <sys/cdefs.h>
30ba405bc8SAlexander Motin __FBSDID("$FreeBSD$");
31ba405bc8SAlexander Motin 
32ba405bc8SAlexander Motin #include <sys/param.h>
33ba405bc8SAlexander Motin #include <sys/ioccom.h>
34ba405bc8SAlexander Motin 
35ba405bc8SAlexander Motin #include <err.h>
36ba405bc8SAlexander Motin #include <fcntl.h>
373b3dd3f7SAlexander Motin #include <stdbool.h>
383b3dd3f7SAlexander Motin #include <stddef.h>
39ba405bc8SAlexander Motin #include <stdio.h>
40ba405bc8SAlexander Motin #include <stdlib.h>
41ba405bc8SAlexander Motin #include <string.h>
42ba405bc8SAlexander Motin #include <unistd.h>
43ba405bc8SAlexander Motin 
44ba405bc8SAlexander Motin #include "nvmecontrol.h"
45ba405bc8SAlexander Motin 
46f634b4c1SWarner Losh /* Tables for command line parsing */
47f634b4c1SWarner Losh 
48f634b4c1SWarner Losh static cmd_fn_t ns;
493b3dd3f7SAlexander Motin static cmd_fn_t nsactive;
503b3dd3f7SAlexander Motin static cmd_fn_t nsallocated;
513b3dd3f7SAlexander Motin static cmd_fn_t nscontrollers;
52f634b4c1SWarner Losh static cmd_fn_t nscreate;
53f634b4c1SWarner Losh static cmd_fn_t nsdelete;
54f634b4c1SWarner Losh static cmd_fn_t nsattach;
55f634b4c1SWarner Losh static cmd_fn_t nsdetach;
563b3dd3f7SAlexander Motin static cmd_fn_t nsattached;
573b3dd3f7SAlexander Motin static cmd_fn_t nsidentify;
58f634b4c1SWarner Losh 
59f634b4c1SWarner Losh #define NONE 0xffffffffu
60f634b4c1SWarner Losh #define NONE64 0xffffffffffffffffull
61f634b4c1SWarner Losh #define OPT(l, s, t, opt, addr, desc) { l, s, t, &opt.addr, desc }
62f634b4c1SWarner Losh #define OPT_END	{ NULL, 0, arg_none, NULL, NULL }
63f634b4c1SWarner Losh 
64f634b4c1SWarner Losh static struct cmd ns_cmd = {
653b3dd3f7SAlexander Motin 	.name = "ns",
663b3dd3f7SAlexander Motin 	.fn = ns,
673b3dd3f7SAlexander Motin 	.descr = "Namespace management commands",
683b3dd3f7SAlexander Motin 	.ctx_size = 0,
693b3dd3f7SAlexander Motin 	.opts = NULL,
703b3dd3f7SAlexander Motin 	.args = NULL,
71f634b4c1SWarner Losh };
72f634b4c1SWarner Losh 
73f634b4c1SWarner Losh CMD_COMMAND(ns_cmd);
74f634b4c1SWarner Losh 
753b3dd3f7SAlexander Motin static struct active_options {
763b3dd3f7SAlexander Motin 	const char	*dev;
773b3dd3f7SAlexander Motin } active_opt = {
783b3dd3f7SAlexander Motin 	.dev = NULL,
793b3dd3f7SAlexander Motin };
803b3dd3f7SAlexander Motin 
813b3dd3f7SAlexander Motin static const struct args active_args[] = {
823b3dd3f7SAlexander Motin 	{ arg_string, &active_opt.dev, "controller-id" },
833b3dd3f7SAlexander Motin 	{ arg_none, NULL, NULL },
843b3dd3f7SAlexander Motin };
853b3dd3f7SAlexander Motin 
863b3dd3f7SAlexander Motin static struct cmd active_cmd = {
873b3dd3f7SAlexander Motin 	.name = "active",
883b3dd3f7SAlexander Motin 	.fn = nsactive,
893b3dd3f7SAlexander Motin 	.descr = "List active (attached) namespaces",
903b3dd3f7SAlexander Motin 	.ctx_size = sizeof(active_opt),
913b3dd3f7SAlexander Motin 	.opts = NULL,
923b3dd3f7SAlexander Motin 	.args = active_args,
933b3dd3f7SAlexander Motin };
943b3dd3f7SAlexander Motin 
953b3dd3f7SAlexander Motin CMD_SUBCOMMAND(ns_cmd, active_cmd);
963b3dd3f7SAlexander Motin 
973b3dd3f7SAlexander Motin static struct cmd allocated_cmd = {
983b3dd3f7SAlexander Motin 	.name = "allocated",
993b3dd3f7SAlexander Motin 	.fn = nsallocated,
1003b3dd3f7SAlexander Motin 	.descr = "List allocated (created) namespaces",
1013b3dd3f7SAlexander Motin 	.ctx_size = sizeof(active_opt),
1023b3dd3f7SAlexander Motin 	.opts = NULL,
1033b3dd3f7SAlexander Motin 	.args = active_args,
1043b3dd3f7SAlexander Motin };
1053b3dd3f7SAlexander Motin 
1063b3dd3f7SAlexander Motin CMD_SUBCOMMAND(ns_cmd, allocated_cmd);
1073b3dd3f7SAlexander Motin 
1083b3dd3f7SAlexander Motin static struct controllers_options {
1093b3dd3f7SAlexander Motin 	const char	*dev;
1103b3dd3f7SAlexander Motin } controllers_opt = {
1113b3dd3f7SAlexander Motin 	.dev = NULL,
1123b3dd3f7SAlexander Motin };
1133b3dd3f7SAlexander Motin 
1143b3dd3f7SAlexander Motin static const struct args controllers_args[] = {
1153b3dd3f7SAlexander Motin 	{ arg_string, &controllers_opt.dev, "controller-id" },
1163b3dd3f7SAlexander Motin 	{ arg_none, NULL, NULL },
1173b3dd3f7SAlexander Motin };
1183b3dd3f7SAlexander Motin 
1193b3dd3f7SAlexander Motin static struct cmd controllers_cmd = {
1203b3dd3f7SAlexander Motin 	.name = "controllers",
1213b3dd3f7SAlexander Motin 	.fn = nscontrollers,
1223b3dd3f7SAlexander Motin 	.descr = "List all controllers in NVM subsystem",
1233b3dd3f7SAlexander Motin 	.ctx_size = sizeof(controllers_opt),
1243b3dd3f7SAlexander Motin 	.opts = NULL,
1253b3dd3f7SAlexander Motin 	.args = controllers_args,
1263b3dd3f7SAlexander Motin };
1273b3dd3f7SAlexander Motin 
1283b3dd3f7SAlexander Motin CMD_SUBCOMMAND(ns_cmd, controllers_cmd);
1293b3dd3f7SAlexander Motin 
130f634b4c1SWarner Losh static struct create_options {
131f634b4c1SWarner Losh 	uint64_t nsze;
132f634b4c1SWarner Losh 	uint64_t cap;
133f634b4c1SWarner Losh 	uint32_t lbaf;
134f634b4c1SWarner Losh 	uint32_t mset;
135f634b4c1SWarner Losh 	uint32_t nmic;
136f634b4c1SWarner Losh 	uint32_t pi;
137f634b4c1SWarner Losh 	uint32_t pil;
138f634b4c1SWarner Losh 	uint32_t flbas;
139f634b4c1SWarner Losh 	uint32_t dps;
140f634b4c1SWarner Losh //	uint32_t block_size;
141f634b4c1SWarner Losh 	const char *dev;
142f634b4c1SWarner Losh } create_opt = {
143f634b4c1SWarner Losh 	.nsze = NONE64,
144f634b4c1SWarner Losh 	.cap = NONE64,
145f634b4c1SWarner Losh 	.lbaf = NONE,
146f634b4c1SWarner Losh 	.mset = NONE,
147f634b4c1SWarner Losh 	.nmic = NONE,
148f634b4c1SWarner Losh 	.pi = NONE,
149f634b4c1SWarner Losh 	.pil = NONE,
150f634b4c1SWarner Losh 	.flbas = NONE,
151f634b4c1SWarner Losh 	.dps = NONE,
152f634b4c1SWarner Losh 	.dev = NULL,
153f634b4c1SWarner Losh //	.block_size = NONE,
154f634b4c1SWarner Losh };
155f634b4c1SWarner Losh 
156f634b4c1SWarner Losh static const struct opts create_opts[] = {
157f634b4c1SWarner Losh 	OPT("nsze", 's', arg_uint64, create_opt, nsze,
158f634b4c1SWarner Losh 	    "The namespace size"),
159f634b4c1SWarner Losh 	OPT("ncap", 'c', arg_uint64, create_opt, cap,
160f634b4c1SWarner Losh 	    "The capacity of the namespace (<= ns size)"),
161f634b4c1SWarner Losh 	OPT("lbaf", 'f', arg_uint32, create_opt, lbaf,
162f634b4c1SWarner Losh 	    "The FMT field of the FLBAS"),
163f634b4c1SWarner Losh 	OPT("mset", 'm', arg_uint32, create_opt, mset,
164f634b4c1SWarner Losh 	    "The MSET field of the FLBAS"),
165f634b4c1SWarner Losh 	OPT("nmic", 'n', arg_uint32, create_opt, nmic,
166f634b4c1SWarner Losh 	    "Namespace multipath and sharing capabilities"),
167f634b4c1SWarner Losh 	OPT("pi", 'p', arg_uint32, create_opt, pi,
168f634b4c1SWarner Losh 	    "PI field of FLBAS"),
169f634b4c1SWarner Losh 	OPT("pil", 'l', arg_uint32, create_opt, pil,
170f634b4c1SWarner Losh 	    "PIL field of FLBAS"),
1713b3dd3f7SAlexander Motin 	OPT("flbas", 'L', arg_uint32, create_opt, flbas,
172f634b4c1SWarner Losh 	    "Namespace formatted logical block size setting"),
173f634b4c1SWarner Losh 	OPT("dps", 'd', arg_uint32, create_opt, dps,
174f634b4c1SWarner Losh 	    "Data protection settings"),
175f634b4c1SWarner Losh //	OPT("block-size", 'b', arg_uint32, create_opt, block_size,
176f634b4c1SWarner Losh //	    "Blocksize of the namespace"),
177f634b4c1SWarner Losh 	OPT_END
178f634b4c1SWarner Losh };
179f634b4c1SWarner Losh 
180f634b4c1SWarner Losh static const struct args create_args[] = {
181f634b4c1SWarner Losh 	{ arg_string, &create_opt.dev, "controller-id" },
182f634b4c1SWarner Losh 	{ arg_none, NULL, NULL },
183f634b4c1SWarner Losh };
184f634b4c1SWarner Losh 
185f634b4c1SWarner Losh static struct cmd create_cmd = {
186f634b4c1SWarner Losh 	.name = "create",
187f634b4c1SWarner Losh 	.fn = nscreate,
1883b3dd3f7SAlexander Motin 	.descr = "Create a namespace",
189f634b4c1SWarner Losh 	.ctx_size = sizeof(create_opt),
190f634b4c1SWarner Losh 	.opts = create_opts,
191f634b4c1SWarner Losh 	.args = create_args,
192f634b4c1SWarner Losh };
193f634b4c1SWarner Losh 
194f634b4c1SWarner Losh CMD_SUBCOMMAND(ns_cmd, create_cmd);
195f634b4c1SWarner Losh 
196f634b4c1SWarner Losh static struct delete_options {
197f634b4c1SWarner Losh 	uint32_t	nsid;
198f634b4c1SWarner Losh 	const char	*dev;
199f634b4c1SWarner Losh } delete_opt = {
200f634b4c1SWarner Losh 	.nsid = NONE,
201f634b4c1SWarner Losh 	.dev = NULL,
202f634b4c1SWarner Losh };
203f634b4c1SWarner Losh 
204f634b4c1SWarner Losh static const struct opts delete_opts[] = {
205f634b4c1SWarner Losh 	OPT("namespace-id", 'n', arg_uint32, delete_opt, nsid,
206f634b4c1SWarner Losh 	    "The namespace ID to delete"),
207f634b4c1SWarner Losh 	OPT_END
208f634b4c1SWarner Losh };
209f634b4c1SWarner Losh 
210f634b4c1SWarner Losh static const struct args delete_args[] = {
211f634b4c1SWarner Losh 	{ arg_string, &delete_opt.dev, "controller-id" },
212f634b4c1SWarner Losh 	{ arg_none, NULL, NULL },
213f634b4c1SWarner Losh };
214f634b4c1SWarner Losh 
215f634b4c1SWarner Losh static struct cmd delete_cmd = {
216f634b4c1SWarner Losh 	.name = "delete",
217f634b4c1SWarner Losh 	.fn = nsdelete,
2183b3dd3f7SAlexander Motin 	.descr = "Delete a namespace",
219f634b4c1SWarner Losh 	.ctx_size = sizeof(delete_opt),
220f634b4c1SWarner Losh 	.opts = delete_opts,
221f634b4c1SWarner Losh 	.args = delete_args,
222f634b4c1SWarner Losh };
223f634b4c1SWarner Losh 
224f634b4c1SWarner Losh CMD_SUBCOMMAND(ns_cmd, delete_cmd);
225f634b4c1SWarner Losh 
226f634b4c1SWarner Losh static struct attach_options {
227f634b4c1SWarner Losh 	uint32_t	nsid;
228f634b4c1SWarner Losh 	uint32_t	ctrlrid;
229f634b4c1SWarner Losh 	const char	*dev;
230f634b4c1SWarner Losh } attach_opt = {
231f634b4c1SWarner Losh 	.nsid = NONE,
232f634b4c1SWarner Losh 	.ctrlrid = NONE - 1,
233f634b4c1SWarner Losh 	.dev = NULL,
234f634b4c1SWarner Losh };
235f634b4c1SWarner Losh 
236f634b4c1SWarner Losh static const struct opts attach_opts[] = {
237f634b4c1SWarner Losh 	OPT("namespace-id", 'n', arg_uint32, attach_opt, nsid,
238f634b4c1SWarner Losh 	    "The namespace ID to attach"),
2393b3dd3f7SAlexander Motin 	OPT("controller", 'c', arg_uint32, attach_opt, ctrlrid,
240f634b4c1SWarner Losh 	    "The controller ID to attach"),
241f634b4c1SWarner Losh 	OPT_END
242f634b4c1SWarner Losh };
243f634b4c1SWarner Losh 
244f634b4c1SWarner Losh static const struct args attach_args[] = {
245f634b4c1SWarner Losh 	{ arg_string, &attach_opt.dev, "controller-id" },
246f634b4c1SWarner Losh 	{ arg_none, NULL, NULL },
247f634b4c1SWarner Losh };
248f634b4c1SWarner Losh 
249f634b4c1SWarner Losh static struct cmd attach_cmd = {
250f634b4c1SWarner Losh 	.name = "attach",
251f634b4c1SWarner Losh 	.fn = nsattach,
2523b3dd3f7SAlexander Motin 	.descr = "Attach a controller to a namespace",
253f634b4c1SWarner Losh 	.ctx_size = sizeof(attach_opt),
254f634b4c1SWarner Losh 	.opts = attach_opts,
255f634b4c1SWarner Losh 	.args = attach_args,
256f634b4c1SWarner Losh };
257f634b4c1SWarner Losh 
258f634b4c1SWarner Losh CMD_SUBCOMMAND(ns_cmd, attach_cmd);
259f634b4c1SWarner Losh 
2603b3dd3f7SAlexander Motin static struct attached_options {
2613b3dd3f7SAlexander Motin 	uint32_t	nsid;
2623b3dd3f7SAlexander Motin 	const char	*dev;
2633b3dd3f7SAlexander Motin } attached_opt = {
2643b3dd3f7SAlexander Motin 	.nsid = NONE,
2653b3dd3f7SAlexander Motin 	.dev = NULL,
2663b3dd3f7SAlexander Motin };
2673b3dd3f7SAlexander Motin 
2683b3dd3f7SAlexander Motin static const struct opts attached_opts[] = {
2693b3dd3f7SAlexander Motin 	OPT("namespace-id", 'n', arg_uint32, attached_opt, nsid,
2703b3dd3f7SAlexander Motin 	    "The namespace ID to request attached controllers"),
2713b3dd3f7SAlexander Motin 	OPT_END
2723b3dd3f7SAlexander Motin };
2733b3dd3f7SAlexander Motin 
2743b3dd3f7SAlexander Motin static const struct args attached_args[] = {
2753b3dd3f7SAlexander Motin 	{ arg_string, &attached_opt.dev, "controller-id" },
2763b3dd3f7SAlexander Motin 	{ arg_none, NULL, NULL },
2773b3dd3f7SAlexander Motin };
2783b3dd3f7SAlexander Motin 
2793b3dd3f7SAlexander Motin static struct cmd attached_cmd = {
2803b3dd3f7SAlexander Motin 	.name = "attached",
2813b3dd3f7SAlexander Motin 	.fn = nsattached,
2823b3dd3f7SAlexander Motin 	.descr = "List controllers attached to a namespace",
2833b3dd3f7SAlexander Motin 	.ctx_size = sizeof(attached_opt),
2843b3dd3f7SAlexander Motin 	.opts = attached_opts,
2853b3dd3f7SAlexander Motin 	.args = attached_args,
2863b3dd3f7SAlexander Motin };
2873b3dd3f7SAlexander Motin 
2883b3dd3f7SAlexander Motin CMD_SUBCOMMAND(ns_cmd, attached_cmd);
2893b3dd3f7SAlexander Motin 
290f634b4c1SWarner Losh static struct detach_options {
291f634b4c1SWarner Losh 	uint32_t	nsid;
292f634b4c1SWarner Losh 	uint32_t	ctrlrid;
293f634b4c1SWarner Losh 	const char	*dev;
294f634b4c1SWarner Losh } detach_opt = {
295f634b4c1SWarner Losh 	.nsid = NONE,
296f634b4c1SWarner Losh 	.ctrlrid = NONE - 1,
297f634b4c1SWarner Losh 	.dev = NULL,
298f634b4c1SWarner Losh };
299f634b4c1SWarner Losh 
300f634b4c1SWarner Losh static const struct opts detach_opts[] = {
301f634b4c1SWarner Losh 	OPT("namespace-id", 'n', arg_uint32, detach_opt, nsid,
302f634b4c1SWarner Losh 	    "The namespace ID to detach"),
3033b3dd3f7SAlexander Motin 	OPT("controller", 'c', arg_uint32, detach_opt, ctrlrid,
304f634b4c1SWarner Losh 	    "The controller ID to detach"),
305f634b4c1SWarner Losh 	OPT_END
306f634b4c1SWarner Losh };
307f634b4c1SWarner Losh 
308f634b4c1SWarner Losh static const struct args detach_args[] = {
309f634b4c1SWarner Losh 	{ arg_string, &detach_opt.dev, "controller-id" },
310f634b4c1SWarner Losh 	{ arg_none, NULL, NULL },
311f634b4c1SWarner Losh };
312f634b4c1SWarner Losh 
313f634b4c1SWarner Losh static struct cmd detach_cmd = {
314f634b4c1SWarner Losh 	.name = "detach",
315f634b4c1SWarner Losh 	.fn = nsdetach,
3163b3dd3f7SAlexander Motin 	.descr = "Detach a controller from a namespace",
317f634b4c1SWarner Losh 	.ctx_size = sizeof(detach_opt),
318f634b4c1SWarner Losh 	.opts = detach_opts,
319f634b4c1SWarner Losh 	.args = detach_args,
320f634b4c1SWarner Losh };
321f634b4c1SWarner Losh 
322f634b4c1SWarner Losh CMD_SUBCOMMAND(ns_cmd, detach_cmd);
323a13a291aSWarner Losh 
3243b3dd3f7SAlexander Motin static struct identify_options {
3253b3dd3f7SAlexander Motin 	bool		hex;
3263b3dd3f7SAlexander Motin 	bool		verbose;
3273b3dd3f7SAlexander Motin 	const char	*dev;
3283b3dd3f7SAlexander Motin 	uint32_t	nsid;
3293b3dd3f7SAlexander Motin } identify_opt = {
3303b3dd3f7SAlexander Motin 	.hex = false,
3313b3dd3f7SAlexander Motin 	.verbose = false,
3323b3dd3f7SAlexander Motin 	.dev = NULL,
3333b3dd3f7SAlexander Motin 	.nsid = NONE,
3343b3dd3f7SAlexander Motin };
3353b3dd3f7SAlexander Motin 
3363b3dd3f7SAlexander Motin static const struct opts identify_opts[] = {
3373b3dd3f7SAlexander Motin 	OPT("hex", 'x', arg_none, identify_opt, hex,
3383b3dd3f7SAlexander Motin 	    "Print identiy information in hex"),
3393b3dd3f7SAlexander Motin 	OPT("verbose", 'v', arg_none, identify_opt, verbose,
3403b3dd3f7SAlexander Motin 	    "More verbosity: print entire identify table"),
3413b3dd3f7SAlexander Motin 	OPT("nsid", 'n', arg_uint32, identify_opt, nsid,
3423b3dd3f7SAlexander Motin 	    "The namespace ID to print IDENTIFY for"),
3433b3dd3f7SAlexander Motin 	{ NULL, 0, arg_none, NULL, NULL }
3443b3dd3f7SAlexander Motin };
3453b3dd3f7SAlexander Motin 
3463b3dd3f7SAlexander Motin static const struct args identify_args[] = {
3473b3dd3f7SAlexander Motin 	{ arg_string, &identify_opt.dev, "controller-id" },
3483b3dd3f7SAlexander Motin 	{ arg_none, NULL, NULL },
3493b3dd3f7SAlexander Motin };
3503b3dd3f7SAlexander Motin 
3513b3dd3f7SAlexander Motin static struct cmd identify_cmd = {
3523b3dd3f7SAlexander Motin 	.name = "identify",
3533b3dd3f7SAlexander Motin 	.fn = nsidentify,
3543b3dd3f7SAlexander Motin 	.descr = "Print IDENTIFY for allocated namespace",
3553b3dd3f7SAlexander Motin 	.ctx_size = sizeof(identify_opt),
3563b3dd3f7SAlexander Motin 	.opts = identify_opts,
3573b3dd3f7SAlexander Motin 	.args = identify_args,
3583b3dd3f7SAlexander Motin };
3593b3dd3f7SAlexander Motin 
3603b3dd3f7SAlexander Motin CMD_SUBCOMMAND(ns_cmd, identify_cmd);
361a13a291aSWarner Losh 
362ba405bc8SAlexander Motin /* handles NVME_OPC_NAMESPACE_MANAGEMENT and ATTACHMENT admin cmds */
363ba405bc8SAlexander Motin 
364ba405bc8SAlexander Motin struct ns_result_str {
365ba405bc8SAlexander Motin 	uint16_t res;
366ba405bc8SAlexander Motin 	const char * str;
367ba405bc8SAlexander Motin };
368ba405bc8SAlexander Motin 
369ba405bc8SAlexander Motin static struct ns_result_str ns_result[] = {
370ba405bc8SAlexander Motin 	{ 0x2,  "Invalid Field"},
371ba405bc8SAlexander Motin 	{ 0xa,  "Invalid Format"},
372ba405bc8SAlexander Motin 	{ 0xb,  "Invalid Namespace or format"},
373ba405bc8SAlexander Motin 	{ 0x15, "Namespace insufficent capacity"},
374ba405bc8SAlexander Motin 	{ 0x16, "Namespace ID unavaliable"},
375ba405bc8SAlexander Motin 	{ 0x18, "Namespace already attached"},
376ba405bc8SAlexander Motin 	{ 0x19, "Namespace is private"},
377ba405bc8SAlexander Motin 	{ 0x1a, "Namespace is not attached"},
378ba405bc8SAlexander Motin 	{ 0x1b, "Thin provisioning not supported"},
379ba405bc8SAlexander Motin 	{ 0x1c, "Controller list invalid"},
3803b3dd3f7SAlexander Motin 	{ 0x24, "ANA Group Identifier Invalid"},
3813b3dd3f7SAlexander Motin 	{ 0x25, "ANA Attach Failed"},
382ba405bc8SAlexander Motin 	{ 0xFFFF, "Unknown"}
383ba405bc8SAlexander Motin };
384ba405bc8SAlexander Motin 
385ba405bc8SAlexander Motin static const char *
386ba405bc8SAlexander Motin get_res_str(uint16_t res)
387ba405bc8SAlexander Motin {
388ba405bc8SAlexander Motin 	struct ns_result_str *t = ns_result;
389ba405bc8SAlexander Motin 
390ba405bc8SAlexander Motin 	while (t->res != 0xFFFF) {
391ba405bc8SAlexander Motin 		if (t->res == res)
392ba405bc8SAlexander Motin 			return (t->str);
393ba405bc8SAlexander Motin 		t++;
394ba405bc8SAlexander Motin 	}
395ba405bc8SAlexander Motin 	return t->str;
396ba405bc8SAlexander Motin }
397ba405bc8SAlexander Motin 
3983b3dd3f7SAlexander Motin static void
3993b3dd3f7SAlexander Motin nsactive(const struct cmd *f, int argc, char *argv[])
4003b3dd3f7SAlexander Motin {
4013b3dd3f7SAlexander Motin 	struct nvme_pt_command	pt;
4023b3dd3f7SAlexander Motin 	int	fd, i;
4033b3dd3f7SAlexander Motin 	uint32_t list[1024];
4043b3dd3f7SAlexander Motin 
4053b3dd3f7SAlexander Motin 	if (arg_parse(argc, argv, f))
4063b3dd3f7SAlexander Motin 		return;
4073b3dd3f7SAlexander Motin 	open_dev(active_opt.dev, &fd, 1, 1);
4083b3dd3f7SAlexander Motin 
4093b3dd3f7SAlexander Motin 	memset(&pt, 0, sizeof(pt));
4103b3dd3f7SAlexander Motin 	pt.cmd.opc = NVME_OPC_IDENTIFY;
4113b3dd3f7SAlexander Motin 	pt.cmd.nsid = htole32(0);
4123b3dd3f7SAlexander Motin 	pt.cmd.cdw10 = htole32(0x02);
4133b3dd3f7SAlexander Motin 	pt.buf = list;
4143b3dd3f7SAlexander Motin 	pt.len = sizeof(list);
4153b3dd3f7SAlexander Motin 	pt.is_read = 1;
4163b3dd3f7SAlexander Motin 	if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
4173b3dd3f7SAlexander Motin 		err(1, "identify request failed");
4183b3dd3f7SAlexander Motin 	if (nvme_completion_is_error(&pt.cpl))
4193b3dd3f7SAlexander Motin 		errx(1, "identify request returned error");
4203b3dd3f7SAlexander Motin 
4213b3dd3f7SAlexander Motin 	printf("Active namespaces:\n");
4223b3dd3f7SAlexander Motin 	for (i = 0; list[i] != 0; i++)
4233b3dd3f7SAlexander Motin 		printf("%10d\n", le32toh(list[i]));
4243b3dd3f7SAlexander Motin 
4253b3dd3f7SAlexander Motin 	exit(0);
4263b3dd3f7SAlexander Motin }
4273b3dd3f7SAlexander Motin 
4283b3dd3f7SAlexander Motin static void
4293b3dd3f7SAlexander Motin nsallocated(const struct cmd *f, int argc, char *argv[])
4303b3dd3f7SAlexander Motin {
4313b3dd3f7SAlexander Motin 	struct nvme_pt_command	pt;
4323b3dd3f7SAlexander Motin 	struct nvme_controller_data cd;
4333b3dd3f7SAlexander Motin 	int	fd, i;
4343b3dd3f7SAlexander Motin 	uint32_t list[1024];
4353b3dd3f7SAlexander Motin 
4363b3dd3f7SAlexander Motin 	if (arg_parse(argc, argv, f))
4373b3dd3f7SAlexander Motin 		return;
4383b3dd3f7SAlexander Motin 	open_dev(active_opt.dev, &fd, 1, 1);
4393b3dd3f7SAlexander Motin 	read_controller_data(fd, &cd);
4403b3dd3f7SAlexander Motin 
4413b3dd3f7SAlexander Motin 	/* Check that controller can execute this command. */
4423b3dd3f7SAlexander Motin 	if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
4433b3dd3f7SAlexander Motin 	    NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
4443b3dd3f7SAlexander Motin 		errx(1, "controller does not support namespace management");
4453b3dd3f7SAlexander Motin 
4463b3dd3f7SAlexander Motin 	memset(&pt, 0, sizeof(pt));
4473b3dd3f7SAlexander Motin 	pt.cmd.opc = NVME_OPC_IDENTIFY;
4483b3dd3f7SAlexander Motin 	pt.cmd.nsid = htole32(0);
4493b3dd3f7SAlexander Motin 	pt.cmd.cdw10 = htole32(0x10);
4503b3dd3f7SAlexander Motin 	pt.buf = list;
4513b3dd3f7SAlexander Motin 	pt.len = sizeof(list);
4523b3dd3f7SAlexander Motin 	pt.is_read = 1;
4533b3dd3f7SAlexander Motin 	if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
4543b3dd3f7SAlexander Motin 		err(1, "identify request failed");
4553b3dd3f7SAlexander Motin 	if (nvme_completion_is_error(&pt.cpl))
4563b3dd3f7SAlexander Motin 		errx(1, "identify request returned error");
4573b3dd3f7SAlexander Motin 
4583b3dd3f7SAlexander Motin 	printf("Allocated namespaces:\n");
4593b3dd3f7SAlexander Motin 	for (i = 0; list[i] != 0; i++)
4603b3dd3f7SAlexander Motin 		printf("%10d\n", le32toh(list[i]));
4613b3dd3f7SAlexander Motin 
4623b3dd3f7SAlexander Motin 	exit(0);
4633b3dd3f7SAlexander Motin }
4643b3dd3f7SAlexander Motin 
4653b3dd3f7SAlexander Motin static void
4663b3dd3f7SAlexander Motin nscontrollers(const struct cmd *f, int argc, char *argv[])
4673b3dd3f7SAlexander Motin {
4683b3dd3f7SAlexander Motin 	struct nvme_pt_command	pt;
4693b3dd3f7SAlexander Motin 	struct nvme_controller_data cd;
4703b3dd3f7SAlexander Motin 	int	fd, i, n;
4713b3dd3f7SAlexander Motin 	uint16_t clist[2048];
4723b3dd3f7SAlexander Motin 
4733b3dd3f7SAlexander Motin 	if (arg_parse(argc, argv, f))
4743b3dd3f7SAlexander Motin 		return;
4753b3dd3f7SAlexander Motin 	open_dev(controllers_opt.dev, &fd, 1, 1);
4763b3dd3f7SAlexander Motin 	read_controller_data(fd, &cd);
4773b3dd3f7SAlexander Motin 
4783b3dd3f7SAlexander Motin 	/* Check that controller can execute this command. */
4793b3dd3f7SAlexander Motin 	if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
4803b3dd3f7SAlexander Motin 	    NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
4813b3dd3f7SAlexander Motin 		errx(1, "controller does not support namespace management");
4823b3dd3f7SAlexander Motin 
4833b3dd3f7SAlexander Motin 	memset(&pt, 0, sizeof(pt));
4843b3dd3f7SAlexander Motin 	pt.cmd.opc = NVME_OPC_IDENTIFY;
4853b3dd3f7SAlexander Motin 	pt.cmd.cdw10 = htole32(0x13);
4863b3dd3f7SAlexander Motin 	pt.buf = clist;
4873b3dd3f7SAlexander Motin 	pt.len = sizeof(clist);
4883b3dd3f7SAlexander Motin 	pt.is_read = 1;
4893b3dd3f7SAlexander Motin 	if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
4903b3dd3f7SAlexander Motin 		err(1, "identify request failed");
4913b3dd3f7SAlexander Motin 	if (nvme_completion_is_error(&pt.cpl))
4923b3dd3f7SAlexander Motin 		errx(1, "identify request returned error");
4933b3dd3f7SAlexander Motin 
4943b3dd3f7SAlexander Motin 	n = le16toh(clist[0]);
4953b3dd3f7SAlexander Motin 	printf("NVM subsystem includes %d controller(s):\n", n);
4963b3dd3f7SAlexander Motin 	for (i = 0; i < n; i++)
4973b3dd3f7SAlexander Motin 		printf("  0x%04x\n", le16toh(clist[i + 1]));
4983b3dd3f7SAlexander Motin 
4993b3dd3f7SAlexander Motin 	exit(0);
5003b3dd3f7SAlexander Motin }
5013b3dd3f7SAlexander Motin 
502ba405bc8SAlexander Motin /*
503ba405bc8SAlexander Motin  * NS MGMT Command specific status values:
504ba405bc8SAlexander Motin  * 0xa = Invalid Format
505ba405bc8SAlexander Motin  * 0x15 = Namespace Insuffience capacity
506ba405bc8SAlexander Motin  * 0x16 = Namespace ID  unavailable (number namespaces exceeded)
507ba405bc8SAlexander Motin  * 0xb = Thin Provisioning Not supported
508ba405bc8SAlexander Motin  */
5090d095c23SWarner Losh static void
510f634b4c1SWarner Losh nscreate(const struct cmd *f, int argc, char *argv[])
511ba405bc8SAlexander Motin {
512ba405bc8SAlexander Motin 	struct nvme_pt_command	pt;
513ba405bc8SAlexander Motin 	struct nvme_controller_data cd;
514ba405bc8SAlexander Motin 	struct nvme_namespace_data nsdata;
515f634b4c1SWarner Losh 	int	fd, result;
516ba405bc8SAlexander Motin 
517f634b4c1SWarner Losh 	if (arg_parse(argc, argv, f))
518f634b4c1SWarner Losh 		return;
519ba405bc8SAlexander Motin 
520f634b4c1SWarner Losh 	if (create_opt.cap == NONE64)
521f634b4c1SWarner Losh 		create_opt.cap = create_opt.nsze;
522f634b4c1SWarner Losh 	if (create_opt.nsze == NONE64) {
523f634b4c1SWarner Losh 		fprintf(stderr,
524f634b4c1SWarner Losh 		    "Size not specified\n");
525f634b4c1SWarner Losh 		arg_help(argc, argv, f);
526ba405bc8SAlexander Motin 	}
527ba405bc8SAlexander Motin 
528f634b4c1SWarner Losh 	open_dev(create_opt.dev, &fd, 1, 1);
529ba405bc8SAlexander Motin 	read_controller_data(fd, &cd);
530ba405bc8SAlexander Motin 
531ba405bc8SAlexander Motin 	/* Check that controller can execute this command. */
532ba405bc8SAlexander Motin 	if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
533ba405bc8SAlexander Motin 	    NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
534ba405bc8SAlexander Motin 		errx(1, "controller does not support namespace management");
535ba405bc8SAlexander Motin 
536ba405bc8SAlexander Motin 	/* Allow namespaces sharing if Multi-Path I/O is supported. */
537f634b4c1SWarner Losh 	if (create_opt.nmic == NONE) {
538f634b4c1SWarner Losh 		create_opt.nmic = cd.mic ? (NVME_NS_DATA_NMIC_MAY_BE_SHARED_MASK <<
539ba405bc8SAlexander Motin 		     NVME_NS_DATA_NMIC_MAY_BE_SHARED_SHIFT) : 0;
540ba405bc8SAlexander Motin 	}
541ba405bc8SAlexander Motin 
542ba405bc8SAlexander Motin 	memset(&nsdata, 0, sizeof(nsdata));
543f634b4c1SWarner Losh 	nsdata.nsze = create_opt.nsze;
544f634b4c1SWarner Losh 	nsdata.ncap = create_opt.cap;
545f634b4c1SWarner Losh 	if (create_opt.flbas == NONE)
546f634b4c1SWarner Losh 		nsdata.flbas = ((create_opt.lbaf & NVME_NS_DATA_FLBAS_FORMAT_MASK)
547ba405bc8SAlexander Motin 		    << NVME_NS_DATA_FLBAS_FORMAT_SHIFT) |
548f634b4c1SWarner Losh 		    ((create_opt.mset & NVME_NS_DATA_FLBAS_EXTENDED_MASK)
549ba405bc8SAlexander Motin 			<< NVME_NS_DATA_FLBAS_EXTENDED_SHIFT);
550f634b4c1SWarner Losh 	else
551f634b4c1SWarner Losh 		nsdata.flbas = create_opt.flbas;
552f634b4c1SWarner Losh 	if (create_opt.dps == NONE)
553f634b4c1SWarner Losh 		nsdata.dps = ((create_opt.pi & NVME_NS_DATA_DPS_MD_START_MASK)
554ba405bc8SAlexander Motin 		    << NVME_NS_DATA_DPS_MD_START_SHIFT) |
555f634b4c1SWarner Losh 		    ((create_opt.pil & NVME_NS_DATA_DPS_PIT_MASK)
556ba405bc8SAlexander Motin 			<< NVME_NS_DATA_DPS_PIT_SHIFT);
557f634b4c1SWarner Losh 	else
558f634b4c1SWarner Losh 		nsdata.dps = create_opt.dps;
559f634b4c1SWarner Losh 	nsdata.nmic = create_opt.nmic;
560ba405bc8SAlexander Motin 	nvme_namespace_data_swapbytes(&nsdata);
561ba405bc8SAlexander Motin 
562ba405bc8SAlexander Motin 	memset(&pt, 0, sizeof(pt));
5639544e6dcSChuck Tuffli 	pt.cmd.opc = NVME_OPC_NAMESPACE_MANAGEMENT;
5643b3dd3f7SAlexander Motin 	pt.cmd.cdw10 = htole32(0); /* create */
565ba405bc8SAlexander Motin 	pt.buf = &nsdata;
566ba405bc8SAlexander Motin 	pt.len = sizeof(struct nvme_namespace_data);
567ba405bc8SAlexander Motin 	pt.is_read = 0; /* passthrough writes data to ctrlr */
568ba405bc8SAlexander Motin 	if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0)
569ba405bc8SAlexander Motin 		errx(1, "ioctl request to %s failed: %d", argv[optind], result);
570ba405bc8SAlexander Motin 
571ba405bc8SAlexander Motin 	if (nvme_completion_is_error(&pt.cpl)) {
572ba405bc8SAlexander Motin 		errx(1, "namespace creation failed: %s",
573ba405bc8SAlexander Motin 		    get_res_str((pt.cpl.status >> NVME_STATUS_SC_SHIFT) &
574ba405bc8SAlexander Motin 		    NVME_STATUS_SC_MASK));
575ba405bc8SAlexander Motin 	}
576ba405bc8SAlexander Motin 	printf("namespace %d created\n", pt.cpl.cdw0);
577ba405bc8SAlexander Motin 	exit(0);
578ba405bc8SAlexander Motin }
579ba405bc8SAlexander Motin 
5800d095c23SWarner Losh static void
581f634b4c1SWarner Losh nsdelete(const struct cmd *f, int argc, char *argv[])
582ba405bc8SAlexander Motin {
583ba405bc8SAlexander Motin 	struct nvme_pt_command	pt;
584ba405bc8SAlexander Motin 	struct nvme_controller_data cd;
585f634b4c1SWarner Losh 	int	fd, result;
586ba405bc8SAlexander Motin 	char buf[2];
587ba405bc8SAlexander Motin 
588f634b4c1SWarner Losh 	if (arg_parse(argc, argv, f))
589f634b4c1SWarner Losh 		return;
590f634b4c1SWarner Losh 	if (delete_opt.nsid == NONE) {
591f634b4c1SWarner Losh 		fprintf(stderr,
592f634b4c1SWarner Losh 		    "No NSID specified");
593f634b4c1SWarner Losh 		arg_help(argc, argv, f);
594ba405bc8SAlexander Motin 	}
595ba405bc8SAlexander Motin 
596f634b4c1SWarner Losh 	open_dev(delete_opt.dev, &fd, 1, 1);
597ba405bc8SAlexander Motin 	read_controller_data(fd, &cd);
598ba405bc8SAlexander Motin 
599ba405bc8SAlexander Motin 	/* Check that controller can execute this command. */
600ba405bc8SAlexander Motin 	if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
601ba405bc8SAlexander Motin 	    NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
602ba405bc8SAlexander Motin 		errx(1, "controller does not support namespace management");
603ba405bc8SAlexander Motin 
604ba405bc8SAlexander Motin 	memset(&pt, 0, sizeof(pt));
6059544e6dcSChuck Tuffli 	pt.cmd.opc = NVME_OPC_NAMESPACE_MANAGEMENT;
6063b3dd3f7SAlexander Motin 	pt.cmd.cdw10 = htole32(1); /* delete */
607ba405bc8SAlexander Motin 	pt.buf = buf;
608ba405bc8SAlexander Motin 	pt.len = sizeof(buf);
609ba405bc8SAlexander Motin 	pt.is_read = 1;
610f634b4c1SWarner Losh 	pt.cmd.nsid = delete_opt.nsid;
611ba405bc8SAlexander Motin 
612ba405bc8SAlexander Motin 	if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0)
613f634b4c1SWarner Losh 		errx(1, "ioctl request to %s failed: %d", delete_opt.dev, result);
614ba405bc8SAlexander Motin 
615ba405bc8SAlexander Motin 	if (nvme_completion_is_error(&pt.cpl)) {
616ba405bc8SAlexander Motin 		errx(1, "namespace deletion failed: %s",
617ba405bc8SAlexander Motin 		    get_res_str((pt.cpl.status >> NVME_STATUS_SC_SHIFT) &
618ba405bc8SAlexander Motin 		    NVME_STATUS_SC_MASK));
619ba405bc8SAlexander Motin 	}
620f634b4c1SWarner Losh 	printf("namespace %d deleted\n", delete_opt.nsid);
621ba405bc8SAlexander Motin 	exit(0);
622ba405bc8SAlexander Motin }
623ba405bc8SAlexander Motin 
624ba405bc8SAlexander Motin /*
625ba405bc8SAlexander Motin  * Attach and Detach use Dword 10, and a controller list (section 4.9)
626ba405bc8SAlexander Motin  * This struct is 4096 bytes in size.
627ba405bc8SAlexander Motin  * 0h = attach
628ba405bc8SAlexander Motin  * 1h = detach
629ba405bc8SAlexander Motin  *
630ba405bc8SAlexander Motin  * Result values for both attach/detach:
631ba405bc8SAlexander Motin  *
632ba405bc8SAlexander Motin  * Completion 18h = Already attached
633ba405bc8SAlexander Motin  *            19h = NS is private and already attached to a controller
634ba405bc8SAlexander Motin  *            1Ah = Not attached, request could not be completed
635ba405bc8SAlexander Motin  *            1Ch = Controller list invalid.
636ba405bc8SAlexander Motin  *
637ba405bc8SAlexander Motin  * 0x2 Invalid Field can occur if ctrlrid d.n.e in system.
638ba405bc8SAlexander Motin  */
6390d095c23SWarner Losh static void
640f634b4c1SWarner Losh nsattach(const struct cmd *f, int argc, char *argv[])
641ba405bc8SAlexander Motin {
642ba405bc8SAlexander Motin 	struct nvme_pt_command	pt;
643ba405bc8SAlexander Motin 	struct nvme_controller_data cd;
644f634b4c1SWarner Losh 	int	fd, result;
645ba405bc8SAlexander Motin 	uint16_t clist[2048];
646ba405bc8SAlexander Motin 
647f634b4c1SWarner Losh 	if (arg_parse(argc, argv, f))
648f634b4c1SWarner Losh 		return;
649f634b4c1SWarner Losh 	if (attach_opt.nsid == NONE) {
650f634b4c1SWarner Losh 		fprintf(stderr, "No valid NSID specified\n");
651f634b4c1SWarner Losh 		arg_help(argc, argv, f);
652ba405bc8SAlexander Motin 	}
653f634b4c1SWarner Losh 	open_dev(attach_opt.dev, &fd, 1, 1);
654ba405bc8SAlexander Motin 	read_controller_data(fd, &cd);
655ba405bc8SAlexander Motin 
656ba405bc8SAlexander Motin 	/* Check that controller can execute this command. */
657ba405bc8SAlexander Motin 	if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
658ba405bc8SAlexander Motin 	    NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
659ba405bc8SAlexander Motin 		errx(1, "controller does not support namespace management");
660ba405bc8SAlexander Motin 
661f634b4c1SWarner Losh 	if (attach_opt.ctrlrid == NONE) {
662ba405bc8SAlexander Motin 		/* Get full list of controllers to attach to. */
663ba405bc8SAlexander Motin 		memset(&pt, 0, sizeof(pt));
6649544e6dcSChuck Tuffli 		pt.cmd.opc = NVME_OPC_IDENTIFY;
665ba405bc8SAlexander Motin 		pt.cmd.cdw10 = htole32(0x13);
666ba405bc8SAlexander Motin 		pt.buf = clist;
667ba405bc8SAlexander Motin 		pt.len = sizeof(clist);
668ba405bc8SAlexander Motin 		pt.is_read = 1;
669ba405bc8SAlexander Motin 		if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
670ba405bc8SAlexander Motin 			err(1, "identify request failed");
671ba405bc8SAlexander Motin 		if (nvme_completion_is_error(&pt.cpl))
672ba405bc8SAlexander Motin 			errx(1, "identify request returned error");
673ba405bc8SAlexander Motin 	} else {
674ba405bc8SAlexander Motin 		/* By default attach to this controller. */
675f634b4c1SWarner Losh 		if (attach_opt.ctrlrid == NONE - 1)
676f634b4c1SWarner Losh 			attach_opt.ctrlrid = cd.ctrlr_id;
677ba405bc8SAlexander Motin 		memset(&clist, 0, sizeof(clist));
678ba405bc8SAlexander Motin 		clist[0] = htole16(1);
679f634b4c1SWarner Losh 		clist[1] = htole16(attach_opt.ctrlrid);
680ba405bc8SAlexander Motin 	}
681ba405bc8SAlexander Motin 
682ba405bc8SAlexander Motin 	memset(&pt, 0, sizeof(pt));
6839544e6dcSChuck Tuffli 	pt.cmd.opc = NVME_OPC_NAMESPACE_ATTACHMENT;
6843b3dd3f7SAlexander Motin 	pt.cmd.cdw10 = htole32(0); /* attach */
685f634b4c1SWarner Losh 	pt.cmd.nsid = attach_opt.nsid;
686ba405bc8SAlexander Motin 	pt.buf = &clist;
687ba405bc8SAlexander Motin 	pt.len = sizeof(clist);
688ba405bc8SAlexander Motin 
689ba405bc8SAlexander Motin 	if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0)
690f634b4c1SWarner Losh 		errx(1, "ioctl request to %s failed: %d", attach_opt.dev, result);
691ba405bc8SAlexander Motin 
692ba405bc8SAlexander Motin 	if (nvme_completion_is_error(&pt.cpl)) {
693ba405bc8SAlexander Motin 		errx(1, "namespace attach failed: %s",
694ba405bc8SAlexander Motin 		    get_res_str((pt.cpl.status >> NVME_STATUS_SC_SHIFT) &
695ba405bc8SAlexander Motin 		    NVME_STATUS_SC_MASK));
696ba405bc8SAlexander Motin 	}
697f634b4c1SWarner Losh 	printf("namespace %d attached\n", attach_opt.nsid);
698ba405bc8SAlexander Motin 	exit(0);
699ba405bc8SAlexander Motin }
700ba405bc8SAlexander Motin 
7010d095c23SWarner Losh static void
702f634b4c1SWarner Losh nsdetach(const struct cmd *f, int argc, char *argv[])
703ba405bc8SAlexander Motin {
704ba405bc8SAlexander Motin 	struct nvme_pt_command	pt;
705ba405bc8SAlexander Motin 	struct nvme_controller_data cd;
706f634b4c1SWarner Losh 	int	fd, result;
707ba405bc8SAlexander Motin 	uint16_t clist[2048];
708ba405bc8SAlexander Motin 
709f634b4c1SWarner Losh 	if (arg_parse(argc, argv, f))
710f634b4c1SWarner Losh 		return;
7113b3dd3f7SAlexander Motin 	if (detach_opt.nsid == NONE) {
712f634b4c1SWarner Losh 		fprintf(stderr, "No valid NSID specified\n");
713f634b4c1SWarner Losh 		arg_help(argc, argv, f);
714ba405bc8SAlexander Motin 	}
7153b3dd3f7SAlexander Motin 	open_dev(detach_opt.dev, &fd, 1, 1);
716ba405bc8SAlexander Motin 	read_controller_data(fd, &cd);
717ba405bc8SAlexander Motin 
718ba405bc8SAlexander Motin 	/* Check that controller can execute this command. */
719ba405bc8SAlexander Motin 	if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
720ba405bc8SAlexander Motin 	    NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
721ba405bc8SAlexander Motin 		errx(1, "controller does not support namespace management");
722ba405bc8SAlexander Motin 
723f634b4c1SWarner Losh 	if (detach_opt.ctrlrid == NONE) {
724ba405bc8SAlexander Motin 		/* Get list of controllers this namespace attached to. */
725ba405bc8SAlexander Motin 		memset(&pt, 0, sizeof(pt));
7269544e6dcSChuck Tuffli 		pt.cmd.opc = NVME_OPC_IDENTIFY;
727f634b4c1SWarner Losh 		pt.cmd.nsid = htole32(detach_opt.nsid);
728ba405bc8SAlexander Motin 		pt.cmd.cdw10 = htole32(0x12);
729ba405bc8SAlexander Motin 		pt.buf = clist;
730ba405bc8SAlexander Motin 		pt.len = sizeof(clist);
731ba405bc8SAlexander Motin 		pt.is_read = 1;
732ba405bc8SAlexander Motin 		if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
733ba405bc8SAlexander Motin 			err(1, "identify request failed");
734ba405bc8SAlexander Motin 		if (nvme_completion_is_error(&pt.cpl))
735ba405bc8SAlexander Motin 			errx(1, "identify request returned error");
736ba405bc8SAlexander Motin 		if (clist[0] == 0) {
737f634b4c1SWarner Losh 			detach_opt.ctrlrid = cd.ctrlr_id;
738ba405bc8SAlexander Motin 			memset(&clist, 0, sizeof(clist));
739ba405bc8SAlexander Motin 			clist[0] = htole16(1);
740f634b4c1SWarner Losh 			clist[1] = htole16(detach_opt.ctrlrid);
741ba405bc8SAlexander Motin 		}
742ba405bc8SAlexander Motin 	} else {
743ba405bc8SAlexander Motin 		/* By default detach from this controller. */
744f634b4c1SWarner Losh 		if (detach_opt.ctrlrid == NONE - 1)
745f634b4c1SWarner Losh 			detach_opt.ctrlrid = cd.ctrlr_id;
746ba405bc8SAlexander Motin 		memset(&clist, 0, sizeof(clist));
747ba405bc8SAlexander Motin 		clist[0] = htole16(1);
748f634b4c1SWarner Losh 		clist[1] = htole16(detach_opt.ctrlrid);
749ba405bc8SAlexander Motin 	}
750ba405bc8SAlexander Motin 
751ba405bc8SAlexander Motin 	memset(&pt, 0, sizeof(pt));
7529544e6dcSChuck Tuffli 	pt.cmd.opc = NVME_OPC_NAMESPACE_ATTACHMENT;
7533b3dd3f7SAlexander Motin 	pt.cmd.cdw10 = htole32(1); /* detach */
754f634b4c1SWarner Losh 	pt.cmd.nsid = detach_opt.nsid;
755ba405bc8SAlexander Motin 	pt.buf = &clist;
756ba405bc8SAlexander Motin 	pt.len = sizeof(clist);
757ba405bc8SAlexander Motin 
758ba405bc8SAlexander Motin 	if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0)
759ba405bc8SAlexander Motin 		errx(1, "ioctl request to %s failed: %d", argv[optind], result);
760ba405bc8SAlexander Motin 
761ba405bc8SAlexander Motin 	if (nvme_completion_is_error(&pt.cpl)) {
762ba405bc8SAlexander Motin 		errx(1, "namespace detach failed: %s",
763ba405bc8SAlexander Motin 		    get_res_str((pt.cpl.status >> NVME_STATUS_SC_SHIFT) &
764ba405bc8SAlexander Motin 		    NVME_STATUS_SC_MASK));
765ba405bc8SAlexander Motin 	}
766f634b4c1SWarner Losh 	printf("namespace %d detached\n", detach_opt.nsid);
767ba405bc8SAlexander Motin 	exit(0);
768ba405bc8SAlexander Motin }
769ba405bc8SAlexander Motin 
770a13a291aSWarner Losh static void
7713b3dd3f7SAlexander Motin nsattached(const struct cmd *f, int argc, char *argv[])
7723b3dd3f7SAlexander Motin {
7733b3dd3f7SAlexander Motin 	struct nvme_pt_command	pt;
7743b3dd3f7SAlexander Motin 	struct nvme_controller_data cd;
7753b3dd3f7SAlexander Motin 	int	fd, i, n;
7763b3dd3f7SAlexander Motin 	uint16_t clist[2048];
7773b3dd3f7SAlexander Motin 
7783b3dd3f7SAlexander Motin 	if (arg_parse(argc, argv, f))
7793b3dd3f7SAlexander Motin 		return;
7803b3dd3f7SAlexander Motin 	if (attached_opt.nsid == NONE) {
7813b3dd3f7SAlexander Motin 		fprintf(stderr, "No valid NSID specified\n");
7823b3dd3f7SAlexander Motin 		arg_help(argc, argv, f);
7833b3dd3f7SAlexander Motin 	}
7843b3dd3f7SAlexander Motin 	open_dev(attached_opt.dev, &fd, 1, 1);
7853b3dd3f7SAlexander Motin 	read_controller_data(fd, &cd);
7863b3dd3f7SAlexander Motin 
7873b3dd3f7SAlexander Motin 	/* Check that controller can execute this command. */
7883b3dd3f7SAlexander Motin 	if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
7893b3dd3f7SAlexander Motin 	    NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
7903b3dd3f7SAlexander Motin 		errx(1, "controller does not support namespace management");
7913b3dd3f7SAlexander Motin 
7923b3dd3f7SAlexander Motin 	memset(&pt, 0, sizeof(pt));
7933b3dd3f7SAlexander Motin 	pt.cmd.opc = NVME_OPC_IDENTIFY;
7943b3dd3f7SAlexander Motin 	pt.cmd.nsid = htole32(attached_opt.nsid);
7953b3dd3f7SAlexander Motin 	pt.cmd.cdw10 = htole32(0x12);
7963b3dd3f7SAlexander Motin 	pt.buf = clist;
7973b3dd3f7SAlexander Motin 	pt.len = sizeof(clist);
7983b3dd3f7SAlexander Motin 	pt.is_read = 1;
7993b3dd3f7SAlexander Motin 	if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
8003b3dd3f7SAlexander Motin 		err(1, "identify request failed");
8013b3dd3f7SAlexander Motin 	if (nvme_completion_is_error(&pt.cpl))
8023b3dd3f7SAlexander Motin 		errx(1, "identify request returned error");
8033b3dd3f7SAlexander Motin 
8043b3dd3f7SAlexander Motin 	n = le16toh(clist[0]);
8053b3dd3f7SAlexander Motin 	printf("Attached %d controller(s):\n", n);
8063b3dd3f7SAlexander Motin 	for (i = 0; i < n; i++)
8073b3dd3f7SAlexander Motin 		printf("  0x%04x\n", le16toh(clist[i + 1]));
8083b3dd3f7SAlexander Motin 
8093b3dd3f7SAlexander Motin 	exit(0);
8103b3dd3f7SAlexander Motin }
8113b3dd3f7SAlexander Motin 
8123b3dd3f7SAlexander Motin static void
8133b3dd3f7SAlexander Motin nsidentify(const struct cmd *f, int argc, char *argv[])
8143b3dd3f7SAlexander Motin {
8153b3dd3f7SAlexander Motin 	struct nvme_pt_command	pt;
8163b3dd3f7SAlexander Motin 	struct nvme_controller_data cd;
8173b3dd3f7SAlexander Motin 	struct nvme_namespace_data nsdata;
8183b3dd3f7SAlexander Motin 	uint8_t	*data;
8193b3dd3f7SAlexander Motin 	int	fd;
8203b3dd3f7SAlexander Motin 	u_int	i;
8213b3dd3f7SAlexander Motin 
8223b3dd3f7SAlexander Motin 	if (arg_parse(argc, argv, f))
8233b3dd3f7SAlexander Motin 		return;
8243b3dd3f7SAlexander Motin 	if (identify_opt.nsid == NONE) {
8253b3dd3f7SAlexander Motin 		fprintf(stderr, "No valid NSID specified\n");
8263b3dd3f7SAlexander Motin 		arg_help(argc, argv, f);
8273b3dd3f7SAlexander Motin 	}
8283b3dd3f7SAlexander Motin 	open_dev(identify_opt.dev, &fd, 1, 1);
8293b3dd3f7SAlexander Motin 	read_controller_data(fd, &cd);
8303b3dd3f7SAlexander Motin 
8313b3dd3f7SAlexander Motin 	/* Check that controller can execute this command. */
8323b3dd3f7SAlexander Motin 	if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
8333b3dd3f7SAlexander Motin 	    NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
8343b3dd3f7SAlexander Motin 		errx(1, "controller does not support namespace management");
8353b3dd3f7SAlexander Motin 
8363b3dd3f7SAlexander Motin 	memset(&pt, 0, sizeof(pt));
8373b3dd3f7SAlexander Motin 	pt.cmd.opc = NVME_OPC_IDENTIFY;
8383b3dd3f7SAlexander Motin 	pt.cmd.nsid = htole32(identify_opt.nsid);
8393b3dd3f7SAlexander Motin 	pt.cmd.cdw10 = htole32(0x11);
8403b3dd3f7SAlexander Motin 	pt.buf = &nsdata;
8413b3dd3f7SAlexander Motin 	pt.len = sizeof(nsdata);
8423b3dd3f7SAlexander Motin 	pt.is_read = 1;
8433b3dd3f7SAlexander Motin 
8443b3dd3f7SAlexander Motin 	if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
8453b3dd3f7SAlexander Motin 		err(1, "identify request failed");
8463b3dd3f7SAlexander Motin 
8473b3dd3f7SAlexander Motin 	if (nvme_completion_is_error(&pt.cpl))
8483b3dd3f7SAlexander Motin 		errx(1, "identify request returned error");
8493b3dd3f7SAlexander Motin 
8503b3dd3f7SAlexander Motin 	close(fd);
8513b3dd3f7SAlexander Motin 
8523b3dd3f7SAlexander Motin 	data = (uint8_t *)&nsdata;
8533b3dd3f7SAlexander Motin 	for (i = 0; i < sizeof(nsdata); i++) {
8543b3dd3f7SAlexander Motin 		if (data[i] != 0)
8553b3dd3f7SAlexander Motin 			break;
8563b3dd3f7SAlexander Motin 	}
8573b3dd3f7SAlexander Motin 	if (i == sizeof(nsdata))
8583b3dd3f7SAlexander Motin 		errx(1, "namespace %d is not allocated", identify_opt.nsid);
8593b3dd3f7SAlexander Motin 
8603b3dd3f7SAlexander Motin 	/* Convert data to host endian */
8613b3dd3f7SAlexander Motin 	nvme_namespace_data_swapbytes(&nsdata);
8623b3dd3f7SAlexander Motin 
8633b3dd3f7SAlexander Motin 	if (identify_opt.hex) {
8643b3dd3f7SAlexander Motin 		i = sizeof(struct nvme_namespace_data);
8653b3dd3f7SAlexander Motin 		if (!identify_opt.verbose) {
8663b3dd3f7SAlexander Motin 			for (; i > 384; i--) {
8673b3dd3f7SAlexander Motin 				if (data[i - 1] != 0)
8683b3dd3f7SAlexander Motin 					break;
8693b3dd3f7SAlexander Motin 			}
8703b3dd3f7SAlexander Motin 		}
8713b3dd3f7SAlexander Motin 		print_hex(&nsdata, i);
8723b3dd3f7SAlexander Motin 		exit(0);
8733b3dd3f7SAlexander Motin 	}
8743b3dd3f7SAlexander Motin 
8753b3dd3f7SAlexander Motin 	print_namespace(&nsdata);
8763b3dd3f7SAlexander Motin 	exit(0);
8773b3dd3f7SAlexander Motin }
8783b3dd3f7SAlexander Motin 
8793b3dd3f7SAlexander Motin static void
880f634b4c1SWarner Losh ns(const struct cmd *nf __unused, int argc, char *argv[])
881ba405bc8SAlexander Motin {
882ba405bc8SAlexander Motin 
883f634b4c1SWarner Losh 	cmd_dispatch(argc, argv, &ns_cmd);
884ba405bc8SAlexander Motin }
885