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 (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) & 420 NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0) 421 errx(EX_UNAVAILABLE, "controller does not support namespace management"); 422 423 memset(&pt, 0, sizeof(pt)); 424 pt.cmd.opc = NVME_OPC_IDENTIFY; 425 pt.cmd.nsid = htole32(0); 426 pt.cmd.cdw10 = htole32(0x02); 427 pt.buf = list; 428 pt.len = sizeof(list); 429 pt.is_read = 1; 430 if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) 431 err(EX_IOERR, "identify request failed"); 432 if (nvme_completion_is_error(&pt.cpl)) 433 errx(EX_IOERR, "identify request returned error"); 434 435 printf("Active namespaces:\n"); 436 for (i = 0; list[i] != 0; i++) 437 printf("%10d\n", le32toh(list[i])); 438 439 exit(0); 440 } 441 442 static void 443 nsallocated(const struct cmd *f, int argc, char *argv[]) 444 { 445 struct nvme_pt_command pt; 446 struct nvme_controller_data cd; 447 int fd, i; 448 char *path; 449 uint32_t nsid; 450 uint32_t list[1024]; 451 452 if (arg_parse(argc, argv, f)) 453 return; 454 open_dev(active_opt.dev, &fd, 0, 1); 455 get_nsid(fd, &path, &nsid); 456 if (nsid != 0) { 457 close(fd); 458 open_dev(path, &fd, 0, 1); 459 } 460 free(path); 461 if (read_controller_data(fd, &cd)) 462 errx(EX_IOERR, "Identify request failed"); 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(EX_UNAVAILABLE, "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(EX_IOERR, "identify request failed"); 478 if (nvme_completion_is_error(&pt.cpl)) 479 errx(EX_IOERR, "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 if (read_controller_data(fd, &cd)) 508 errx(EX_IOERR, "Identify request failed"); 509 510 /* Check that controller can execute this command. */ 511 if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) & 512 NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0) 513 errx(EX_UNAVAILABLE, "controller does not support namespace management"); 514 515 memset(&pt, 0, sizeof(pt)); 516 pt.cmd.opc = NVME_OPC_IDENTIFY; 517 pt.cmd.cdw10 = htole32(0x13); 518 pt.buf = clist; 519 pt.len = sizeof(clist); 520 pt.is_read = 1; 521 if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) 522 err(EX_IOERR, "identify request failed"); 523 if (nvme_completion_is_error(&pt.cpl)) 524 errx(EX_IOERR, "identify request returned error"); 525 526 n = le16toh(clist[0]); 527 printf("NVM subsystem includes %d controller(s):\n", n); 528 for (i = 0; i < n; i++) 529 printf(" 0x%04x\n", le16toh(clist[i + 1])); 530 531 exit(0); 532 } 533 534 /* 535 * NS MGMT Command specific status values: 536 * 0xa = Invalid Format 537 * 0x15 = Namespace Insuffience capacity 538 * 0x16 = Namespace ID unavailable (number namespaces exceeded) 539 * 0xb = Thin Provisioning Not supported 540 */ 541 static void 542 nscreate(const struct cmd *f, int argc, char *argv[]) 543 { 544 struct nvme_pt_command pt; 545 struct nvme_controller_data cd; 546 struct nvme_namespace_data nsdata; 547 int fd, result; 548 char *path; 549 uint32_t nsid; 550 551 if (arg_parse(argc, argv, f)) 552 return; 553 554 if (create_opt.cap == NONE64) 555 create_opt.cap = create_opt.nsze; 556 if (create_opt.nsze == NONE64) { 557 fprintf(stderr, 558 "Size not specified\n"); 559 arg_help(argc, argv, f); 560 } 561 562 open_dev(create_opt.dev, &fd, 1, 1); 563 get_nsid(fd, &path, &nsid); 564 if (nsid != 0) { 565 close(fd); 566 open_dev(path, &fd, 1, 1); 567 } 568 free(path); 569 if (read_controller_data(fd, &cd)) 570 errx(EX_IOERR, "Identify request failed"); 571 572 /* Check that controller can execute this command. */ 573 if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) & 574 NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0) 575 errx(EX_UNAVAILABLE, "controller does not support namespace management"); 576 577 memset(&nsdata, 0, sizeof(nsdata)); 578 nsdata.nsze = create_opt.nsze; 579 nsdata.ncap = create_opt.cap; 580 if (create_opt.flbas != NONE) { 581 nsdata.flbas = create_opt.flbas; 582 } else { 583 /* Default to the first format, whatever it is. */ 584 nsdata.flbas = 0; 585 if (create_opt.lbaf != NONE) { 586 nsdata.flbas |= (create_opt.lbaf & 587 NVME_NS_DATA_FLBAS_FORMAT_MASK) 588 << NVME_NS_DATA_FLBAS_FORMAT_SHIFT; 589 } 590 if (create_opt.mset != NONE) { 591 nsdata.flbas |= (create_opt.mset & 592 NVME_NS_DATA_FLBAS_EXTENDED_MASK) 593 << NVME_NS_DATA_FLBAS_EXTENDED_SHIFT; 594 } 595 } 596 if (create_opt.dps != NONE) { 597 nsdata.dps = create_opt.dps; 598 } else { 599 /* Default to protection disabled. */ 600 nsdata.dps = 0; 601 if (create_opt.pi != NONE) { 602 nsdata.dps |= (create_opt.pi & 603 NVME_NS_DATA_DPS_MD_START_MASK) 604 << NVME_NS_DATA_DPS_MD_START_SHIFT; 605 } 606 if (create_opt.pil != NONE) { 607 nsdata.dps |= (create_opt.pil & 608 NVME_NS_DATA_DPS_PIT_MASK) 609 << NVME_NS_DATA_DPS_PIT_SHIFT; 610 } 611 } 612 if (create_opt.nmic != NONE) { 613 nsdata.nmic = create_opt.nmic; 614 } else { 615 /* Allow namespaces sharing if Multi-Path I/O is supported. */ 616 nsdata.nmic = cd.mic ? (NVME_NS_DATA_NMIC_MAY_BE_SHARED_MASK << 617 NVME_NS_DATA_NMIC_MAY_BE_SHARED_SHIFT) : 0; 618 } 619 nvme_namespace_data_swapbytes(&nsdata); 620 621 memset(&pt, 0, sizeof(pt)); 622 pt.cmd.opc = NVME_OPC_NAMESPACE_MANAGEMENT; 623 pt.cmd.cdw10 = htole32(0); /* create */ 624 pt.buf = &nsdata; 625 pt.len = sizeof(struct nvme_namespace_data); 626 pt.is_read = 0; /* passthrough writes data to ctrlr */ 627 if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0) 628 errx(EX_IOERR, "ioctl request to %s failed: %d", create_opt.dev, result); 629 630 if (nvme_completion_is_error(&pt.cpl)) { 631 errx(EX_IOERR, "namespace creation failed: %s", 632 get_res_str((pt.cpl.status >> NVME_STATUS_SC_SHIFT) & 633 NVME_STATUS_SC_MASK)); 634 } 635 printf("namespace %d created\n", pt.cpl.cdw0); 636 exit(0); 637 } 638 639 static void 640 nsdelete(const struct cmd *f, int argc, char *argv[]) 641 { 642 struct nvme_pt_command pt; 643 struct nvme_controller_data cd; 644 int fd, result; 645 char *path; 646 uint32_t nsid; 647 char buf[2]; 648 649 if (arg_parse(argc, argv, f)) 650 return; 651 652 open_dev(delete_opt.dev, &fd, 1, 1); 653 get_nsid(fd, &path, &nsid); 654 if (nsid != 0) { 655 close(fd); 656 open_dev(path, &fd, 1, 1); 657 } else if (delete_opt.nsid == NONE - 1) { 658 close(fd); 659 fprintf(stderr, "No NSID specified"); 660 arg_help(argc, argv, f); 661 } 662 if (delete_opt.nsid != NONE - 1) 663 nsid = delete_opt.nsid; 664 free(path); 665 if (read_controller_data(fd, &cd)) 666 errx(EX_IOERR, "Identify request failed"); 667 668 /* Check that controller can execute this command. */ 669 if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) & 670 NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0) 671 errx(EX_UNAVAILABLE, "controller does not support namespace management"); 672 673 memset(&pt, 0, sizeof(pt)); 674 pt.cmd.opc = NVME_OPC_NAMESPACE_MANAGEMENT; 675 pt.cmd.cdw10 = htole32(1); /* delete */ 676 pt.buf = buf; 677 pt.len = sizeof(buf); 678 pt.is_read = 1; 679 pt.cmd.nsid = nsid; 680 681 if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0) 682 errx(EX_IOERR, "ioctl request to %s failed: %d", delete_opt.dev, result); 683 684 if (nvme_completion_is_error(&pt.cpl)) { 685 errx(EX_IOERR, "namespace deletion failed: %s", 686 get_res_str((pt.cpl.status >> NVME_STATUS_SC_SHIFT) & 687 NVME_STATUS_SC_MASK)); 688 } 689 printf("namespace %d deleted\n", nsid); 690 exit(0); 691 } 692 693 /* 694 * Attach and Detach use Dword 10, and a controller list (section 4.9) 695 * This struct is 4096 bytes in size. 696 * 0h = attach 697 * 1h = detach 698 * 699 * Result values for both attach/detach: 700 * 701 * Completion 18h = Already attached 702 * 19h = NS is private and already attached to a controller 703 * 1Ah = Not attached, request could not be completed 704 * 1Ch = Controller list invalid. 705 * 706 * 0x2 Invalid Field can occur if ctrlrid d.n.e in system. 707 */ 708 static void 709 nsattach(const struct cmd *f, int argc, char *argv[]) 710 { 711 struct nvme_pt_command pt; 712 struct nvme_controller_data cd; 713 int fd, result; 714 char *path; 715 uint32_t nsid; 716 uint16_t clist[2048]; 717 718 if (arg_parse(argc, argv, f)) 719 return; 720 open_dev(attach_opt.dev, &fd, 1, 1); 721 get_nsid(fd, &path, &nsid); 722 if (nsid != 0) { 723 close(fd); 724 open_dev(path, &fd, 1, 1); 725 } else if (attach_opt.nsid == NONE) { 726 close(fd); 727 fprintf(stderr, "No NSID specified"); 728 arg_help(argc, argv, f); 729 } 730 if (attach_opt.nsid != NONE) 731 nsid = attach_opt.nsid; 732 if (read_controller_data(fd, &cd)) 733 errx(EX_IOERR, "Identify request failed"); 734 735 /* Check that controller can execute this command. */ 736 if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) & 737 NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0) 738 errx(EX_UNAVAILABLE, "controller does not support namespace management"); 739 740 if (attach_opt.ctrlrid == NONE) { 741 /* Get full list of controllers to attach to. */ 742 memset(&pt, 0, sizeof(pt)); 743 pt.cmd.opc = NVME_OPC_IDENTIFY; 744 pt.cmd.cdw10 = htole32(0x13); 745 pt.buf = clist; 746 pt.len = sizeof(clist); 747 pt.is_read = 1; 748 if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) 749 err(EX_IOERR, "identify request failed"); 750 if (nvme_completion_is_error(&pt.cpl)) 751 errx(EX_IOERR, "identify request returned error"); 752 } else { 753 /* By default attach to this controller. */ 754 if (attach_opt.ctrlrid == NONE - 1) 755 attach_opt.ctrlrid = cd.ctrlr_id; 756 memset(&clist, 0, sizeof(clist)); 757 clist[0] = htole16(1); 758 clist[1] = htole16(attach_opt.ctrlrid); 759 } 760 761 memset(&pt, 0, sizeof(pt)); 762 pt.cmd.opc = NVME_OPC_NAMESPACE_ATTACHMENT; 763 pt.cmd.cdw10 = htole32(0); /* attach */ 764 pt.cmd.nsid = nsid; 765 pt.buf = &clist; 766 pt.len = sizeof(clist); 767 768 if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0) 769 errx(EX_IOERR, "ioctl request to %s failed: %d", attach_opt.dev, result); 770 771 if (nvme_completion_is_error(&pt.cpl)) { 772 errx(EX_IOERR, "namespace attach failed: %s", 773 get_res_str((pt.cpl.status >> NVME_STATUS_SC_SHIFT) & 774 NVME_STATUS_SC_MASK)); 775 } 776 printf("namespace %d attached\n", nsid); 777 exit(0); 778 } 779 780 static void 781 nsdetach(const struct cmd *f, int argc, char *argv[]) 782 { 783 struct nvme_pt_command pt; 784 struct nvme_controller_data cd; 785 int fd, result; 786 char *path; 787 uint32_t nsid; 788 uint16_t clist[2048]; 789 790 if (arg_parse(argc, argv, f)) 791 return; 792 open_dev(detach_opt.dev, &fd, 1, 1); 793 get_nsid(fd, &path, &nsid); 794 if (nsid != 0) { 795 close(fd); 796 open_dev(path, &fd, 1, 1); 797 } else if (detach_opt.nsid == NONE) { 798 close(fd); 799 fprintf(stderr, "No NSID specified"); 800 arg_help(argc, argv, f); 801 } 802 if (detach_opt.nsid != NONE) 803 nsid = detach_opt.nsid; 804 if (read_controller_data(fd, &cd)) 805 errx(EX_IOERR, "Identify request failed"); 806 807 /* Check that controller can execute this command. */ 808 if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) & 809 NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0) 810 errx(EX_UNAVAILABLE, "controller does not support namespace management"); 811 812 if (detach_opt.ctrlrid == NONE) { 813 /* Get list of controllers this namespace attached to. */ 814 memset(&pt, 0, sizeof(pt)); 815 pt.cmd.opc = NVME_OPC_IDENTIFY; 816 pt.cmd.nsid = htole32(nsid); 817 pt.cmd.cdw10 = htole32(0x12); 818 pt.buf = clist; 819 pt.len = sizeof(clist); 820 pt.is_read = 1; 821 if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) 822 err(EX_IOERR, "identify request failed"); 823 if (nvme_completion_is_error(&pt.cpl)) 824 errx(EX_IOERR, "identify request returned error"); 825 if (clist[0] == 0) { 826 detach_opt.ctrlrid = cd.ctrlr_id; 827 memset(&clist, 0, sizeof(clist)); 828 clist[0] = htole16(1); 829 clist[1] = htole16(detach_opt.ctrlrid); 830 } 831 } else { 832 /* By default detach from this controller. */ 833 if (detach_opt.ctrlrid == NONE - 1) 834 detach_opt.ctrlrid = cd.ctrlr_id; 835 memset(&clist, 0, sizeof(clist)); 836 clist[0] = htole16(1); 837 clist[1] = htole16(detach_opt.ctrlrid); 838 } 839 840 memset(&pt, 0, sizeof(pt)); 841 pt.cmd.opc = NVME_OPC_NAMESPACE_ATTACHMENT; 842 pt.cmd.cdw10 = htole32(1); /* detach */ 843 pt.cmd.nsid = nsid; 844 pt.buf = &clist; 845 pt.len = sizeof(clist); 846 847 if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0) 848 errx(EX_IOERR, "ioctl request to %s failed: %d", detach_opt.dev, result); 849 850 if (nvme_completion_is_error(&pt.cpl)) { 851 errx(EX_IOERR, "namespace detach failed: %s", 852 get_res_str((pt.cpl.status >> NVME_STATUS_SC_SHIFT) & 853 NVME_STATUS_SC_MASK)); 854 } 855 printf("namespace %d detached\n", nsid); 856 exit(0); 857 } 858 859 static void 860 nsattached(const struct cmd *f, int argc, char *argv[]) 861 { 862 struct nvme_pt_command pt; 863 struct nvme_controller_data cd; 864 int fd, i, n; 865 char *path; 866 uint32_t nsid; 867 uint16_t clist[2048]; 868 869 if (arg_parse(argc, argv, f)) 870 return; 871 open_dev(attached_opt.dev, &fd, 0, 1); 872 get_nsid(fd, &path, &nsid); 873 if (nsid != 0) { 874 close(fd); 875 open_dev(path, &fd, 1, 1); 876 } else if (attached_opt.nsid == NONE) { 877 close(fd); 878 fprintf(stderr, "No NSID specified"); 879 arg_help(argc, argv, f); 880 } 881 if (attached_opt.nsid != NONE) 882 nsid = attached_opt.nsid; 883 if (read_controller_data(fd, &cd)) 884 errx(EX_IOERR, "Identify request failed"); 885 886 /* Check that controller can execute this command. */ 887 if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) & 888 NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0) 889 errx(EX_UNAVAILABLE, "controller does not support namespace management"); 890 891 memset(&pt, 0, sizeof(pt)); 892 pt.cmd.opc = NVME_OPC_IDENTIFY; 893 pt.cmd.nsid = htole32(nsid); 894 pt.cmd.cdw10 = htole32(0x12); 895 pt.buf = clist; 896 pt.len = sizeof(clist); 897 pt.is_read = 1; 898 if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) 899 err(EX_IOERR, "identify request failed"); 900 if (nvme_completion_is_error(&pt.cpl)) 901 errx(EX_IOERR, "identify request returned error"); 902 903 n = le16toh(clist[0]); 904 printf("Attached %d controller(s):\n", n); 905 for (i = 0; i < n; i++) 906 printf(" 0x%04x\n", le16toh(clist[i + 1])); 907 908 exit(0); 909 } 910 911 static void 912 nsidentify(const struct cmd *f, int argc, char *argv[]) 913 { 914 struct nvme_pt_command pt; 915 struct nvme_controller_data cd; 916 struct nvme_namespace_data nsdata; 917 uint8_t *data; 918 int fd; 919 char *path; 920 uint32_t nsid; 921 u_int i; 922 923 if (arg_parse(argc, argv, f)) 924 return; 925 open_dev(identify_opt.dev, &fd, 0, 1); 926 get_nsid(fd, &path, &nsid); 927 if (nsid != 0) { 928 close(fd); 929 open_dev(path, &fd, 1, 1); 930 } else if (identify_opt.nsid == NONE) { 931 close(fd); 932 fprintf(stderr, "No NSID specified"); 933 arg_help(argc, argv, f); 934 } 935 if (identify_opt.nsid != NONE) 936 nsid = identify_opt.nsid; 937 if (read_controller_data(fd, &cd)) 938 errx(EX_IOERR, "Identify request failed"); 939 940 /* Check that controller can execute this command. */ 941 if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) & 942 NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0) 943 errx(EX_UNAVAILABLE, "controller does not support namespace management"); 944 945 memset(&pt, 0, sizeof(pt)); 946 pt.cmd.opc = NVME_OPC_IDENTIFY; 947 pt.cmd.nsid = htole32(nsid); 948 pt.cmd.cdw10 = htole32(0x11); 949 pt.buf = &nsdata; 950 pt.len = sizeof(nsdata); 951 pt.is_read = 1; 952 953 if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) 954 err(EX_IOERR, "identify request failed"); 955 956 if (nvme_completion_is_error(&pt.cpl)) 957 errx(EX_IOERR, "identify request returned error"); 958 959 close(fd); 960 961 data = (uint8_t *)&nsdata; 962 for (i = 0; i < sizeof(nsdata); i++) { 963 if (data[i] != 0) 964 break; 965 } 966 if (i == sizeof(nsdata)) 967 errx(EX_UNAVAILABLE, "namespace %d is not allocated", nsid); 968 969 /* Convert data to host endian */ 970 nvme_namespace_data_swapbytes(&nsdata); 971 972 if (identify_opt.hex) { 973 i = sizeof(struct nvme_namespace_data); 974 if (!identify_opt.verbose) { 975 for (; i > 384; i--) { 976 if (data[i - 1] != 0) 977 break; 978 } 979 } 980 print_hex(&nsdata, i); 981 exit(0); 982 } 983 984 print_namespace(&nsdata); 985 exit(0); 986 } 987 988 static void 989 ns(const struct cmd *nf __unused, int argc, char *argv[]) 990 { 991 992 cmd_dispatch(argc, argv, &ns_cmd); 993 } 994