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