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 /* Tables for command line parsing */
47 static cmd_fn_t nscreate;
48 static cmd_fn_t nsdelete;
49 static cmd_fn_t nsattach;
50 static cmd_fn_t nsdetach;
52 #define NONE 0xffffffffu
53 #define NONE64 0xffffffffffffffffull
54 #define OPT(l, s, t, opt, addr, desc) { l, s, t, &opt.addr, desc }
55 #define OPT_END { NULL, 0, arg_none, NULL, NULL }
57 static struct cmd ns_cmd = {
58 .name = "ns", .fn = ns, .descr = "Namespace commands", .ctx_size = 0, .opts = NULL, .args = NULL,
63 static struct create_options {
73 // uint32_t block_size;
86 // .block_size = NONE,
89 static const struct opts create_opts[] = {
90 OPT("nsze", 's', arg_uint64, create_opt, nsze,
91 "The namespace size"),
92 OPT("ncap", 'c', arg_uint64, create_opt, cap,
93 "The capacity of the namespace (<= ns size)"),
94 OPT("lbaf", 'f', arg_uint32, create_opt, lbaf,
95 "The FMT field of the FLBAS"),
96 OPT("mset", 'm', arg_uint32, create_opt, mset,
97 "The MSET field of the FLBAS"),
98 OPT("nmic", 'n', arg_uint32, create_opt, nmic,
99 "Namespace multipath and sharing capabilities"),
100 OPT("pi", 'p', arg_uint32, create_opt, pi,
101 "PI field of FLBAS"),
102 OPT("pil", 'l', arg_uint32, create_opt, pil,
103 "PIL field of FLBAS"),
104 OPT("flbas", 'l', arg_uint32, create_opt, flbas,
105 "Namespace formatted logical block size setting"),
106 OPT("dps", 'd', arg_uint32, create_opt, dps,
107 "Data protection settings"),
108 // OPT("block-size", 'b', arg_uint32, create_opt, block_size,
109 // "Blocksize of the namespace"),
113 static const struct args create_args[] = {
114 { arg_string, &create_opt.dev, "controller-id" },
115 { arg_none, NULL, NULL },
118 static struct cmd create_cmd = {
121 .descr = "Create a new namespace",
122 .ctx_size = sizeof(create_opt),
127 CMD_SUBCOMMAND(ns_cmd, create_cmd);
129 static struct delete_options {
137 static const struct opts delete_opts[] = {
138 OPT("namespace-id", 'n', arg_uint32, delete_opt, nsid,
139 "The namespace ID to delete"),
143 static const struct args delete_args[] = {
144 { arg_string, &delete_opt.dev, "controller-id" },
145 { arg_none, NULL, NULL },
148 static struct cmd delete_cmd = {
151 .descr = "Delete a new namespace",
152 .ctx_size = sizeof(delete_opt),
157 CMD_SUBCOMMAND(ns_cmd, delete_cmd);
159 static struct attach_options {
169 static const struct opts attach_opts[] = {
170 OPT("namespace-id", 'n', arg_uint32, attach_opt, nsid,
171 "The namespace ID to attach"),
172 OPT("controller", 'c', arg_uint32, attach_opt, nsid,
173 "The controller ID to attach"),
177 static const struct args attach_args[] = {
178 { arg_string, &attach_opt.dev, "controller-id" },
179 { arg_none, NULL, NULL },
182 static struct cmd attach_cmd = {
185 .descr = "Attach a new namespace",
186 .ctx_size = sizeof(attach_opt),
191 CMD_SUBCOMMAND(ns_cmd, attach_cmd);
193 static struct detach_options {
203 static const struct opts detach_opts[] = {
204 OPT("namespace-id", 'n', arg_uint32, detach_opt, nsid,
205 "The namespace ID to detach"),
206 OPT("controller", 'c', arg_uint32, detach_opt, nsid,
207 "The controller ID to detach"),
211 static const struct args detach_args[] = {
212 { arg_string, &detach_opt.dev, "controller-id" },
213 { arg_none, NULL, NULL },
216 static struct cmd detach_cmd = {
219 .descr = "Detach a new namespace",
220 .ctx_size = sizeof(detach_opt),
225 CMD_SUBCOMMAND(ns_cmd, detach_cmd);
228 "ns (create|delete|attach|detach)\n"
230 /* handles NVME_OPC_NAMESPACE_MANAGEMENT and ATTACHMENT admin cmds */
232 struct ns_result_str {
237 static struct ns_result_str ns_result[] = {
238 { 0x2, "Invalid Field"},
239 { 0xa, "Invalid Format"},
240 { 0xb, "Invalid Namespace or format"},
241 { 0x15, "Namespace insufficent capacity"},
242 { 0x16, "Namespace ID unavaliable"},
243 { 0x18, "Namespace already attached"},
244 { 0x19, "Namespace is private"},
245 { 0x1a, "Namespace is not attached"},
246 { 0x1b, "Thin provisioning not supported"},
247 { 0x1c, "Controller list invalid"},
252 get_res_str(uint16_t res)
254 struct ns_result_str *t = ns_result;
256 while (t->res != 0xFFFF) {
265 * NS MGMT Command specific status values:
266 * 0xa = Invalid Format
267 * 0x15 = Namespace Insuffience capacity
268 * 0x16 = Namespace ID unavailable (number namespaces exceeded)
269 * 0xb = Thin Provisioning Not supported
272 nscreate(const struct cmd *f, int argc, char *argv[])
274 struct nvme_pt_command pt;
275 struct nvme_controller_data cd;
276 struct nvme_namespace_data nsdata;
279 if (arg_parse(argc, argv, f))
282 if (create_opt.cap == NONE64)
283 create_opt.cap = create_opt.nsze;
284 if (create_opt.nsze == NONE64) {
286 "Size not specified\n");
287 arg_help(argc, argv, f);
290 open_dev(create_opt.dev, &fd, 1, 1);
291 read_controller_data(fd, &cd);
293 /* Check that controller can execute this command. */
294 if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
295 NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
296 errx(1, "controller does not support namespace management");
298 /* Allow namespaces sharing if Multi-Path I/O is supported. */
299 if (create_opt.nmic == NONE) {
300 create_opt.nmic = cd.mic ? (NVME_NS_DATA_NMIC_MAY_BE_SHARED_MASK <<
301 NVME_NS_DATA_NMIC_MAY_BE_SHARED_SHIFT) : 0;
304 memset(&nsdata, 0, sizeof(nsdata));
305 nsdata.nsze = create_opt.nsze;
306 nsdata.ncap = create_opt.cap;
307 if (create_opt.flbas == NONE)
308 nsdata.flbas = ((create_opt.lbaf & NVME_NS_DATA_FLBAS_FORMAT_MASK)
309 << NVME_NS_DATA_FLBAS_FORMAT_SHIFT) |
310 ((create_opt.mset & NVME_NS_DATA_FLBAS_EXTENDED_MASK)
311 << NVME_NS_DATA_FLBAS_EXTENDED_SHIFT);
313 nsdata.flbas = create_opt.flbas;
314 if (create_opt.dps == NONE)
315 nsdata.dps = ((create_opt.pi & NVME_NS_DATA_DPS_MD_START_MASK)
316 << NVME_NS_DATA_DPS_MD_START_SHIFT) |
317 ((create_opt.pil & NVME_NS_DATA_DPS_PIT_MASK)
318 << NVME_NS_DATA_DPS_PIT_SHIFT);
320 nsdata.dps = create_opt.dps;
321 nsdata.nmic = create_opt.nmic;
322 nvme_namespace_data_swapbytes(&nsdata);
324 memset(&pt, 0, sizeof(pt));
325 pt.cmd.opc = NVME_OPC_NAMESPACE_MANAGEMENT;
327 pt.cmd.cdw10 = 0; /* create */
329 pt.len = sizeof(struct nvme_namespace_data);
330 pt.is_read = 0; /* passthrough writes data to ctrlr */
331 if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0)
332 errx(1, "ioctl request to %s failed: %d", argv[optind], result);
334 if (nvme_completion_is_error(&pt.cpl)) {
335 errx(1, "namespace creation failed: %s",
336 get_res_str((pt.cpl.status >> NVME_STATUS_SC_SHIFT) &
337 NVME_STATUS_SC_MASK));
339 printf("namespace %d created\n", pt.cpl.cdw0);
344 nsdelete(const struct cmd *f, int argc, char *argv[])
346 struct nvme_pt_command pt;
347 struct nvme_controller_data cd;
351 if (arg_parse(argc, argv, f))
353 if (delete_opt.nsid == NONE) {
355 "No NSID specified");
356 arg_help(argc, argv, f);
359 open_dev(delete_opt.dev, &fd, 1, 1);
360 read_controller_data(fd, &cd);
362 /* Check that controller can execute this command. */
363 if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
364 NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
365 errx(1, "controller does not support namespace management");
367 memset(&pt, 0, sizeof(pt));
368 pt.cmd.opc = NVME_OPC_NAMESPACE_MANAGEMENT;
369 pt.cmd.cdw10 = 1; /* delete */
371 pt.len = sizeof(buf);
373 pt.cmd.nsid = delete_opt.nsid;
375 if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0)
376 errx(1, "ioctl request to %s failed: %d", delete_opt.dev, result);
378 if (nvme_completion_is_error(&pt.cpl)) {
379 errx(1, "namespace deletion failed: %s",
380 get_res_str((pt.cpl.status >> NVME_STATUS_SC_SHIFT) &
381 NVME_STATUS_SC_MASK));
383 printf("namespace %d deleted\n", delete_opt.nsid);
388 * Attach and Detach use Dword 10, and a controller list (section 4.9)
389 * This struct is 4096 bytes in size.
393 * Result values for both attach/detach:
395 * Completion 18h = Already attached
396 * 19h = NS is private and already attached to a controller
397 * 1Ah = Not attached, request could not be completed
398 * 1Ch = Controller list invalid.
400 * 0x2 Invalid Field can occur if ctrlrid d.n.e in system.
403 nsattach(const struct cmd *f, int argc, char *argv[])
405 struct nvme_pt_command pt;
406 struct nvme_controller_data cd;
408 uint16_t clist[2048];
410 if (arg_parse(argc, argv, f))
412 if (attach_opt.nsid == NONE) {
413 fprintf(stderr, "No valid NSID specified\n");
414 arg_help(argc, argv, f);
416 open_dev(attach_opt.dev, &fd, 1, 1);
417 read_controller_data(fd, &cd);
419 /* Check that controller can execute this command. */
420 if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
421 NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
422 errx(1, "controller does not support namespace management");
424 if (attach_opt.ctrlrid == NONE) {
425 /* Get full list of controllers to attach to. */
426 memset(&pt, 0, sizeof(pt));
427 pt.cmd.opc = NVME_OPC_IDENTIFY;
428 pt.cmd.cdw10 = htole32(0x13);
430 pt.len = sizeof(clist);
432 if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
433 err(1, "identify request failed");
434 if (nvme_completion_is_error(&pt.cpl))
435 errx(1, "identify request returned error");
437 /* By default attach to this controller. */
438 if (attach_opt.ctrlrid == NONE - 1)
439 attach_opt.ctrlrid = cd.ctrlr_id;
440 memset(&clist, 0, sizeof(clist));
441 clist[0] = htole16(1);
442 clist[1] = htole16(attach_opt.ctrlrid);
445 memset(&pt, 0, sizeof(pt));
446 pt.cmd.opc = NVME_OPC_NAMESPACE_ATTACHMENT;
447 pt.cmd.cdw10 = 0; /* attach */
448 pt.cmd.nsid = attach_opt.nsid;
450 pt.len = sizeof(clist);
452 if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0)
453 errx(1, "ioctl request to %s failed: %d", attach_opt.dev, result);
455 if (nvme_completion_is_error(&pt.cpl)) {
456 errx(1, "namespace attach failed: %s",
457 get_res_str((pt.cpl.status >> NVME_STATUS_SC_SHIFT) &
458 NVME_STATUS_SC_MASK));
460 printf("namespace %d attached\n", attach_opt.nsid);
465 nsdetach(const struct cmd *f, int argc, char *argv[])
467 struct nvme_pt_command pt;
468 struct nvme_controller_data cd;
470 uint16_t clist[2048];
472 if (arg_parse(argc, argv, f))
474 if (attach_opt.nsid == NONE) {
475 fprintf(stderr, "No valid NSID specified\n");
476 arg_help(argc, argv, f);
478 open_dev(attach_opt.dev, &fd, 1, 1);
479 read_controller_data(fd, &cd);
481 /* Check that controller can execute this command. */
482 if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
483 NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
484 errx(1, "controller does not support namespace management");
486 if (detach_opt.ctrlrid == NONE) {
487 /* Get list of controllers this namespace attached to. */
488 memset(&pt, 0, sizeof(pt));
489 pt.cmd.opc = NVME_OPC_IDENTIFY;
490 pt.cmd.nsid = htole32(detach_opt.nsid);
491 pt.cmd.cdw10 = htole32(0x12);
493 pt.len = sizeof(clist);
495 if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
496 err(1, "identify request failed");
497 if (nvme_completion_is_error(&pt.cpl))
498 errx(1, "identify request returned error");
500 detach_opt.ctrlrid = cd.ctrlr_id;
501 memset(&clist, 0, sizeof(clist));
502 clist[0] = htole16(1);
503 clist[1] = htole16(detach_opt.ctrlrid);
506 /* By default detach from this controller. */
507 if (detach_opt.ctrlrid == NONE - 1)
508 detach_opt.ctrlrid = cd.ctrlr_id;
509 memset(&clist, 0, sizeof(clist));
510 clist[0] = htole16(1);
511 clist[1] = htole16(detach_opt.ctrlrid);
514 memset(&pt, 0, sizeof(pt));
515 pt.cmd.opc = NVME_OPC_NAMESPACE_ATTACHMENT;
516 pt.cmd.cdw10 = 1; /* detach */
517 pt.cmd.nsid = detach_opt.nsid;
519 pt.len = sizeof(clist);
521 if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0)
522 errx(1, "ioctl request to %s failed: %d", argv[optind], result);
524 if (nvme_completion_is_error(&pt.cpl)) {
525 errx(1, "namespace detach failed: %s",
526 get_res_str((pt.cpl.status >> NVME_STATUS_SC_SHIFT) &
527 NVME_STATUS_SC_MASK));
529 printf("namespace %d detached\n", detach_opt.nsid);
534 ns(const struct cmd *nf __unused, int argc, char *argv[])
537 cmd_dispatch(argc, argv, &ns_cmd);