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