1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2017 Netflix, Inc 5 * Copyright (C) 2018 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 <stdio.h> 38 #include <stdlib.h> 39 #include <string.h> 40 #include <unistd.h> 41 42 #include "nvmecontrol.h" 43 44 /* handles NVME_OPC_NAMESPACE_MANAGEMENT and ATTACHMENT admin cmds */ 45 46 #define NSCREATE_USAGE \ 47 " nvmecontrol ns create -s size [-c cap] [-f fmt] [-m mset] [-n nmic] [-p pi] [-l pil] nvmeN\n" 48 49 #define NSDELETE_USAGE \ 50 " nvmecontrol ns delete -n nsid nvmeN\n" 51 52 #define NSATTACH_USAGE \ 53 " nvmecontrol ns attach -n nsid [-c ctrlrid] nvmeN \n" 54 55 #define NSDETACH_USAGE \ 56 " nvmecontrol ns detach -n nsid [-c ctrlrid] nvmeN\n" 57 58 void nscreate(int argc, char *argv[]); 59 void nsdelete(int argc, char *argv[]); 60 void nsattach(int argc, char *argv[]); 61 void nsdetach(int argc, char *argv[]); 62 63 static struct nvme_function ns_funcs[] = { 64 {"create", nscreate, NSCREATE_USAGE}, 65 {"delete", nsdelete, NSDELETE_USAGE}, 66 {"attach", nsattach, NSATTACH_USAGE}, 67 {"detach", nsdetach, NSDETACH_USAGE}, 68 {NULL, NULL, NULL}, 69 }; 70 71 static void 72 nscreate_usage(void) 73 { 74 fprintf(stderr, "usage:\n"); 75 fprintf(stderr, NSCREATE_USAGE); 76 exit(1); 77 } 78 79 static void 80 nsdelete_usage(void) 81 { 82 fprintf(stderr, "usage:\n"); 83 fprintf(stderr, NSDELETE_USAGE); 84 exit(1); 85 } 86 87 static void 88 nsattach_usage(void) 89 { 90 fprintf(stderr, "usage:\n"); 91 fprintf(stderr, NSATTACH_USAGE); 92 exit(1); 93 } 94 95 static void 96 nsdetach_usage(void) 97 { 98 fprintf(stderr, "usage:\n"); 99 fprintf(stderr, NSDETACH_USAGE); 100 exit(1); 101 } 102 103 struct ns_result_str { 104 uint16_t res; 105 const char * str; 106 }; 107 108 static struct ns_result_str ns_result[] = { 109 { 0x2, "Invalid Field"}, 110 { 0xa, "Invalid Format"}, 111 { 0xb, "Invalid Namespace or format"}, 112 { 0x15, "Namespace insufficent capacity"}, 113 { 0x16, "Namespace ID unavaliable"}, 114 { 0x18, "Namespace already attached"}, 115 { 0x19, "Namespace is private"}, 116 { 0x1a, "Namespace is not attached"}, 117 { 0x1b, "Thin provisioning not supported"}, 118 { 0x1c, "Controller list invalid"}, 119 { 0xFFFF, "Unknown"} 120 }; 121 122 static const char * 123 get_res_str(uint16_t res) 124 { 125 struct ns_result_str *t = ns_result; 126 127 while (t->res != 0xFFFF) { 128 if (t->res == res) 129 return (t->str); 130 t++; 131 } 132 return t->str; 133 } 134 135 /* 136 * NS MGMT Command specific status values: 137 * 0xa = Invalid Format 138 * 0x15 = Namespace Insuffience capacity 139 * 0x16 = Namespace ID unavailable (number namespaces exceeded) 140 * 0xb = Thin Provisioning Not supported 141 */ 142 void 143 nscreate(int argc, char *argv[]) 144 { 145 struct nvme_pt_command pt; 146 struct nvme_controller_data cd; 147 struct nvme_namespace_data nsdata; 148 int64_t nsze = -1, cap = -1; 149 int ch, fd, result, lbaf = 0, mset = 0, nmic = -1, pi = 0, pil = 0; 150 151 if (optind >= argc) 152 nscreate_usage(); 153 154 while ((ch = getopt(argc, argv, "s:c:f:m:n:p:l:")) != -1) { 155 switch (ch) { 156 case 's': 157 nsze = strtol(optarg, (char **)NULL, 0); 158 break; 159 case 'c': 160 cap = strtol(optarg, (char **)NULL, 0); 161 break; 162 case 'f': 163 lbaf = strtol(optarg, (char **)NULL, 0); 164 break; 165 case 'm': 166 mset = strtol(optarg, NULL, 0); 167 break; 168 case 'n': 169 nmic = strtol(optarg, NULL, 0); 170 break; 171 case 'p': 172 pi = strtol(optarg, NULL, 0); 173 break; 174 case 'l': 175 pil = strtol(optarg, NULL, 0); 176 break; 177 default: 178 nscreate_usage(); 179 } 180 } 181 182 if (optind >= argc) 183 nscreate_usage(); 184 185 if (cap == -1) 186 cap = nsze; 187 if (nsze == -1 || cap == -1) 188 nscreate_usage(); 189 190 open_dev(argv[optind], &fd, 1, 1); 191 read_controller_data(fd, &cd); 192 193 /* Check that controller can execute this command. */ 194 if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) & 195 NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0) 196 errx(1, "controller does not support namespace management"); 197 198 /* Allow namespaces sharing if Multi-Path I/O is supported. */ 199 if (nmic == -1) { 200 nmic = cd.mic ? (NVME_NS_DATA_NMIC_MAY_BE_SHARED_MASK << 201 NVME_NS_DATA_NMIC_MAY_BE_SHARED_SHIFT) : 0; 202 } 203 204 memset(&nsdata, 0, sizeof(nsdata)); 205 nsdata.nsze = (uint64_t)nsze; 206 nsdata.ncap = (uint64_t)cap; 207 nsdata.flbas = ((lbaf & NVME_NS_DATA_FLBAS_FORMAT_MASK) 208 << NVME_NS_DATA_FLBAS_FORMAT_SHIFT) | 209 ((mset & NVME_NS_DATA_FLBAS_EXTENDED_MASK) 210 << NVME_NS_DATA_FLBAS_EXTENDED_SHIFT); 211 nsdata.dps = ((pi & NVME_NS_DATA_DPS_MD_START_MASK) 212 << NVME_NS_DATA_DPS_MD_START_SHIFT) | 213 ((pil & NVME_NS_DATA_DPS_PIT_MASK) 214 << NVME_NS_DATA_DPS_PIT_SHIFT); 215 nsdata.nmic = nmic; 216 nvme_namespace_data_swapbytes(&nsdata); 217 218 memset(&pt, 0, sizeof(pt)); 219 pt.cmd.opc = NVME_OPC_NAMESPACE_MANAGEMENT; 220 221 pt.cmd.cdw10 = 0; /* create */ 222 pt.buf = &nsdata; 223 pt.len = sizeof(struct nvme_namespace_data); 224 pt.is_read = 0; /* passthrough writes data to ctrlr */ 225 if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0) 226 errx(1, "ioctl request to %s failed: %d", argv[optind], result); 227 228 if (nvme_completion_is_error(&pt.cpl)) { 229 errx(1, "namespace creation failed: %s", 230 get_res_str((pt.cpl.status >> NVME_STATUS_SC_SHIFT) & 231 NVME_STATUS_SC_MASK)); 232 } 233 printf("namespace %d created\n", pt.cpl.cdw0); 234 exit(0); 235 } 236 237 void 238 nsdelete(int argc, char *argv[]) 239 { 240 struct nvme_pt_command pt; 241 struct nvme_controller_data cd; 242 int ch, fd, result, nsid = -2; 243 char buf[2]; 244 245 if (optind >= argc) 246 nsdelete_usage(); 247 248 while ((ch = getopt(argc, argv, "n:")) != -1) { 249 switch ((char)ch) { 250 case 'n': 251 nsid = strtol(optarg, (char **)NULL, 0); 252 break; 253 default: 254 nsdelete_usage(); 255 } 256 } 257 258 if (optind >= argc || nsid == -2) 259 nsdelete_usage(); 260 261 open_dev(argv[optind], &fd, 1, 1); 262 read_controller_data(fd, &cd); 263 264 /* Check that controller can execute this command. */ 265 if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) & 266 NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0) 267 errx(1, "controller does not support namespace management"); 268 269 memset(&pt, 0, sizeof(pt)); 270 pt.cmd.opc = NVME_OPC_NAMESPACE_MANAGEMENT; 271 pt.cmd.cdw10 = 1; /* delete */ 272 pt.buf = buf; 273 pt.len = sizeof(buf); 274 pt.is_read = 1; 275 pt.cmd.nsid = (uint32_t)nsid; 276 277 if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0) 278 errx(1, "ioctl request to %s failed: %d", argv[optind], result); 279 280 if (nvme_completion_is_error(&pt.cpl)) { 281 errx(1, "namespace deletion failed: %s", 282 get_res_str((pt.cpl.status >> NVME_STATUS_SC_SHIFT) & 283 NVME_STATUS_SC_MASK)); 284 } 285 printf("namespace %d deleted\n", nsid); 286 exit(0); 287 } 288 289 /* 290 * Attach and Detach use Dword 10, and a controller list (section 4.9) 291 * This struct is 4096 bytes in size. 292 * 0h = attach 293 * 1h = detach 294 * 295 * Result values for both attach/detach: 296 * 297 * Completion 18h = Already attached 298 * 19h = NS is private and already attached to a controller 299 * 1Ah = Not attached, request could not be completed 300 * 1Ch = Controller list invalid. 301 * 302 * 0x2 Invalid Field can occur if ctrlrid d.n.e in system. 303 */ 304 void 305 nsattach(int argc, char *argv[]) 306 { 307 struct nvme_pt_command pt; 308 struct nvme_controller_data cd; 309 int ctrlrid = -2; 310 int fd, ch, result, nsid = -1; 311 uint16_t clist[2048]; 312 313 if (optind >= argc) 314 nsattach_usage(); 315 316 while ((ch = getopt(argc, argv, "n:c:")) != -1) { 317 switch (ch) { 318 case 'n': 319 nsid = strtol(optarg, (char **)NULL, 0); 320 break; 321 case 'c': 322 ctrlrid = strtol(optarg, (char **)NULL, 0); 323 break; 324 default: 325 nsattach_usage(); 326 } 327 } 328 329 if (optind >= argc) 330 nsattach_usage(); 331 332 if (nsid == -1 ) 333 nsattach_usage(); 334 335 open_dev(argv[optind], &fd, 1, 1); 336 read_controller_data(fd, &cd); 337 338 /* Check that controller can execute this command. */ 339 if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) & 340 NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0) 341 errx(1, "controller does not support namespace management"); 342 343 if (ctrlrid == -1) { 344 /* Get full list of controllers to attach to. */ 345 memset(&pt, 0, sizeof(pt)); 346 pt.cmd.opc = NVME_OPC_IDENTIFY; 347 pt.cmd.cdw10 = htole32(0x13); 348 pt.buf = clist; 349 pt.len = sizeof(clist); 350 pt.is_read = 1; 351 if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) 352 err(1, "identify request failed"); 353 if (nvme_completion_is_error(&pt.cpl)) 354 errx(1, "identify request returned error"); 355 } else { 356 /* By default attach to this controller. */ 357 if (ctrlrid == -2) 358 ctrlrid = cd.ctrlr_id; 359 memset(&clist, 0, sizeof(clist)); 360 clist[0] = htole16(1); 361 clist[1] = htole16(ctrlrid); 362 } 363 364 memset(&pt, 0, sizeof(pt)); 365 pt.cmd.opc = NVME_OPC_NAMESPACE_ATTACHMENT; 366 pt.cmd.cdw10 = 0; /* attach */ 367 pt.cmd.nsid = (uint32_t)nsid; 368 pt.buf = &clist; 369 pt.len = sizeof(clist); 370 371 if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0) 372 errx(1, "ioctl request to %s failed: %d", argv[optind], result); 373 374 if (nvme_completion_is_error(&pt.cpl)) { 375 errx(1, "namespace attach failed: %s", 376 get_res_str((pt.cpl.status >> NVME_STATUS_SC_SHIFT) & 377 NVME_STATUS_SC_MASK)); 378 } 379 printf("namespace %d attached\n", nsid); 380 exit(0); 381 } 382 383 void 384 nsdetach(int argc, char *argv[]) 385 { 386 struct nvme_pt_command pt; 387 struct nvme_controller_data cd; 388 int ctrlrid = -2; 389 int fd, ch, result, nsid = -1; 390 uint16_t clist[2048]; 391 392 if (optind >= argc) 393 nsdetach_usage(); 394 395 while ((ch = getopt(argc, argv, "n:c:")) != -1) { 396 switch (ch) { 397 case 'n': 398 nsid = strtol(optarg, (char **)NULL, 0); 399 break; 400 case 'c': 401 ctrlrid = strtol(optarg, (char **)NULL, 0); 402 break; 403 default: 404 nsdetach_usage(); 405 } 406 } 407 408 if (optind >= argc) 409 nsdetach_usage(); 410 411 if (nsid == -1) 412 nsdetach_usage(); 413 414 open_dev(argv[optind], &fd, 1, 1); 415 read_controller_data(fd, &cd); 416 417 /* Check that controller can execute this command. */ 418 if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) & 419 NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0) 420 errx(1, "controller does not support namespace management"); 421 422 if (ctrlrid == -1) { 423 /* Get list of controllers this namespace attached to. */ 424 memset(&pt, 0, sizeof(pt)); 425 pt.cmd.opc = NVME_OPC_IDENTIFY; 426 pt.cmd.nsid = htole32(nsid); 427 pt.cmd.cdw10 = htole32(0x12); 428 pt.buf = clist; 429 pt.len = sizeof(clist); 430 pt.is_read = 1; 431 if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) 432 err(1, "identify request failed"); 433 if (nvme_completion_is_error(&pt.cpl)) 434 errx(1, "identify request returned error"); 435 if (clist[0] == 0) { 436 ctrlrid = cd.ctrlr_id; 437 memset(&clist, 0, sizeof(clist)); 438 clist[0] = htole16(1); 439 clist[1] = htole16(ctrlrid); 440 } 441 } else { 442 /* By default detach from this controller. */ 443 if (ctrlrid == -2) 444 ctrlrid = cd.ctrlr_id; 445 memset(&clist, 0, sizeof(clist)); 446 clist[0] = htole16(1); 447 clist[1] = htole16(ctrlrid); 448 } 449 450 memset(&pt, 0, sizeof(pt)); 451 pt.cmd.opc = NVME_OPC_NAMESPACE_ATTACHMENT; 452 pt.cmd.cdw10 = 1; /* detach */ 453 pt.cmd.nsid = (uint32_t)nsid; 454 pt.buf = &clist; 455 pt.len = sizeof(clist); 456 457 if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0) 458 errx(1, "ioctl request to %s failed: %d", argv[optind], result); 459 460 if (nvme_completion_is_error(&pt.cpl)) { 461 errx(1, "namespace detach failed: %s", 462 get_res_str((pt.cpl.status >> NVME_STATUS_SC_SHIFT) & 463 NVME_STATUS_SC_MASK)); 464 } 465 printf("namespace %d detached\n", nsid); 466 exit(0); 467 } 468 469 void 470 ns(int argc, char *argv[]) 471 { 472 473 dispatch(argc, argv, ns_funcs); 474 } 475