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