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