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