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