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