2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2017 Netflix, Inc
5 * Copyright (C) 2018 Alexander Motin <mav@FreeBSD.org>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer,
12 * without modification, immediately at the beginning of the file.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
32 #include <sys/param.h>
33 #include <sys/ioccom.h>
42 #include "nvmecontrol.h"
44 /* handles NVME_OPC_NAMESPACE_MANAGEMENT and ATTACHMENT admin cmds */
46 #define NSCREATE_USAGE \
47 " nvmecontrol ns create -s size [-c cap] [-f fmt] [-m mset] [-n nmic] [-p pi] [-l pil] nvmeN\n"
49 #define NSDELETE_USAGE \
50 " nvmecontrol ns delete -n nsid nvmeN\n"
52 #define NSATTACH_USAGE \
53 " nvmecontrol ns attach -n nsid [-c ctrlrid] nvmeN \n"
55 #define NSDETACH_USAGE \
56 " nvmecontrol ns detach -n nsid [-c ctrlrid] nvmeN\n"
58 void nscreate(int argc, char *argv[]);
59 void nsdelete(int argc, char *argv[]);
60 void nsattach(int argc, char *argv[]);
61 void nsdetach(int argc, char *argv[]);
63 static struct nvme_function ns_funcs[] = {
64 {"create", nscreate, NSCREATE_USAGE},
65 {"delete", nsdelete, NSDELETE_USAGE},
66 {"attach", nsattach, NSATTACH_USAGE},
67 {"detach", nsdetach, NSDETACH_USAGE},
74 fprintf(stderr, "usage:\n");
75 fprintf(stderr, NSCREATE_USAGE);
82 fprintf(stderr, "usage:\n");
83 fprintf(stderr, NSDELETE_USAGE);
90 fprintf(stderr, "usage:\n");
91 fprintf(stderr, NSATTACH_USAGE);
98 fprintf(stderr, "usage:\n");
99 fprintf(stderr, NSDETACH_USAGE);
103 struct ns_result_str {
108 static struct ns_result_str ns_result[] = {
109 { 0x2, "Invalid Field"},
110 { 0xa, "Invalid Format"},
111 { 0xb, "Invalid Namespace or format"},
112 { 0x15, "Namespace insufficent capacity"},
113 { 0x16, "Namespace ID unavaliable"},
114 { 0x18, "Namespace already attached"},
115 { 0x19, "Namespace is private"},
116 { 0x1a, "Namespace is not attached"},
117 { 0x1b, "Thin provisioning not supported"},
118 { 0x1c, "Controller list invalid"},
123 get_res_str(uint16_t res)
125 struct ns_result_str *t = ns_result;
127 while (t->res != 0xFFFF) {
136 * NS MGMT Command specific status values:
137 * 0xa = Invalid Format
138 * 0x15 = Namespace Insuffience capacity
139 * 0x16 = Namespace ID unavailable (number namespaces exceeded)
140 * 0xb = Thin Provisioning Not supported
143 nscreate(int argc, char *argv[])
145 struct nvme_pt_command pt;
146 struct nvme_controller_data cd;
147 struct nvme_namespace_data nsdata;
148 int64_t nsze = -1, cap = -1;
149 int ch, fd, result, lbaf = 0, mset = 0, nmic = -1, pi = 0, pil = 0;
154 while ((ch = getopt(argc, argv, "s:c:f:m:n:p:l:")) != -1) {
157 nsze = strtol(optarg, (char **)NULL, 0);
160 cap = strtol(optarg, (char **)NULL, 0);
163 lbaf = strtol(optarg, (char **)NULL, 0);
166 mset = strtol(optarg, NULL, 0);
169 nmic = strtol(optarg, NULL, 0);
172 pi = strtol(optarg, NULL, 0);
175 pil = strtol(optarg, NULL, 0);
187 if (nsze == -1 || cap == -1)
190 open_dev(argv[optind], &fd, 1, 1);
191 read_controller_data(fd, &cd);
193 /* Check that controller can execute this command. */
194 if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
195 NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
196 errx(1, "controller does not support namespace management");
198 /* Allow namespaces sharing if Multi-Path I/O is supported. */
200 nmic = cd.mic ? (NVME_NS_DATA_NMIC_MAY_BE_SHARED_MASK <<
201 NVME_NS_DATA_NMIC_MAY_BE_SHARED_SHIFT) : 0;
204 memset(&nsdata, 0, sizeof(nsdata));
205 nsdata.nsze = (uint64_t)nsze;
206 nsdata.ncap = (uint64_t)cap;
207 nsdata.flbas = ((lbaf & NVME_NS_DATA_FLBAS_FORMAT_MASK)
208 << NVME_NS_DATA_FLBAS_FORMAT_SHIFT) |
209 ((mset & NVME_NS_DATA_FLBAS_EXTENDED_MASK)
210 << NVME_NS_DATA_FLBAS_EXTENDED_SHIFT);
211 nsdata.dps = ((pi & NVME_NS_DATA_DPS_MD_START_MASK)
212 << NVME_NS_DATA_DPS_MD_START_SHIFT) |
213 ((pil & NVME_NS_DATA_DPS_PIT_MASK)
214 << NVME_NS_DATA_DPS_PIT_SHIFT);
216 nvme_namespace_data_swapbytes(&nsdata);
218 memset(&pt, 0, sizeof(pt));
219 pt.cmd.opc_fuse = NVME_CMD_SET_OPC(NVME_OPC_NAMESPACE_MANAGEMENT);
221 pt.cmd.cdw10 = 0; /* create */
223 pt.len = sizeof(struct nvme_namespace_data);
224 pt.is_read = 0; /* passthrough writes data to ctrlr */
225 if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0)
226 errx(1, "ioctl request to %s failed: %d", argv[optind], result);
228 if (nvme_completion_is_error(&pt.cpl)) {
229 errx(1, "namespace creation failed: %s",
230 get_res_str((pt.cpl.status >> NVME_STATUS_SC_SHIFT) &
231 NVME_STATUS_SC_MASK));
233 printf("namespace %d created\n", pt.cpl.cdw0);
238 nsdelete(int argc, char *argv[])
240 struct nvme_pt_command pt;
241 struct nvme_controller_data cd;
242 int ch, fd, result, nsid = -2;
248 while ((ch = getopt(argc, argv, "n:")) != -1) {
251 nsid = strtol(optarg, (char **)NULL, 0);
258 if (optind >= argc || nsid == -2)
261 open_dev(argv[optind], &fd, 1, 1);
262 read_controller_data(fd, &cd);
264 /* Check that controller can execute this command. */
265 if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
266 NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
267 errx(1, "controller does not support namespace management");
269 memset(&pt, 0, sizeof(pt));
270 pt.cmd.opc_fuse = NVME_CMD_SET_OPC(NVME_OPC_NAMESPACE_MANAGEMENT);
271 pt.cmd.cdw10 = 1; /* delete */
273 pt.len = sizeof(buf);
275 pt.cmd.nsid = (uint32_t)nsid;
277 if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0)
278 errx(1, "ioctl request to %s failed: %d", argv[optind], result);
280 if (nvme_completion_is_error(&pt.cpl)) {
281 errx(1, "namespace deletion failed: %s",
282 get_res_str((pt.cpl.status >> NVME_STATUS_SC_SHIFT) &
283 NVME_STATUS_SC_MASK));
285 printf("namespace %d deleted\n", nsid);
290 * Attach and Detach use Dword 10, and a controller list (section 4.9)
291 * This struct is 4096 bytes in size.
295 * Result values for both attach/detach:
297 * Completion 18h = Already attached
298 * 19h = NS is private and already attached to a controller
299 * 1Ah = Not attached, request could not be completed
300 * 1Ch = Controller list invalid.
302 * 0x2 Invalid Field can occur if ctrlrid d.n.e in system.
305 nsattach(int argc, char *argv[])
307 struct nvme_pt_command pt;
308 struct nvme_controller_data cd;
310 int fd, ch, result, nsid = -1;
311 uint16_t clist[2048];
316 while ((ch = getopt(argc, argv, "n:c:")) != -1) {
319 nsid = strtol(optarg, (char **)NULL, 0);
322 ctrlrid = strtol(optarg, (char **)NULL, 0);
335 open_dev(argv[optind], &fd, 1, 1);
336 read_controller_data(fd, &cd);
338 /* Check that controller can execute this command. */
339 if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
340 NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
341 errx(1, "controller does not support namespace management");
344 /* Get full list of controllers to attach to. */
345 memset(&pt, 0, sizeof(pt));
346 pt.cmd.opc_fuse = NVME_CMD_SET_OPC(NVME_OPC_IDENTIFY);
347 pt.cmd.cdw10 = htole32(0x13);
349 pt.len = sizeof(clist);
351 if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
352 err(1, "identify request failed");
353 if (nvme_completion_is_error(&pt.cpl))
354 errx(1, "identify request returned error");
356 /* By default attach to this controller. */
358 ctrlrid = cd.ctrlr_id;
359 memset(&clist, 0, sizeof(clist));
360 clist[0] = htole16(1);
361 clist[1] = htole16(ctrlrid);
364 memset(&pt, 0, sizeof(pt));
365 pt.cmd.opc_fuse = NVME_CMD_SET_OPC(NVME_OPC_NAMESPACE_ATTACHMENT);
366 pt.cmd.cdw10 = 0; /* attach */
367 pt.cmd.nsid = (uint32_t)nsid;
369 pt.len = sizeof(clist);
371 if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0)
372 errx(1, "ioctl request to %s failed: %d", argv[optind], result);
374 if (nvme_completion_is_error(&pt.cpl)) {
375 errx(1, "namespace attach failed: %s",
376 get_res_str((pt.cpl.status >> NVME_STATUS_SC_SHIFT) &
377 NVME_STATUS_SC_MASK));
379 printf("namespace %d attached\n", nsid);
384 nsdetach(int argc, char *argv[])
386 struct nvme_pt_command pt;
387 struct nvme_controller_data cd;
389 int fd, ch, result, nsid = -1;
390 uint16_t clist[2048];
395 while ((ch = getopt(argc, argv, "n:c:")) != -1) {
398 nsid = strtol(optarg, (char **)NULL, 0);
401 ctrlrid = strtol(optarg, (char **)NULL, 0);
414 open_dev(argv[optind], &fd, 1, 1);
415 read_controller_data(fd, &cd);
417 /* Check that controller can execute this command. */
418 if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
419 NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
420 errx(1, "controller does not support namespace management");
423 /* Get list of controllers this namespace attached to. */
424 memset(&pt, 0, sizeof(pt));
425 pt.cmd.opc_fuse = NVME_CMD_SET_OPC(NVME_OPC_IDENTIFY);
426 pt.cmd.nsid = htole32(nsid);
427 pt.cmd.cdw10 = htole32(0x12);
429 pt.len = sizeof(clist);
431 if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
432 err(1, "identify request failed");
433 if (nvme_completion_is_error(&pt.cpl))
434 errx(1, "identify request returned error");
436 ctrlrid = cd.ctrlr_id;
437 memset(&clist, 0, sizeof(clist));
438 clist[0] = htole16(1);
439 clist[1] = htole16(ctrlrid);
442 /* By default detach from this controller. */
444 ctrlrid = cd.ctrlr_id;
445 memset(&clist, 0, sizeof(clist));
446 clist[0] = htole16(1);
447 clist[1] = htole16(ctrlrid);
450 memset(&pt, 0, sizeof(pt));
451 pt.cmd.opc_fuse = NVME_CMD_SET_OPC(NVME_OPC_NAMESPACE_ATTACHMENT);
452 pt.cmd.cdw10 = 1; /* detach */
453 pt.cmd.nsid = (uint32_t)nsid;
455 pt.len = sizeof(clist);
457 if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0)
458 errx(1, "ioctl request to %s failed: %d", argv[optind], result);
460 if (nvme_completion_is_error(&pt.cpl)) {
461 errx(1, "namespace detach failed: %s",
462 get_res_str((pt.cpl.status >> NVME_STATUS_SC_SHIFT) &
463 NVME_STATUS_SC_MASK));
465 printf("namespace %d detached\n", nsid);
470 ns(int argc, char *argv[])
473 dispatch(argc, argv, ns_funcs);