xref: /freebsd/sbin/nvmecontrol/ns.c (revision ba405bc811e86e7bad91b1195771c1138dfdecbd)
1*ba405bc8SAlexander Motin /*-
2*ba405bc8SAlexander Motin  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*ba405bc8SAlexander Motin  *
4*ba405bc8SAlexander Motin  * Copyright (c) 2017 Netflix, Inc
5*ba405bc8SAlexander Motin  * Copyright (C) 2018 Alexander Motin <mav@FreeBSD.org>
6*ba405bc8SAlexander Motin  *
7*ba405bc8SAlexander Motin  * Redistribution and use in source and binary forms, with or without
8*ba405bc8SAlexander Motin  * modification, are permitted provided that the following conditions
9*ba405bc8SAlexander Motin  * are met:
10*ba405bc8SAlexander Motin  * 1. Redistributions of source code must retain the above copyright
11*ba405bc8SAlexander Motin  *    notice, this list of conditions and the following disclaimer,
12*ba405bc8SAlexander Motin  *    without modification, immediately at the beginning of the file.
13*ba405bc8SAlexander Motin  * 2. Redistributions in binary form must reproduce the above copyright
14*ba405bc8SAlexander Motin  *    notice, this list of conditions and the following disclaimer in the
15*ba405bc8SAlexander Motin  *    documentation and/or other materials provided with the distribution.
16*ba405bc8SAlexander Motin  *
17*ba405bc8SAlexander Motin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18*ba405bc8SAlexander Motin  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19*ba405bc8SAlexander Motin  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20*ba405bc8SAlexander Motin  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21*ba405bc8SAlexander Motin  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22*ba405bc8SAlexander Motin  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23*ba405bc8SAlexander Motin  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24*ba405bc8SAlexander Motin  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25*ba405bc8SAlexander Motin  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26*ba405bc8SAlexander Motin  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27*ba405bc8SAlexander Motin  */
28*ba405bc8SAlexander Motin 
29*ba405bc8SAlexander Motin #include <sys/cdefs.h>
30*ba405bc8SAlexander Motin __FBSDID("$FreeBSD$");
31*ba405bc8SAlexander Motin 
32*ba405bc8SAlexander Motin #include <sys/param.h>
33*ba405bc8SAlexander Motin #include <sys/ioccom.h>
34*ba405bc8SAlexander Motin 
35*ba405bc8SAlexander Motin #include <err.h>
36*ba405bc8SAlexander Motin #include <fcntl.h>
37*ba405bc8SAlexander Motin #include <stdio.h>
38*ba405bc8SAlexander Motin #include <stdlib.h>
39*ba405bc8SAlexander Motin #include <string.h>
40*ba405bc8SAlexander Motin #include <unistd.h>
41*ba405bc8SAlexander Motin 
42*ba405bc8SAlexander Motin #include "nvmecontrol.h"
43*ba405bc8SAlexander Motin 
44*ba405bc8SAlexander Motin /* handles NVME_OPC_NAMESPACE_MANAGEMENT and ATTACHMENT admin cmds */
45*ba405bc8SAlexander Motin 
46*ba405bc8SAlexander Motin #define NSCREATE_USAGE							\
47*ba405bc8SAlexander Motin "       nvmecontrol ns create -s size [-c cap] [-f fmt] [-m mset] [-n nmic] [-p pi] [-l pil] nvmeN\n"
48*ba405bc8SAlexander Motin 
49*ba405bc8SAlexander Motin #define NSDELETE_USAGE							\
50*ba405bc8SAlexander Motin "       nvmecontrol ns delete -n nsid nvmeN\n"
51*ba405bc8SAlexander Motin 
52*ba405bc8SAlexander Motin #define NSATTACH_USAGE							\
53*ba405bc8SAlexander Motin "       nvmecontrol ns attach -n nsid [-c ctrlrid] nvmeN \n"
54*ba405bc8SAlexander Motin 
55*ba405bc8SAlexander Motin #define NSDETACH_USAGE							\
56*ba405bc8SAlexander Motin "       nvmecontrol ns detach -n nsid [-c ctrlrid] nvmeN\n"
57*ba405bc8SAlexander Motin 
58*ba405bc8SAlexander Motin void nscreate(int argc, char *argv[]);
59*ba405bc8SAlexander Motin void nsdelete(int argc, char *argv[]);
60*ba405bc8SAlexander Motin void nsattach(int argc, char *argv[]);
61*ba405bc8SAlexander Motin void nsdetach(int argc, char *argv[]);
62*ba405bc8SAlexander Motin 
63*ba405bc8SAlexander Motin static struct nvme_function ns_funcs[] = {
64*ba405bc8SAlexander Motin 	{"create",	nscreate, NSCREATE_USAGE},
65*ba405bc8SAlexander Motin 	{"delete",	nsdelete, NSDELETE_USAGE},
66*ba405bc8SAlexander Motin 	{"attach",	nsattach, NSATTACH_USAGE},
67*ba405bc8SAlexander Motin 	{"detach",	nsdetach, NSDETACH_USAGE},
68*ba405bc8SAlexander Motin 	{NULL,		NULL,		NULL},
69*ba405bc8SAlexander Motin };
70*ba405bc8SAlexander Motin 
71*ba405bc8SAlexander Motin static void
72*ba405bc8SAlexander Motin nscreate_usage(void)
73*ba405bc8SAlexander Motin {
74*ba405bc8SAlexander Motin 	fprintf(stderr, "usage:\n");
75*ba405bc8SAlexander Motin 	fprintf(stderr, NSCREATE_USAGE);
76*ba405bc8SAlexander Motin 	exit(1);
77*ba405bc8SAlexander Motin }
78*ba405bc8SAlexander Motin 
79*ba405bc8SAlexander Motin static void
80*ba405bc8SAlexander Motin nsdelete_usage(void)
81*ba405bc8SAlexander Motin {
82*ba405bc8SAlexander Motin 	fprintf(stderr, "usage:\n");
83*ba405bc8SAlexander Motin 	fprintf(stderr, NSDELETE_USAGE);
84*ba405bc8SAlexander Motin 	exit(1);
85*ba405bc8SAlexander Motin }
86*ba405bc8SAlexander Motin 
87*ba405bc8SAlexander Motin static void
88*ba405bc8SAlexander Motin nsattach_usage(void)
89*ba405bc8SAlexander Motin {
90*ba405bc8SAlexander Motin 	fprintf(stderr, "usage:\n");
91*ba405bc8SAlexander Motin 	fprintf(stderr, NSATTACH_USAGE);
92*ba405bc8SAlexander Motin 	exit(1);
93*ba405bc8SAlexander Motin }
94*ba405bc8SAlexander Motin 
95*ba405bc8SAlexander Motin static void
96*ba405bc8SAlexander Motin nsdetach_usage(void)
97*ba405bc8SAlexander Motin {
98*ba405bc8SAlexander Motin 	fprintf(stderr, "usage:\n");
99*ba405bc8SAlexander Motin 	fprintf(stderr, NSDETACH_USAGE);
100*ba405bc8SAlexander Motin 	exit(1);
101*ba405bc8SAlexander Motin }
102*ba405bc8SAlexander Motin 
103*ba405bc8SAlexander Motin struct ns_result_str {
104*ba405bc8SAlexander Motin 	uint16_t res;
105*ba405bc8SAlexander Motin 	const char * str;
106*ba405bc8SAlexander Motin };
107*ba405bc8SAlexander Motin 
108*ba405bc8SAlexander Motin static struct ns_result_str ns_result[] = {
109*ba405bc8SAlexander Motin 	{ 0x2,  "Invalid Field"},
110*ba405bc8SAlexander Motin 	{ 0xa,  "Invalid Format"},
111*ba405bc8SAlexander Motin 	{ 0xb,  "Invalid Namespace or format"},
112*ba405bc8SAlexander Motin 	{ 0x15, "Namespace insufficent capacity"},
113*ba405bc8SAlexander Motin 	{ 0x16, "Namespace ID unavaliable"},
114*ba405bc8SAlexander Motin 	{ 0x18, "Namespace already attached"},
115*ba405bc8SAlexander Motin 	{ 0x19, "Namespace is private"},
116*ba405bc8SAlexander Motin 	{ 0x1a, "Namespace is not attached"},
117*ba405bc8SAlexander Motin 	{ 0x1b, "Thin provisioning not supported"},
118*ba405bc8SAlexander Motin 	{ 0x1c, "Controller list invalid"},
119*ba405bc8SAlexander Motin 	{ 0xFFFF, "Unknown"}
120*ba405bc8SAlexander Motin };
121*ba405bc8SAlexander Motin 
122*ba405bc8SAlexander Motin static const char *
123*ba405bc8SAlexander Motin get_res_str(uint16_t res)
124*ba405bc8SAlexander Motin {
125*ba405bc8SAlexander Motin 	struct ns_result_str *t = ns_result;
126*ba405bc8SAlexander Motin 
127*ba405bc8SAlexander Motin 	while (t->res != 0xFFFF) {
128*ba405bc8SAlexander Motin 		if (t->res == res)
129*ba405bc8SAlexander Motin 			return (t->str);
130*ba405bc8SAlexander Motin 		t++;
131*ba405bc8SAlexander Motin 	}
132*ba405bc8SAlexander Motin 	return t->str;
133*ba405bc8SAlexander Motin }
134*ba405bc8SAlexander Motin 
135*ba405bc8SAlexander Motin /*
136*ba405bc8SAlexander Motin  * NS MGMT Command specific status values:
137*ba405bc8SAlexander Motin  * 0xa = Invalid Format
138*ba405bc8SAlexander Motin  * 0x15 = Namespace Insuffience capacity
139*ba405bc8SAlexander Motin  * 0x16 = Namespace ID  unavailable (number namespaces exceeded)
140*ba405bc8SAlexander Motin  * 0xb = Thin Provisioning Not supported
141*ba405bc8SAlexander Motin  */
142*ba405bc8SAlexander Motin void
143*ba405bc8SAlexander Motin nscreate(int argc, char *argv[])
144*ba405bc8SAlexander Motin {
145*ba405bc8SAlexander Motin 	struct nvme_pt_command	pt;
146*ba405bc8SAlexander Motin 	struct nvme_controller_data cd;
147*ba405bc8SAlexander Motin 	struct nvme_namespace_data nsdata;
148*ba405bc8SAlexander Motin 	int64_t	nsze = -1, cap = -1;
149*ba405bc8SAlexander Motin 	int	ch, fd, result, lbaf = 0, mset = 0, nmic = -1, pi = 0, pil = 0;
150*ba405bc8SAlexander Motin 
151*ba405bc8SAlexander Motin 	if (optind >= argc)
152*ba405bc8SAlexander Motin 		nscreate_usage();
153*ba405bc8SAlexander Motin 
154*ba405bc8SAlexander Motin 	while ((ch = getopt(argc, argv, "s:c:f:m:n:p:l:")) != -1) {
155*ba405bc8SAlexander Motin 		switch (ch) {
156*ba405bc8SAlexander Motin 		case 's':
157*ba405bc8SAlexander Motin 			nsze = strtol(optarg, (char **)NULL, 0);
158*ba405bc8SAlexander Motin 			break;
159*ba405bc8SAlexander Motin 		case 'c':
160*ba405bc8SAlexander Motin 			cap = strtol(optarg, (char **)NULL, 0);
161*ba405bc8SAlexander Motin 			break;
162*ba405bc8SAlexander Motin 		case 'f':
163*ba405bc8SAlexander Motin 			lbaf = strtol(optarg, (char **)NULL, 0);
164*ba405bc8SAlexander Motin 			break;
165*ba405bc8SAlexander Motin 		case 'm':
166*ba405bc8SAlexander Motin 			mset = strtol(optarg, NULL, 0);
167*ba405bc8SAlexander Motin 			break;
168*ba405bc8SAlexander Motin 		case 'n':
169*ba405bc8SAlexander Motin 			nmic = strtol(optarg, NULL, 0);
170*ba405bc8SAlexander Motin 			break;
171*ba405bc8SAlexander Motin 		case 'p':
172*ba405bc8SAlexander Motin 			pi = strtol(optarg, NULL, 0);
173*ba405bc8SAlexander Motin 			break;
174*ba405bc8SAlexander Motin 		case 'l':
175*ba405bc8SAlexander Motin 			pil = strtol(optarg, NULL, 0);
176*ba405bc8SAlexander Motin 			break;
177*ba405bc8SAlexander Motin 		default:
178*ba405bc8SAlexander Motin 			nscreate_usage();
179*ba405bc8SAlexander Motin 		}
180*ba405bc8SAlexander Motin 	}
181*ba405bc8SAlexander Motin 
182*ba405bc8SAlexander Motin 	if (optind >= argc)
183*ba405bc8SAlexander Motin 		nscreate_usage();
184*ba405bc8SAlexander Motin 
185*ba405bc8SAlexander Motin 	if (cap == -1)
186*ba405bc8SAlexander Motin 		cap = nsze;
187*ba405bc8SAlexander Motin 	if (nsze == -1 || cap == -1)
188*ba405bc8SAlexander Motin 		nscreate_usage();
189*ba405bc8SAlexander Motin 
190*ba405bc8SAlexander Motin 	open_dev(argv[optind], &fd, 1, 1);
191*ba405bc8SAlexander Motin 	read_controller_data(fd, &cd);
192*ba405bc8SAlexander Motin 
193*ba405bc8SAlexander Motin 	/* Check that controller can execute this command. */
194*ba405bc8SAlexander Motin 	if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
195*ba405bc8SAlexander Motin 	    NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
196*ba405bc8SAlexander Motin 		errx(1, "controller does not support namespace management");
197*ba405bc8SAlexander Motin 
198*ba405bc8SAlexander Motin 	/* Allow namespaces sharing if Multi-Path I/O is supported. */
199*ba405bc8SAlexander Motin 	if (nmic == -1) {
200*ba405bc8SAlexander Motin 		nmic = cd.mic ? (NVME_NS_DATA_NMIC_MAY_BE_SHARED_MASK <<
201*ba405bc8SAlexander Motin 		     NVME_NS_DATA_NMIC_MAY_BE_SHARED_SHIFT) : 0;
202*ba405bc8SAlexander Motin 	}
203*ba405bc8SAlexander Motin 
204*ba405bc8SAlexander Motin 	memset(&nsdata, 0, sizeof(nsdata));
205*ba405bc8SAlexander Motin 	nsdata.nsze = (uint64_t)nsze;
206*ba405bc8SAlexander Motin 	nsdata.ncap = (uint64_t)cap;
207*ba405bc8SAlexander Motin 	nsdata.flbas = ((lbaf & NVME_NS_DATA_FLBAS_FORMAT_MASK)
208*ba405bc8SAlexander Motin 	     << NVME_NS_DATA_FLBAS_FORMAT_SHIFT) |
209*ba405bc8SAlexander Motin 	    ((mset & NVME_NS_DATA_FLBAS_EXTENDED_MASK)
210*ba405bc8SAlexander Motin 	     << NVME_NS_DATA_FLBAS_EXTENDED_SHIFT);
211*ba405bc8SAlexander Motin 	nsdata.dps = ((pi & NVME_NS_DATA_DPS_MD_START_MASK)
212*ba405bc8SAlexander Motin 	     << NVME_NS_DATA_DPS_MD_START_SHIFT) |
213*ba405bc8SAlexander Motin 	    ((pil & NVME_NS_DATA_DPS_PIT_MASK)
214*ba405bc8SAlexander Motin 	     << NVME_NS_DATA_DPS_PIT_SHIFT);
215*ba405bc8SAlexander Motin 	nsdata.nmic = nmic;
216*ba405bc8SAlexander Motin 	nvme_namespace_data_swapbytes(&nsdata);
217*ba405bc8SAlexander Motin 
218*ba405bc8SAlexander Motin 	memset(&pt, 0, sizeof(pt));
219*ba405bc8SAlexander Motin 	pt.cmd.opc_fuse = NVME_CMD_SET_OPC(NVME_OPC_NAMESPACE_MANAGEMENT);
220*ba405bc8SAlexander Motin 
221*ba405bc8SAlexander Motin 	pt.cmd.cdw10 = 0; /* create */
222*ba405bc8SAlexander Motin 	pt.buf = &nsdata;
223*ba405bc8SAlexander Motin 	pt.len = sizeof(struct nvme_namespace_data);
224*ba405bc8SAlexander Motin 	pt.is_read = 0; /* passthrough writes data to ctrlr */
225*ba405bc8SAlexander Motin 	if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0)
226*ba405bc8SAlexander Motin 		errx(1, "ioctl request to %s failed: %d", argv[optind], result);
227*ba405bc8SAlexander Motin 
228*ba405bc8SAlexander Motin 	if (nvme_completion_is_error(&pt.cpl)) {
229*ba405bc8SAlexander Motin 		errx(1, "namespace creation failed: %s",
230*ba405bc8SAlexander Motin 		    get_res_str((pt.cpl.status >> NVME_STATUS_SC_SHIFT) &
231*ba405bc8SAlexander Motin 		    NVME_STATUS_SC_MASK));
232*ba405bc8SAlexander Motin 	}
233*ba405bc8SAlexander Motin 	printf("namespace %d created\n", pt.cpl.cdw0);
234*ba405bc8SAlexander Motin 	exit(0);
235*ba405bc8SAlexander Motin }
236*ba405bc8SAlexander Motin 
237*ba405bc8SAlexander Motin void
238*ba405bc8SAlexander Motin nsdelete(int argc, char *argv[])
239*ba405bc8SAlexander Motin {
240*ba405bc8SAlexander Motin 	struct nvme_pt_command	pt;
241*ba405bc8SAlexander Motin 	struct nvme_controller_data cd;
242*ba405bc8SAlexander Motin 	int	ch, fd, result, nsid = -2;
243*ba405bc8SAlexander Motin 	char buf[2];
244*ba405bc8SAlexander Motin 
245*ba405bc8SAlexander Motin 	if (optind >= argc)
246*ba405bc8SAlexander Motin 		nsdelete_usage();
247*ba405bc8SAlexander Motin 
248*ba405bc8SAlexander Motin 	while ((ch = getopt(argc, argv, "n:")) != -1) {
249*ba405bc8SAlexander Motin 		switch ((char)ch) {
250*ba405bc8SAlexander Motin 		case  'n':
251*ba405bc8SAlexander Motin 			nsid = strtol(optarg, (char **)NULL, 0);
252*ba405bc8SAlexander Motin 			break;
253*ba405bc8SAlexander Motin 		default:
254*ba405bc8SAlexander Motin 			nsdelete_usage();
255*ba405bc8SAlexander Motin 		}
256*ba405bc8SAlexander Motin 	}
257*ba405bc8SAlexander Motin 
258*ba405bc8SAlexander Motin 	if (optind >= argc || nsid == -2)
259*ba405bc8SAlexander Motin 		nsdelete_usage();
260*ba405bc8SAlexander Motin 
261*ba405bc8SAlexander Motin 	open_dev(argv[optind], &fd, 1, 1);
262*ba405bc8SAlexander Motin 	read_controller_data(fd, &cd);
263*ba405bc8SAlexander Motin 
264*ba405bc8SAlexander Motin 	/* Check that controller can execute this command. */
265*ba405bc8SAlexander Motin 	if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
266*ba405bc8SAlexander Motin 	    NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
267*ba405bc8SAlexander Motin 		errx(1, "controller does not support namespace management");
268*ba405bc8SAlexander Motin 
269*ba405bc8SAlexander Motin 	memset(&pt, 0, sizeof(pt));
270*ba405bc8SAlexander Motin 	pt.cmd.opc_fuse = NVME_CMD_SET_OPC(NVME_OPC_NAMESPACE_MANAGEMENT);
271*ba405bc8SAlexander Motin 	pt.cmd.cdw10 = 1; /* delete */
272*ba405bc8SAlexander Motin 	pt.buf = buf;
273*ba405bc8SAlexander Motin 	pt.len = sizeof(buf);
274*ba405bc8SAlexander Motin 	pt.is_read = 1;
275*ba405bc8SAlexander Motin 	pt.cmd.nsid = (uint32_t)nsid;
276*ba405bc8SAlexander Motin 
277*ba405bc8SAlexander Motin 	if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0)
278*ba405bc8SAlexander Motin 		errx(1, "ioctl request to %s failed: %d", argv[optind], result);
279*ba405bc8SAlexander Motin 
280*ba405bc8SAlexander Motin 	if (nvme_completion_is_error(&pt.cpl)) {
281*ba405bc8SAlexander Motin 		errx(1, "namespace deletion failed: %s",
282*ba405bc8SAlexander Motin 		    get_res_str((pt.cpl.status >> NVME_STATUS_SC_SHIFT) &
283*ba405bc8SAlexander Motin 		    NVME_STATUS_SC_MASK));
284*ba405bc8SAlexander Motin 	}
285*ba405bc8SAlexander Motin 	printf("namespace %d deleted\n", nsid);
286*ba405bc8SAlexander Motin 	exit(0);
287*ba405bc8SAlexander Motin }
288*ba405bc8SAlexander Motin 
289*ba405bc8SAlexander Motin /*
290*ba405bc8SAlexander Motin  * Attach and Detach use Dword 10, and a controller list (section 4.9)
291*ba405bc8SAlexander Motin  * This struct is 4096 bytes in size.
292*ba405bc8SAlexander Motin  * 0h = attach
293*ba405bc8SAlexander Motin  * 1h = detach
294*ba405bc8SAlexander Motin  *
295*ba405bc8SAlexander Motin  * Result values for both attach/detach:
296*ba405bc8SAlexander Motin  *
297*ba405bc8SAlexander Motin  * Completion 18h = Already attached
298*ba405bc8SAlexander Motin  *            19h = NS is private and already attached to a controller
299*ba405bc8SAlexander Motin  *            1Ah = Not attached, request could not be completed
300*ba405bc8SAlexander Motin  *            1Ch = Controller list invalid.
301*ba405bc8SAlexander Motin  *
302*ba405bc8SAlexander Motin  * 0x2 Invalid Field can occur if ctrlrid d.n.e in system.
303*ba405bc8SAlexander Motin  */
304*ba405bc8SAlexander Motin void
305*ba405bc8SAlexander Motin nsattach(int argc, char *argv[])
306*ba405bc8SAlexander Motin {
307*ba405bc8SAlexander Motin 	struct nvme_pt_command	pt;
308*ba405bc8SAlexander Motin 	struct nvme_controller_data cd;
309*ba405bc8SAlexander Motin 	int	ctrlrid = -2;
310*ba405bc8SAlexander Motin 	int	fd, ch, result, nsid = -1;
311*ba405bc8SAlexander Motin 	uint16_t clist[2048];
312*ba405bc8SAlexander Motin 
313*ba405bc8SAlexander Motin 	if (optind >= argc)
314*ba405bc8SAlexander Motin 		nsattach_usage();
315*ba405bc8SAlexander Motin 
316*ba405bc8SAlexander Motin 	while ((ch = getopt(argc, argv, "n:c:")) != -1) {
317*ba405bc8SAlexander Motin 		switch (ch) {
318*ba405bc8SAlexander Motin 		case 'n':
319*ba405bc8SAlexander Motin 			nsid = strtol(optarg, (char **)NULL, 0);
320*ba405bc8SAlexander Motin 			break;
321*ba405bc8SAlexander Motin 		case 'c':
322*ba405bc8SAlexander Motin 			ctrlrid = strtol(optarg, (char **)NULL, 0);
323*ba405bc8SAlexander Motin 			break;
324*ba405bc8SAlexander Motin 		default:
325*ba405bc8SAlexander Motin 			nsattach_usage();
326*ba405bc8SAlexander Motin 		}
327*ba405bc8SAlexander Motin 	}
328*ba405bc8SAlexander Motin 
329*ba405bc8SAlexander Motin 	if (optind >= argc)
330*ba405bc8SAlexander Motin 		nsattach_usage();
331*ba405bc8SAlexander Motin 
332*ba405bc8SAlexander Motin 	if (nsid == -1 )
333*ba405bc8SAlexander Motin 		nsattach_usage();
334*ba405bc8SAlexander Motin 
335*ba405bc8SAlexander Motin 	open_dev(argv[optind], &fd, 1, 1);
336*ba405bc8SAlexander Motin 	read_controller_data(fd, &cd);
337*ba405bc8SAlexander Motin 
338*ba405bc8SAlexander Motin 	/* Check that controller can execute this command. */
339*ba405bc8SAlexander Motin 	if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
340*ba405bc8SAlexander Motin 	    NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
341*ba405bc8SAlexander Motin 		errx(1, "controller does not support namespace management");
342*ba405bc8SAlexander Motin 
343*ba405bc8SAlexander Motin 	if (ctrlrid == -1) {
344*ba405bc8SAlexander Motin 		/* Get full list of controllers to attach to. */
345*ba405bc8SAlexander Motin 		memset(&pt, 0, sizeof(pt));
346*ba405bc8SAlexander Motin 		pt.cmd.opc_fuse = NVME_CMD_SET_OPC(NVME_OPC_IDENTIFY);
347*ba405bc8SAlexander Motin 		pt.cmd.cdw10 = htole32(0x13);
348*ba405bc8SAlexander Motin 		pt.buf = clist;
349*ba405bc8SAlexander Motin 		pt.len = sizeof(clist);
350*ba405bc8SAlexander Motin 		pt.is_read = 1;
351*ba405bc8SAlexander Motin 		if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
352*ba405bc8SAlexander Motin 			err(1, "identify request failed");
353*ba405bc8SAlexander Motin 		if (nvme_completion_is_error(&pt.cpl))
354*ba405bc8SAlexander Motin 			errx(1, "identify request returned error");
355*ba405bc8SAlexander Motin 	} else {
356*ba405bc8SAlexander Motin 		/* By default attach to this controller. */
357*ba405bc8SAlexander Motin 		if (ctrlrid == -2)
358*ba405bc8SAlexander Motin 			ctrlrid = cd.ctrlr_id;
359*ba405bc8SAlexander Motin 		memset(&clist, 0, sizeof(clist));
360*ba405bc8SAlexander Motin 		clist[0] = htole16(1);
361*ba405bc8SAlexander Motin 		clist[1] = htole16(ctrlrid);
362*ba405bc8SAlexander Motin 	}
363*ba405bc8SAlexander Motin 
364*ba405bc8SAlexander Motin 	memset(&pt, 0, sizeof(pt));
365*ba405bc8SAlexander Motin 	pt.cmd.opc_fuse = NVME_CMD_SET_OPC(NVME_OPC_NAMESPACE_ATTACHMENT);
366*ba405bc8SAlexander Motin 	pt.cmd.cdw10 = 0; /* attach */
367*ba405bc8SAlexander Motin 	pt.cmd.nsid = (uint32_t)nsid;
368*ba405bc8SAlexander Motin 	pt.buf = &clist;
369*ba405bc8SAlexander Motin 	pt.len = sizeof(clist);
370*ba405bc8SAlexander Motin 
371*ba405bc8SAlexander Motin 	if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0)
372*ba405bc8SAlexander Motin 		errx(1, "ioctl request to %s failed: %d", argv[optind], result);
373*ba405bc8SAlexander Motin 
374*ba405bc8SAlexander Motin 	if (nvme_completion_is_error(&pt.cpl)) {
375*ba405bc8SAlexander Motin 		errx(1, "namespace attach failed: %s",
376*ba405bc8SAlexander Motin 		    get_res_str((pt.cpl.status >> NVME_STATUS_SC_SHIFT) &
377*ba405bc8SAlexander Motin 		    NVME_STATUS_SC_MASK));
378*ba405bc8SAlexander Motin 	}
379*ba405bc8SAlexander Motin 	printf("namespace %d attached\n", nsid);
380*ba405bc8SAlexander Motin 	exit(0);
381*ba405bc8SAlexander Motin }
382*ba405bc8SAlexander Motin 
383*ba405bc8SAlexander Motin void
384*ba405bc8SAlexander Motin nsdetach(int argc, char *argv[])
385*ba405bc8SAlexander Motin {
386*ba405bc8SAlexander Motin 	struct nvme_pt_command	pt;
387*ba405bc8SAlexander Motin 	struct nvme_controller_data cd;
388*ba405bc8SAlexander Motin 	int	ctrlrid = -2;
389*ba405bc8SAlexander Motin 	int	fd, ch, result, nsid = -1;
390*ba405bc8SAlexander Motin 	uint16_t clist[2048];
391*ba405bc8SAlexander Motin 
392*ba405bc8SAlexander Motin 	if (optind >= argc)
393*ba405bc8SAlexander Motin 		nsdetach_usage();
394*ba405bc8SAlexander Motin 
395*ba405bc8SAlexander Motin 	while ((ch = getopt(argc, argv, "n:c:")) != -1) {
396*ba405bc8SAlexander Motin 		switch (ch) {
397*ba405bc8SAlexander Motin 		case 'n':
398*ba405bc8SAlexander Motin 			nsid = strtol(optarg, (char **)NULL, 0);
399*ba405bc8SAlexander Motin 			break;
400*ba405bc8SAlexander Motin 		case 'c':
401*ba405bc8SAlexander Motin 			ctrlrid = strtol(optarg, (char **)NULL, 0);
402*ba405bc8SAlexander Motin 			break;
403*ba405bc8SAlexander Motin 		default:
404*ba405bc8SAlexander Motin 			nsdetach_usage();
405*ba405bc8SAlexander Motin 		}
406*ba405bc8SAlexander Motin 	}
407*ba405bc8SAlexander Motin 
408*ba405bc8SAlexander Motin 	if (optind >= argc)
409*ba405bc8SAlexander Motin 		nsdetach_usage();
410*ba405bc8SAlexander Motin 
411*ba405bc8SAlexander Motin 	if (nsid == -1)
412*ba405bc8SAlexander Motin 		nsdetach_usage();
413*ba405bc8SAlexander Motin 
414*ba405bc8SAlexander Motin 	open_dev(argv[optind], &fd, 1, 1);
415*ba405bc8SAlexander Motin 	read_controller_data(fd, &cd);
416*ba405bc8SAlexander Motin 
417*ba405bc8SAlexander Motin 	/* Check that controller can execute this command. */
418*ba405bc8SAlexander Motin 	if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
419*ba405bc8SAlexander Motin 	    NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
420*ba405bc8SAlexander Motin 		errx(1, "controller does not support namespace management");
421*ba405bc8SAlexander Motin 
422*ba405bc8SAlexander Motin 	if (ctrlrid == -1) {
423*ba405bc8SAlexander Motin 		/* Get list of controllers this namespace attached to. */
424*ba405bc8SAlexander Motin 		memset(&pt, 0, sizeof(pt));
425*ba405bc8SAlexander Motin 		pt.cmd.opc_fuse = NVME_CMD_SET_OPC(NVME_OPC_IDENTIFY);
426*ba405bc8SAlexander Motin 		pt.cmd.nsid = htole32(nsid);
427*ba405bc8SAlexander Motin 		pt.cmd.cdw10 = htole32(0x12);
428*ba405bc8SAlexander Motin 		pt.buf = clist;
429*ba405bc8SAlexander Motin 		pt.len = sizeof(clist);
430*ba405bc8SAlexander Motin 		pt.is_read = 1;
431*ba405bc8SAlexander Motin 		if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
432*ba405bc8SAlexander Motin 			err(1, "identify request failed");
433*ba405bc8SAlexander Motin 		if (nvme_completion_is_error(&pt.cpl))
434*ba405bc8SAlexander Motin 			errx(1, "identify request returned error");
435*ba405bc8SAlexander Motin 		if (clist[0] == 0) {
436*ba405bc8SAlexander Motin 			ctrlrid = cd.ctrlr_id;
437*ba405bc8SAlexander Motin 			memset(&clist, 0, sizeof(clist));
438*ba405bc8SAlexander Motin 			clist[0] = htole16(1);
439*ba405bc8SAlexander Motin 			clist[1] = htole16(ctrlrid);
440*ba405bc8SAlexander Motin 		}
441*ba405bc8SAlexander Motin 	} else {
442*ba405bc8SAlexander Motin 		/* By default detach from this controller. */
443*ba405bc8SAlexander Motin 		if (ctrlrid == -2)
444*ba405bc8SAlexander Motin 			ctrlrid = cd.ctrlr_id;
445*ba405bc8SAlexander Motin 		memset(&clist, 0, sizeof(clist));
446*ba405bc8SAlexander Motin 		clist[0] = htole16(1);
447*ba405bc8SAlexander Motin 		clist[1] = htole16(ctrlrid);
448*ba405bc8SAlexander Motin 	}
449*ba405bc8SAlexander Motin 
450*ba405bc8SAlexander Motin 	memset(&pt, 0, sizeof(pt));
451*ba405bc8SAlexander Motin 	pt.cmd.opc_fuse = NVME_CMD_SET_OPC(NVME_OPC_NAMESPACE_ATTACHMENT);
452*ba405bc8SAlexander Motin 	pt.cmd.cdw10 = 1; /* detach */
453*ba405bc8SAlexander Motin 	pt.cmd.nsid = (uint32_t)nsid;
454*ba405bc8SAlexander Motin 	pt.buf = &clist;
455*ba405bc8SAlexander Motin 	pt.len = sizeof(clist);
456*ba405bc8SAlexander Motin 
457*ba405bc8SAlexander Motin 	if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0)
458*ba405bc8SAlexander Motin 		errx(1, "ioctl request to %s failed: %d", argv[optind], result);
459*ba405bc8SAlexander Motin 
460*ba405bc8SAlexander Motin 	if (nvme_completion_is_error(&pt.cpl)) {
461*ba405bc8SAlexander Motin 		errx(1, "namespace detach failed: %s",
462*ba405bc8SAlexander Motin 		    get_res_str((pt.cpl.status >> NVME_STATUS_SC_SHIFT) &
463*ba405bc8SAlexander Motin 		    NVME_STATUS_SC_MASK));
464*ba405bc8SAlexander Motin 	}
465*ba405bc8SAlexander Motin 	printf("namespace %d detached\n", nsid);
466*ba405bc8SAlexander Motin 	exit(0);
467*ba405bc8SAlexander Motin }
468*ba405bc8SAlexander Motin 
469*ba405bc8SAlexander Motin void
470*ba405bc8SAlexander Motin ns(int argc, char *argv[])
471*ba405bc8SAlexander Motin {
472*ba405bc8SAlexander Motin 
473*ba405bc8SAlexander Motin 	dispatch(argc, argv, ns_funcs);
474*ba405bc8SAlexander Motin }
475