]> git.proxmox.com Git - ceph.git/blame - ceph/src/spdk/examples/nvme/nvme_manage/nvme_manage.c
update download target update for octopus release
[ceph.git] / ceph / src / spdk / examples / nvme / nvme_manage / nvme_manage.c
CommitLineData
7c673cae
FG
1/*-
2 * BSD LICENSE
3 *
4 * Copyright (c) Intel Corporation.
5 * All rights reserved.
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 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * * Neither the name of Intel Corporation nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
11fdf7f2 34#include "spdk/stdinc.h"
7c673cae
FG
35
36#include "spdk/nvme.h"
37#include "spdk/env.h"
38#include "spdk/util.h"
39
40#define MAX_DEVS 64
41
42struct dev {
43 struct spdk_pci_addr pci_addr;
11fdf7f2 44 struct spdk_nvme_ctrlr *ctrlr;
7c673cae
FG
45 const struct spdk_nvme_ctrlr_data *cdata;
46 struct spdk_nvme_ns_data *common_ns_data;
47 int outstanding_admin_cmds;
48};
49
50static struct dev devs[MAX_DEVS];
51static int num_devs = 0;
11fdf7f2 52static int g_shm_id = -1;
7c673cae
FG
53
54#define foreach_dev(iter) \
55 for (iter = devs; iter - devs < num_devs; iter++)
56
57enum controller_display_model {
58 CONTROLLER_DISPLAY_ALL = 0x0,
59 CONTROLLER_DISPLAY_SIMPLISTIC = 0x1,
60};
61
62static int
63cmp_devs(const void *ap, const void *bp)
64{
65 const struct dev *a = ap, *b = bp;
66
67 return spdk_pci_addr_compare(&a->pci_addr, &b->pci_addr);
68}
69
70static bool
71probe_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
72 struct spdk_nvme_ctrlr_opts *opts)
73{
74 return true;
75}
76
77static void
78identify_common_ns_cb(void *cb_arg, const struct spdk_nvme_cpl *cpl)
79{
80 struct dev *dev = cb_arg;
81
82 if (cpl->status.sc != SPDK_NVME_SC_SUCCESS) {
83 /* Identify Namespace for NSID = FFFFFFFFh is optional, so failure is not fatal. */
11fdf7f2 84 spdk_dma_free(dev->common_ns_data);
7c673cae
FG
85 dev->common_ns_data = NULL;
86 }
87
88 dev->outstanding_admin_cmds--;
89}
90
91static void
92attach_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
93 struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_ctrlr_opts *opts)
94{
95 struct dev *dev;
96 struct spdk_nvme_cmd cmd;
97
98 /* add to dev list */
99 dev = &devs[num_devs++];
100 spdk_pci_addr_parse(&dev->pci_addr, trid->traddr);
101 dev->ctrlr = ctrlr;
102
103 /* Retrieve controller data */
104 dev->cdata = spdk_nvme_ctrlr_get_data(dev->ctrlr);
105
11fdf7f2 106 dev->common_ns_data = spdk_dma_zmalloc(sizeof(struct spdk_nvme_ns_data), 4096, NULL);
7c673cae
FG
107 if (dev->common_ns_data == NULL) {
108 fprintf(stderr, "common_ns_data allocation failure\n");
109 return;
110 }
111
112 /* Identify Namespace with NSID set to FFFFFFFFh to get common namespace capabilities. */
113 memset(&cmd, 0, sizeof(cmd));
114 cmd.opc = SPDK_NVME_OPC_IDENTIFY;
115 cmd.cdw10 = 0; /* CNS = 0 (Identify Namespace) */
116 cmd.nsid = SPDK_NVME_GLOBAL_NS_TAG;
117
118 dev->outstanding_admin_cmds++;
119 if (spdk_nvme_ctrlr_cmd_admin_raw(ctrlr, &cmd, dev->common_ns_data,
120 sizeof(struct spdk_nvme_ns_data), identify_common_ns_cb, dev) != 0) {
121 dev->outstanding_admin_cmds--;
11fdf7f2 122 spdk_dma_free(dev->common_ns_data);
7c673cae
FG
123 dev->common_ns_data = NULL;
124 }
125
126 while (dev->outstanding_admin_cmds) {
127 spdk_nvme_ctrlr_process_admin_completions(ctrlr);
128 }
129}
130
131static void usage(void)
132{
133 printf("NVMe Management Options");
134 printf("\n");
135 printf("\t[1: list controllers]\n");
136 printf("\t[2: create namespace]\n");
137 printf("\t[3: delete namespace]\n");
138 printf("\t[4: attach namespace to controller]\n");
139 printf("\t[5: detach namespace from controller]\n");
140 printf("\t[6: format namespace or controller]\n");
141 printf("\t[7: firmware update]\n");
142 printf("\t[8: quit]\n");
143}
144
145static void
146display_namespace_dpc(const struct spdk_nvme_ns_data *nsdata)
147{
148 if (nsdata->dpc.pit1 || nsdata->dpc.pit2 || nsdata->dpc.pit3) {
149 if (nsdata->dpc.pit1) {
150 printf("PIT1 ");
151 }
152
153 if (nsdata->dpc.pit2) {
154 printf("PIT2 ");
155 }
156
157 if (nsdata->dpc.pit3) {
158 printf("PIT3 ");
159 }
160 } else {
161 printf("Not Supported\n");
162 return;
163 }
164
165 if (nsdata->dpc.md_start && nsdata->dpc.md_end) {
166 printf("Location: Head or Tail\n");
167 } else if (nsdata->dpc.md_start) {
168 printf("Location: Head\n");
169 } else if (nsdata->dpc.md_end) {
170 printf("Location: Tail\n");
171 } else {
172 printf("Not Supported\n");
173 }
174}
175
176static void
177display_namespace(struct spdk_nvme_ns *ns)
178{
179 const struct spdk_nvme_ns_data *nsdata;
180 uint32_t i;
181
182 nsdata = spdk_nvme_ns_get_data(ns);
183
184 printf("Namespace ID:%d\n", spdk_nvme_ns_get_id(ns));
185
186 printf("Size (in LBAs): %lld (%lldM)\n",
187 (long long)nsdata->nsze,
188 (long long)nsdata->nsze / 1024 / 1024);
189 printf("Capacity (in LBAs): %lld (%lldM)\n",
190 (long long)nsdata->ncap,
191 (long long)nsdata->ncap / 1024 / 1024);
192 printf("Utilization (in LBAs): %lld (%lldM)\n",
193 (long long)nsdata->nuse,
194 (long long)nsdata->nuse / 1024 / 1024);
195 printf("Format Progress Indicator: %s\n",
196 nsdata->fpi.fpi_supported ? "Supported" : "Not Supported");
11fdf7f2 197 if (nsdata->fpi.fpi_supported && nsdata->fpi.percentage_remaining) {
7c673cae 198 printf("Formatted Percentage: %d%%\n", 100 - nsdata->fpi.percentage_remaining);
11fdf7f2 199 }
7c673cae
FG
200 printf("Number of LBA Formats: %d\n", nsdata->nlbaf + 1);
201 printf("Current LBA Format: LBA Format #%02d\n",
202 nsdata->flbas.format);
203 for (i = 0; i <= nsdata->nlbaf; i++)
204 printf("LBA Format #%02d: Data Size: %5d Metadata Size: %5d\n",
205 i, 1 << nsdata->lbaf[i].lbads, nsdata->lbaf[i].ms);
206 printf("Data Protection Capabilities:");
207 display_namespace_dpc(nsdata);
208 if (SPDK_NVME_FMT_NVM_PROTECTION_DISABLE == nsdata->dps.pit) {
209 printf("Data Protection Setting: N/A\n");
210 } else {
211 printf("Data Protection Setting: PIT%d Location: %s\n",
212 nsdata->dps.pit, nsdata->dps.md_start ? "Head" : "Tail");
213 }
214 printf("Multipath IO and Sharing: %s\n",
215 nsdata->nmic.can_share ? "Supported" : "Not Supported");
216 printf("\n");
217}
218
219static void
220display_controller(struct dev *dev, int model)
221{
222 struct spdk_nvme_ns *ns;
223 const struct spdk_nvme_ctrlr_data *cdata;
224 uint8_t str[128];
225 uint32_t i;
226
227 cdata = spdk_nvme_ctrlr_get_data(dev->ctrlr);
228
229 if (model == CONTROLLER_DISPLAY_SIMPLISTIC) {
230 printf("%04x:%02x:%02x.%02x ",
231 dev->pci_addr.domain, dev->pci_addr.bus, dev->pci_addr.dev, dev->pci_addr.func);
232 printf("%-40.40s %-20.20s ",
233 cdata->mn, cdata->sn);
234 printf("%5d ", cdata->cntlid);
235 printf("\n");
236 return;
237 }
238
239 printf("=====================================================\n");
240 printf("NVMe Controller: %04x:%02x:%02x.%02x\n",
241 dev->pci_addr.domain, dev->pci_addr.bus, dev->pci_addr.dev, dev->pci_addr.func);
242 printf("============================\n");
243 printf("Controller Capabilities/Features\n");
244 printf("Controller ID: %d\n", cdata->cntlid);
245 snprintf(str, sizeof(cdata->sn) + 1, "%s", cdata->sn);
246 printf("Serial Number: %s\n", str);
247 printf("\n");
248
249 printf("Admin Command Set Attributes\n");
250 printf("============================\n");
251 printf("Namespace Manage And Attach: %s\n",
252 cdata->oacs.ns_manage ? "Supported" : "Not Supported");
253 printf("Namespace Format: %s\n",
254 cdata->oacs.format ? "Supported" : "Not Supported");
255 printf("\n");
256 printf("NVM Command Set Attributes\n");
257 printf("============================\n");
258 if (cdata->fna.format_all_ns) {
259 printf("Namespace format operation applies to all namespaces\n");
260 } else {
261 printf("Namespace format operation applies to per namespace\n");
262 }
263 printf("\n");
264 printf("Namespace Attributes\n");
265 printf("============================\n");
266 for (i = 1; i <= spdk_nvme_ctrlr_get_num_ns(dev->ctrlr); i++) {
267 ns = spdk_nvme_ctrlr_get_ns(dev->ctrlr, i);
268 if (ns == NULL) {
269 continue;
270 }
271 display_namespace(ns);
272 }
273}
274
275static void
276display_controller_list(void)
277{
278 struct dev *iter;
279
280 foreach_dev(iter) {
281 display_controller(iter, CONTROLLER_DISPLAY_ALL);
282 }
283}
284
11fdf7f2
TL
285static char *
286get_line(char *buf, int buf_size, FILE *f)
287{
288 char *ret;
289 size_t len;
290
291 ret = fgets(buf, buf_size, f);
292 if (ret == NULL) {
293 return NULL;
294 }
295
296 len = strlen(buf);
297 if (len > 0 && buf[len - 1] == '\n') {
298 buf[len - 1] = '\0';
299 }
300 return buf;
301}
302
7c673cae
FG
303static struct dev *
304get_controller(void)
305{
306 struct spdk_pci_addr pci_addr;
307 char address[64];
308 char *p;
309 int ch;
310 struct dev *iter;
311
312 memset(address, 0, sizeof(address));
313
314 foreach_dev(iter) {
315 display_controller(iter, CONTROLLER_DISPLAY_SIMPLISTIC);
316 }
317
11fdf7f2 318 printf("Please Input PCI Address(domain:bus:dev.func):\n");
7c673cae
FG
319
320 while ((ch = getchar()) != '\n' && ch != EOF);
11fdf7f2 321 p = get_line(address, 64, stdin);
7c673cae
FG
322 if (p == NULL) {
323 return NULL;
324 }
325
326 while (isspace(*p)) {
327 p++;
328 }
329
330 if (spdk_pci_addr_parse(&pci_addr, p) < 0) {
331 return NULL;
332 }
333
334 foreach_dev(iter) {
335 if (spdk_pci_addr_compare(&pci_addr, &iter->pci_addr) == 0) {
336 return iter;
337 }
338 }
339 return NULL;
340}
341
342static int
343get_lba_format(const struct spdk_nvme_ns_data *ns_data)
344{
345 int lbaf, i;
346
347 printf("\nSupported LBA formats:\n");
348 for (i = 0; i <= ns_data->nlbaf; i++) {
349 printf("%2d: %d data bytes", i, 1 << ns_data->lbaf[i].lbads);
350 if (ns_data->lbaf[i].ms) {
351 printf(" + %d metadata bytes", ns_data->lbaf[i].ms);
352 }
353 printf("\n");
354 }
355
356 printf("Please input LBA format index (0 - %d):\n", ns_data->nlbaf);
357 if (scanf("%d", &lbaf) != 1 || lbaf > ns_data->nlbaf) {
358 return -1;
359 }
360
361 return lbaf;
362}
363
364static void
365identify_allocated_ns_cb(void *cb_arg, const struct spdk_nvme_cpl *cpl)
366{
367 struct dev *dev = cb_arg;
368
369 dev->outstanding_admin_cmds--;
370}
371
372static uint32_t
373get_allocated_nsid(struct dev *dev)
374{
375 uint32_t nsid;
376 size_t i;
377 struct spdk_nvme_ns_list *ns_list;
378 struct spdk_nvme_cmd cmd = {0};
379
11fdf7f2 380 ns_list = spdk_dma_zmalloc(sizeof(*ns_list), 4096, NULL);
7c673cae
FG
381 if (ns_list == NULL) {
382 printf("Allocation error\n");
383 return 0;
384 }
385
386 cmd.opc = SPDK_NVME_OPC_IDENTIFY;
387 cmd.cdw10 = SPDK_NVME_IDENTIFY_ALLOCATED_NS_LIST;
388 cmd.nsid = 0;
389
390 dev->outstanding_admin_cmds++;
391 if (spdk_nvme_ctrlr_cmd_admin_raw(dev->ctrlr, &cmd, ns_list, sizeof(*ns_list),
392 identify_allocated_ns_cb, dev)) {
393 printf("Identify command failed\n");
11fdf7f2 394 spdk_dma_free(ns_list);
7c673cae
FG
395 return 0;
396 }
397
398 while (dev->outstanding_admin_cmds) {
399 spdk_nvme_ctrlr_process_admin_completions(dev->ctrlr);
400 }
401
402 printf("Allocated Namespace IDs:\n");
403 for (i = 0; i < SPDK_COUNTOF(ns_list->ns_list); i++) {
404 if (ns_list->ns_list[i] == 0) {
405 break;
406 }
407 printf("%u\n", ns_list->ns_list[i]);
408 }
409
11fdf7f2 410 spdk_dma_free(ns_list);
7c673cae 411
11fdf7f2 412 printf("Please Input Namespace ID:\n");
7c673cae
FG
413 if (!scanf("%u", &nsid)) {
414 printf("Invalid Namespace ID\n");
415 nsid = 0;
416 }
417
418 return nsid;
419}
420
421static void
422ns_attach(struct dev *device, int attachment_op, int ctrlr_id, int ns_id)
423{
424 int ret = 0;
425 struct spdk_nvme_ctrlr_list *ctrlr_list;
426
11fdf7f2
TL
427 ctrlr_list = spdk_dma_zmalloc(sizeof(struct spdk_nvme_ctrlr_list),
428 4096, NULL);
7c673cae
FG
429 if (ctrlr_list == NULL) {
430 printf("Allocation error (controller list)\n");
431 exit(1);
432 }
433
434 ctrlr_list->ctrlr_count = 1;
435 ctrlr_list->ctrlr_list[0] = ctrlr_id;
436
437 if (attachment_op == SPDK_NVME_NS_CTRLR_ATTACH) {
438 ret = spdk_nvme_ctrlr_attach_ns(device->ctrlr, ns_id, ctrlr_list);
439 } else if (attachment_op == SPDK_NVME_NS_CTRLR_DETACH) {
440 ret = spdk_nvme_ctrlr_detach_ns(device->ctrlr, ns_id, ctrlr_list);
441 }
442
443 if (ret) {
444 fprintf(stdout, "ns attach: Failed\n");
445 }
446
11fdf7f2 447 spdk_dma_free(ctrlr_list);
7c673cae
FG
448}
449
450static void
451ns_manage_add(struct dev *device, uint64_t ns_size, uint64_t ns_capacity, int ns_lbasize,
452 uint8_t ns_dps_type, uint8_t ns_dps_location, uint8_t ns_nmic)
453{
454 uint32_t nsid;
455 struct spdk_nvme_ns_data *ndata;
456
11fdf7f2 457 ndata = spdk_dma_zmalloc(sizeof(struct spdk_nvme_ns_data), 4096, NULL);
7c673cae
FG
458 if (ndata == NULL) {
459 printf("Allocation error (namespace data)\n");
460 exit(1);
461 }
462
463 ndata->nsze = ns_size;
464 ndata->ncap = ns_capacity;
465 ndata->flbas.format = ns_lbasize;
466 if (SPDK_NVME_FMT_NVM_PROTECTION_DISABLE != ns_dps_type) {
467 ndata->dps.pit = ns_dps_type;
468 ndata->dps.md_start = ns_dps_location;
469 }
470 ndata->nmic.can_share = ns_nmic;
471 nsid = spdk_nvme_ctrlr_create_ns(device->ctrlr, ndata);
472 if (nsid == 0) {
473 fprintf(stdout, "ns manage: Failed\n");
474 } else {
475 printf("Created namespace ID %u\n", nsid);
476 }
477
11fdf7f2 478 spdk_dma_free(ndata);
7c673cae
FG
479}
480
481static void
482ns_manage_delete(struct dev *device, int ns_id)
483{
484 int ret = 0;
485
486 ret = spdk_nvme_ctrlr_delete_ns(device->ctrlr, ns_id);
487 if (ret) {
488 fprintf(stdout, "ns manage: Failed\n");
489 return;
490 }
491}
492
493static void
494nvme_manage_format(struct dev *device, int ns_id, int ses, int pi, int pil, int ms, int lbaf)
495{
496 int ret = 0;
497 struct spdk_nvme_format format = {};
498
499 format.lbaf = lbaf;
500 format.ms = ms;
501 format.pi = pi;
502 format.pil = pil;
503 format.ses = ses;
504 ret = spdk_nvme_ctrlr_format(device->ctrlr, ns_id, &format);
505 if (ret) {
506 fprintf(stdout, "nvme format: Failed\n");
507 return;
508 }
509}
510
511static void
512attach_and_detach_ns(int attachment_op)
513{
514 uint32_t nsid;
515 struct dev *ctrlr;
516
517 ctrlr = get_controller();
518 if (ctrlr == NULL) {
519 printf("Invalid controller PCI Address.\n");
520 return;
521 }
522
523 if (!ctrlr->cdata->oacs.ns_manage) {
524 printf("Controller does not support ns management\n");
525 return;
526 }
527
528 nsid = get_allocated_nsid(ctrlr);
529 if (nsid == 0) {
530 printf("Invalid Namespace ID\n");
531 return;
532 }
533
534 ns_attach(ctrlr, attachment_op, ctrlr->cdata->cntlid, nsid);
535}
536
537static void
538add_ns(void)
539{
540 uint64_t ns_size = 0;
541 uint64_t ns_capacity = 0;
542 int ns_lbasize;
11fdf7f2
TL
543 int ns_dps_type = 0;
544 int ns_dps_location = 0;
545 int ns_nmic = 0;
7c673cae
FG
546 struct dev *ctrlr = NULL;
547
548 ctrlr = get_controller();
549 if (ctrlr == NULL) {
550 printf("Invalid controller PCI Address.\n");
551 return;
552 }
553
554 if (!ctrlr->cdata->oacs.ns_manage) {
555 printf("Controller does not support ns management\n");
556 return;
557 }
558
559 if (!ctrlr->common_ns_data) {
560 printf("Controller did not return common namespace capabilities\n");
561 return;
562 }
563
564 ns_lbasize = get_lba_format(ctrlr->common_ns_data);
565 if (ns_lbasize < 0) {
566 printf("Invalid LBA format number\n");
567 return;
568 }
569
11fdf7f2
TL
570 printf("Please Input Namespace Size (in LBAs):\n");
571 if (!scanf("%" SCNu64, &ns_size)) {
7c673cae
FG
572 printf("Invalid Namespace Size\n");
573 while (getchar() != '\n');
574 return;
575 }
576
11fdf7f2
TL
577 printf("Please Input Namespace Capacity (in LBAs):\n");
578 if (!scanf("%" SCNu64, &ns_capacity)) {
7c673cae
FG
579 printf("Invalid Namespace Capacity\n");
580 while (getchar() != '\n');
581 return;
582 }
583
11fdf7f2 584 printf("Please Input Data Protection Type (0 - 3):\n");
7c673cae
FG
585 if (!scanf("%d", &ns_dps_type)) {
586 printf("Invalid Data Protection Type\n");
587 while (getchar() != '\n');
588 return;
589 }
590
591 if (SPDK_NVME_FMT_NVM_PROTECTION_DISABLE != ns_dps_type) {
11fdf7f2 592 printf("Please Input Data Protection Location (1: Head; 0: Tail):\n");
7c673cae
FG
593 if (!scanf("%d", &ns_dps_location)) {
594 printf("Invalid Data Protection Location\n");
595 while (getchar() != '\n');
596 return;
597 }
598 }
599
11fdf7f2 600 printf("Please Input Multi-path IO and Sharing Capabilities (1: Share; 0: Private):\n");
7c673cae
FG
601 if (!scanf("%d", &ns_nmic)) {
602 printf("Invalid Multi-path IO and Sharing Capabilities\n");
603 while (getchar() != '\n');
604 return;
605 }
606
607 ns_manage_add(ctrlr, ns_size, ns_capacity, ns_lbasize,
608 ns_dps_type, ns_dps_location, ns_nmic);
609}
610
611static void
612delete_ns(void)
613{
11fdf7f2 614 int ns_id;
7c673cae
FG
615 struct dev *ctrlr;
616
617 ctrlr = get_controller();
618 if (ctrlr == NULL) {
619 printf("Invalid controller PCI Address.\n");
620 return;
621 }
622
623 if (!ctrlr->cdata->oacs.ns_manage) {
624 printf("Controller does not support ns management\n");
625 return;
626 }
627
11fdf7f2 628 printf("Please Input Namespace ID:\n");
7c673cae
FG
629 if (!scanf("%d", &ns_id)) {
630 printf("Invalid Namespace ID\n");
631 while (getchar() != '\n');
632 return;
633 }
634
635 ns_manage_delete(ctrlr, ns_id);
636}
637
638static void
639format_nvm(void)
640{
11fdf7f2 641 int ns_id;
7c673cae
FG
642 int ses;
643 int pil;
644 int pi;
645 int ms;
646 int lbaf;
647 char option;
648 struct dev *ctrlr;
649 const struct spdk_nvme_ctrlr_data *cdata;
650 struct spdk_nvme_ns *ns;
651 const struct spdk_nvme_ns_data *nsdata;
652
653 ctrlr = get_controller();
654 if (ctrlr == NULL) {
655 printf("Invalid controller PCI BDF.\n");
656 return;
657 }
658
659 cdata = ctrlr->cdata;
660
661 if (!cdata->oacs.format) {
662 printf("Controller does not support Format NVM command\n");
663 return;
664 }
665
666 if (cdata->fna.format_all_ns) {
667 ns_id = SPDK_NVME_GLOBAL_NS_TAG;
668 ns = spdk_nvme_ctrlr_get_ns(ctrlr->ctrlr, 1);
669 } else {
11fdf7f2 670 printf("Please Input Namespace ID (1 - %d):\n", cdata->nn);
7c673cae
FG
671 if (!scanf("%d", &ns_id)) {
672 printf("Invalid Namespace ID\n");
673 while (getchar() != '\n');
674 return;
675 }
676 ns = spdk_nvme_ctrlr_get_ns(ctrlr->ctrlr, ns_id);
677 }
678
679 if (ns == NULL) {
680 printf("Namespace ID %d not found\n", ns_id);
681 while (getchar() != '\n');
682 return;
683 }
684
685 nsdata = spdk_nvme_ns_get_data(ns);
686
11fdf7f2 687 printf("Please Input Secure Erase Setting:\n");
7c673cae
FG
688 printf(" 0: No secure erase operation requested\n");
689 printf(" 1: User data erase\n");
690 if (cdata->fna.crypto_erase_supported) {
691 printf(" 2: Cryptographic erase\n");
692 }
693 if (!scanf("%d", &ses)) {
694 printf("Invalid Secure Erase Setting\n");
695 while (getchar() != '\n');
696 return;
697 }
698
699 lbaf = get_lba_format(nsdata);
700 if (lbaf < 0) {
701 printf("Invalid LBA format number\n");
702 return;
703 }
704
705 if (nsdata->lbaf[lbaf].ms) {
11fdf7f2 706 printf("Please Input Protection Information:\n");
7c673cae
FG
707 printf(" 0: Protection information is not enabled\n");
708 printf(" 1: Protection information is enabled, Type 1\n");
709 printf(" 2: Protection information is enabled, Type 2\n");
710 printf(" 3: Protection information is enabled, Type 3\n");
711 if (!scanf("%d", &pi)) {
712 printf("Invalid protection information\n");
713 while (getchar() != '\n');
714 return;
715 }
716
717 if (pi) {
11fdf7f2 718 printf("Please Input Protection Information Location:\n");
7c673cae
FG
719 printf(" 0: Protection information transferred as the last eight bytes of metadata\n");
720 printf(" 1: Protection information transferred as the first eight bytes of metadata\n");
721 if (!scanf("%d", &pil)) {
722 printf("Invalid protection information location\n");
723 while (getchar() != '\n');
724 return;
725 }
726 } else {
727 pil = 0;
728 }
729
11fdf7f2 730 printf("Please Input Metadata Setting:\n");
7c673cae
FG
731 printf(" 0: Metadata is transferred as part of a separate buffer\n");
732 printf(" 1: Metadata is transferred as part of an extended data LBA\n");
733 if (!scanf("%d", &ms)) {
734 printf("Invalid metadata setting\n");
735 while (getchar() != '\n');
736 return;
737 }
738 } else {
739 ms = 0;
740 pi = 0;
741 pil = 0;
742 }
743
744 printf("Warning: use this utility at your own risk.\n"
745 "This command will format your namespace and all data will be lost.\n"
746 "This command may take several minutes to complete,\n"
747 "so do not interrupt the utility until it completes.\n"
748 "Press 'Y' to continue with the format operation.\n");
749
750 while (getchar() != '\n');
751 if (!scanf("%c", &option)) {
752 printf("Invalid option\n");
753 while (getchar() != '\n');
754 return;
755 }
756
757 if (option == 'y' || option == 'Y') {
758 nvme_manage_format(ctrlr, ns_id, ses, pi, pil, ms, lbaf);
759 } else {
760 printf("NVMe format abort\n");
761 }
762}
763
764static void
765update_firmware_image(void)
766{
767 int rc;
768 int fd = -1;
769 int slot;
770 unsigned int size;
771 struct stat fw_stat;
772 char path[256];
773 void *fw_image;
774 struct dev *ctrlr;
775 const struct spdk_nvme_ctrlr_data *cdata;
11fdf7f2
TL
776 enum spdk_nvme_fw_commit_action commit_action;
777 struct spdk_nvme_status status;
7c673cae
FG
778
779 ctrlr = get_controller();
780 if (ctrlr == NULL) {
781 printf("Invalid controller PCI BDF.\n");
782 return;
783 }
784
785 cdata = ctrlr->cdata;
786
787 if (!cdata->oacs.firmware) {
788 printf("Controller does not support firmware download and commit command\n");
789 return;
790 }
791
792 printf("Please Input The Path Of Firmware Image\n");
793
11fdf7f2 794 if (get_line(path, sizeof(path), stdin) == NULL) {
7c673cae
FG
795 printf("Invalid path setting\n");
796 while (getchar() != '\n');
797 return;
798 }
799
800 fd = open(path, O_RDONLY);
801 if (fd < 0) {
802 perror("Open file failed");
803 return;
804 }
805 rc = fstat(fd, &fw_stat);
806 if (rc < 0) {
807 printf("Fstat failed\n");
808 close(fd);
809 return;
810 }
811
812 if (fw_stat.st_size % 4) {
813 printf("Firmware image size is not multiple of 4\n");
814 close(fd);
815 return;
816 }
817
818 size = fw_stat.st_size;
819
11fdf7f2 820 fw_image = spdk_dma_zmalloc(size, 4096, NULL);
7c673cae
FG
821 if (fw_image == NULL) {
822 printf("Allocation error\n");
823 close(fd);
824 return;
825 }
826
827 if (read(fd, fw_image, size) != ((ssize_t)(size))) {
828 printf("Read firmware image failed\n");
829 close(fd);
11fdf7f2 830 spdk_dma_free(fw_image);
7c673cae
FG
831 return;
832 }
833 close(fd);
834
11fdf7f2 835 printf("Please Input Slot(0 - 7):\n");
7c673cae
FG
836 if (!scanf("%d", &slot)) {
837 printf("Invalid Slot\n");
11fdf7f2 838 spdk_dma_free(fw_image);
7c673cae
FG
839 while (getchar() != '\n');
840 return;
841 }
842
11fdf7f2
TL
843 commit_action = SPDK_NVME_FW_COMMIT_REPLACE_AND_ENABLE_IMG;
844 rc = spdk_nvme_ctrlr_update_firmware(ctrlr->ctrlr, fw_image, size, slot, commit_action, &status);
845 if (rc == -ENXIO && status.sct == SPDK_NVME_SCT_COMMAND_SPECIFIC &&
846 status.sc == SPDK_NVME_SC_FIRMWARE_REQ_CONVENTIONAL_RESET) {
847 printf("conventional reset is needed to enable firmware !\n");
848 } else if (rc) {
7c673cae
FG
849 printf("spdk_nvme_ctrlr_update_firmware failed\n");
850 } else {
851 printf("spdk_nvme_ctrlr_update_firmware success\n");
852 }
11fdf7f2
TL
853 spdk_dma_free(fw_image);
854}
855
856static void
857args_usage(const char *program_name)
858{
859 printf("%s [options]", program_name);
860 printf("\n");
861 printf("options:\n");
862 printf(" -i shared memory group ID\n");
863}
864
865static int
866parse_args(int argc, char **argv)
867{
868 int op;
869
870 while ((op = getopt(argc, argv, "i:")) != -1) {
871 switch (op) {
872 case 'i':
873 g_shm_id = atoi(optarg);
874 break;
875 default:
876 args_usage(argv[0]);
877 return 1;
878 }
879 }
880
881 return 0;
7c673cae
FG
882}
883
884int main(int argc, char **argv)
885{
11fdf7f2 886 int i, rc;
7c673cae
FG
887 struct spdk_env_opts opts;
888
11fdf7f2
TL
889 rc = parse_args(argc, argv);
890 if (rc != 0) {
891 return rc;
892 }
893
7c673cae
FG
894 spdk_env_opts_init(&opts);
895 opts.name = "nvme_manage";
896 opts.core_mask = "0x1";
11fdf7f2
TL
897 opts.shm_id = g_shm_id;
898 if (spdk_env_init(&opts) < 0) {
899 fprintf(stderr, "Unable to initialize SPDK env\n");
900 return 1;
901 }
7c673cae
FG
902
903 if (spdk_nvme_probe(NULL, NULL, probe_cb, attach_cb, NULL) != 0) {
904 fprintf(stderr, "spdk_nvme_probe() failed\n");
905 return 1;
906 }
907
908 qsort(devs, num_devs, sizeof(devs[0]), cmp_devs);
909
910 usage();
911
912 while (1) {
913 int cmd;
914 bool exit_flag = false;
915
916 if (!scanf("%d", &cmd)) {
11fdf7f2 917 printf("Invalid Command: command must be number 1-8\n");
7c673cae 918 while (getchar() != '\n');
11fdf7f2
TL
919 usage();
920 continue;
7c673cae
FG
921 }
922 switch (cmd) {
923 case 1:
924 display_controller_list();
925 break;
926 case 2:
927 add_ns();
928 break;
929 case 3:
930 delete_ns();
931 break;
932 case 4:
933 attach_and_detach_ns(SPDK_NVME_NS_CTRLR_ATTACH);
934 break;
935 case 5:
936 attach_and_detach_ns(SPDK_NVME_NS_CTRLR_DETACH);
937 break;
938 case 6:
939 format_nvm();
940 break;
941 case 7:
942 update_firmware_image();
943 break;
944 case 8:
945 exit_flag = true;
946 break;
947 default:
948 printf("Invalid Command\n");
949 break;
950 }
951
11fdf7f2 952 if (exit_flag) {
7c673cae 953 break;
11fdf7f2 954 }
7c673cae
FG
955
956 while (getchar() != '\n');
957 printf("press Enter to display cmd menu ...\n");
958 while (getchar() != '\n');
959 usage();
960 }
961
962 printf("Cleaning up...\n");
963
964 for (i = 0; i < num_devs; i++) {
965 struct dev *dev = &devs[i];
966 spdk_nvme_detach(dev->ctrlr);
967 }
968
969 return 0;
970}