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