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 NVME_CMD_DECLARE(ns, struct nvme_function);
47 "ns (create|delete|attach|detach)\n"
49 /* handles NVME_OPC_NAMESPACE_MANAGEMENT and ATTACHMENT admin cmds */
51 #define NSCREATE_USAGE \
52 "ns create -s size [-c cap] [-f fmt] [-m mset] [-n nmic] [-p pi] [-l pil] nvmeN\n"
54 #define NSDELETE_USAGE \
55 "ns delete -n nsid nvmeN\n"
57 #define NSATTACH_USAGE \
58 "ns attach -n nsid [-c ctrlrid] nvmeN \n"
60 #define NSDETACH_USAGE \
61 "ns detach -n nsid [-c ctrlrid] nvmeN\n"
63 static void nscreate(const struct nvme_function *nf, int argc, char *argv[]);
64 static void nsdelete(const struct nvme_function *nf, int argc, char *argv[]);
65 static void nsattach(const struct nvme_function *nf, int argc, char *argv[]);
66 static void nsdetach(const struct nvme_function *nf, int argc, char *argv[]);
68 NVME_COMMAND(ns, create, nscreate, NSCREATE_USAGE);
69 NVME_COMMAND(ns, delete, nsdelete, NSDELETE_USAGE);
70 NVME_COMMAND(ns, attach, nsattach, NSATTACH_USAGE);
71 NVME_COMMAND(ns, detach, nsdetach, NSDETACH_USAGE);
73 struct ns_result_str {
78 static struct ns_result_str ns_result[] = {
79 { 0x2, "Invalid Field"},
80 { 0xa, "Invalid Format"},
81 { 0xb, "Invalid Namespace or format"},
82 { 0x15, "Namespace insufficent capacity"},
83 { 0x16, "Namespace ID unavaliable"},
84 { 0x18, "Namespace already attached"},
85 { 0x19, "Namespace is private"},
86 { 0x1a, "Namespace is not attached"},
87 { 0x1b, "Thin provisioning not supported"},
88 { 0x1c, "Controller list invalid"},
93 get_res_str(uint16_t res)
95 struct ns_result_str *t = ns_result;
97 while (t->res != 0xFFFF) {
106 * NS MGMT Command specific status values:
107 * 0xa = Invalid Format
108 * 0x15 = Namespace Insuffience capacity
109 * 0x16 = Namespace ID unavailable (number namespaces exceeded)
110 * 0xb = Thin Provisioning Not supported
113 nscreate(const struct nvme_function *nf, int argc, char *argv[])
115 struct nvme_pt_command pt;
116 struct nvme_controller_data cd;
117 struct nvme_namespace_data nsdata;
118 int64_t nsze = -1, cap = -1;
119 int ch, fd, result, lbaf = 0, mset = 0, nmic = -1, pi = 0, pil = 0;
124 while ((ch = getopt(argc, argv, "s:c:f:m:n:p:l:")) != -1) {
127 nsze = strtol(optarg, (char **)NULL, 0);
130 cap = strtol(optarg, (char **)NULL, 0);
133 lbaf = strtol(optarg, (char **)NULL, 0);
136 mset = strtol(optarg, NULL, 0);
139 nmic = strtol(optarg, NULL, 0);
142 pi = strtol(optarg, NULL, 0);
145 pil = strtol(optarg, NULL, 0);
157 if (nsze == -1 || cap == -1)
160 open_dev(argv[optind], &fd, 1, 1);
161 read_controller_data(fd, &cd);
163 /* Check that controller can execute this command. */
164 if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
165 NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
166 errx(1, "controller does not support namespace management");
168 /* Allow namespaces sharing if Multi-Path I/O is supported. */
170 nmic = cd.mic ? (NVME_NS_DATA_NMIC_MAY_BE_SHARED_MASK <<
171 NVME_NS_DATA_NMIC_MAY_BE_SHARED_SHIFT) : 0;
174 memset(&nsdata, 0, sizeof(nsdata));
175 nsdata.nsze = (uint64_t)nsze;
176 nsdata.ncap = (uint64_t)cap;
177 nsdata.flbas = ((lbaf & NVME_NS_DATA_FLBAS_FORMAT_MASK)
178 << NVME_NS_DATA_FLBAS_FORMAT_SHIFT) |
179 ((mset & NVME_NS_DATA_FLBAS_EXTENDED_MASK)
180 << NVME_NS_DATA_FLBAS_EXTENDED_SHIFT);
181 nsdata.dps = ((pi & NVME_NS_DATA_DPS_MD_START_MASK)
182 << NVME_NS_DATA_DPS_MD_START_SHIFT) |
183 ((pil & NVME_NS_DATA_DPS_PIT_MASK)
184 << NVME_NS_DATA_DPS_PIT_SHIFT);
186 nvme_namespace_data_swapbytes(&nsdata);
188 memset(&pt, 0, sizeof(pt));
189 pt.cmd.opc = NVME_OPC_NAMESPACE_MANAGEMENT;
191 pt.cmd.cdw10 = 0; /* create */
193 pt.len = sizeof(struct nvme_namespace_data);
194 pt.is_read = 0; /* passthrough writes data to ctrlr */
195 if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0)
196 errx(1, "ioctl request to %s failed: %d", argv[optind], result);
198 if (nvme_completion_is_error(&pt.cpl)) {
199 errx(1, "namespace creation failed: %s",
200 get_res_str((pt.cpl.status >> NVME_STATUS_SC_SHIFT) &
201 NVME_STATUS_SC_MASK));
203 printf("namespace %d created\n", pt.cpl.cdw0);
208 nsdelete(const struct nvme_function *nf, int argc, char *argv[])
210 struct nvme_pt_command pt;
211 struct nvme_controller_data cd;
212 int ch, fd, result, nsid = -2;
218 while ((ch = getopt(argc, argv, "n:")) != -1) {
221 nsid = strtol(optarg, (char **)NULL, 0);
228 if (optind >= argc || nsid == -2)
231 open_dev(argv[optind], &fd, 1, 1);
232 read_controller_data(fd, &cd);
234 /* Check that controller can execute this command. */
235 if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
236 NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
237 errx(1, "controller does not support namespace management");
239 memset(&pt, 0, sizeof(pt));
240 pt.cmd.opc = NVME_OPC_NAMESPACE_MANAGEMENT;
241 pt.cmd.cdw10 = 1; /* delete */
243 pt.len = sizeof(buf);
245 pt.cmd.nsid = (uint32_t)nsid;
247 if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0)
248 errx(1, "ioctl request to %s failed: %d", argv[optind], result);
250 if (nvme_completion_is_error(&pt.cpl)) {
251 errx(1, "namespace deletion failed: %s",
252 get_res_str((pt.cpl.status >> NVME_STATUS_SC_SHIFT) &
253 NVME_STATUS_SC_MASK));
255 printf("namespace %d deleted\n", nsid);
260 * Attach and Detach use Dword 10, and a controller list (section 4.9)
261 * This struct is 4096 bytes in size.
265 * Result values for both attach/detach:
267 * Completion 18h = Already attached
268 * 19h = NS is private and already attached to a controller
269 * 1Ah = Not attached, request could not be completed
270 * 1Ch = Controller list invalid.
272 * 0x2 Invalid Field can occur if ctrlrid d.n.e in system.
275 nsattach(const struct nvme_function *nf, int argc, char *argv[])
277 struct nvme_pt_command pt;
278 struct nvme_controller_data cd;
280 int fd, ch, result, nsid = -1;
281 uint16_t clist[2048];
286 while ((ch = getopt(argc, argv, "n:c:")) != -1) {
289 nsid = strtol(optarg, (char **)NULL, 0);
292 ctrlrid = strtol(optarg, (char **)NULL, 0);
305 open_dev(argv[optind], &fd, 1, 1);
306 read_controller_data(fd, &cd);
308 /* Check that controller can execute this command. */
309 if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
310 NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
311 errx(1, "controller does not support namespace management");
314 /* Get full list of controllers to attach to. */
315 memset(&pt, 0, sizeof(pt));
316 pt.cmd.opc = NVME_OPC_IDENTIFY;
317 pt.cmd.cdw10 = htole32(0x13);
319 pt.len = sizeof(clist);
321 if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
322 err(1, "identify request failed");
323 if (nvme_completion_is_error(&pt.cpl))
324 errx(1, "identify request returned error");
326 /* By default attach to this controller. */
328 ctrlrid = cd.ctrlr_id;
329 memset(&clist, 0, sizeof(clist));
330 clist[0] = htole16(1);
331 clist[1] = htole16(ctrlrid);
334 memset(&pt, 0, sizeof(pt));
335 pt.cmd.opc = NVME_OPC_NAMESPACE_ATTACHMENT;
336 pt.cmd.cdw10 = 0; /* attach */
337 pt.cmd.nsid = (uint32_t)nsid;
339 pt.len = sizeof(clist);
341 if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0)
342 errx(1, "ioctl request to %s failed: %d", argv[optind], result);
344 if (nvme_completion_is_error(&pt.cpl)) {
345 errx(1, "namespace attach failed: %s",
346 get_res_str((pt.cpl.status >> NVME_STATUS_SC_SHIFT) &
347 NVME_STATUS_SC_MASK));
349 printf("namespace %d attached\n", nsid);
354 nsdetach(const struct nvme_function *nf, int argc, char *argv[])
356 struct nvme_pt_command pt;
357 struct nvme_controller_data cd;
359 int fd, ch, result, nsid = -1;
360 uint16_t clist[2048];
365 while ((ch = getopt(argc, argv, "n:c:")) != -1) {
368 nsid = strtol(optarg, (char **)NULL, 0);
371 ctrlrid = strtol(optarg, (char **)NULL, 0);
384 open_dev(argv[optind], &fd, 1, 1);
385 read_controller_data(fd, &cd);
387 /* Check that controller can execute this command. */
388 if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
389 NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
390 errx(1, "controller does not support namespace management");
393 /* Get list of controllers this namespace attached to. */
394 memset(&pt, 0, sizeof(pt));
395 pt.cmd.opc = NVME_OPC_IDENTIFY;
396 pt.cmd.nsid = htole32(nsid);
397 pt.cmd.cdw10 = htole32(0x12);
399 pt.len = sizeof(clist);
401 if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
402 err(1, "identify request failed");
403 if (nvme_completion_is_error(&pt.cpl))
404 errx(1, "identify request returned error");
406 ctrlrid = cd.ctrlr_id;
407 memset(&clist, 0, sizeof(clist));
408 clist[0] = htole16(1);
409 clist[1] = htole16(ctrlrid);
412 /* By default detach from this controller. */
414 ctrlrid = cd.ctrlr_id;
415 memset(&clist, 0, sizeof(clist));
416 clist[0] = htole16(1);
417 clist[1] = htole16(ctrlrid);
420 memset(&pt, 0, sizeof(pt));
421 pt.cmd.opc = NVME_OPC_NAMESPACE_ATTACHMENT;
422 pt.cmd.cdw10 = 1; /* detach */
423 pt.cmd.nsid = (uint32_t)nsid;
425 pt.len = sizeof(clist);
427 if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0)
428 errx(1, "ioctl request to %s failed: %d", argv[optind], result);
430 if (nvme_completion_is_error(&pt.cpl)) {
431 errx(1, "namespace detach failed: %s",
432 get_res_str((pt.cpl.status >> NVME_STATUS_SC_SHIFT) &
433 NVME_STATUS_SC_MASK));
435 printf("namespace %d detached\n", nsid);
440 ns(const struct nvme_function *nf __unused, int argc, char *argv[])
443 DISPATCH(argc, argv, ns);
446 NVME_COMMAND(top, ns, ns, NS_USAGE);