1 | #include <machine/rtems-bsd-user-space.h> |
---|
2 | |
---|
3 | /*- |
---|
4 | * SPDX-License-Identifier: BSD-2-Clause-FreeBSD |
---|
5 | * |
---|
6 | * Copyright (c) 2017 Netflix, Inc. |
---|
7 | * Copyright (C) 2018-2019 Alexander Motin <mav@FreeBSD.org> |
---|
8 | * |
---|
9 | * Redistribution and use in source and binary forms, with or without |
---|
10 | * modification, are permitted provided that the following conditions |
---|
11 | * are met: |
---|
12 | * 1. Redistributions of source code must retain the above copyright |
---|
13 | * notice, this list of conditions and the following disclaimer, |
---|
14 | * without modification, immediately at the beginning of the file. |
---|
15 | * 2. Redistributions in binary form must reproduce the above copyright |
---|
16 | * notice, this list of conditions and the following disclaimer in the |
---|
17 | * documentation and/or other materials provided with the distribution. |
---|
18 | * |
---|
19 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
---|
20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
---|
21 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
---|
22 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
---|
23 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
---|
24 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
---|
25 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
---|
26 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
---|
27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
---|
28 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
---|
29 | */ |
---|
30 | |
---|
31 | #include <sys/cdefs.h> |
---|
32 | __FBSDID("$FreeBSD$"); |
---|
33 | |
---|
34 | #include <sys/param.h> |
---|
35 | #include <sys/ioccom.h> |
---|
36 | |
---|
37 | #include <err.h> |
---|
38 | #include <fcntl.h> |
---|
39 | #include <stdbool.h> |
---|
40 | #include <stddef.h> |
---|
41 | #include <stdio.h> |
---|
42 | #include <stdlib.h> |
---|
43 | #include <string.h> |
---|
44 | #include <unistd.h> |
---|
45 | |
---|
46 | #include "nvmecontrol.h" |
---|
47 | |
---|
48 | /* Tables for command line parsing */ |
---|
49 | |
---|
50 | static cmd_fn_t ns; |
---|
51 | static cmd_fn_t nsactive; |
---|
52 | static cmd_fn_t nsallocated; |
---|
53 | static cmd_fn_t nscontrollers; |
---|
54 | static cmd_fn_t nscreate; |
---|
55 | static cmd_fn_t nsdelete; |
---|
56 | static cmd_fn_t nsattach; |
---|
57 | static cmd_fn_t nsdetach; |
---|
58 | static cmd_fn_t nsattached; |
---|
59 | static cmd_fn_t nsidentify; |
---|
60 | |
---|
61 | #define NONE 0xffffffffu |
---|
62 | #define NONE64 0xffffffffffffffffull |
---|
63 | #define OPT(l, s, t, opt, addr, desc) { l, s, t, &opt.addr, desc } |
---|
64 | #define OPT_END { NULL, 0, arg_none, NULL, NULL } |
---|
65 | |
---|
66 | static struct cmd ns_cmd = { |
---|
67 | .name = "ns", |
---|
68 | .fn = ns, |
---|
69 | .descr = "Namespace management commands", |
---|
70 | .ctx_size = 0, |
---|
71 | .opts = NULL, |
---|
72 | .args = NULL, |
---|
73 | }; |
---|
74 | |
---|
75 | CMD_COMMAND(ns_cmd); |
---|
76 | |
---|
77 | static struct active_options { |
---|
78 | const char *dev; |
---|
79 | } active_opt = { |
---|
80 | .dev = NULL, |
---|
81 | }; |
---|
82 | |
---|
83 | static const struct args active_args[] = { |
---|
84 | { arg_string, &active_opt.dev, "controller-id" }, |
---|
85 | { arg_none, NULL, NULL }, |
---|
86 | }; |
---|
87 | |
---|
88 | static struct cmd active_cmd = { |
---|
89 | .name = "active", |
---|
90 | .fn = nsactive, |
---|
91 | .descr = "List active (attached) namespaces", |
---|
92 | .ctx_size = sizeof(active_opt), |
---|
93 | .opts = NULL, |
---|
94 | .args = active_args, |
---|
95 | }; |
---|
96 | |
---|
97 | CMD_SUBCOMMAND(ns_cmd, active_cmd); |
---|
98 | |
---|
99 | static struct cmd allocated_cmd = { |
---|
100 | .name = "allocated", |
---|
101 | .fn = nsallocated, |
---|
102 | .descr = "List allocated (created) namespaces", |
---|
103 | .ctx_size = sizeof(active_opt), |
---|
104 | .opts = NULL, |
---|
105 | .args = active_args, |
---|
106 | }; |
---|
107 | |
---|
108 | CMD_SUBCOMMAND(ns_cmd, allocated_cmd); |
---|
109 | |
---|
110 | static struct controllers_options { |
---|
111 | const char *dev; |
---|
112 | } controllers_opt = { |
---|
113 | .dev = NULL, |
---|
114 | }; |
---|
115 | |
---|
116 | static const struct args controllers_args[] = { |
---|
117 | { arg_string, &controllers_opt.dev, "controller-id" }, |
---|
118 | { arg_none, NULL, NULL }, |
---|
119 | }; |
---|
120 | |
---|
121 | static struct cmd controllers_cmd = { |
---|
122 | .name = "controllers", |
---|
123 | .fn = nscontrollers, |
---|
124 | .descr = "List all controllers in NVM subsystem", |
---|
125 | .ctx_size = sizeof(controllers_opt), |
---|
126 | .opts = NULL, |
---|
127 | .args = controllers_args, |
---|
128 | }; |
---|
129 | |
---|
130 | CMD_SUBCOMMAND(ns_cmd, controllers_cmd); |
---|
131 | |
---|
132 | static struct create_options { |
---|
133 | uint64_t nsze; |
---|
134 | uint64_t cap; |
---|
135 | uint32_t lbaf; |
---|
136 | uint32_t mset; |
---|
137 | uint32_t nmic; |
---|
138 | uint32_t pi; |
---|
139 | uint32_t pil; |
---|
140 | uint32_t flbas; |
---|
141 | uint32_t dps; |
---|
142 | // uint32_t block_size; |
---|
143 | const char *dev; |
---|
144 | } create_opt = { |
---|
145 | .nsze = NONE64, |
---|
146 | .cap = NONE64, |
---|
147 | .lbaf = NONE, |
---|
148 | .mset = NONE, |
---|
149 | .nmic = NONE, |
---|
150 | .pi = NONE, |
---|
151 | .pil = NONE, |
---|
152 | .flbas = NONE, |
---|
153 | .dps = NONE, |
---|
154 | .dev = NULL, |
---|
155 | // .block_size = NONE, |
---|
156 | }; |
---|
157 | |
---|
158 | static const struct opts create_opts[] = { |
---|
159 | OPT("nsze", 's', arg_uint64, create_opt, nsze, |
---|
160 | "The namespace size"), |
---|
161 | OPT("ncap", 'c', arg_uint64, create_opt, cap, |
---|
162 | "The capacity of the namespace (<= ns size)"), |
---|
163 | OPT("lbaf", 'f', arg_uint32, create_opt, lbaf, |
---|
164 | "The FMT field of the FLBAS"), |
---|
165 | OPT("mset", 'm', arg_uint32, create_opt, mset, |
---|
166 | "The MSET field of the FLBAS"), |
---|
167 | OPT("nmic", 'n', arg_uint32, create_opt, nmic, |
---|
168 | "Namespace multipath and sharing capabilities"), |
---|
169 | OPT("pi", 'p', arg_uint32, create_opt, pi, |
---|
170 | "PI field of FLBAS"), |
---|
171 | OPT("pil", 'l', arg_uint32, create_opt, pil, |
---|
172 | "PIL field of FLBAS"), |
---|
173 | OPT("flbas", 'L', arg_uint32, create_opt, flbas, |
---|
174 | "Namespace formatted logical block size setting"), |
---|
175 | OPT("dps", 'd', arg_uint32, create_opt, dps, |
---|
176 | "Data protection settings"), |
---|
177 | // OPT("block-size", 'b', arg_uint32, create_opt, block_size, |
---|
178 | // "Blocksize of the namespace"), |
---|
179 | OPT_END |
---|
180 | }; |
---|
181 | |
---|
182 | static const struct args create_args[] = { |
---|
183 | { arg_string, &create_opt.dev, "controller-id" }, |
---|
184 | { arg_none, NULL, NULL }, |
---|
185 | }; |
---|
186 | |
---|
187 | static struct cmd create_cmd = { |
---|
188 | .name = "create", |
---|
189 | .fn = nscreate, |
---|
190 | .descr = "Create a namespace", |
---|
191 | .ctx_size = sizeof(create_opt), |
---|
192 | .opts = create_opts, |
---|
193 | .args = create_args, |
---|
194 | }; |
---|
195 | |
---|
196 | CMD_SUBCOMMAND(ns_cmd, create_cmd); |
---|
197 | |
---|
198 | static struct delete_options { |
---|
199 | uint32_t nsid; |
---|
200 | const char *dev; |
---|
201 | } delete_opt = { |
---|
202 | .nsid = NONE, |
---|
203 | .dev = NULL, |
---|
204 | }; |
---|
205 | |
---|
206 | static const struct opts delete_opts[] = { |
---|
207 | OPT("namespace-id", 'n', arg_uint32, delete_opt, nsid, |
---|
208 | "The namespace ID to delete"), |
---|
209 | OPT_END |
---|
210 | }; |
---|
211 | |
---|
212 | static const struct args delete_args[] = { |
---|
213 | { arg_string, &delete_opt.dev, "controller-id" }, |
---|
214 | { arg_none, NULL, NULL }, |
---|
215 | }; |
---|
216 | |
---|
217 | static struct cmd delete_cmd = { |
---|
218 | .name = "delete", |
---|
219 | .fn = nsdelete, |
---|
220 | .descr = "Delete a namespace", |
---|
221 | .ctx_size = sizeof(delete_opt), |
---|
222 | .opts = delete_opts, |
---|
223 | .args = delete_args, |
---|
224 | }; |
---|
225 | |
---|
226 | CMD_SUBCOMMAND(ns_cmd, delete_cmd); |
---|
227 | |
---|
228 | static struct attach_options { |
---|
229 | uint32_t nsid; |
---|
230 | uint32_t ctrlrid; |
---|
231 | const char *dev; |
---|
232 | } attach_opt = { |
---|
233 | .nsid = NONE, |
---|
234 | .ctrlrid = NONE - 1, |
---|
235 | .dev = NULL, |
---|
236 | }; |
---|
237 | |
---|
238 | static const struct opts attach_opts[] = { |
---|
239 | OPT("namespace-id", 'n', arg_uint32, attach_opt, nsid, |
---|
240 | "The namespace ID to attach"), |
---|
241 | OPT("controller", 'c', arg_uint32, attach_opt, ctrlrid, |
---|
242 | "The controller ID to attach"), |
---|
243 | OPT_END |
---|
244 | }; |
---|
245 | |
---|
246 | static const struct args attach_args[] = { |
---|
247 | { arg_string, &attach_opt.dev, "controller-id" }, |
---|
248 | { arg_none, NULL, NULL }, |
---|
249 | }; |
---|
250 | |
---|
251 | static struct cmd attach_cmd = { |
---|
252 | .name = "attach", |
---|
253 | .fn = nsattach, |
---|
254 | .descr = "Attach a controller to a namespace", |
---|
255 | .ctx_size = sizeof(attach_opt), |
---|
256 | .opts = attach_opts, |
---|
257 | .args = attach_args, |
---|
258 | }; |
---|
259 | |
---|
260 | CMD_SUBCOMMAND(ns_cmd, attach_cmd); |
---|
261 | |
---|
262 | static struct attached_options { |
---|
263 | uint32_t nsid; |
---|
264 | const char *dev; |
---|
265 | } attached_opt = { |
---|
266 | .nsid = NONE, |
---|
267 | .dev = NULL, |
---|
268 | }; |
---|
269 | |
---|
270 | static const struct opts attached_opts[] = { |
---|
271 | OPT("namespace-id", 'n', arg_uint32, attached_opt, nsid, |
---|
272 | "The namespace ID to request attached controllers"), |
---|
273 | OPT_END |
---|
274 | }; |
---|
275 | |
---|
276 | static const struct args attached_args[] = { |
---|
277 | { arg_string, &attached_opt.dev, "controller-id" }, |
---|
278 | { arg_none, NULL, NULL }, |
---|
279 | }; |
---|
280 | |
---|
281 | static struct cmd attached_cmd = { |
---|
282 | .name = "attached", |
---|
283 | .fn = nsattached, |
---|
284 | .descr = "List controllers attached to a namespace", |
---|
285 | .ctx_size = sizeof(attached_opt), |
---|
286 | .opts = attached_opts, |
---|
287 | .args = attached_args, |
---|
288 | }; |
---|
289 | |
---|
290 | CMD_SUBCOMMAND(ns_cmd, attached_cmd); |
---|
291 | |
---|
292 | static struct detach_options { |
---|
293 | uint32_t nsid; |
---|
294 | uint32_t ctrlrid; |
---|
295 | const char *dev; |
---|
296 | } detach_opt = { |
---|
297 | .nsid = NONE, |
---|
298 | .ctrlrid = NONE - 1, |
---|
299 | .dev = NULL, |
---|
300 | }; |
---|
301 | |
---|
302 | static const struct opts detach_opts[] = { |
---|
303 | OPT("namespace-id", 'n', arg_uint32, detach_opt, nsid, |
---|
304 | "The namespace ID to detach"), |
---|
305 | OPT("controller", 'c', arg_uint32, detach_opt, ctrlrid, |
---|
306 | "The controller ID to detach"), |
---|
307 | OPT_END |
---|
308 | }; |
---|
309 | |
---|
310 | static const struct args detach_args[] = { |
---|
311 | { arg_string, &detach_opt.dev, "controller-id" }, |
---|
312 | { arg_none, NULL, NULL }, |
---|
313 | }; |
---|
314 | |
---|
315 | static struct cmd detach_cmd = { |
---|
316 | .name = "detach", |
---|
317 | .fn = nsdetach, |
---|
318 | .descr = "Detach a controller from a namespace", |
---|
319 | .ctx_size = sizeof(detach_opt), |
---|
320 | .opts = detach_opts, |
---|
321 | .args = detach_args, |
---|
322 | }; |
---|
323 | |
---|
324 | CMD_SUBCOMMAND(ns_cmd, detach_cmd); |
---|
325 | |
---|
326 | static struct identify_options { |
---|
327 | bool hex; |
---|
328 | bool verbose; |
---|
329 | const char *dev; |
---|
330 | uint32_t nsid; |
---|
331 | } identify_opt = { |
---|
332 | .hex = false, |
---|
333 | .verbose = false, |
---|
334 | .dev = NULL, |
---|
335 | .nsid = NONE, |
---|
336 | }; |
---|
337 | |
---|
338 | static const struct opts identify_opts[] = { |
---|
339 | OPT("hex", 'x', arg_none, identify_opt, hex, |
---|
340 | "Print identiy information in hex"), |
---|
341 | OPT("verbose", 'v', arg_none, identify_opt, verbose, |
---|
342 | "More verbosity: print entire identify table"), |
---|
343 | OPT("nsid", 'n', arg_uint32, identify_opt, nsid, |
---|
344 | "The namespace ID to print IDENTIFY for"), |
---|
345 | { NULL, 0, arg_none, NULL, NULL } |
---|
346 | }; |
---|
347 | |
---|
348 | static const struct args identify_args[] = { |
---|
349 | { arg_string, &identify_opt.dev, "controller-id" }, |
---|
350 | { arg_none, NULL, NULL }, |
---|
351 | }; |
---|
352 | |
---|
353 | static struct cmd identify_cmd = { |
---|
354 | .name = "identify", |
---|
355 | .fn = nsidentify, |
---|
356 | .descr = "Print IDENTIFY for allocated namespace", |
---|
357 | .ctx_size = sizeof(identify_opt), |
---|
358 | .opts = identify_opts, |
---|
359 | .args = identify_args, |
---|
360 | }; |
---|
361 | |
---|
362 | CMD_SUBCOMMAND(ns_cmd, identify_cmd); |
---|
363 | |
---|
364 | /* handles NVME_OPC_NAMESPACE_MANAGEMENT and ATTACHMENT admin cmds */ |
---|
365 | |
---|
366 | struct ns_result_str { |
---|
367 | uint16_t res; |
---|
368 | const char * str; |
---|
369 | }; |
---|
370 | |
---|
371 | static struct ns_result_str ns_result[] = { |
---|
372 | { 0x2, "Invalid Field"}, |
---|
373 | { 0xa, "Invalid Format"}, |
---|
374 | { 0xb, "Invalid Namespace or format"}, |
---|
375 | { 0x15, "Namespace insufficent capacity"}, |
---|
376 | { 0x16, "Namespace ID unavaliable"}, |
---|
377 | { 0x18, "Namespace already attached"}, |
---|
378 | { 0x19, "Namespace is private"}, |
---|
379 | { 0x1a, "Namespace is not attached"}, |
---|
380 | { 0x1b, "Thin provisioning not supported"}, |
---|
381 | { 0x1c, "Controller list invalid"}, |
---|
382 | { 0x24, "ANA Group Identifier Invalid"}, |
---|
383 | { 0x25, "ANA Attach Failed"}, |
---|
384 | { 0xFFFF, "Unknown"} |
---|
385 | }; |
---|
386 | |
---|
387 | static const char * |
---|
388 | get_res_str(uint16_t res) |
---|
389 | { |
---|
390 | struct ns_result_str *t = ns_result; |
---|
391 | |
---|
392 | while (t->res != 0xFFFF) { |
---|
393 | if (t->res == res) |
---|
394 | return (t->str); |
---|
395 | t++; |
---|
396 | } |
---|
397 | return t->str; |
---|
398 | } |
---|
399 | |
---|
400 | static void |
---|
401 | nsactive(const struct cmd *f, int argc, char *argv[]) |
---|
402 | { |
---|
403 | struct nvme_pt_command pt; |
---|
404 | int fd, i; |
---|
405 | uint32_t list[1024]; |
---|
406 | |
---|
407 | if (arg_parse(argc, argv, f)) |
---|
408 | return; |
---|
409 | open_dev(active_opt.dev, &fd, 1, 1); |
---|
410 | |
---|
411 | memset(&pt, 0, sizeof(pt)); |
---|
412 | pt.cmd.opc = NVME_OPC_IDENTIFY; |
---|
413 | pt.cmd.nsid = htole32(0); |
---|
414 | pt.cmd.cdw10 = htole32(0x02); |
---|
415 | pt.buf = list; |
---|
416 | pt.len = sizeof(list); |
---|
417 | pt.is_read = 1; |
---|
418 | if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) |
---|
419 | err(1, "identify request failed"); |
---|
420 | if (nvme_completion_is_error(&pt.cpl)) |
---|
421 | errx(1, "identify request returned error"); |
---|
422 | |
---|
423 | printf("Active namespaces:\n"); |
---|
424 | for (i = 0; list[i] != 0; i++) |
---|
425 | printf("%10d\n", le32toh(list[i])); |
---|
426 | |
---|
427 | exit(0); |
---|
428 | } |
---|
429 | |
---|
430 | static void |
---|
431 | nsallocated(const struct cmd *f, int argc, char *argv[]) |
---|
432 | { |
---|
433 | struct nvme_pt_command pt; |
---|
434 | struct nvme_controller_data cd; |
---|
435 | int fd, i; |
---|
436 | uint32_t list[1024]; |
---|
437 | |
---|
438 | if (arg_parse(argc, argv, f)) |
---|
439 | return; |
---|
440 | open_dev(active_opt.dev, &fd, 1, 1); |
---|
441 | read_controller_data(fd, &cd); |
---|
442 | |
---|
443 | /* Check that controller can execute this command. */ |
---|
444 | if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) & |
---|
445 | NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0) |
---|
446 | errx(1, "controller does not support namespace management"); |
---|
447 | |
---|
448 | memset(&pt, 0, sizeof(pt)); |
---|
449 | pt.cmd.opc = NVME_OPC_IDENTIFY; |
---|
450 | pt.cmd.nsid = htole32(0); |
---|
451 | pt.cmd.cdw10 = htole32(0x10); |
---|
452 | pt.buf = list; |
---|
453 | pt.len = sizeof(list); |
---|
454 | pt.is_read = 1; |
---|
455 | if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) |
---|
456 | err(1, "identify request failed"); |
---|
457 | if (nvme_completion_is_error(&pt.cpl)) |
---|
458 | errx(1, "identify request returned error"); |
---|
459 | |
---|
460 | printf("Allocated namespaces:\n"); |
---|
461 | for (i = 0; list[i] != 0; i++) |
---|
462 | printf("%10d\n", le32toh(list[i])); |
---|
463 | |
---|
464 | exit(0); |
---|
465 | } |
---|
466 | |
---|
467 | static void |
---|
468 | nscontrollers(const struct cmd *f, int argc, char *argv[]) |
---|
469 | { |
---|
470 | struct nvme_pt_command pt; |
---|
471 | struct nvme_controller_data cd; |
---|
472 | int fd, i, n; |
---|
473 | uint16_t clist[2048]; |
---|
474 | |
---|
475 | if (arg_parse(argc, argv, f)) |
---|
476 | return; |
---|
477 | open_dev(controllers_opt.dev, &fd, 1, 1); |
---|
478 | read_controller_data(fd, &cd); |
---|
479 | |
---|
480 | /* Check that controller can execute this command. */ |
---|
481 | if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) & |
---|
482 | NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0) |
---|
483 | errx(1, "controller does not support namespace management"); |
---|
484 | |
---|
485 | memset(&pt, 0, sizeof(pt)); |
---|
486 | pt.cmd.opc = NVME_OPC_IDENTIFY; |
---|
487 | pt.cmd.cdw10 = htole32(0x13); |
---|
488 | pt.buf = clist; |
---|
489 | pt.len = sizeof(clist); |
---|
490 | pt.is_read = 1; |
---|
491 | if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) |
---|
492 | err(1, "identify request failed"); |
---|
493 | if (nvme_completion_is_error(&pt.cpl)) |
---|
494 | errx(1, "identify request returned error"); |
---|
495 | |
---|
496 | n = le16toh(clist[0]); |
---|
497 | printf("NVM subsystem includes %d controller(s):\n", n); |
---|
498 | for (i = 0; i < n; i++) |
---|
499 | printf(" 0x%04x\n", le16toh(clist[i + 1])); |
---|
500 | |
---|
501 | exit(0); |
---|
502 | } |
---|
503 | |
---|
504 | /* |
---|
505 | * NS MGMT Command specific status values: |
---|
506 | * 0xa = Invalid Format |
---|
507 | * 0x15 = Namespace Insuffience capacity |
---|
508 | * 0x16 = Namespace ID unavailable (number namespaces exceeded) |
---|
509 | * 0xb = Thin Provisioning Not supported |
---|
510 | */ |
---|
511 | static void |
---|
512 | nscreate(const struct cmd *f, int argc, char *argv[]) |
---|
513 | { |
---|
514 | struct nvme_pt_command pt; |
---|
515 | struct nvme_controller_data cd; |
---|
516 | struct nvme_namespace_data nsdata; |
---|
517 | int fd, result; |
---|
518 | |
---|
519 | if (arg_parse(argc, argv, f)) |
---|
520 | return; |
---|
521 | |
---|
522 | if (create_opt.cap == NONE64) |
---|
523 | create_opt.cap = create_opt.nsze; |
---|
524 | if (create_opt.nsze == NONE64) { |
---|
525 | fprintf(stderr, |
---|
526 | "Size not specified\n"); |
---|
527 | arg_help(argc, argv, f); |
---|
528 | } |
---|
529 | |
---|
530 | open_dev(create_opt.dev, &fd, 1, 1); |
---|
531 | read_controller_data(fd, &cd); |
---|
532 | |
---|
533 | /* Check that controller can execute this command. */ |
---|
534 | if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) & |
---|
535 | NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0) |
---|
536 | errx(1, "controller does not support namespace management"); |
---|
537 | |
---|
538 | /* Allow namespaces sharing if Multi-Path I/O is supported. */ |
---|
539 | if (create_opt.nmic == NONE) { |
---|
540 | create_opt.nmic = cd.mic ? (NVME_NS_DATA_NMIC_MAY_BE_SHARED_MASK << |
---|
541 | NVME_NS_DATA_NMIC_MAY_BE_SHARED_SHIFT) : 0; |
---|
542 | } |
---|
543 | |
---|
544 | memset(&nsdata, 0, sizeof(nsdata)); |
---|
545 | nsdata.nsze = create_opt.nsze; |
---|
546 | nsdata.ncap = create_opt.cap; |
---|
547 | if (create_opt.flbas == NONE) |
---|
548 | nsdata.flbas = ((create_opt.lbaf & NVME_NS_DATA_FLBAS_FORMAT_MASK) |
---|
549 | << NVME_NS_DATA_FLBAS_FORMAT_SHIFT) | |
---|
550 | ((create_opt.mset & NVME_NS_DATA_FLBAS_EXTENDED_MASK) |
---|
551 | << NVME_NS_DATA_FLBAS_EXTENDED_SHIFT); |
---|
552 | else |
---|
553 | nsdata.flbas = create_opt.flbas; |
---|
554 | if (create_opt.dps == NONE) |
---|
555 | nsdata.dps = ((create_opt.pi & NVME_NS_DATA_DPS_MD_START_MASK) |
---|
556 | << NVME_NS_DATA_DPS_MD_START_SHIFT) | |
---|
557 | ((create_opt.pil & NVME_NS_DATA_DPS_PIT_MASK) |
---|
558 | << NVME_NS_DATA_DPS_PIT_SHIFT); |
---|
559 | else |
---|
560 | nsdata.dps = create_opt.dps; |
---|
561 | nsdata.nmic = create_opt.nmic; |
---|
562 | nvme_namespace_data_swapbytes(&nsdata); |
---|
563 | |
---|
564 | memset(&pt, 0, sizeof(pt)); |
---|
565 | pt.cmd.opc = NVME_OPC_NAMESPACE_MANAGEMENT; |
---|
566 | pt.cmd.cdw10 = htole32(0); /* create */ |
---|
567 | pt.buf = &nsdata; |
---|
568 | pt.len = sizeof(struct nvme_namespace_data); |
---|
569 | pt.is_read = 0; /* passthrough writes data to ctrlr */ |
---|
570 | if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0) |
---|
571 | errx(1, "ioctl request to %s failed: %d", argv[optind], result); |
---|
572 | |
---|
573 | if (nvme_completion_is_error(&pt.cpl)) { |
---|
574 | errx(1, "namespace creation failed: %s", |
---|
575 | get_res_str((pt.cpl.status >> NVME_STATUS_SC_SHIFT) & |
---|
576 | NVME_STATUS_SC_MASK)); |
---|
577 | } |
---|
578 | printf("namespace %d created\n", pt.cpl.cdw0); |
---|
579 | exit(0); |
---|
580 | } |
---|
581 | |
---|
582 | static void |
---|
583 | nsdelete(const struct cmd *f, int argc, char *argv[]) |
---|
584 | { |
---|
585 | struct nvme_pt_command pt; |
---|
586 | struct nvme_controller_data cd; |
---|
587 | int fd, result; |
---|
588 | char buf[2]; |
---|
589 | |
---|
590 | if (arg_parse(argc, argv, f)) |
---|
591 | return; |
---|
592 | if (delete_opt.nsid == NONE) { |
---|
593 | fprintf(stderr, |
---|
594 | "No NSID specified"); |
---|
595 | arg_help(argc, argv, f); |
---|
596 | } |
---|
597 | |
---|
598 | open_dev(delete_opt.dev, &fd, 1, 1); |
---|
599 | read_controller_data(fd, &cd); |
---|
600 | |
---|
601 | /* Check that controller can execute this command. */ |
---|
602 | if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) & |
---|
603 | NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0) |
---|
604 | errx(1, "controller does not support namespace management"); |
---|
605 | |
---|
606 | memset(&pt, 0, sizeof(pt)); |
---|
607 | pt.cmd.opc = NVME_OPC_NAMESPACE_MANAGEMENT; |
---|
608 | pt.cmd.cdw10 = htole32(1); /* delete */ |
---|
609 | pt.buf = buf; |
---|
610 | pt.len = sizeof(buf); |
---|
611 | pt.is_read = 1; |
---|
612 | pt.cmd.nsid = delete_opt.nsid; |
---|
613 | |
---|
614 | if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0) |
---|
615 | errx(1, "ioctl request to %s failed: %d", delete_opt.dev, result); |
---|
616 | |
---|
617 | if (nvme_completion_is_error(&pt.cpl)) { |
---|
618 | errx(1, "namespace deletion failed: %s", |
---|
619 | get_res_str((pt.cpl.status >> NVME_STATUS_SC_SHIFT) & |
---|
620 | NVME_STATUS_SC_MASK)); |
---|
621 | } |
---|
622 | printf("namespace %d deleted\n", delete_opt.nsid); |
---|
623 | exit(0); |
---|
624 | } |
---|
625 | |
---|
626 | /* |
---|
627 | * Attach and Detach use Dword 10, and a controller list (section 4.9) |
---|
628 | * This struct is 4096 bytes in size. |
---|
629 | * 0h = attach |
---|
630 | * 1h = detach |
---|
631 | * |
---|
632 | * Result values for both attach/detach: |
---|
633 | * |
---|
634 | * Completion 18h = Already attached |
---|
635 | * 19h = NS is private and already attached to a controller |
---|
636 | * 1Ah = Not attached, request could not be completed |
---|
637 | * 1Ch = Controller list invalid. |
---|
638 | * |
---|
639 | * 0x2 Invalid Field can occur if ctrlrid d.n.e in system. |
---|
640 | */ |
---|
641 | static void |
---|
642 | nsattach(const struct cmd *f, int argc, char *argv[]) |
---|
643 | { |
---|
644 | struct nvme_pt_command pt; |
---|
645 | struct nvme_controller_data cd; |
---|
646 | int fd, result; |
---|
647 | uint16_t clist[2048]; |
---|
648 | |
---|
649 | if (arg_parse(argc, argv, f)) |
---|
650 | return; |
---|
651 | if (attach_opt.nsid == NONE) { |
---|
652 | fprintf(stderr, "No valid NSID specified\n"); |
---|
653 | arg_help(argc, argv, f); |
---|
654 | } |
---|
655 | open_dev(attach_opt.dev, &fd, 1, 1); |
---|
656 | read_controller_data(fd, &cd); |
---|
657 | |
---|
658 | /* Check that controller can execute this command. */ |
---|
659 | if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) & |
---|
660 | NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0) |
---|
661 | errx(1, "controller does not support namespace management"); |
---|
662 | |
---|
663 | if (attach_opt.ctrlrid == NONE) { |
---|
664 | /* Get full list of controllers to attach to. */ |
---|
665 | memset(&pt, 0, sizeof(pt)); |
---|
666 | pt.cmd.opc = NVME_OPC_IDENTIFY; |
---|
667 | pt.cmd.cdw10 = htole32(0x13); |
---|
668 | pt.buf = clist; |
---|
669 | pt.len = sizeof(clist); |
---|
670 | pt.is_read = 1; |
---|
671 | if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) |
---|
672 | err(1, "identify request failed"); |
---|
673 | if (nvme_completion_is_error(&pt.cpl)) |
---|
674 | errx(1, "identify request returned error"); |
---|
675 | } else { |
---|
676 | /* By default attach to this controller. */ |
---|
677 | if (attach_opt.ctrlrid == NONE - 1) |
---|
678 | attach_opt.ctrlrid = cd.ctrlr_id; |
---|
679 | memset(&clist, 0, sizeof(clist)); |
---|
680 | clist[0] = htole16(1); |
---|
681 | clist[1] = htole16(attach_opt.ctrlrid); |
---|
682 | } |
---|
683 | |
---|
684 | memset(&pt, 0, sizeof(pt)); |
---|
685 | pt.cmd.opc = NVME_OPC_NAMESPACE_ATTACHMENT; |
---|
686 | pt.cmd.cdw10 = htole32(0); /* attach */ |
---|
687 | pt.cmd.nsid = attach_opt.nsid; |
---|
688 | pt.buf = &clist; |
---|
689 | pt.len = sizeof(clist); |
---|
690 | |
---|
691 | if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0) |
---|
692 | errx(1, "ioctl request to %s failed: %d", attach_opt.dev, result); |
---|
693 | |
---|
694 | if (nvme_completion_is_error(&pt.cpl)) { |
---|
695 | errx(1, "namespace attach failed: %s", |
---|
696 | get_res_str((pt.cpl.status >> NVME_STATUS_SC_SHIFT) & |
---|
697 | NVME_STATUS_SC_MASK)); |
---|
698 | } |
---|
699 | printf("namespace %d attached\n", attach_opt.nsid); |
---|
700 | exit(0); |
---|
701 | } |
---|
702 | |
---|
703 | static void |
---|
704 | nsdetach(const struct cmd *f, int argc, char *argv[]) |
---|
705 | { |
---|
706 | struct nvme_pt_command pt; |
---|
707 | struct nvme_controller_data cd; |
---|
708 | int fd, result; |
---|
709 | uint16_t clist[2048]; |
---|
710 | |
---|
711 | if (arg_parse(argc, argv, f)) |
---|
712 | return; |
---|
713 | if (detach_opt.nsid == NONE) { |
---|
714 | fprintf(stderr, "No valid NSID specified\n"); |
---|
715 | arg_help(argc, argv, f); |
---|
716 | } |
---|
717 | open_dev(detach_opt.dev, &fd, 1, 1); |
---|
718 | read_controller_data(fd, &cd); |
---|
719 | |
---|
720 | /* Check that controller can execute this command. */ |
---|
721 | if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) & |
---|
722 | NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0) |
---|
723 | errx(1, "controller does not support namespace management"); |
---|
724 | |
---|
725 | if (detach_opt.ctrlrid == NONE) { |
---|
726 | /* Get list of controllers this namespace attached to. */ |
---|
727 | memset(&pt, 0, sizeof(pt)); |
---|
728 | pt.cmd.opc = NVME_OPC_IDENTIFY; |
---|
729 | pt.cmd.nsid = htole32(detach_opt.nsid); |
---|
730 | pt.cmd.cdw10 = htole32(0x12); |
---|
731 | pt.buf = clist; |
---|
732 | pt.len = sizeof(clist); |
---|
733 | pt.is_read = 1; |
---|
734 | if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) |
---|
735 | err(1, "identify request failed"); |
---|
736 | if (nvme_completion_is_error(&pt.cpl)) |
---|
737 | errx(1, "identify request returned error"); |
---|
738 | if (clist[0] == 0) { |
---|
739 | detach_opt.ctrlrid = cd.ctrlr_id; |
---|
740 | memset(&clist, 0, sizeof(clist)); |
---|
741 | clist[0] = htole16(1); |
---|
742 | clist[1] = htole16(detach_opt.ctrlrid); |
---|
743 | } |
---|
744 | } else { |
---|
745 | /* By default detach from this controller. */ |
---|
746 | if (detach_opt.ctrlrid == NONE - 1) |
---|
747 | detach_opt.ctrlrid = cd.ctrlr_id; |
---|
748 | memset(&clist, 0, sizeof(clist)); |
---|
749 | clist[0] = htole16(1); |
---|
750 | clist[1] = htole16(detach_opt.ctrlrid); |
---|
751 | } |
---|
752 | |
---|
753 | memset(&pt, 0, sizeof(pt)); |
---|
754 | pt.cmd.opc = NVME_OPC_NAMESPACE_ATTACHMENT; |
---|
755 | pt.cmd.cdw10 = htole32(1); /* detach */ |
---|
756 | pt.cmd.nsid = detach_opt.nsid; |
---|
757 | pt.buf = &clist; |
---|
758 | pt.len = sizeof(clist); |
---|
759 | |
---|
760 | if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0) |
---|
761 | errx(1, "ioctl request to %s failed: %d", argv[optind], result); |
---|
762 | |
---|
763 | if (nvme_completion_is_error(&pt.cpl)) { |
---|
764 | errx(1, "namespace detach failed: %s", |
---|
765 | get_res_str((pt.cpl.status >> NVME_STATUS_SC_SHIFT) & |
---|
766 | NVME_STATUS_SC_MASK)); |
---|
767 | } |
---|
768 | printf("namespace %d detached\n", detach_opt.nsid); |
---|
769 | exit(0); |
---|
770 | } |
---|
771 | |
---|
772 | static void |
---|
773 | nsattached(const struct cmd *f, int argc, char *argv[]) |
---|
774 | { |
---|
775 | struct nvme_pt_command pt; |
---|
776 | struct nvme_controller_data cd; |
---|
777 | int fd, i, n; |
---|
778 | uint16_t clist[2048]; |
---|
779 | |
---|
780 | if (arg_parse(argc, argv, f)) |
---|
781 | return; |
---|
782 | if (attached_opt.nsid == NONE) { |
---|
783 | fprintf(stderr, "No valid NSID specified\n"); |
---|
784 | arg_help(argc, argv, f); |
---|
785 | } |
---|
786 | open_dev(attached_opt.dev, &fd, 1, 1); |
---|
787 | read_controller_data(fd, &cd); |
---|
788 | |
---|
789 | /* Check that controller can execute this command. */ |
---|
790 | if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) & |
---|
791 | NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0) |
---|
792 | errx(1, "controller does not support namespace management"); |
---|
793 | |
---|
794 | memset(&pt, 0, sizeof(pt)); |
---|
795 | pt.cmd.opc = NVME_OPC_IDENTIFY; |
---|
796 | pt.cmd.nsid = htole32(attached_opt.nsid); |
---|
797 | pt.cmd.cdw10 = htole32(0x12); |
---|
798 | pt.buf = clist; |
---|
799 | pt.len = sizeof(clist); |
---|
800 | pt.is_read = 1; |
---|
801 | if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) |
---|
802 | err(1, "identify request failed"); |
---|
803 | if (nvme_completion_is_error(&pt.cpl)) |
---|
804 | errx(1, "identify request returned error"); |
---|
805 | |
---|
806 | n = le16toh(clist[0]); |
---|
807 | printf("Attached %d controller(s):\n", n); |
---|
808 | for (i = 0; i < n; i++) |
---|
809 | printf(" 0x%04x\n", le16toh(clist[i + 1])); |
---|
810 | |
---|
811 | exit(0); |
---|
812 | } |
---|
813 | |
---|
814 | static void |
---|
815 | nsidentify(const struct cmd *f, int argc, char *argv[]) |
---|
816 | { |
---|
817 | struct nvme_pt_command pt; |
---|
818 | struct nvme_controller_data cd; |
---|
819 | struct nvme_namespace_data nsdata; |
---|
820 | uint8_t *data; |
---|
821 | int fd; |
---|
822 | u_int i; |
---|
823 | |
---|
824 | if (arg_parse(argc, argv, f)) |
---|
825 | return; |
---|
826 | if (identify_opt.nsid == NONE) { |
---|
827 | fprintf(stderr, "No valid NSID specified\n"); |
---|
828 | arg_help(argc, argv, f); |
---|
829 | } |
---|
830 | open_dev(identify_opt.dev, &fd, 1, 1); |
---|
831 | read_controller_data(fd, &cd); |
---|
832 | |
---|
833 | /* Check that controller can execute this command. */ |
---|
834 | if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) & |
---|
835 | NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0) |
---|
836 | errx(1, "controller does not support namespace management"); |
---|
837 | |
---|
838 | memset(&pt, 0, sizeof(pt)); |
---|
839 | pt.cmd.opc = NVME_OPC_IDENTIFY; |
---|
840 | pt.cmd.nsid = htole32(identify_opt.nsid); |
---|
841 | pt.cmd.cdw10 = htole32(0x11); |
---|
842 | pt.buf = &nsdata; |
---|
843 | pt.len = sizeof(nsdata); |
---|
844 | pt.is_read = 1; |
---|
845 | |
---|
846 | if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) |
---|
847 | err(1, "identify request failed"); |
---|
848 | |
---|
849 | if (nvme_completion_is_error(&pt.cpl)) |
---|
850 | errx(1, "identify request returned error"); |
---|
851 | |
---|
852 | close(fd); |
---|
853 | |
---|
854 | data = (uint8_t *)&nsdata; |
---|
855 | for (i = 0; i < sizeof(nsdata); i++) { |
---|
856 | if (data[i] != 0) |
---|
857 | break; |
---|
858 | } |
---|
859 | if (i == sizeof(nsdata)) |
---|
860 | errx(1, "namespace %d is not allocated", identify_opt.nsid); |
---|
861 | |
---|
862 | /* Convert data to host endian */ |
---|
863 | nvme_namespace_data_swapbytes(&nsdata); |
---|
864 | |
---|
865 | if (identify_opt.hex) { |
---|
866 | i = sizeof(struct nvme_namespace_data); |
---|
867 | if (!identify_opt.verbose) { |
---|
868 | for (; i > 384; i--) { |
---|
869 | if (data[i - 1] != 0) |
---|
870 | break; |
---|
871 | } |
---|
872 | } |
---|
873 | print_hex(&nsdata, i); |
---|
874 | exit(0); |
---|
875 | } |
---|
876 | |
---|
877 | print_namespace(&nsdata); |
---|
878 | exit(0); |
---|
879 | } |
---|
880 | |
---|
881 | static void |
---|
882 | ns(const struct cmd *nf __unused, int argc, char *argv[]) |
---|
883 | { |
---|
884 | |
---|
885 | cmd_dispatch(argc, argv, &ns_cmd); |
---|
886 | } |
---|