xref: /spdk/examples/nvme/nvme_manage/nvme_manage.c (revision 57fd99b91e71a4baa5543e19ff83958dc99d4dac)
1488570ebSJim Harris /*   SPDX-License-Identifier: BSD-3-Clause
2a6dbe372Spaul luse  *   Copyright (C) 2016 Intel Corporation.
398416108SCunyin Chang  *   All rights reserved.
498416108SCunyin Chang  */
598416108SCunyin Chang 
6b961d9ccSBen Walker #include "spdk/stdinc.h"
798416108SCunyin Chang 
898416108SCunyin Chang #include "spdk/nvme.h"
90dd80395SBen Walker #include "spdk/env.h"
100f9dc2afSShuhei Matsumoto #include "spdk/string.h"
11b58a5d73SDaniel Verkamp #include "spdk/util.h"
1255f5b205SHui, Chunyang #include "spdk/opal.h"
1398416108SCunyin Chang 
1498416108SCunyin Chang #define MAX_DEVS 64
1598416108SCunyin Chang 
1698416108SCunyin Chang struct dev {
17fcb00f37SDaniel Verkamp 	struct spdk_pci_addr			pci_addr;
1898416108SCunyin Chang 	struct spdk_nvme_ctrlr			*ctrlr;
1998416108SCunyin Chang 	const struct spdk_nvme_ctrlr_data	*cdata;
208f876a61SDaniel Verkamp 	struct spdk_nvme_ns_data		*common_ns_data;
218f876a61SDaniel Verkamp 	int					outstanding_admin_cmds;
2255f5b205SHui, Chunyang 	struct spdk_opal_dev			*opal_dev;
2398416108SCunyin Chang };
2498416108SCunyin Chang 
2598416108SCunyin Chang static struct dev devs[MAX_DEVS];
2698416108SCunyin Chang static int num_devs = 0;
27f07ed6efSGangCao static int g_shm_id = -1;
2898416108SCunyin Chang 
2998416108SCunyin Chang #define foreach_dev(iter) \
3098416108SCunyin Chang 	for (iter = devs; iter - devs < num_devs; iter++)
3198416108SCunyin Chang 
3273b0afa8SCunyin Chang enum controller_display_model {
3373b0afa8SCunyin Chang 	CONTROLLER_DISPLAY_ALL			= 0x0,
3473b0afa8SCunyin Chang 	CONTROLLER_DISPLAY_SIMPLISTIC		= 0x1,
3573b0afa8SCunyin Chang };
3673b0afa8SCunyin Chang 
372e61a144SDaniel Verkamp static int
382e61a144SDaniel Verkamp cmp_devs(const void *ap, const void *bp)
392e61a144SDaniel Verkamp {
402e61a144SDaniel Verkamp 	const struct dev *a = ap, *b = bp;
412e61a144SDaniel Verkamp 
42fcb00f37SDaniel Verkamp 	return spdk_pci_addr_compare(&a->pci_addr, &b->pci_addr);
432e61a144SDaniel Verkamp }
442e61a144SDaniel Verkamp 
4598416108SCunyin Chang static bool
4632e838afSBen Walker probe_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
47fcb00f37SDaniel Verkamp 	 struct spdk_nvme_ctrlr_opts *opts)
4898416108SCunyin Chang {
4998416108SCunyin Chang 	return true;
5098416108SCunyin Chang }
5198416108SCunyin Chang 
5298416108SCunyin Chang static void
538f876a61SDaniel Verkamp identify_common_ns_cb(void *cb_arg, const struct spdk_nvme_cpl *cpl)
548f876a61SDaniel Verkamp {
558f876a61SDaniel Verkamp 	struct dev *dev = cb_arg;
568f876a61SDaniel Verkamp 
578f876a61SDaniel Verkamp 	if (cpl->status.sc != SPDK_NVME_SC_SUCCESS) {
588f876a61SDaniel Verkamp 		/* Identify Namespace for NSID = FFFFFFFFh is optional, so failure is not fatal. */
598a44220bSJohn Meneghini 		spdk_dma_free(dev->common_ns_data);
608f876a61SDaniel Verkamp 		dev->common_ns_data = NULL;
618f876a61SDaniel Verkamp 	}
628f876a61SDaniel Verkamp 
638f876a61SDaniel Verkamp 	dev->outstanding_admin_cmds--;
648f876a61SDaniel Verkamp }
658f876a61SDaniel Verkamp 
668f876a61SDaniel Verkamp static void
6732e838afSBen Walker attach_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
68fcb00f37SDaniel Verkamp 	  struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_ctrlr_opts *opts)
6998416108SCunyin Chang {
7098416108SCunyin Chang 	struct dev *dev;
718f876a61SDaniel Verkamp 	struct spdk_nvme_cmd cmd;
7298416108SCunyin Chang 
7398416108SCunyin Chang 	/* add to dev list */
74592fc6f4SGangCao 	dev = &devs[num_devs];
75592fc6f4SGangCao 	if (spdk_pci_addr_parse(&dev->pci_addr, trid->traddr) != 0) {
76592fc6f4SGangCao 		fprintf(stderr, "spdk_pci_addr_parse failure\n");
77592fc6f4SGangCao 		assert(false);
78592fc6f4SGangCao 		return;
79592fc6f4SGangCao 	}
80592fc6f4SGangCao 	num_devs++;
81592fc6f4SGangCao 
8298416108SCunyin Chang 	dev->ctrlr = ctrlr;
838f876a61SDaniel Verkamp 
848f876a61SDaniel Verkamp 	/* Retrieve controller data */
858f876a61SDaniel Verkamp 	dev->cdata = spdk_nvme_ctrlr_get_data(dev->ctrlr);
868f876a61SDaniel Verkamp 
878a44220bSJohn Meneghini 	dev->common_ns_data = spdk_dma_zmalloc(sizeof(struct spdk_nvme_ns_data), 4096, NULL);
888f876a61SDaniel Verkamp 	if (dev->common_ns_data == NULL) {
898f876a61SDaniel Verkamp 		fprintf(stderr, "common_ns_data allocation failure\n");
908f876a61SDaniel Verkamp 		return;
918f876a61SDaniel Verkamp 	}
928f876a61SDaniel Verkamp 
938f876a61SDaniel Verkamp 	/* Identify Namespace with NSID set to FFFFFFFFh to get common namespace capabilities. */
948f876a61SDaniel Verkamp 	memset(&cmd, 0, sizeof(cmd));
958f876a61SDaniel Verkamp 	cmd.opc = SPDK_NVME_OPC_IDENTIFY;
961fea1fccSChangpeng Liu 	cmd.cdw10_bits.identify.cns = 0; /* CNS = 0 (Identify Namespace) */
978f876a61SDaniel Verkamp 	cmd.nsid = SPDK_NVME_GLOBAL_NS_TAG;
988f876a61SDaniel Verkamp 
998f876a61SDaniel Verkamp 	dev->outstanding_admin_cmds++;
1008f876a61SDaniel Verkamp 	if (spdk_nvme_ctrlr_cmd_admin_raw(ctrlr, &cmd, dev->common_ns_data,
1018f876a61SDaniel Verkamp 					  sizeof(struct spdk_nvme_ns_data), identify_common_ns_cb, dev) != 0) {
1028f876a61SDaniel Verkamp 		dev->outstanding_admin_cmds--;
1038a44220bSJohn Meneghini 		spdk_dma_free(dev->common_ns_data);
1048f876a61SDaniel Verkamp 		dev->common_ns_data = NULL;
1058f876a61SDaniel Verkamp 	}
1068f876a61SDaniel Verkamp 
1078f876a61SDaniel Verkamp 	while (dev->outstanding_admin_cmds) {
1088f876a61SDaniel Verkamp 		spdk_nvme_ctrlr_process_admin_completions(ctrlr);
1098f876a61SDaniel Verkamp 	}
11098416108SCunyin Chang }
11198416108SCunyin Chang 
1128dd1cd21SBen Walker static void
1138dd1cd21SBen Walker usage(void)
11498416108SCunyin Chang {
11598416108SCunyin Chang 	printf("NVMe Management Options");
11698416108SCunyin Chang 	printf("\n");
11798416108SCunyin Chang 	printf("\t[1: list controllers]\n");
11898416108SCunyin Chang 	printf("\t[2: create namespace]\n");
11998416108SCunyin Chang 	printf("\t[3: delete namespace]\n");
12098416108SCunyin Chang 	printf("\t[4: attach namespace to controller]\n");
12198416108SCunyin Chang 	printf("\t[5: detach namespace from controller]\n");
122eae68857SCunyin Chang 	printf("\t[6: format namespace or controller]\n");
1230f805b36SCunyin Chang 	printf("\t[7: firmware update]\n");
1247250ec64SChunyang Hui 	printf("\t[8: opal]\n");
12555f5b205SHui, Chunyang 	printf("\t[9: quit]\n");
12698416108SCunyin Chang }
12798416108SCunyin Chang 
12898416108SCunyin Chang static void
1294e91a0b0SGangCao display_namespace_dpc(const struct spdk_nvme_ns_data *nsdata)
1304e91a0b0SGangCao {
1314e91a0b0SGangCao 	if (nsdata->dpc.pit1 || nsdata->dpc.pit2 || nsdata->dpc.pit3) {
1324e91a0b0SGangCao 		if (nsdata->dpc.pit1) {
1334e91a0b0SGangCao 			printf("PIT1 ");
1344e91a0b0SGangCao 		}
1354e91a0b0SGangCao 
1364e91a0b0SGangCao 		if (nsdata->dpc.pit2) {
1374e91a0b0SGangCao 			printf("PIT2 ");
1384e91a0b0SGangCao 		}
1394e91a0b0SGangCao 
1404e91a0b0SGangCao 		if (nsdata->dpc.pit3) {
1414e91a0b0SGangCao 			printf("PIT3 ");
1424e91a0b0SGangCao 		}
1434e91a0b0SGangCao 	} else {
1444e91a0b0SGangCao 		printf("Not Supported\n");
1454e91a0b0SGangCao 		return;
1464e91a0b0SGangCao 	}
1474e91a0b0SGangCao 
1484e91a0b0SGangCao 	if (nsdata->dpc.md_start && nsdata->dpc.md_end) {
1494e91a0b0SGangCao 		printf("Location: Head or Tail\n");
1504e91a0b0SGangCao 	} else if (nsdata->dpc.md_start) {
1514e91a0b0SGangCao 		printf("Location: Head\n");
1524e91a0b0SGangCao 	} else if (nsdata->dpc.md_end) {
1534e91a0b0SGangCao 		printf("Location: Tail\n");
1544e91a0b0SGangCao 	} else {
1554e91a0b0SGangCao 		printf("Not Supported\n");
1564e91a0b0SGangCao 	}
1574e91a0b0SGangCao }
1584e91a0b0SGangCao 
1594e91a0b0SGangCao static void
16098416108SCunyin Chang display_namespace(struct spdk_nvme_ns *ns)
16198416108SCunyin Chang {
16298416108SCunyin Chang 	const struct spdk_nvme_ns_data		*nsdata;
16398416108SCunyin Chang 	uint32_t				i;
1647bbeb80aSAnkit Kumar 	uint32_t				format_index;
16598416108SCunyin Chang 
16698416108SCunyin Chang 	nsdata = spdk_nvme_ns_get_data(ns);
1677bbeb80aSAnkit Kumar 	format_index = spdk_nvme_ns_get_format_index(nsdata);
16898416108SCunyin Chang 
16998416108SCunyin Chang 	printf("Namespace ID:%d\n", spdk_nvme_ns_get_id(ns));
17098416108SCunyin Chang 
17198416108SCunyin Chang 	printf("Size (in LBAs):              %lld (%lldM)\n",
17298416108SCunyin Chang 	       (long long)nsdata->nsze,
17398416108SCunyin Chang 	       (long long)nsdata->nsze / 1024 / 1024);
17498416108SCunyin Chang 	printf("Capacity (in LBAs):          %lld (%lldM)\n",
17598416108SCunyin Chang 	       (long long)nsdata->ncap,
17698416108SCunyin Chang 	       (long long)nsdata->ncap / 1024 / 1024);
17798416108SCunyin Chang 	printf("Utilization (in LBAs):       %lld (%lldM)\n",
17898416108SCunyin Chang 	       (long long)nsdata->nuse,
17998416108SCunyin Chang 	       (long long)nsdata->nuse / 1024 / 1024);
18030089f89SCunyin Chang 	printf("Format Progress Indicator:   %s\n",
18130089f89SCunyin Chang 	       nsdata->fpi.fpi_supported ? "Supported" : "Not Supported");
18259970a89SDaniel Verkamp 	if (nsdata->fpi.fpi_supported && nsdata->fpi.percentage_remaining) {
18330089f89SCunyin Chang 		printf("Formatted Percentage:	%d%%\n", 100 - nsdata->fpi.percentage_remaining);
18459970a89SDaniel Verkamp 	}
18598416108SCunyin Chang 	printf("Number of LBA Formats:       %d\n", nsdata->nlbaf + 1);
18698416108SCunyin Chang 	printf("Current LBA Format:          LBA Format #%02d\n",
1877bbeb80aSAnkit Kumar 	       format_index);
18898416108SCunyin Chang 	for (i = 0; i <= nsdata->nlbaf; i++)
18998416108SCunyin Chang 		printf("LBA Format #%02d: Data Size: %5d  Metadata Size: %5d\n",
19098416108SCunyin Chang 		       i, 1 << nsdata->lbaf[i].lbads, nsdata->lbaf[i].ms);
1914e91a0b0SGangCao 	printf("Data Protection Capabilities:");
1924e91a0b0SGangCao 	display_namespace_dpc(nsdata);
1934e91a0b0SGangCao 	if (SPDK_NVME_FMT_NVM_PROTECTION_DISABLE == nsdata->dps.pit) {
1944e91a0b0SGangCao 		printf("Data Protection Setting:     N/A\n");
1954e91a0b0SGangCao 	} else {
1964e91a0b0SGangCao 		printf("Data Protection Setting:     PIT%d Location: %s\n",
1974e91a0b0SGangCao 		       nsdata->dps.pit, nsdata->dps.md_start ? "Head" : "Tail");
1984e91a0b0SGangCao 	}
1994e91a0b0SGangCao 	printf("Multipath IO and Sharing:    %s\n",
2004e91a0b0SGangCao 	       nsdata->nmic.can_share ? "Supported" : "Not Supported");
20198416108SCunyin Chang 	printf("\n");
20298416108SCunyin Chang }
20398416108SCunyin Chang 
20498416108SCunyin Chang static void
20573b0afa8SCunyin Chang display_controller(struct dev *dev, int model)
20698416108SCunyin Chang {
2078bab99fbSTomasz Zawadzki 	struct spdk_nvme_ns			*ns;
20898416108SCunyin Chang 	const struct spdk_nvme_ctrlr_data	*cdata;
20998416108SCunyin Chang 	uint8_t					str[128];
210aa09ce09SChunyang Hui 	uint32_t				nsid;
21198416108SCunyin Chang 
21298416108SCunyin Chang 	cdata = spdk_nvme_ctrlr_get_data(dev->ctrlr);
213173b4144SDaniel Verkamp 
214173b4144SDaniel Verkamp 	if (model == CONTROLLER_DISPLAY_SIMPLISTIC) {
215173b4144SDaniel Verkamp 		printf("%04x:%02x:%02x.%02x ",
216fcb00f37SDaniel Verkamp 		       dev->pci_addr.domain, dev->pci_addr.bus, dev->pci_addr.dev, dev->pci_addr.func);
217173b4144SDaniel Verkamp 		printf("%-40.40s %-20.20s ",
218173b4144SDaniel Verkamp 		       cdata->mn, cdata->sn);
219173b4144SDaniel Verkamp 		printf("%5d ", cdata->cntlid);
220173b4144SDaniel Verkamp 		printf("\n");
221173b4144SDaniel Verkamp 		return;
222173b4144SDaniel Verkamp 	}
223173b4144SDaniel Verkamp 
22498416108SCunyin Chang 	printf("=====================================================\n");
22573b0afa8SCunyin Chang 	printf("NVMe Controller:	%04x:%02x:%02x.%02x\n",
226fcb00f37SDaniel Verkamp 	       dev->pci_addr.domain, dev->pci_addr.bus, dev->pci_addr.dev, dev->pci_addr.func);
22773b0afa8SCunyin Chang 	printf("============================\n");
22898416108SCunyin Chang 	printf("Controller Capabilities/Features\n");
22998416108SCunyin Chang 	printf("Controller ID:		%d\n", cdata->cntlid);
23098416108SCunyin Chang 	snprintf(str, sizeof(cdata->sn) + 1, "%s", cdata->sn);
23198416108SCunyin Chang 	printf("Serial Number:		%s\n", str);
23298416108SCunyin Chang 	printf("\n");
233173b4144SDaniel Verkamp 
23498416108SCunyin Chang 	printf("Admin Command Set Attributes\n");
23598416108SCunyin Chang 	printf("============================\n");
23698416108SCunyin Chang 	printf("Namespace Manage And Attach:		%s\n",
23798416108SCunyin Chang 	       cdata->oacs.ns_manage ? "Supported" : "Not Supported");
238eae68857SCunyin Chang 	printf("Namespace Format:			%s\n",
239eae68857SCunyin Chang 	       cdata->oacs.format ? "Supported" : "Not Supported");
240eae68857SCunyin Chang 	printf("\n");
241eae68857SCunyin Chang 	printf("NVM Command Set Attributes\n");
242eae68857SCunyin Chang 	printf("============================\n");
243eae68857SCunyin Chang 	if (cdata->fna.format_all_ns) {
244eae68857SCunyin Chang 		printf("Namespace format operation applies to all namespaces\n");
245eae68857SCunyin Chang 	} else {
246eae68857SCunyin Chang 		printf("Namespace format operation applies to per namespace\n");
247eae68857SCunyin Chang 	}
24898416108SCunyin Chang 	printf("\n");
24998416108SCunyin Chang 	printf("Namespace Attributes\n");
25098416108SCunyin Chang 	printf("============================\n");
251aa09ce09SChunyang Hui 	for (nsid = spdk_nvme_ctrlr_get_first_active_ns(dev->ctrlr);
252aa09ce09SChunyang Hui 	     nsid != 0; nsid = spdk_nvme_ctrlr_get_next_active_ns(dev->ctrlr, nsid)) {
2538bab99fbSTomasz Zawadzki 		ns = spdk_nvme_ctrlr_get_ns(dev->ctrlr, nsid);
2548bab99fbSTomasz Zawadzki 		assert(ns != NULL);
2558bab99fbSTomasz Zawadzki 		display_namespace(ns);
25698416108SCunyin Chang 	}
25798416108SCunyin Chang }
25898416108SCunyin Chang 
25998416108SCunyin Chang static void
26098416108SCunyin Chang display_controller_list(void)
26198416108SCunyin Chang {
26298416108SCunyin Chang 	struct dev			*iter;
26398416108SCunyin Chang 
26498416108SCunyin Chang 	foreach_dev(iter) {
26573b0afa8SCunyin Chang 		display_controller(iter, CONTROLLER_DISPLAY_ALL);
26673b0afa8SCunyin Chang 	}
26773b0afa8SCunyin Chang }
26873b0afa8SCunyin Chang 
26973c9bd29SIsaac Otsiabah static char *
27063133871SChunyang Hui get_line(char *buf, int buf_size, FILE *f, bool secret)
27173c9bd29SIsaac Otsiabah {
27263133871SChunyang Hui 	char *ch;
27373c9bd29SIsaac Otsiabah 	size_t len;
27463133871SChunyang Hui 	struct termios default_attr = {}, new_attr = {};
27563133871SChunyang Hui 	int ret;
27673c9bd29SIsaac Otsiabah 
27763133871SChunyang Hui 	if (secret) {
27863133871SChunyang Hui 		ret = tcgetattr(STDIN_FILENO, &default_attr);
27963133871SChunyang Hui 		if (ret) {
28073c9bd29SIsaac Otsiabah 			return NULL;
28173c9bd29SIsaac Otsiabah 		}
28273c9bd29SIsaac Otsiabah 
28363133871SChunyang Hui 		new_attr = default_attr;
28463133871SChunyang Hui 		new_attr.c_lflag &= ~ECHO;  /* disable echo */
28563133871SChunyang Hui 		ret = tcsetattr(STDIN_FILENO, TCSAFLUSH, &new_attr);
28663133871SChunyang Hui 		if (ret) {
28763133871SChunyang Hui 			return NULL;
28863133871SChunyang Hui 		}
28963133871SChunyang Hui 	}
29063133871SChunyang Hui 
29163133871SChunyang Hui 	ch = fgets(buf, buf_size, f);
29263133871SChunyang Hui 	if (ch == NULL) {
29363133871SChunyang Hui 		return NULL;
29463133871SChunyang Hui 	}
29563133871SChunyang Hui 
29663133871SChunyang Hui 	if (secret) {
29734edd9f1SKamil Godzwon 		ret = tcsetattr(STDIN_FILENO, TCSAFLUSH, &default_attr); /* restore default config */
29863133871SChunyang Hui 		if (ret) {
29963133871SChunyang Hui 			return NULL;
30063133871SChunyang Hui 		}
30163133871SChunyang Hui 	}
30263133871SChunyang Hui 
30373c9bd29SIsaac Otsiabah 	len = strlen(buf);
30473c9bd29SIsaac Otsiabah 	if (len > 0 && buf[len - 1] == '\n') {
30573c9bd29SIsaac Otsiabah 		buf[len - 1] = '\0';
30673c9bd29SIsaac Otsiabah 	}
30773c9bd29SIsaac Otsiabah 	return buf;
30873c9bd29SIsaac Otsiabah }
30973c9bd29SIsaac Otsiabah 
31073b0afa8SCunyin Chang static struct dev *
31173b0afa8SCunyin Chang get_controller(void)
31273b0afa8SCunyin Chang {
31303aa3af0SDaniel Verkamp 	struct spdk_pci_addr			pci_addr;
31473b0afa8SCunyin Chang 	char					address[64];
31573b0afa8SCunyin Chang 	char					*p;
31673b0afa8SCunyin Chang 	int					ch;
31773b0afa8SCunyin Chang 	struct dev				*iter;
31873b0afa8SCunyin Chang 
31973b0afa8SCunyin Chang 	memset(address, 0, sizeof(address));
32073b0afa8SCunyin Chang 
32173b0afa8SCunyin Chang 	foreach_dev(iter) {
32273b0afa8SCunyin Chang 		display_controller(iter, CONTROLLER_DISPLAY_SIMPLISTIC);
32373b0afa8SCunyin Chang 	}
32473b0afa8SCunyin Chang 
32573b0afa8SCunyin Chang 	printf("Please Input PCI Address(domain:bus:dev.func):\n");
32673b0afa8SCunyin Chang 
32773b0afa8SCunyin Chang 	while ((ch = getchar()) != '\n' && ch != EOF);
32863133871SChunyang Hui 	p = get_line(address, 64, stdin, false);
32916986894SDaniel Verkamp 	if (p == NULL) {
33016986894SDaniel Verkamp 		return NULL;
33116986894SDaniel Verkamp 	}
33273b0afa8SCunyin Chang 
33373b0afa8SCunyin Chang 	while (isspace(*p)) {
33473b0afa8SCunyin Chang 		p++;
33573b0afa8SCunyin Chang 	}
33673b0afa8SCunyin Chang 
337bbd7e1c4SDaniel Verkamp 	if (spdk_pci_addr_parse(&pci_addr, p) < 0) {
338e3cabfafSDaniel Verkamp 		return NULL;
339e3cabfafSDaniel Verkamp 	}
340e3cabfafSDaniel Verkamp 
34173b0afa8SCunyin Chang 	foreach_dev(iter) {
342fcb00f37SDaniel Verkamp 		if (spdk_pci_addr_compare(&pci_addr, &iter->pci_addr) == 0) {
34373b0afa8SCunyin Chang 			return iter;
34473b0afa8SCunyin Chang 		}
34573b0afa8SCunyin Chang 	}
34673b0afa8SCunyin Chang 	return NULL;
34773b0afa8SCunyin Chang }
34873b0afa8SCunyin Chang 
3498f876a61SDaniel Verkamp static int
3508f876a61SDaniel Verkamp get_lba_format(const struct spdk_nvme_ns_data *ns_data)
3518f876a61SDaniel Verkamp {
3528f876a61SDaniel Verkamp 	int lbaf, i;
3538f876a61SDaniel Verkamp 
3548f876a61SDaniel Verkamp 	printf("\nSupported LBA formats:\n");
3558f876a61SDaniel Verkamp 	for (i = 0; i <= ns_data->nlbaf; i++) {
3568f876a61SDaniel Verkamp 		printf("%2d: %d data bytes", i, 1 << ns_data->lbaf[i].lbads);
3578f876a61SDaniel Verkamp 		if (ns_data->lbaf[i].ms) {
3588f876a61SDaniel Verkamp 			printf(" + %d metadata bytes", ns_data->lbaf[i].ms);
3598f876a61SDaniel Verkamp 		}
3608f876a61SDaniel Verkamp 		printf("\n");
3618f876a61SDaniel Verkamp 	}
3628f876a61SDaniel Verkamp 
3638f876a61SDaniel Verkamp 	printf("Please input LBA format index (0 - %d):\n", ns_data->nlbaf);
3648f876a61SDaniel Verkamp 	if (scanf("%d", &lbaf) != 1 || lbaf > ns_data->nlbaf) {
3658f876a61SDaniel Verkamp 		return -1;
3668f876a61SDaniel Verkamp 	}
3678f876a61SDaniel Verkamp 
3688f876a61SDaniel Verkamp 	return lbaf;
3698f876a61SDaniel Verkamp }
3708f876a61SDaniel Verkamp 
37173b0afa8SCunyin Chang static void
372fc8d73f8SDaniel Verkamp identify_allocated_ns_cb(void *cb_arg, const struct spdk_nvme_cpl *cpl)
373fc8d73f8SDaniel Verkamp {
374fc8d73f8SDaniel Verkamp 	struct dev *dev = cb_arg;
375fc8d73f8SDaniel Verkamp 
376fc8d73f8SDaniel Verkamp 	dev->outstanding_admin_cmds--;
377fc8d73f8SDaniel Verkamp }
378fc8d73f8SDaniel Verkamp 
379fc8d73f8SDaniel Verkamp static uint32_t
380fc8d73f8SDaniel Verkamp get_allocated_nsid(struct dev *dev)
381fc8d73f8SDaniel Verkamp {
382fc8d73f8SDaniel Verkamp 	uint32_t nsid;
383fc8d73f8SDaniel Verkamp 	size_t i;
384fc8d73f8SDaniel Verkamp 	struct spdk_nvme_ns_list *ns_list;
385fc8d73f8SDaniel Verkamp 	struct spdk_nvme_cmd cmd = {0};
386fc8d73f8SDaniel Verkamp 
3878a44220bSJohn Meneghini 	ns_list = spdk_dma_zmalloc(sizeof(*ns_list), 4096, NULL);
388fc8d73f8SDaniel Verkamp 	if (ns_list == NULL) {
389fc8d73f8SDaniel Verkamp 		printf("Allocation error\n");
390fc8d73f8SDaniel Verkamp 		return 0;
391fc8d73f8SDaniel Verkamp 	}
392fc8d73f8SDaniel Verkamp 
393fc8d73f8SDaniel Verkamp 	cmd.opc = SPDK_NVME_OPC_IDENTIFY;
3941fea1fccSChangpeng Liu 	cmd.cdw10_bits.identify.cns = SPDK_NVME_IDENTIFY_ALLOCATED_NS_LIST;
395fc8d73f8SDaniel Verkamp 	cmd.nsid = 0;
396fc8d73f8SDaniel Verkamp 
397fc8d73f8SDaniel Verkamp 	dev->outstanding_admin_cmds++;
398fc8d73f8SDaniel Verkamp 	if (spdk_nvme_ctrlr_cmd_admin_raw(dev->ctrlr, &cmd, ns_list, sizeof(*ns_list),
399fc8d73f8SDaniel Verkamp 					  identify_allocated_ns_cb, dev)) {
400fc8d73f8SDaniel Verkamp 		printf("Identify command failed\n");
4018a44220bSJohn Meneghini 		spdk_dma_free(ns_list);
402fc8d73f8SDaniel Verkamp 		return 0;
403fc8d73f8SDaniel Verkamp 	}
404fc8d73f8SDaniel Verkamp 
405fc8d73f8SDaniel Verkamp 	while (dev->outstanding_admin_cmds) {
406fc8d73f8SDaniel Verkamp 		spdk_nvme_ctrlr_process_admin_completions(dev->ctrlr);
407fc8d73f8SDaniel Verkamp 	}
408fc8d73f8SDaniel Verkamp 
409fc8d73f8SDaniel Verkamp 	printf("Allocated Namespace IDs:\n");
410b58a5d73SDaniel Verkamp 	for (i = 0; i < SPDK_COUNTOF(ns_list->ns_list); i++) {
411fc8d73f8SDaniel Verkamp 		if (ns_list->ns_list[i] == 0) {
412fc8d73f8SDaniel Verkamp 			break;
413fc8d73f8SDaniel Verkamp 		}
414fc8d73f8SDaniel Verkamp 		printf("%u\n", ns_list->ns_list[i]);
415fc8d73f8SDaniel Verkamp 	}
416fc8d73f8SDaniel Verkamp 
4178a44220bSJohn Meneghini 	spdk_dma_free(ns_list);
418fc8d73f8SDaniel Verkamp 
419fc8d73f8SDaniel Verkamp 	printf("Please Input Namespace ID:\n");
420fc8d73f8SDaniel Verkamp 	if (!scanf("%u", &nsid)) {
421fc8d73f8SDaniel Verkamp 		printf("Invalid Namespace ID\n");
422fc8d73f8SDaniel Verkamp 		nsid = 0;
423fc8d73f8SDaniel Verkamp 	}
424fc8d73f8SDaniel Verkamp 
425fc8d73f8SDaniel Verkamp 	return nsid;
426fc8d73f8SDaniel Verkamp }
427fc8d73f8SDaniel Verkamp 
428fc8d73f8SDaniel Verkamp static void
42973b0afa8SCunyin Chang ns_attach(struct dev *device, int attachment_op, int ctrlr_id, int ns_id)
43073b0afa8SCunyin Chang {
43173b0afa8SCunyin Chang 	int ret = 0;
43273b0afa8SCunyin Chang 	struct spdk_nvme_ctrlr_list *ctrlr_list;
43373b0afa8SCunyin Chang 
4348a44220bSJohn Meneghini 	ctrlr_list = spdk_dma_zmalloc(sizeof(struct spdk_nvme_ctrlr_list),
4352224ff21SBen Walker 				      4096, NULL);
43673b0afa8SCunyin Chang 	if (ctrlr_list == NULL) {
43773b0afa8SCunyin Chang 		printf("Allocation error (controller list)\n");
43873b0afa8SCunyin Chang 		exit(1);
43973b0afa8SCunyin Chang 	}
44073b0afa8SCunyin Chang 
44173b0afa8SCunyin Chang 	ctrlr_list->ctrlr_count = 1;
44273b0afa8SCunyin Chang 	ctrlr_list->ctrlr_list[0] = ctrlr_id;
44373b0afa8SCunyin Chang 
44473b0afa8SCunyin Chang 	if (attachment_op == SPDK_NVME_NS_CTRLR_ATTACH) {
44573b0afa8SCunyin Chang 		ret = spdk_nvme_ctrlr_attach_ns(device->ctrlr, ns_id, ctrlr_list);
44673b0afa8SCunyin Chang 	} else if (attachment_op == SPDK_NVME_NS_CTRLR_DETACH) {
44773b0afa8SCunyin Chang 		ret = spdk_nvme_ctrlr_detach_ns(device->ctrlr, ns_id, ctrlr_list);
44873b0afa8SCunyin Chang 	}
44973b0afa8SCunyin Chang 
45073b0afa8SCunyin Chang 	if (ret) {
45173b0afa8SCunyin Chang 		fprintf(stdout, "ns attach: Failed\n");
45273b0afa8SCunyin Chang 	}
45373b0afa8SCunyin Chang 
4548a44220bSJohn Meneghini 	spdk_dma_free(ctrlr_list);
45573b0afa8SCunyin Chang }
45673b0afa8SCunyin Chang 
45773b0afa8SCunyin Chang static void
4584e91a0b0SGangCao ns_manage_add(struct dev *device, uint64_t ns_size, uint64_t ns_capacity, int ns_lbasize,
4594e91a0b0SGangCao 	      uint8_t ns_dps_type, uint8_t ns_dps_location, uint8_t ns_nmic)
46073b0afa8SCunyin Chang {
4614957d264SDaniel Verkamp 	uint32_t nsid;
46273b0afa8SCunyin Chang 	struct spdk_nvme_ns_data *ndata;
46373b0afa8SCunyin Chang 
4648a44220bSJohn Meneghini 	ndata = spdk_dma_zmalloc(sizeof(struct spdk_nvme_ns_data), 4096, NULL);
46573b0afa8SCunyin Chang 	if (ndata == NULL) {
46673b0afa8SCunyin Chang 		printf("Allocation error (namespace data)\n");
46773b0afa8SCunyin Chang 		exit(1);
46873b0afa8SCunyin Chang 	}
46973b0afa8SCunyin Chang 
47073b0afa8SCunyin Chang 	ndata->nsze = ns_size;
47173b0afa8SCunyin Chang 	ndata->ncap = ns_capacity;
4727bbeb80aSAnkit Kumar 	ndata->flbas.format = ns_lbasize & 0xF;
4737bbeb80aSAnkit Kumar 	ndata->flbas.msb_format = (ns_lbasize >> 4) & 0x3;
4744e91a0b0SGangCao 	if (SPDK_NVME_FMT_NVM_PROTECTION_DISABLE != ns_dps_type) {
4754e91a0b0SGangCao 		ndata->dps.pit = ns_dps_type;
4764e91a0b0SGangCao 		ndata->dps.md_start = ns_dps_location;
4774e91a0b0SGangCao 	}
4784e91a0b0SGangCao 	ndata->nmic.can_share = ns_nmic;
4794957d264SDaniel Verkamp 	nsid = spdk_nvme_ctrlr_create_ns(device->ctrlr, ndata);
4804957d264SDaniel Verkamp 	if (nsid == 0) {
48173b0afa8SCunyin Chang 		fprintf(stdout, "ns manage: Failed\n");
4824957d264SDaniel Verkamp 	} else {
4834957d264SDaniel Verkamp 		printf("Created namespace ID %u\n", nsid);
48473b0afa8SCunyin Chang 	}
48573b0afa8SCunyin Chang 
4868a44220bSJohn Meneghini 	spdk_dma_free(ndata);
48773b0afa8SCunyin Chang }
48873b0afa8SCunyin Chang 
48973b0afa8SCunyin Chang static void
49073b0afa8SCunyin Chang ns_manage_delete(struct dev *device, int ns_id)
49173b0afa8SCunyin Chang {
49273b0afa8SCunyin Chang 	int ret = 0;
49373b0afa8SCunyin Chang 
49473b0afa8SCunyin Chang 	ret = spdk_nvme_ctrlr_delete_ns(device->ctrlr, ns_id);
49573b0afa8SCunyin Chang 	if (ret) {
49673b0afa8SCunyin Chang 		fprintf(stdout, "ns manage: Failed\n");
49773b0afa8SCunyin Chang 		return;
49898416108SCunyin Chang 	}
49998416108SCunyin Chang }
50098416108SCunyin Chang 
50198416108SCunyin Chang static void
502eae68857SCunyin Chang nvme_manage_format(struct dev *device, int ns_id, int ses, int pi, int pil, int ms, int lbaf)
503eae68857SCunyin Chang {
504eae68857SCunyin Chang 	int ret = 0;
505eae68857SCunyin Chang 	struct spdk_nvme_format format = {};
506eae68857SCunyin Chang 
5077bbeb80aSAnkit Kumar 	format.lbaf	= lbaf & 0xF;
508eae68857SCunyin Chang 	format.ms	= ms;
509eae68857SCunyin Chang 	format.pi	= pi;
510eae68857SCunyin Chang 	format.pil	= pil;
511eae68857SCunyin Chang 	format.ses	= ses;
5127bbeb80aSAnkit Kumar 	format.lbafu	= (lbaf >> 4) & 0x3;
513eae68857SCunyin Chang 	ret = spdk_nvme_ctrlr_format(device->ctrlr, ns_id, &format);
514eae68857SCunyin Chang 	if (ret) {
515eae68857SCunyin Chang 		fprintf(stdout, "nvme format: Failed\n");
516eae68857SCunyin Chang 		return;
517eae68857SCunyin Chang 	}
518eae68857SCunyin Chang }
519eae68857SCunyin Chang 
520eae68857SCunyin Chang static void
52198416108SCunyin Chang attach_and_detach_ns(int attachment_op)
52298416108SCunyin Chang {
523fc8d73f8SDaniel Verkamp 	uint32_t	nsid;
52498416108SCunyin Chang 	struct dev	*ctrlr;
52598416108SCunyin Chang 
52698416108SCunyin Chang 	ctrlr = get_controller();
52798416108SCunyin Chang 	if (ctrlr == NULL) {
52873b0afa8SCunyin Chang 		printf("Invalid controller PCI Address.\n");
52998416108SCunyin Chang 		return;
53098416108SCunyin Chang 	}
53198416108SCunyin Chang 
532ce13ccf8SDaniel Verkamp 	if (!ctrlr->cdata->oacs.ns_manage) {
533ce13ccf8SDaniel Verkamp 		printf("Controller does not support ns management\n");
534ce13ccf8SDaniel Verkamp 		return;
535ce13ccf8SDaniel Verkamp 	}
536ce13ccf8SDaniel Verkamp 
537fc8d73f8SDaniel Verkamp 	nsid = get_allocated_nsid(ctrlr);
538fc8d73f8SDaniel Verkamp 	if (nsid == 0) {
53998416108SCunyin Chang 		printf("Invalid Namespace ID\n");
54098416108SCunyin Chang 		return;
54198416108SCunyin Chang 	}
54298416108SCunyin Chang 
543fc8d73f8SDaniel Verkamp 	ns_attach(ctrlr, attachment_op, ctrlr->cdata->cntlid, nsid);
54498416108SCunyin Chang }
54598416108SCunyin Chang 
54698416108SCunyin Chang static void
54798416108SCunyin Chang add_ns(void)
54898416108SCunyin Chang {
5494e91a0b0SGangCao 	uint64_t	ns_size		= 0;
5504e91a0b0SGangCao 	uint64_t	ns_capacity	= 0;
5518f876a61SDaniel Verkamp 	int		ns_lbasize;
5524e91a0b0SGangCao 	int		ns_dps_type	= 0;
5534e91a0b0SGangCao 	int		ns_dps_location	= 0;
5544e91a0b0SGangCao 	int		ns_nmic		= 0;
5554e91a0b0SGangCao 	struct dev	*ctrlr		= NULL;
55698416108SCunyin Chang 
55798416108SCunyin Chang 	ctrlr = get_controller();
55898416108SCunyin Chang 	if (ctrlr == NULL) {
55973b0afa8SCunyin Chang 		printf("Invalid controller PCI Address.\n");
56098416108SCunyin Chang 		return;
56198416108SCunyin Chang 	}
56298416108SCunyin Chang 
563ce13ccf8SDaniel Verkamp 	if (!ctrlr->cdata->oacs.ns_manage) {
564ce13ccf8SDaniel Verkamp 		printf("Controller does not support ns management\n");
565ce13ccf8SDaniel Verkamp 		return;
566ce13ccf8SDaniel Verkamp 	}
567ce13ccf8SDaniel Verkamp 
5688f876a61SDaniel Verkamp 	if (!ctrlr->common_ns_data) {
5698f876a61SDaniel Verkamp 		printf("Controller did not return common namespace capabilities\n");
5708f876a61SDaniel Verkamp 		return;
5718f876a61SDaniel Verkamp 	}
5728f876a61SDaniel Verkamp 
5738f876a61SDaniel Verkamp 	ns_lbasize = get_lba_format(ctrlr->common_ns_data);
5748f876a61SDaniel Verkamp 	if (ns_lbasize < 0) {
5758f876a61SDaniel Verkamp 		printf("Invalid LBA format number\n");
5768f876a61SDaniel Verkamp 		return;
5778f876a61SDaniel Verkamp 	}
5788f876a61SDaniel Verkamp 
57998416108SCunyin Chang 	printf("Please Input Namespace Size (in LBAs):\n");
580121d632cSJim Harris 	if (!scanf("%" SCNu64, &ns_size)) {
58198416108SCunyin Chang 		printf("Invalid Namespace Size\n");
58298416108SCunyin Chang 		while (getchar() != '\n');
58398416108SCunyin Chang 		return;
58498416108SCunyin Chang 	}
58598416108SCunyin Chang 
58698416108SCunyin Chang 	printf("Please Input Namespace Capacity (in LBAs):\n");
587121d632cSJim Harris 	if (!scanf("%" SCNu64, &ns_capacity)) {
58898416108SCunyin Chang 		printf("Invalid Namespace Capacity\n");
58998416108SCunyin Chang 		while (getchar() != '\n');
59098416108SCunyin Chang 		return;
59198416108SCunyin Chang 	}
59298416108SCunyin Chang 
5934e91a0b0SGangCao 	printf("Please Input Data Protection Type (0 - 3):\n");
5944e91a0b0SGangCao 	if (!scanf("%d", &ns_dps_type)) {
5954e91a0b0SGangCao 		printf("Invalid Data Protection Type\n");
5964e91a0b0SGangCao 		while (getchar() != '\n');
5974e91a0b0SGangCao 		return;
5984e91a0b0SGangCao 	}
5994e91a0b0SGangCao 
6004e91a0b0SGangCao 	if (SPDK_NVME_FMT_NVM_PROTECTION_DISABLE != ns_dps_type) {
6014e91a0b0SGangCao 		printf("Please Input Data Protection Location (1: Head; 0: Tail):\n");
6024e91a0b0SGangCao 		if (!scanf("%d", &ns_dps_location)) {
6034e91a0b0SGangCao 			printf("Invalid Data Protection Location\n");
6044e91a0b0SGangCao 			while (getchar() != '\n');
6054e91a0b0SGangCao 			return;
6064e91a0b0SGangCao 		}
6074e91a0b0SGangCao 	}
6084e91a0b0SGangCao 
6094e91a0b0SGangCao 	printf("Please Input Multi-path IO and Sharing Capabilities (1: Share; 0: Private):\n");
6104e91a0b0SGangCao 	if (!scanf("%d", &ns_nmic)) {
6114e91a0b0SGangCao 		printf("Invalid Multi-path IO and Sharing Capabilities\n");
6124e91a0b0SGangCao 		while (getchar() != '\n');
6134e91a0b0SGangCao 		return;
6144e91a0b0SGangCao 	}
6154e91a0b0SGangCao 
6164e91a0b0SGangCao 	ns_manage_add(ctrlr, ns_size, ns_capacity, ns_lbasize,
6174e91a0b0SGangCao 		      ns_dps_type, ns_dps_location, ns_nmic);
61898416108SCunyin Chang }
61998416108SCunyin Chang 
62098416108SCunyin Chang static void
62198416108SCunyin Chang delete_ns(void)
62298416108SCunyin Chang {
62398416108SCunyin Chang 	int					ns_id;
62498416108SCunyin Chang 	struct dev				*ctrlr;
62598416108SCunyin Chang 
62698416108SCunyin Chang 	ctrlr = get_controller();
62798416108SCunyin Chang 	if (ctrlr == NULL) {
62873b0afa8SCunyin Chang 		printf("Invalid controller PCI Address.\n");
62998416108SCunyin Chang 		return;
63098416108SCunyin Chang 	}
63198416108SCunyin Chang 
632ce13ccf8SDaniel Verkamp 	if (!ctrlr->cdata->oacs.ns_manage) {
633ce13ccf8SDaniel Verkamp 		printf("Controller does not support ns management\n");
634ce13ccf8SDaniel Verkamp 		return;
635ce13ccf8SDaniel Verkamp 	}
636ce13ccf8SDaniel Verkamp 
63798416108SCunyin Chang 	printf("Please Input Namespace ID:\n");
63898416108SCunyin Chang 	if (!scanf("%d", &ns_id)) {
63998416108SCunyin Chang 		printf("Invalid Namespace ID\n");
64098416108SCunyin Chang 		while (getchar() != '\n');
64198416108SCunyin Chang 		return;
64298416108SCunyin Chang 	}
64398416108SCunyin Chang 
64498416108SCunyin Chang 	ns_manage_delete(ctrlr, ns_id);
64598416108SCunyin Chang }
64698416108SCunyin Chang 
647eae68857SCunyin Chang static void
648eae68857SCunyin Chang format_nvm(void)
649eae68857SCunyin Chang {
650eae68857SCunyin Chang 	int					ns_id;
651eae68857SCunyin Chang 	int					ses;
652eae68857SCunyin Chang 	int					pil;
653eae68857SCunyin Chang 	int					pi;
654eae68857SCunyin Chang 	int					ms;
655eae68857SCunyin Chang 	int					lbaf;
656eae68857SCunyin Chang 	char					option;
657eae68857SCunyin Chang 	struct dev				*ctrlr;
6584fe88e43SDaniel Verkamp 	const struct spdk_nvme_ctrlr_data	*cdata;
6596a3735e3SDaniel Verkamp 	struct spdk_nvme_ns			*ns;
6606a3735e3SDaniel Verkamp 	const struct spdk_nvme_ns_data		*nsdata;
661eae68857SCunyin Chang 
662eae68857SCunyin Chang 	ctrlr = get_controller();
663eae68857SCunyin Chang 	if (ctrlr == NULL) {
664eae68857SCunyin Chang 		printf("Invalid controller PCI BDF.\n");
665eae68857SCunyin Chang 		return;
666eae68857SCunyin Chang 	}
6674fe88e43SDaniel Verkamp 
6684fe88e43SDaniel Verkamp 	cdata = ctrlr->cdata;
6694fe88e43SDaniel Verkamp 
6704fe88e43SDaniel Verkamp 	if (!cdata->oacs.format) {
671eae68857SCunyin Chang 		printf("Controller does not support Format NVM command\n");
672eae68857SCunyin Chang 		return;
673eae68857SCunyin Chang 	}
674eae68857SCunyin Chang 
6754fe88e43SDaniel Verkamp 	if (cdata->fna.format_all_ns) {
6765bb16e86SDaniel Verkamp 		ns_id = SPDK_NVME_GLOBAL_NS_TAG;
6776a3735e3SDaniel Verkamp 		ns = spdk_nvme_ctrlr_get_ns(ctrlr->ctrlr, 1);
678eae68857SCunyin Chang 	} else {
6794fe88e43SDaniel Verkamp 		printf("Please Input Namespace ID (1 - %d):\n", cdata->nn);
680eae68857SCunyin Chang 		if (!scanf("%d", &ns_id)) {
681eae68857SCunyin Chang 			printf("Invalid Namespace ID\n");
682eae68857SCunyin Chang 			while (getchar() != '\n');
683eae68857SCunyin Chang 			return;
684eae68857SCunyin Chang 		}
6856a3735e3SDaniel Verkamp 		ns = spdk_nvme_ctrlr_get_ns(ctrlr->ctrlr, ns_id);
686eae68857SCunyin Chang 	}
687eae68857SCunyin Chang 
6886a3735e3SDaniel Verkamp 	if (ns == NULL) {
6896a3735e3SDaniel Verkamp 		printf("Namespace ID %d not found\n", ns_id);
6906a3735e3SDaniel Verkamp 		while (getchar() != '\n');
6916a3735e3SDaniel Verkamp 		return;
6926a3735e3SDaniel Verkamp 	}
6936a3735e3SDaniel Verkamp 
6946a3735e3SDaniel Verkamp 	nsdata = spdk_nvme_ns_get_data(ns);
6956a3735e3SDaniel Verkamp 
696eae68857SCunyin Chang 	printf("Please Input Secure Erase Setting:\n");
697eae68857SCunyin Chang 	printf("	0: No secure erase operation requested\n");
698eae68857SCunyin Chang 	printf("	1: User data erase\n");
6994fe88e43SDaniel Verkamp 	if (cdata->fna.crypto_erase_supported) {
700eae68857SCunyin Chang 		printf("	2: Cryptographic erase\n");
7014fe88e43SDaniel Verkamp 	}
702eae68857SCunyin Chang 	if (!scanf("%d", &ses)) {
703eae68857SCunyin Chang 		printf("Invalid Secure Erase Setting\n");
704eae68857SCunyin Chang 		while (getchar() != '\n');
705eae68857SCunyin Chang 		return;
706eae68857SCunyin Chang 	}
707eae68857SCunyin Chang 
7088f876a61SDaniel Verkamp 	lbaf = get_lba_format(nsdata);
7098f876a61SDaniel Verkamp 	if (lbaf < 0) {
7104fe88e43SDaniel Verkamp 		printf("Invalid LBA format number\n");
7114fe88e43SDaniel Verkamp 		return;
7124fe88e43SDaniel Verkamp 	}
7134fe88e43SDaniel Verkamp 
7144fe88e43SDaniel Verkamp 	if (nsdata->lbaf[lbaf].ms) {
7154fe88e43SDaniel Verkamp 		printf("Please Input Protection Information:\n");
7164fe88e43SDaniel Verkamp 		printf("	0: Protection information is not enabled\n");
7174fe88e43SDaniel Verkamp 		printf("	1: Protection information is enabled, Type 1\n");
7184fe88e43SDaniel Verkamp 		printf("	2: Protection information is enabled, Type 2\n");
7194fe88e43SDaniel Verkamp 		printf("	3: Protection information is enabled, Type 3\n");
7204fe88e43SDaniel Verkamp 		if (!scanf("%d", &pi)) {
7214fe88e43SDaniel Verkamp 			printf("Invalid protection information\n");
7224fe88e43SDaniel Verkamp 			while (getchar() != '\n');
7234fe88e43SDaniel Verkamp 			return;
7244fe88e43SDaniel Verkamp 		}
7254fe88e43SDaniel Verkamp 
7264fe88e43SDaniel Verkamp 		if (pi) {
7274fe88e43SDaniel Verkamp 			printf("Please Input Protection Information Location:\n");
7284fe88e43SDaniel Verkamp 			printf("	0: Protection information transferred as the last eight bytes of metadata\n");
7294fe88e43SDaniel Verkamp 			printf("	1: Protection information transferred as the first eight bytes of metadata\n");
7304fe88e43SDaniel Verkamp 			if (!scanf("%d", &pil)) {
7314fe88e43SDaniel Verkamp 				printf("Invalid protection information location\n");
7324fe88e43SDaniel Verkamp 				while (getchar() != '\n');
7334fe88e43SDaniel Verkamp 				return;
7344fe88e43SDaniel Verkamp 			}
7354fe88e43SDaniel Verkamp 		} else {
7364fe88e43SDaniel Verkamp 			pil = 0;
7374fe88e43SDaniel Verkamp 		}
7384fe88e43SDaniel Verkamp 
7394fe88e43SDaniel Verkamp 		printf("Please Input Metadata Setting:\n");
7404fe88e43SDaniel Verkamp 		printf("	0: Metadata is transferred as part of a separate buffer\n");
7414fe88e43SDaniel Verkamp 		printf("	1: Metadata is transferred as part of an extended data LBA\n");
7424fe88e43SDaniel Verkamp 		if (!scanf("%d", &ms)) {
7434fe88e43SDaniel Verkamp 			printf("Invalid metadata setting\n");
7444fe88e43SDaniel Verkamp 			while (getchar() != '\n');
7454fe88e43SDaniel Verkamp 			return;
7464fe88e43SDaniel Verkamp 		}
7474fe88e43SDaniel Verkamp 	} else {
7484fe88e43SDaniel Verkamp 		ms = 0;
7494fe88e43SDaniel Verkamp 		pi = 0;
7504fe88e43SDaniel Verkamp 		pil = 0;
7514fe88e43SDaniel Verkamp 	}
7524fe88e43SDaniel Verkamp 
753eae68857SCunyin Chang 	printf("Warning: use this utility at your own risk.\n"
754eae68857SCunyin Chang 	       "This command will format your namespace and all data will be lost.\n"
755eae68857SCunyin Chang 	       "This command may take several minutes to complete,\n"
756eae68857SCunyin Chang 	       "so do not interrupt the utility until it completes.\n"
757eae68857SCunyin Chang 	       "Press 'Y' to continue with the format operation.\n");
758eae68857SCunyin Chang 
759eae68857SCunyin Chang 	while (getchar() != '\n');
760eae68857SCunyin Chang 	if (!scanf("%c", &option)) {
761eae68857SCunyin Chang 		printf("Invalid option\n");
762eae68857SCunyin Chang 		while (getchar() != '\n');
763eae68857SCunyin Chang 		return;
764eae68857SCunyin Chang 	}
765eae68857SCunyin Chang 
766eae68857SCunyin Chang 	if (option == 'y' || option == 'Y') {
767eae68857SCunyin Chang 		nvme_manage_format(ctrlr, ns_id, ses, pi, pil, ms, lbaf);
768eae68857SCunyin Chang 	} else {
769eae68857SCunyin Chang 		printf("NVMe format abort\n");
770eae68857SCunyin Chang 	}
771eae68857SCunyin Chang }
772eae68857SCunyin Chang 
7730f805b36SCunyin Chang static void
7740f805b36SCunyin Chang update_firmware_image(void)
7750f805b36SCunyin Chang {
7760f805b36SCunyin Chang 	int					rc;
7770f805b36SCunyin Chang 	int					fd = -1;
7780f805b36SCunyin Chang 	int					slot;
7790f805b36SCunyin Chang 	unsigned int				size;
7800f805b36SCunyin Chang 	struct stat				fw_stat;
7810f805b36SCunyin Chang 	char					path[256];
7820f805b36SCunyin Chang 	void					*fw_image;
7830f805b36SCunyin Chang 	struct dev				*ctrlr;
7840f805b36SCunyin Chang 	const struct spdk_nvme_ctrlr_data	*cdata;
7856fb1ce42SIsaac Otsiabah 	enum spdk_nvme_fw_commit_action		commit_action;
7866fb1ce42SIsaac Otsiabah 	struct spdk_nvme_status			status;
7870f805b36SCunyin Chang 
7880f805b36SCunyin Chang 	ctrlr = get_controller();
7890f805b36SCunyin Chang 	if (ctrlr == NULL) {
7900f805b36SCunyin Chang 		printf("Invalid controller PCI BDF.\n");
7910f805b36SCunyin Chang 		return;
7920f805b36SCunyin Chang 	}
7930f805b36SCunyin Chang 
7940f805b36SCunyin Chang 	cdata = ctrlr->cdata;
7950f805b36SCunyin Chang 
7960f805b36SCunyin Chang 	if (!cdata->oacs.firmware) {
7970f805b36SCunyin Chang 		printf("Controller does not support firmware download and commit command\n");
7980f805b36SCunyin Chang 		return;
7990f805b36SCunyin Chang 	}
8000f805b36SCunyin Chang 
8010f805b36SCunyin Chang 	printf("Please Input The Path Of Firmware Image\n");
8020f805b36SCunyin Chang 
80363133871SChunyang Hui 	if (get_line(path, sizeof(path), stdin, false) == NULL) {
8040f805b36SCunyin Chang 		printf("Invalid path setting\n");
8050f805b36SCunyin Chang 		while (getchar() != '\n');
8060f805b36SCunyin Chang 		return;
8070f805b36SCunyin Chang 	}
8080f805b36SCunyin Chang 
8090f805b36SCunyin Chang 	fd = open(path, O_RDONLY);
8100f805b36SCunyin Chang 	if (fd < 0) {
8110f805b36SCunyin Chang 		perror("Open file failed");
8120f805b36SCunyin Chang 		return;
8130f805b36SCunyin Chang 	}
8140f805b36SCunyin Chang 	rc = fstat(fd, &fw_stat);
8150f805b36SCunyin Chang 	if (rc < 0) {
8160f805b36SCunyin Chang 		printf("Fstat failed\n");
8170f805b36SCunyin Chang 		close(fd);
8180f805b36SCunyin Chang 		return;
8190f805b36SCunyin Chang 	}
8200f805b36SCunyin Chang 
8210f805b36SCunyin Chang 	if (fw_stat.st_size % 4) {
8220f805b36SCunyin Chang 		printf("Firmware image size is not multiple of 4\n");
8230f805b36SCunyin Chang 		close(fd);
8240f805b36SCunyin Chang 		return;
8250f805b36SCunyin Chang 	}
8260f805b36SCunyin Chang 
8270f805b36SCunyin Chang 	size = fw_stat.st_size;
8280f805b36SCunyin Chang 
8298a44220bSJohn Meneghini 	fw_image = spdk_dma_zmalloc(size, 4096, NULL);
8300f805b36SCunyin Chang 	if (fw_image == NULL) {
8310f805b36SCunyin Chang 		printf("Allocation error\n");
8320f805b36SCunyin Chang 		close(fd);
8330f805b36SCunyin Chang 		return;
8340f805b36SCunyin Chang 	}
8350f805b36SCunyin Chang 
8360f805b36SCunyin Chang 	if (read(fd, fw_image, size) != ((ssize_t)(size))) {
8370f805b36SCunyin Chang 		printf("Read firmware image failed\n");
8380f805b36SCunyin Chang 		close(fd);
8398a44220bSJohn Meneghini 		spdk_dma_free(fw_image);
8400f805b36SCunyin Chang 		return;
8410f805b36SCunyin Chang 	}
8420f805b36SCunyin Chang 	close(fd);
8430f805b36SCunyin Chang 
8440f805b36SCunyin Chang 	printf("Please Input Slot(0 - 7):\n");
8450f805b36SCunyin Chang 	if (!scanf("%d", &slot)) {
8460f805b36SCunyin Chang 		printf("Invalid Slot\n");
8478a44220bSJohn Meneghini 		spdk_dma_free(fw_image);
8480f805b36SCunyin Chang 		while (getchar() != '\n');
8490f805b36SCunyin Chang 		return;
8500f805b36SCunyin Chang 	}
8510f805b36SCunyin Chang 
8526fb1ce42SIsaac Otsiabah 	commit_action = SPDK_NVME_FW_COMMIT_REPLACE_AND_ENABLE_IMG;
8536fb1ce42SIsaac Otsiabah 	rc = spdk_nvme_ctrlr_update_firmware(ctrlr->ctrlr, fw_image, size, slot, commit_action, &status);
8546fb1ce42SIsaac Otsiabah 	if (rc == -ENXIO && status.sct == SPDK_NVME_SCT_COMMAND_SPECIFIC &&
8556fb1ce42SIsaac Otsiabah 	    status.sc == SPDK_NVME_SC_FIRMWARE_REQ_CONVENTIONAL_RESET) {
8566fb1ce42SIsaac Otsiabah 		printf("conventional reset is needed to enable firmware !\n");
8576fb1ce42SIsaac Otsiabah 	} else if (rc) {
8580f805b36SCunyin Chang 		printf("spdk_nvme_ctrlr_update_firmware failed\n");
8590f805b36SCunyin Chang 	} else {
8600f805b36SCunyin Chang 		printf("spdk_nvme_ctrlr_update_firmware success\n");
8610f805b36SCunyin Chang 	}
8628a44220bSJohn Meneghini 	spdk_dma_free(fw_image);
8630f805b36SCunyin Chang }
8640f805b36SCunyin Chang 
8657250ec64SChunyang Hui static void
86601ddd112SChangpeng Liu opal_dump_info(struct spdk_opal_d0_features_info *feat)
86755f5b205SHui, Chunyang {
86801ddd112SChangpeng Liu 	if (feat->tper.hdr.code) {
86955f5b205SHui, Chunyang 		printf("\nOpal TPer feature:\n");
87001ddd112SChangpeng Liu 		printf("ACKNACK = %s", (feat->tper.acknack ? "Y, " : "N, "));
87101ddd112SChangpeng Liu 		printf("ASYNC = %s", (feat->tper.async ? "Y, " : "N, "));
87201ddd112SChangpeng Liu 		printf("BufferManagement = %s\n", (feat->tper.buffer_management ? "Y, " : "N, "));
87301ddd112SChangpeng Liu 		printf("ComIDManagement = %s", (feat->tper.comid_management ? "Y, " : "N, "));
87401ddd112SChangpeng Liu 		printf("Streaming = %s", (feat->tper.streaming ? "Y, " : "N, "));
87501ddd112SChangpeng Liu 		printf("Sync = %s\n", (feat->tper.sync ? "Y" : "N"));
87655f5b205SHui, Chunyang 		printf("\n");
87755f5b205SHui, Chunyang 	}
87855f5b205SHui, Chunyang 
87901ddd112SChangpeng Liu 	if (feat->locking.hdr.code) {
88055f5b205SHui, Chunyang 		printf("Opal Locking feature:\n");
88101ddd112SChangpeng Liu 		printf("Locked = %s", (feat->locking.locked ? "Y, " : "N, "));
88201ddd112SChangpeng Liu 		printf("Locking Enabled = %s", (feat->locking.locking_enabled ? "Y, " : "N, "));
88301ddd112SChangpeng Liu 		printf("Locking supported = %s\n", (feat->locking.locking_supported ? "Y" : "N"));
88455f5b205SHui, Chunyang 
88501ddd112SChangpeng Liu 		printf("MBR done = %s", (feat->locking.mbr_done ? "Y, " : "N, "));
88601ddd112SChangpeng Liu 		printf("MBR enabled = %s", (feat->locking.mbr_enabled ? "Y, " : "N, "));
88701ddd112SChangpeng Liu 		printf("Media encrypt = %s\n", (feat->locking.media_encryption ? "Y" : "N"));
88855f5b205SHui, Chunyang 		printf("\n");
88955f5b205SHui, Chunyang 	}
89055f5b205SHui, Chunyang 
89101ddd112SChangpeng Liu 	if (feat->geo.hdr.code) {
89255f5b205SHui, Chunyang 		printf("Opal Geometry feature:\n");
89301ddd112SChangpeng Liu 		printf("Align = %s", (feat->geo.alignment_granularity ? "Y, " : "N, "));
89401ddd112SChangpeng Liu 		printf("Logical block size = %d, ", from_be32(&feat->geo.logical_block_size));
895bb19c18fSNick Connolly 		printf("Lowest aligned LBA = %" PRIu64 "\n", from_be64(&feat->geo.lowest_aligned_lba));
89655f5b205SHui, Chunyang 		printf("\n");
89755f5b205SHui, Chunyang 	}
89855f5b205SHui, Chunyang 
89901ddd112SChangpeng Liu 	if (feat->single_user.hdr.code) {
90055f5b205SHui, Chunyang 		printf("Opal Single User Mode feature:\n");
90101ddd112SChangpeng Liu 		printf("Any in SUM = %s", (feat->single_user.any ? "Y, " : "N, "));
90201ddd112SChangpeng Liu 		printf("All in SUM = %s", (feat->single_user.all ? "Y, " : "N, "));
90301ddd112SChangpeng Liu 		printf("Policy: %s Authority,\n", (feat->single_user.policy ? "Admin" : "Users"));
90401ddd112SChangpeng Liu 		printf("Number of locking objects = %d\n ", from_be32(&feat->single_user.num_locking_objects));
90555f5b205SHui, Chunyang 		printf("\n");
90655f5b205SHui, Chunyang 	}
90755f5b205SHui, Chunyang 
90801ddd112SChangpeng Liu 	if (feat->datastore.hdr.code) {
90955f5b205SHui, Chunyang 		printf("Opal DataStore feature:\n");
91001ddd112SChangpeng Liu 		printf("Table alignment = %d, ", from_be32(&feat->datastore.alignment));
91101ddd112SChangpeng Liu 		printf("Max number of tables = %d, ", from_be16(&feat->datastore.max_tables));
91201ddd112SChangpeng Liu 		printf("Max size of tables = %d\n", from_be32(&feat->datastore.max_table_size));
91355f5b205SHui, Chunyang 		printf("\n");
91455f5b205SHui, Chunyang 	}
91555f5b205SHui, Chunyang 
91601ddd112SChangpeng Liu 	if (feat->v100.hdr.code) {
91755f5b205SHui, Chunyang 		printf("Opal V100 feature:\n");
91801ddd112SChangpeng Liu 		printf("Base comID = %d, ", from_be16(&feat->v100.base_comid));
91901ddd112SChangpeng Liu 		printf("Number of comIDs = %d, ", from_be16(&feat->v100.number_comids));
92001ddd112SChangpeng Liu 		printf("Range crossing = %s\n", (feat->v100.range_crossing ? "N" : "Y"));
92155f5b205SHui, Chunyang 		printf("\n");
92255f5b205SHui, Chunyang 	}
92355f5b205SHui, Chunyang 
92401ddd112SChangpeng Liu 	if (feat->v200.hdr.code) {
92555f5b205SHui, Chunyang 		printf("Opal V200 feature:\n");
92601ddd112SChangpeng Liu 		printf("Base comID = %d, ", from_be16(&feat->v200.base_comid));
92701ddd112SChangpeng Liu 		printf("Number of comIDs = %d, ", from_be16(&feat->v200.num_comids));
92801ddd112SChangpeng Liu 		printf("Initial PIN = %d,\n", feat->v200.initial_pin);
92901ddd112SChangpeng Liu 		printf("Reverted PIN = %d, ", feat->v200.reverted_pin);
93001ddd112SChangpeng Liu 		printf("Number of admins = %d, ", from_be16(&feat->v200.num_locking_admin_auth));
93101ddd112SChangpeng Liu 		printf("Number of users = %d\n", from_be16(&feat->v200.num_locking_user_auth));
932defe09d3SChunyang Hui 		printf("\n");
93355f5b205SHui, Chunyang 	}
93455f5b205SHui, Chunyang }
93555f5b205SHui, Chunyang 
93655f5b205SHui, Chunyang static void
9377250ec64SChunyang Hui opal_usage(void)
93855f5b205SHui, Chunyang {
9397250ec64SChunyang Hui 	printf("Opal General Usage:\n");
9407250ec64SChunyang Hui 	printf("\n");
9417250ec64SChunyang Hui 	printf("\t[1: scan device]\n");
942755b4390SChunyang Hui 	printf("\t[2: init - take ownership and activate locking]\n");
9430fae4f64SChunyang Hui 	printf("\t[3: revert tper]\n");
9440fae4f64SChunyang Hui 	printf("\t[4: setup locking range]\n");
9450fae4f64SChunyang Hui 	printf("\t[5: list locking ranges]\n");
9460fae4f64SChunyang Hui 	printf("\t[6: enable user]\n");
9470fae4f64SChunyang Hui 	printf("\t[7: set new password]\n");
9480fae4f64SChunyang Hui 	printf("\t[8: add user to locking range]\n");
9490fae4f64SChunyang Hui 	printf("\t[9: lock/unlock range]\n");
9500fae4f64SChunyang Hui 	printf("\t[10: erase locking range]\n");
9517250ec64SChunyang Hui 	printf("\t[0: quit]\n");
9527250ec64SChunyang Hui }
95355f5b205SHui, Chunyang 
9547250ec64SChunyang Hui static void
9557250ec64SChunyang Hui opal_scan(struct dev *iter)
9567250ec64SChunyang Hui {
957defe09d3SChunyang Hui 	while (getchar() != '\n');
95855f5b205SHui, Chunyang 	if (spdk_nvme_ctrlr_get_flags(iter->ctrlr) & SPDK_NVME_CTRLR_SECURITY_SEND_RECV_SUPPORTED) {
959c61b70c3SChangpeng Liu 		iter->opal_dev = spdk_opal_dev_construct(iter->ctrlr);
96055f5b205SHui, Chunyang 		if (iter->opal_dev == NULL) {
96155f5b205SHui, Chunyang 			return;
96255f5b205SHui, Chunyang 		}
9637250ec64SChunyang Hui 
96455f5b205SHui, Chunyang 		printf("\n\nOpal Supported:\n");
96555f5b205SHui, Chunyang 		display_controller(iter, CONTROLLER_DISPLAY_SIMPLISTIC);
96601ddd112SChangpeng Liu 		opal_dump_info(spdk_opal_get_d0_features_info(iter->opal_dev));
967c61b70c3SChangpeng Liu 		spdk_opal_dev_destruct(iter->opal_dev);
96855f5b205SHui, Chunyang 	} else {
96955f5b205SHui, Chunyang 		printf("%04x:%02x:%02x.%02x: NVMe Security Support/Receive Not supported.\n",
97055f5b205SHui, Chunyang 		       iter->pci_addr.domain, iter->pci_addr.bus, iter->pci_addr.dev, iter->pci_addr.func);
97155f5b205SHui, Chunyang 		printf("%04x:%02x:%02x.%02x: Opal Not Supported\n\n\n",
97255f5b205SHui, Chunyang 		       iter->pci_addr.domain, iter->pci_addr.bus, iter->pci_addr.dev, iter->pci_addr.func);
97355f5b205SHui, Chunyang 	}
97455f5b205SHui, Chunyang }
9757250ec64SChunyang Hui 
9767250ec64SChunyang Hui static void
977755b4390SChunyang Hui opal_init(struct dev *iter)
9787250ec64SChunyang Hui {
9790cd8b292SChangpeng Liu 	char new_passwd[SPDK_OPAL_MAX_PASSWORD_SIZE] = {0};
9807250ec64SChunyang Hui 	char *passwd_p;
9817250ec64SChunyang Hui 	int ret;
9827250ec64SChunyang Hui 	int ch;
9837250ec64SChunyang Hui 
9847250ec64SChunyang Hui 	if (spdk_nvme_ctrlr_get_flags(iter->ctrlr) & SPDK_NVME_CTRLR_SECURITY_SEND_RECV_SUPPORTED) {
985c61b70c3SChangpeng Liu 		iter->opal_dev = spdk_opal_dev_construct(iter->ctrlr);
9867250ec64SChunyang Hui 		if (iter->opal_dev == NULL) {
9877250ec64SChunyang Hui 			return;
9887250ec64SChunyang Hui 		}
989defe09d3SChunyang Hui 		printf("Please input the new password for ownership:");
9907250ec64SChunyang Hui 		while ((ch = getchar()) != '\n' && ch != EOF);
9910cd8b292SChangpeng Liu 		passwd_p = get_line(new_passwd, SPDK_OPAL_MAX_PASSWORD_SIZE, stdin, true);
992defe09d3SChunyang Hui 		printf("\n...\n");
9937250ec64SChunyang Hui 		if (passwd_p) {
9949f988238SChunyang Hui 			ret = spdk_opal_cmd_take_ownership(iter->opal_dev, passwd_p);
9957250ec64SChunyang Hui 			if (ret) {
9967250ec64SChunyang Hui 				printf("Take ownership failure: %d\n", ret);
997c61b70c3SChangpeng Liu 				spdk_opal_dev_destruct(iter->opal_dev);
9987250ec64SChunyang Hui 				return;
9997250ec64SChunyang Hui 			}
1000755b4390SChunyang Hui 
1001755b4390SChunyang Hui 			ret = spdk_opal_cmd_activate_locking_sp(iter->opal_dev, passwd_p);
1002755b4390SChunyang Hui 			if (ret) {
1003755b4390SChunyang Hui 				printf("Locking SP activate failure: %d\n", ret);
1004c61b70c3SChangpeng Liu 				spdk_opal_dev_destruct(iter->opal_dev);
1005755b4390SChunyang Hui 				return;
1006755b4390SChunyang Hui 			}
1007defe09d3SChunyang Hui 			printf("...\nOpal Init Success\n");
10087250ec64SChunyang Hui 		} else {
1009755b4390SChunyang Hui 			printf("Input password invalid. Opal Init failure\n");
10107250ec64SChunyang Hui 		}
1011c61b70c3SChangpeng Liu 		spdk_opal_dev_destruct(iter->opal_dev);
10127250ec64SChunyang Hui 	} else {
10136b48e743SChunyang Hui 		printf("%04x:%02x:%02x.%02x: NVMe Security Support/Receive Not supported.\nOpal Not Supported\n\n\n",
10147250ec64SChunyang Hui 		       iter->pci_addr.domain, iter->pci_addr.bus, iter->pci_addr.dev, iter->pci_addr.func);
10156b48e743SChunyang Hui 	}
10166b48e743SChunyang Hui }
10176b48e743SChunyang Hui 
10186b48e743SChunyang Hui static void
1019505dbf59SChunyang Hui opal_locking_usage(void)
1020505dbf59SChunyang Hui {
1021505dbf59SChunyang Hui 	printf("Choose Opal locking state:\n");
1022505dbf59SChunyang Hui 	printf("\n");
1023505dbf59SChunyang Hui 	printf("\t[1: read write lock]\n");
1024505dbf59SChunyang Hui 	printf("\t[2: read only]\n");
1025505dbf59SChunyang Hui 	printf("\t[3: read write unlock]\n");
1026505dbf59SChunyang Hui }
1027505dbf59SChunyang Hui 
1028505dbf59SChunyang Hui static void
1029fbd2f3fdSChunyang Hui opal_setup_lockingrange(struct dev *iter)
1030505dbf59SChunyang Hui {
10310cd8b292SChangpeng Liu 	char passwd[SPDK_OPAL_MAX_PASSWORD_SIZE] = {0};
1032505dbf59SChunyang Hui 	char *passwd_p;
1033505dbf59SChunyang Hui 	int ret;
1034505dbf59SChunyang Hui 	int ch;
1035fbd2f3fdSChunyang Hui 	uint64_t range_start;
1036fbd2f3fdSChunyang Hui 	uint64_t range_length;
10378522624dSChunyang Hui 	int locking_range_id;
1038fbd2f3fdSChunyang Hui 	struct spdk_opal_locking_range_info *info;
1039505dbf59SChunyang Hui 
1040505dbf59SChunyang Hui 	if (spdk_nvme_ctrlr_get_flags(iter->ctrlr) & SPDK_NVME_CTRLR_SECURITY_SEND_RECV_SUPPORTED) {
1041c61b70c3SChangpeng Liu 		iter->opal_dev = spdk_opal_dev_construct(iter->ctrlr);
1042505dbf59SChunyang Hui 		if (iter->opal_dev == NULL) {
1043505dbf59SChunyang Hui 			return;
1044505dbf59SChunyang Hui 		}
1045defe09d3SChunyang Hui 		printf("Please input the password for setting up locking range:");
1046505dbf59SChunyang Hui 		while ((ch = getchar()) != '\n' && ch != EOF);
10470cd8b292SChangpeng Liu 		passwd_p = get_line(passwd, SPDK_OPAL_MAX_PASSWORD_SIZE, stdin, true);
1048defe09d3SChunyang Hui 		printf("\n");
1049505dbf59SChunyang Hui 		if (passwd_p) {
1050fbd2f3fdSChunyang Hui 			printf("Specify locking range id:\n");
10518522624dSChunyang Hui 			if (!scanf("%d", &locking_range_id)) {
1052fbd2f3fdSChunyang Hui 				printf("Invalid locking range id\n");
1053c61b70c3SChangpeng Liu 				spdk_opal_dev_destruct(iter->opal_dev);
105407f43264SChunyang Hui 				return;
1055fbd2f3fdSChunyang Hui 			}
1056fbd2f3fdSChunyang Hui 
1057fbd2f3fdSChunyang Hui 			printf("range length:\n");
1058a2664e74STomasz Zawadzki 			if (!scanf("%" SCNu64, &range_length)) {
1059fbd2f3fdSChunyang Hui 				printf("Invalid range length\n");
1060c61b70c3SChangpeng Liu 				spdk_opal_dev_destruct(iter->opal_dev);
106107f43264SChunyang Hui 				return;
1062fbd2f3fdSChunyang Hui 			}
1063fbd2f3fdSChunyang Hui 
1064fbd2f3fdSChunyang Hui 			printf("range start:\n");
1065a2664e74STomasz Zawadzki 			if (!scanf("%" SCNu64, &range_start)) {
1066fbd2f3fdSChunyang Hui 				printf("Invalid range start address\n");
1067c61b70c3SChangpeng Liu 				spdk_opal_dev_destruct(iter->opal_dev);
106807f43264SChunyang Hui 				return;
1069505dbf59SChunyang Hui 			}
1070defe09d3SChunyang Hui 			while (getchar() != '\n');
1071505dbf59SChunyang Hui 
1072fbd2f3fdSChunyang Hui 			ret = spdk_opal_cmd_setup_locking_range(iter->opal_dev,
10738522624dSChunyang Hui 								OPAL_ADMIN1, locking_range_id, range_start, range_length, passwd_p);
1074505dbf59SChunyang Hui 			if (ret) {
1075fbd2f3fdSChunyang Hui 				printf("Setup locking range failure: %d\n", ret);
1076c61b70c3SChangpeng Liu 				spdk_opal_dev_destruct(iter->opal_dev);
1077505dbf59SChunyang Hui 				return;
1078505dbf59SChunyang Hui 			}
1079505dbf59SChunyang Hui 
1080fbd2f3fdSChunyang Hui 			ret = spdk_opal_cmd_get_locking_range_info(iter->opal_dev,
10818522624dSChunyang Hui 					passwd_p, OPAL_ADMIN1, locking_range_id);
1082fbd2f3fdSChunyang Hui 			if (ret) {
1083fbd2f3fdSChunyang Hui 				printf("Get locking range info failure: %d\n", ret);
1084c61b70c3SChangpeng Liu 				spdk_opal_dev_destruct(iter->opal_dev);
1085fbd2f3fdSChunyang Hui 				return;
1086fbd2f3fdSChunyang Hui 			}
10878522624dSChunyang Hui 			info = spdk_opal_get_locking_range_info(iter->opal_dev, locking_range_id);
1088fbd2f3fdSChunyang Hui 
1089defe09d3SChunyang Hui 			printf("\nlocking range ID: %d\n", info->locking_range_id);
1090bb19c18fSNick Connolly 			printf("range start: %" PRIu64 "\n", info->range_start);
1091bb19c18fSNick Connolly 			printf("range length: %" PRIu64 "\n", info->range_length);
1092fbd2f3fdSChunyang Hui 			printf("read lock enabled: %d\n", info->read_lock_enabled);
1093fbd2f3fdSChunyang Hui 			printf("write lock enabled: %d\n", info->write_lock_enabled);
1094fbd2f3fdSChunyang Hui 			printf("read locked: %d\n", info->read_locked);
1095fbd2f3fdSChunyang Hui 			printf("write locked: %d\n", info->write_locked);
1096fbd2f3fdSChunyang Hui 
1097505dbf59SChunyang Hui 			printf("...\n...\nOpal setup locking range success\n");
1098505dbf59SChunyang Hui 		} else {
1099505dbf59SChunyang Hui 			printf("Input password invalid. Opal setup locking range failure\n");
1100505dbf59SChunyang Hui 		}
1101c61b70c3SChangpeng Liu 		spdk_opal_dev_destruct(iter->opal_dev);
1102505dbf59SChunyang Hui 	} else {
1103505dbf59SChunyang Hui 		printf("%04x:%02x:%02x.%02x: NVMe Security Support/Receive Not supported.\nOpal Not Supported\n\n\n",
1104505dbf59SChunyang Hui 		       iter->pci_addr.domain, iter->pci_addr.bus, iter->pci_addr.dev, iter->pci_addr.func);
1105505dbf59SChunyang Hui 	}
1106505dbf59SChunyang Hui }
1107505dbf59SChunyang Hui 
1108505dbf59SChunyang Hui static void
1109fbd2f3fdSChunyang Hui opal_list_locking_ranges(struct dev *iter)
1110fbd2f3fdSChunyang Hui {
11110cd8b292SChangpeng Liu 	char passwd[SPDK_OPAL_MAX_PASSWORD_SIZE] = {0};
1112fbd2f3fdSChunyang Hui 	char *passwd_p;
1113fbd2f3fdSChunyang Hui 	int ret;
1114fbd2f3fdSChunyang Hui 	int ch;
1115fbd2f3fdSChunyang Hui 	int max_ranges;
1116fbd2f3fdSChunyang Hui 	int i;
1117fbd2f3fdSChunyang Hui 	struct spdk_opal_locking_range_info *info;
1118fbd2f3fdSChunyang Hui 
1119fbd2f3fdSChunyang Hui 	if (spdk_nvme_ctrlr_get_flags(iter->ctrlr) & SPDK_NVME_CTRLR_SECURITY_SEND_RECV_SUPPORTED) {
1120c61b70c3SChangpeng Liu 		iter->opal_dev = spdk_opal_dev_construct(iter->ctrlr);
1121fbd2f3fdSChunyang Hui 		if (iter->opal_dev == NULL) {
1122fbd2f3fdSChunyang Hui 			return;
1123fbd2f3fdSChunyang Hui 		}
1124defe09d3SChunyang Hui 		printf("Please input password:");
1125fbd2f3fdSChunyang Hui 		while ((ch = getchar()) != '\n' && ch != EOF);
11260cd8b292SChangpeng Liu 		passwd_p = get_line(passwd, SPDK_OPAL_MAX_PASSWORD_SIZE, stdin, true);
1127defe09d3SChunyang Hui 		printf("\n");
1128fbd2f3fdSChunyang Hui 		if (passwd_p) {
1129fbd2f3fdSChunyang Hui 			ret = spdk_opal_cmd_get_max_ranges(iter->opal_dev, passwd_p);
1130a3363de3SChangpeng Liu 			if (ret <= 0) {
1131fbd2f3fdSChunyang Hui 				printf("get max ranges failure: %d\n", ret);
1132c61b70c3SChangpeng Liu 				spdk_opal_dev_destruct(iter->opal_dev);
1133fbd2f3fdSChunyang Hui 				return;
1134fbd2f3fdSChunyang Hui 			}
1135fbd2f3fdSChunyang Hui 
1136a3363de3SChangpeng Liu 			max_ranges = ret;
1137fbd2f3fdSChunyang Hui 			for (i = 0; i < max_ranges; i++) {
1138fbd2f3fdSChunyang Hui 				ret = spdk_opal_cmd_get_locking_range_info(iter->opal_dev,
11398522624dSChunyang Hui 						passwd_p, OPAL_ADMIN1, i);
1140fbd2f3fdSChunyang Hui 				if (ret) {
1141fbd2f3fdSChunyang Hui 					printf("Get locking range info failure: %d\n", ret);
1142c61b70c3SChangpeng Liu 					spdk_opal_dev_destruct(iter->opal_dev);
1143fbd2f3fdSChunyang Hui 					return;
1144fbd2f3fdSChunyang Hui 				}
1145fbd2f3fdSChunyang Hui 				info = spdk_opal_get_locking_range_info(iter->opal_dev, i);
1146fbd2f3fdSChunyang Hui 				if (info == NULL) {
1147fbd2f3fdSChunyang Hui 					continue;
1148fbd2f3fdSChunyang Hui 				}
1149fbd2f3fdSChunyang Hui 
1150fbd2f3fdSChunyang Hui 				printf("===============================================\n");
1151fbd2f3fdSChunyang Hui 				printf("locking range ID: %d\t", info->locking_range_id);
1152fbd2f3fdSChunyang Hui 				if (i == 0) { printf("(Global Range)"); }
1153fbd2f3fdSChunyang Hui 				printf("\n===============================================\n");
1154bb19c18fSNick Connolly 				printf("range start: %" PRIu64 "\t", info->range_start);
1155bb19c18fSNick Connolly 				printf("range length: %" PRIu64 "\n", info->range_length);
1156fbd2f3fdSChunyang Hui 				printf("read lock enabled: %d\t", info->read_lock_enabled);
1157fbd2f3fdSChunyang Hui 				printf("write lock enabled: %d\t", info->write_lock_enabled);
1158fbd2f3fdSChunyang Hui 				printf("read locked: %d\t", info->read_locked);
1159fbd2f3fdSChunyang Hui 				printf("write locked: %d\n", info->write_locked);
1160fbd2f3fdSChunyang Hui 				printf("\n");
1161fbd2f3fdSChunyang Hui 			}
1162fbd2f3fdSChunyang Hui 		} else {
1163fbd2f3fdSChunyang Hui 			printf("Input password invalid. List locking ranges failure\n");
1164fbd2f3fdSChunyang Hui 		}
1165c61b70c3SChangpeng Liu 		spdk_opal_dev_destruct(iter->opal_dev);
1166fbd2f3fdSChunyang Hui 	} else {
1167fbd2f3fdSChunyang Hui 		printf("%04x:%02x:%02x.%02x: NVMe Security Support/Receive Not supported.\nOpal Not Supported\n\n\n",
1168fbd2f3fdSChunyang Hui 		       iter->pci_addr.domain, iter->pci_addr.bus, iter->pci_addr.dev, iter->pci_addr.func);
1169fbd2f3fdSChunyang Hui 	}
1170fbd2f3fdSChunyang Hui }
1171fbd2f3fdSChunyang Hui 
1172fbd2f3fdSChunyang Hui static void
11738522624dSChunyang Hui opal_new_user_enable(struct dev *iter)
11748522624dSChunyang Hui {
11758522624dSChunyang Hui 	int user_id;
11760cd8b292SChangpeng Liu 	char passwd[SPDK_OPAL_MAX_PASSWORD_SIZE] = {0};
11778522624dSChunyang Hui 	char *passwd_p;
11780cd8b292SChangpeng Liu 	char user_pw[SPDK_OPAL_MAX_PASSWORD_SIZE] = {0};
11798522624dSChunyang Hui 	char *user_pw_p;
11808522624dSChunyang Hui 	int ret;
11818522624dSChunyang Hui 	int ch;
11828522624dSChunyang Hui 
11838522624dSChunyang Hui 	if (spdk_nvme_ctrlr_get_flags(iter->ctrlr) & SPDK_NVME_CTRLR_SECURITY_SEND_RECV_SUPPORTED) {
1184c61b70c3SChangpeng Liu 		iter->opal_dev = spdk_opal_dev_construct(iter->ctrlr);
11858522624dSChunyang Hui 		if (iter->opal_dev == NULL) {
11868522624dSChunyang Hui 			return;
11878522624dSChunyang Hui 		}
1188defe09d3SChunyang Hui 		printf("Please input admin password:");
11898522624dSChunyang Hui 		while ((ch = getchar()) != '\n' && ch != EOF);
11900cd8b292SChangpeng Liu 		passwd_p = get_line(passwd, SPDK_OPAL_MAX_PASSWORD_SIZE, stdin, true);
1191defe09d3SChunyang Hui 		printf("\n");
11928522624dSChunyang Hui 		if (passwd_p) {
11938522624dSChunyang Hui 			printf("which user to enable: ");
11948522624dSChunyang Hui 			if (!scanf("%d", &user_id)) {
11958522624dSChunyang Hui 				printf("Invalid user id\n");
1196c61b70c3SChangpeng Liu 				spdk_opal_dev_destruct(iter->opal_dev);
11978522624dSChunyang Hui 				return;
11988522624dSChunyang Hui 			}
11998522624dSChunyang Hui 
12008522624dSChunyang Hui 			ret = spdk_opal_cmd_enable_user(iter->opal_dev, user_id, passwd_p);
12018522624dSChunyang Hui 			if (ret) {
12028522624dSChunyang Hui 				printf("Enable user failure error code: %d\n", ret);
1203c61b70c3SChangpeng Liu 				spdk_opal_dev_destruct(iter->opal_dev);
12048522624dSChunyang Hui 				return;
12058522624dSChunyang Hui 			}
1206defe09d3SChunyang Hui 			printf("Please set a new password for this user:");
12078522624dSChunyang Hui 			while ((ch = getchar()) != '\n' && ch != EOF);
12080cd8b292SChangpeng Liu 			user_pw_p = get_line(user_pw, SPDK_OPAL_MAX_PASSWORD_SIZE, stdin, true);
12098522624dSChunyang Hui 			if (user_pw_p == NULL) {
12108522624dSChunyang Hui 				printf("Input password invalid. Enable user failure\n");
1211c61b70c3SChangpeng Liu 				spdk_opal_dev_destruct(iter->opal_dev);
12128522624dSChunyang Hui 				return;
12138522624dSChunyang Hui 			}
12148522624dSChunyang Hui 
12158522624dSChunyang Hui 			ret = spdk_opal_cmd_set_new_passwd(iter->opal_dev, user_id, user_pw_p, passwd_p, true);
12168522624dSChunyang Hui 			if (ret) {
12178522624dSChunyang Hui 				printf("Set new password failure error code: %d\n", ret);
1218c61b70c3SChangpeng Liu 				spdk_opal_dev_destruct(iter->opal_dev);
12198522624dSChunyang Hui 				return;
12208522624dSChunyang Hui 			}
12218522624dSChunyang Hui 
1222defe09d3SChunyang Hui 			printf("\n...\n...\nEnable User Success\n");
12238522624dSChunyang Hui 		} else {
12248522624dSChunyang Hui 			printf("Input password invalid. Enable user failure\n");
12258522624dSChunyang Hui 		}
1226c61b70c3SChangpeng Liu 		spdk_opal_dev_destruct(iter->opal_dev);
12278522624dSChunyang Hui 	} else {
12288522624dSChunyang Hui 		printf("%04x:%02x:%02x.%02x: NVMe Security Support/Receive Not supported.\nOpal Not Supported\n\n\n",
12298522624dSChunyang Hui 		       iter->pci_addr.domain, iter->pci_addr.bus, iter->pci_addr.dev, iter->pci_addr.func);
12308522624dSChunyang Hui 	}
12318522624dSChunyang Hui }
12328522624dSChunyang Hui 
12338522624dSChunyang Hui static void
12348522624dSChunyang Hui opal_change_password(struct dev *iter)
12358522624dSChunyang Hui {
12368522624dSChunyang Hui 	int user_id;
12370cd8b292SChangpeng Liu 	char old_passwd[SPDK_OPAL_MAX_PASSWORD_SIZE] = {0};
12388522624dSChunyang Hui 	char *old_passwd_p;
12390cd8b292SChangpeng Liu 	char new_passwd[SPDK_OPAL_MAX_PASSWORD_SIZE] = {0};
12408522624dSChunyang Hui 	char *new_passwd_p;
12418522624dSChunyang Hui 	int ret;
12428522624dSChunyang Hui 	int ch;
12438522624dSChunyang Hui 
12448522624dSChunyang Hui 	if (spdk_nvme_ctrlr_get_flags(iter->ctrlr) & SPDK_NVME_CTRLR_SECURITY_SEND_RECV_SUPPORTED) {
1245c61b70c3SChangpeng Liu 		iter->opal_dev = spdk_opal_dev_construct(iter->ctrlr);
12468522624dSChunyang Hui 		if (iter->opal_dev == NULL) {
12478522624dSChunyang Hui 			return;
12488522624dSChunyang Hui 		}
12498522624dSChunyang Hui 		printf("user id: ");
12508522624dSChunyang Hui 		if (!scanf("%d", &user_id)) {
12518522624dSChunyang Hui 			printf("Invalid user id\n");
1252c61b70c3SChangpeng Liu 			spdk_opal_dev_destruct(iter->opal_dev);
12538522624dSChunyang Hui 			return;
12548522624dSChunyang Hui 		}
1255defe09d3SChunyang Hui 		printf("Password:");
12568522624dSChunyang Hui 		while ((ch = getchar()) != '\n' && ch != EOF);
12570cd8b292SChangpeng Liu 		old_passwd_p = get_line(old_passwd, SPDK_OPAL_MAX_PASSWORD_SIZE, stdin, true);
1258defe09d3SChunyang Hui 		printf("\n");
12598522624dSChunyang Hui 		if (old_passwd_p) {
12608522624dSChunyang Hui 			printf("Please input new password:\n");
12610cd8b292SChangpeng Liu 			new_passwd_p = get_line(new_passwd, SPDK_OPAL_MAX_PASSWORD_SIZE, stdin, true);
1262defe09d3SChunyang Hui 			printf("\n");
12638522624dSChunyang Hui 			if (new_passwd_p == NULL) {
12648522624dSChunyang Hui 				printf("Input password invalid. Change password failure\n");
1265c61b70c3SChangpeng Liu 				spdk_opal_dev_destruct(iter->opal_dev);
12668522624dSChunyang Hui 				return;
12678522624dSChunyang Hui 			}
12688522624dSChunyang Hui 
12698522624dSChunyang Hui 			ret = spdk_opal_cmd_set_new_passwd(iter->opal_dev, user_id, new_passwd_p, old_passwd_p, false);
12708522624dSChunyang Hui 			if (ret) {
12718522624dSChunyang Hui 				printf("Set new password failure error code: %d\n", ret);
1272c61b70c3SChangpeng Liu 				spdk_opal_dev_destruct(iter->opal_dev);
12738522624dSChunyang Hui 				return;
12748522624dSChunyang Hui 			}
12758522624dSChunyang Hui 
12768522624dSChunyang Hui 			printf("...\n...\nChange password Success\n");
12778522624dSChunyang Hui 		} else {
12788522624dSChunyang Hui 			printf("Input password invalid. Change password failure\n");
12798522624dSChunyang Hui 		}
1280c61b70c3SChangpeng Liu 		spdk_opal_dev_destruct(iter->opal_dev);
12818522624dSChunyang Hui 	} else {
12828522624dSChunyang Hui 		printf("%04x:%02x:%02x.%02x: NVMe Security Support/Receive Not supported.\nOpal Not Supported\n\n\n",
12838522624dSChunyang Hui 		       iter->pci_addr.domain, iter->pci_addr.bus, iter->pci_addr.dev, iter->pci_addr.func);
12848522624dSChunyang Hui 	}
12858522624dSChunyang Hui }
12868522624dSChunyang Hui 
12878522624dSChunyang Hui static void
12888522624dSChunyang Hui opal_add_user_to_locking_range(struct dev *iter)
12898522624dSChunyang Hui {
12908522624dSChunyang Hui 	int locking_range_id, user_id;
12910cd8b292SChangpeng Liu 	char passwd[SPDK_OPAL_MAX_PASSWORD_SIZE] = {0};
12928522624dSChunyang Hui 	char *passwd_p;
12938522624dSChunyang Hui 	int ret;
12948522624dSChunyang Hui 	int ch;
12958522624dSChunyang Hui 
12968522624dSChunyang Hui 	if (spdk_nvme_ctrlr_get_flags(iter->ctrlr) & SPDK_NVME_CTRLR_SECURITY_SEND_RECV_SUPPORTED) {
1297c61b70c3SChangpeng Liu 		iter->opal_dev = spdk_opal_dev_construct(iter->ctrlr);
12988522624dSChunyang Hui 		if (iter->opal_dev == NULL) {
12998522624dSChunyang Hui 			return;
13008522624dSChunyang Hui 		}
1301defe09d3SChunyang Hui 		printf("Please input admin password:");
13028522624dSChunyang Hui 		while ((ch = getchar()) != '\n' && ch != EOF);
13030cd8b292SChangpeng Liu 		passwd_p = get_line(passwd, SPDK_OPAL_MAX_PASSWORD_SIZE, stdin, true);
1304defe09d3SChunyang Hui 		printf("\n");
13058522624dSChunyang Hui 		if (passwd_p) {
13068522624dSChunyang Hui 			printf("Specify locking range id:\n");
13078522624dSChunyang Hui 			if (!scanf("%d", &locking_range_id)) {
13088522624dSChunyang Hui 				printf("Invalid locking range id\n");
1309c61b70c3SChangpeng Liu 				spdk_opal_dev_destruct(iter->opal_dev);
13108522624dSChunyang Hui 				return;
13118522624dSChunyang Hui 			}
13128522624dSChunyang Hui 
13138522624dSChunyang Hui 			printf("which user to enable:\n");
13148522624dSChunyang Hui 			if (!scanf("%d", &user_id)) {
13158522624dSChunyang Hui 				printf("Invalid user id\n");
1316c61b70c3SChangpeng Liu 				spdk_opal_dev_destruct(iter->opal_dev);
13178522624dSChunyang Hui 				return;
13188522624dSChunyang Hui 			}
1319defe09d3SChunyang Hui 			while (getchar() != '\n');
13208522624dSChunyang Hui 
13218522624dSChunyang Hui 			ret = spdk_opal_cmd_add_user_to_locking_range(iter->opal_dev, user_id, locking_range_id,
1322b2947f52SChangpeng Liu 					OPAL_READONLY, passwd_p);
13238522624dSChunyang Hui 			ret += spdk_opal_cmd_add_user_to_locking_range(iter->opal_dev, user_id, locking_range_id,
1324b2947f52SChangpeng Liu 					OPAL_READWRITE, passwd_p);
13258522624dSChunyang Hui 			if (ret) {
13268522624dSChunyang Hui 				printf("Add user to locking range error: %d\n", ret);
1327c61b70c3SChangpeng Liu 				spdk_opal_dev_destruct(iter->opal_dev);
13288522624dSChunyang Hui 				return;
13298522624dSChunyang Hui 			}
13308522624dSChunyang Hui 
13318522624dSChunyang Hui 			printf("...\n...\nAdd user to locking range Success\n");
13328522624dSChunyang Hui 		} else {
13338522624dSChunyang Hui 			printf("Input password invalid. Add user to locking range failure\n");
13348522624dSChunyang Hui 		}
1335c61b70c3SChangpeng Liu 		spdk_opal_dev_destruct(iter->opal_dev);
13368522624dSChunyang Hui 	} else {
13378522624dSChunyang Hui 		printf("%04x:%02x:%02x.%02x: NVMe Security Support/Receive Not supported.\nOpal Not Supported\n\n\n",
13388522624dSChunyang Hui 		       iter->pci_addr.domain, iter->pci_addr.bus, iter->pci_addr.dev, iter->pci_addr.func);
13398522624dSChunyang Hui 	}
13408522624dSChunyang Hui }
13418522624dSChunyang Hui 
13428522624dSChunyang Hui static void
13438522624dSChunyang Hui opal_user_lock_unlock_range(struct dev *iter)
13448522624dSChunyang Hui {
13450cd8b292SChangpeng Liu 	char passwd[SPDK_OPAL_MAX_PASSWORD_SIZE] = {0};
13468522624dSChunyang Hui 	char *passwd_p;
13478522624dSChunyang Hui 	int ch;
13488522624dSChunyang Hui 	int ret;
13498522624dSChunyang Hui 	int user_id;
13508522624dSChunyang Hui 	int locking_range_id;
13518522624dSChunyang Hui 	int state;
13528522624dSChunyang Hui 	enum spdk_opal_lock_state state_flag;
13538522624dSChunyang Hui 
13548522624dSChunyang Hui 	if (spdk_nvme_ctrlr_get_flags(iter->ctrlr) & SPDK_NVME_CTRLR_SECURITY_SEND_RECV_SUPPORTED) {
1355c61b70c3SChangpeng Liu 		iter->opal_dev = spdk_opal_dev_construct(iter->ctrlr);
13568522624dSChunyang Hui 		if (iter->opal_dev == NULL) {
13578522624dSChunyang Hui 			return;
13588522624dSChunyang Hui 		}
13598522624dSChunyang Hui 		printf("User id: ");
13608522624dSChunyang Hui 		if (!scanf("%d", &user_id)) {
13618522624dSChunyang Hui 			printf("Invalid user id\n");
1362c61b70c3SChangpeng Liu 			spdk_opal_dev_destruct(iter->opal_dev);
13638522624dSChunyang Hui 			return;
13648522624dSChunyang Hui 		}
13658522624dSChunyang Hui 
1366defe09d3SChunyang Hui 		printf("Please input password:");
13678522624dSChunyang Hui 		while ((ch = getchar()) != '\n' && ch != EOF);
13680cd8b292SChangpeng Liu 		passwd_p = get_line(passwd, SPDK_OPAL_MAX_PASSWORD_SIZE, stdin, true);
1369defe09d3SChunyang Hui 		printf("\n");
13708522624dSChunyang Hui 		if (passwd_p) {
13718522624dSChunyang Hui 			printf("Specify locking range id:\n");
13728522624dSChunyang Hui 			if (!scanf("%d", &locking_range_id)) {
13738522624dSChunyang Hui 				printf("Invalid locking range id\n");
1374c61b70c3SChangpeng Liu 				spdk_opal_dev_destruct(iter->opal_dev);
13758522624dSChunyang Hui 				return;
13768522624dSChunyang Hui 			}
13778522624dSChunyang Hui 
13788522624dSChunyang Hui 			opal_locking_usage();
13798522624dSChunyang Hui 			if (!scanf("%d", &state)) {
13808522624dSChunyang Hui 				printf("Invalid option\n");
13818522624dSChunyang Hui 			}
13828522624dSChunyang Hui 			switch (state) {
13838522624dSChunyang Hui 			case 1:
13848522624dSChunyang Hui 				state_flag = OPAL_RWLOCK;
13858522624dSChunyang Hui 				break;
13868522624dSChunyang Hui 			case 2:
13878522624dSChunyang Hui 				state_flag = OPAL_READONLY;
13888522624dSChunyang Hui 				break;
13898522624dSChunyang Hui 			case 3:
13908522624dSChunyang Hui 				state_flag = OPAL_READWRITE;
13918522624dSChunyang Hui 				break;
13928522624dSChunyang Hui 			default:
13938522624dSChunyang Hui 				printf("Invalid options\n");
1394c61b70c3SChangpeng Liu 				spdk_opal_dev_destruct(iter->opal_dev);
13958522624dSChunyang Hui 				return;
13968522624dSChunyang Hui 			}
1397defe09d3SChunyang Hui 			while (getchar() != '\n');
13988522624dSChunyang Hui 
13998522624dSChunyang Hui 			ret = spdk_opal_cmd_lock_unlock(iter->opal_dev, user_id, state_flag,
14008522624dSChunyang Hui 							locking_range_id, passwd_p);
14018522624dSChunyang Hui 			if (ret) {
14028522624dSChunyang Hui 				printf("lock/unlock range failure: %d\n", ret);
1403c61b70c3SChangpeng Liu 				spdk_opal_dev_destruct(iter->opal_dev);
14048522624dSChunyang Hui 				return;
14058522624dSChunyang Hui 			}
14068522624dSChunyang Hui 			printf("...\n...\nLock/unlock range Success\n");
14078522624dSChunyang Hui 		} else {
14088522624dSChunyang Hui 			printf("Input password invalid. lock/unlock range failure\n");
14098522624dSChunyang Hui 		}
1410c61b70c3SChangpeng Liu 		spdk_opal_dev_destruct(iter->opal_dev);
14118522624dSChunyang Hui 	} else {
14128522624dSChunyang Hui 		printf("%04x:%02x:%02x.%02x: NVMe Security Support/Receive Not supported.\nOpal Not Supported\n\n\n",
14138522624dSChunyang Hui 		       iter->pci_addr.domain, iter->pci_addr.bus, iter->pci_addr.dev, iter->pci_addr.func);
14148522624dSChunyang Hui 	}
14158522624dSChunyang Hui }
14168522624dSChunyang Hui 
14178522624dSChunyang Hui static void
14186b48e743SChunyang Hui opal_revert_tper(struct dev *iter)
14196b48e743SChunyang Hui {
14200cd8b292SChangpeng Liu 	char passwd[SPDK_OPAL_MAX_PASSWORD_SIZE] = {0};
14216b48e743SChunyang Hui 	char *passwd_p;
14226b48e743SChunyang Hui 	int ret;
14236b48e743SChunyang Hui 	int ch;
14246b48e743SChunyang Hui 
14256b48e743SChunyang Hui 	if (spdk_nvme_ctrlr_get_flags(iter->ctrlr) & SPDK_NVME_CTRLR_SECURITY_SEND_RECV_SUPPORTED) {
1426c61b70c3SChangpeng Liu 		iter->opal_dev = spdk_opal_dev_construct(iter->ctrlr);
14276b48e743SChunyang Hui 		if (iter->opal_dev == NULL) {
14286b48e743SChunyang Hui 			return;
14296b48e743SChunyang Hui 		}
14306b48e743SChunyang Hui 		printf("Please be noted this operation will erase ALL DATA on this drive\n");
1431b7876f9aSJosh Soref 		printf("Please don't terminate this execution. Otherwise undefined error may occur\n");
1432defe09d3SChunyang Hui 		printf("Please input password for revert TPer:");
14336b48e743SChunyang Hui 		while ((ch = getchar()) != '\n' && ch != EOF);
14340cd8b292SChangpeng Liu 		passwd_p = get_line(passwd, SPDK_OPAL_MAX_PASSWORD_SIZE, stdin, true);
1435defe09d3SChunyang Hui 		printf("\n...\n");
14366b48e743SChunyang Hui 		if (passwd_p) {
14379f988238SChunyang Hui 			ret = spdk_opal_cmd_revert_tper(iter->opal_dev, passwd_p);
14386b48e743SChunyang Hui 			if (ret) {
14396b48e743SChunyang Hui 				printf("Revert TPer failure: %d\n", ret);
1440c61b70c3SChangpeng Liu 				spdk_opal_dev_destruct(iter->opal_dev);
14416b48e743SChunyang Hui 				return;
14426b48e743SChunyang Hui 			}
1443defe09d3SChunyang Hui 			printf("...\nRevert TPer Success\n");
14446b48e743SChunyang Hui 		} else {
14456b48e743SChunyang Hui 			printf("Input password invalid. Revert TPer failure\n");
14466b48e743SChunyang Hui 		}
1447c61b70c3SChangpeng Liu 		spdk_opal_dev_destruct(iter->opal_dev);
14486b48e743SChunyang Hui 	} else {
14496b48e743SChunyang Hui 		printf("%04x:%02x:%02x.%02x: NVMe Security Support/Receive Not supported.\nOpal Not Supported\n\n\n",
14507250ec64SChunyang Hui 		       iter->pci_addr.domain, iter->pci_addr.bus, iter->pci_addr.dev, iter->pci_addr.func);
14517250ec64SChunyang Hui 	}
14527250ec64SChunyang Hui }
14537250ec64SChunyang Hui 
14547250ec64SChunyang Hui static void
14550fae4f64SChunyang Hui opal_erase_locking_range(struct dev *iter)
14560fae4f64SChunyang Hui {
14570cd8b292SChangpeng Liu 	char passwd[SPDK_OPAL_MAX_PASSWORD_SIZE] = {0};
14580fae4f64SChunyang Hui 	char *passwd_p;
14590fae4f64SChunyang Hui 	int ret;
14600fae4f64SChunyang Hui 	int ch;
14610fae4f64SChunyang Hui 	int locking_range_id;
14620fae4f64SChunyang Hui 
14630fae4f64SChunyang Hui 	if (spdk_nvme_ctrlr_get_flags(iter->ctrlr) & SPDK_NVME_CTRLR_SECURITY_SEND_RECV_SUPPORTED) {
1464c61b70c3SChangpeng Liu 		iter->opal_dev = spdk_opal_dev_construct(iter->ctrlr);
14650fae4f64SChunyang Hui 		if (iter->opal_dev == NULL) {
14660fae4f64SChunyang Hui 			return;
14670fae4f64SChunyang Hui 		}
14680fae4f64SChunyang Hui 		printf("Please be noted this operation will erase ALL DATA on this range\n");
14690fae4f64SChunyang Hui 		printf("Please input password for erase locking range:");
14700fae4f64SChunyang Hui 		while ((ch = getchar()) != '\n' && ch != EOF);
14710cd8b292SChangpeng Liu 		passwd_p = get_line(passwd, SPDK_OPAL_MAX_PASSWORD_SIZE, stdin, true);
14720fae4f64SChunyang Hui 		if (passwd_p) {
14730fae4f64SChunyang Hui 			printf("\nSpecify locking range id:\n");
14740fae4f64SChunyang Hui 			if (!scanf("%d", &locking_range_id)) {
14750fae4f64SChunyang Hui 				printf("Invalid locking range id\n");
1476c61b70c3SChangpeng Liu 				spdk_opal_dev_destruct(iter->opal_dev);
14770fae4f64SChunyang Hui 				return;
14780fae4f64SChunyang Hui 			}
14790fae4f64SChunyang Hui 			printf("\n...\n");
1480ebb01092SChangpeng Liu 			ret = spdk_opal_cmd_secure_erase_locking_range(iter->opal_dev, OPAL_ADMIN1, locking_range_id,
1481ebb01092SChangpeng Liu 					passwd_p);
14820fae4f64SChunyang Hui 			if (ret) {
14830fae4f64SChunyang Hui 				printf("Erase locking range failure: %d\n", ret);
1484c61b70c3SChangpeng Liu 				spdk_opal_dev_destruct(iter->opal_dev);
14850fae4f64SChunyang Hui 				return;
14860fae4f64SChunyang Hui 			}
14870fae4f64SChunyang Hui 			printf("...\nErase locking range Success\n");
14880fae4f64SChunyang Hui 		} else {
14890fae4f64SChunyang Hui 			printf("Input password invalid. Erase locking range failure\n");
14900fae4f64SChunyang Hui 		}
1491c61b70c3SChangpeng Liu 		spdk_opal_dev_destruct(iter->opal_dev);
14920fae4f64SChunyang Hui 	} else {
14930fae4f64SChunyang Hui 		printf("%04x:%02x:%02x.%02x: NVMe Security Support/Receive Not supported.\nOpal Not Supported\n\n\n",
14940fae4f64SChunyang Hui 		       iter->pci_addr.domain, iter->pci_addr.bus, iter->pci_addr.dev, iter->pci_addr.func);
14950fae4f64SChunyang Hui 	}
14960fae4f64SChunyang Hui }
14970fae4f64SChunyang Hui 
14980fae4f64SChunyang Hui static void
14997250ec64SChunyang Hui test_opal(void)
15007250ec64SChunyang Hui {
15017250ec64SChunyang Hui 	int exit_flag = false;
15027250ec64SChunyang Hui 	struct dev *ctrlr;
15037250ec64SChunyang Hui 
15047250ec64SChunyang Hui 	ctrlr = get_controller();
15057250ec64SChunyang Hui 	if (ctrlr == NULL) {
15067250ec64SChunyang Hui 		printf("Invalid controller PCI Address.\n");
15077250ec64SChunyang Hui 		return;
15087250ec64SChunyang Hui 	}
15097250ec64SChunyang Hui 
15107250ec64SChunyang Hui 	opal_usage();
15117250ec64SChunyang Hui 	while (!exit_flag) {
15127250ec64SChunyang Hui 		int cmd;
15137250ec64SChunyang Hui 		if (!scanf("%d", &cmd)) {
1514505dbf59SChunyang Hui 			printf("Invalid Command: command must be number 0-9\n");
15157250ec64SChunyang Hui 			while (getchar() != '\n');
15167250ec64SChunyang Hui 			opal_usage();
15177250ec64SChunyang Hui 			continue;
15187250ec64SChunyang Hui 		}
15197250ec64SChunyang Hui 
15207250ec64SChunyang Hui 		switch (cmd) {
15217250ec64SChunyang Hui 		case 0:
15227250ec64SChunyang Hui 			exit_flag = true;
15237250ec64SChunyang Hui 			continue;
15247250ec64SChunyang Hui 		case 1:
15257250ec64SChunyang Hui 			opal_scan(ctrlr);
15267250ec64SChunyang Hui 			break;
15277250ec64SChunyang Hui 		case 2:
1528755b4390SChunyang Hui 			opal_init(ctrlr);   /* Take ownership, Activate Locking SP */
15297250ec64SChunyang Hui 			break;
15306b48e743SChunyang Hui 		case 3:
15310fae4f64SChunyang Hui 			opal_revert_tper(ctrlr);
1532fbd2f3fdSChunyang Hui 			break;
1533fbd2f3fdSChunyang Hui 		case 4:
15340fae4f64SChunyang Hui 			opal_setup_lockingrange(ctrlr);
1535505dbf59SChunyang Hui 			break;
15368522624dSChunyang Hui 		case 5:
15370fae4f64SChunyang Hui 			opal_list_locking_ranges(ctrlr);
15388522624dSChunyang Hui 			break;
15398522624dSChunyang Hui 		case 6:
15400fae4f64SChunyang Hui 			opal_new_user_enable(ctrlr);
15418522624dSChunyang Hui 			break;
15428522624dSChunyang Hui 		case 7:
15430fae4f64SChunyang Hui 			opal_change_password(ctrlr);
15448522624dSChunyang Hui 			break;
15458522624dSChunyang Hui 		case 8:
15460fae4f64SChunyang Hui 			opal_add_user_to_locking_range(ctrlr);
15478522624dSChunyang Hui 			break;
1548505dbf59SChunyang Hui 		case 9:
15490fae4f64SChunyang Hui 			opal_user_lock_unlock_range(ctrlr);
15500fae4f64SChunyang Hui 			break;
15510fae4f64SChunyang Hui 		case 10:
15520fae4f64SChunyang Hui 			opal_erase_locking_range(ctrlr);
15536b48e743SChunyang Hui 			break;
15547250ec64SChunyang Hui 
15557250ec64SChunyang Hui 		default:
15567250ec64SChunyang Hui 			printf("Invalid option\n");
15577250ec64SChunyang Hui 		}
15587250ec64SChunyang Hui 
1559defe09d3SChunyang Hui 		printf("\npress Enter to display Opal cmd menu ...\n");
15607250ec64SChunyang Hui 		while (getchar() != '\n');
15617250ec64SChunyang Hui 		opal_usage();
15627250ec64SChunyang Hui 	}
156355f5b205SHui, Chunyang }
156455f5b205SHui, Chunyang 
1565f07ed6efSGangCao static void
1566f07ed6efSGangCao args_usage(const char *program_name)
1567f07ed6efSGangCao {
1568f07ed6efSGangCao 	printf("%s [options]", program_name);
1569f07ed6efSGangCao 	printf("\n");
1570f07ed6efSGangCao 	printf("options:\n");
1571f07ed6efSGangCao 	printf(" -i         shared memory group ID\n");
1572f07ed6efSGangCao }
1573f07ed6efSGangCao 
1574f07ed6efSGangCao static int
1575f07ed6efSGangCao parse_args(int argc, char **argv)
1576f07ed6efSGangCao {
1577f07ed6efSGangCao 	int op;
1578f07ed6efSGangCao 
1579f07ed6efSGangCao 	while ((op = getopt(argc, argv, "i:")) != -1) {
1580f07ed6efSGangCao 		switch (op) {
1581f07ed6efSGangCao 		case 'i':
15820f9dc2afSShuhei Matsumoto 			g_shm_id = spdk_strtol(optarg, 10);
15830f9dc2afSShuhei Matsumoto 			if (g_shm_id < 0) {
15840f9dc2afSShuhei Matsumoto 				fprintf(stderr, "Invalid shared memory ID\n");
15850f9dc2afSShuhei Matsumoto 				return g_shm_id;
15860f9dc2afSShuhei Matsumoto 			}
1587f07ed6efSGangCao 			break;
1588f07ed6efSGangCao 		default:
1589f07ed6efSGangCao 			args_usage(argv[0]);
1590f07ed6efSGangCao 			return 1;
1591f07ed6efSGangCao 		}
1592f07ed6efSGangCao 	}
1593f07ed6efSGangCao 
1594f07ed6efSGangCao 	return 0;
1595f07ed6efSGangCao }
1596f07ed6efSGangCao 
15978dd1cd21SBen Walker int
15988dd1cd21SBen Walker main(int argc, char **argv)
159998416108SCunyin Chang {
160047d4ead9SShuhei Matsumoto 	int			rc;
160118d26e42SBen Walker 	struct spdk_env_opts	opts;
160247d4ead9SShuhei Matsumoto 	struct dev		*dev;
16030a903c91SShuhei Matsumoto 	struct spdk_nvme_detach_ctx *detach_ctx = NULL;
160498416108SCunyin Chang 
1605f07ed6efSGangCao 	rc = parse_args(argc, argv);
1606f07ed6efSGangCao 	if (rc != 0) {
1607f07ed6efSGangCao 		return rc;
1608f07ed6efSGangCao 	}
1609f07ed6efSGangCao 
1610*57fd99b9SJim Harris 	opts.opts_size = sizeof(opts);
161118d26e42SBen Walker 	spdk_env_opts_init(&opts);
161218d26e42SBen Walker 	opts.name = "nvme_manage";
161318d26e42SBen Walker 	opts.core_mask = "0x1";
1614f07ed6efSGangCao 	opts.shm_id = g_shm_id;
1615095f4254SLance Hartmann 	if (spdk_env_init(&opts) < 0) {
1616095f4254SLance Hartmann 		fprintf(stderr, "Unable to initialize SPDK env\n");
1617095f4254SLance Hartmann 		return 1;
1618095f4254SLance Hartmann 	}
161998416108SCunyin Chang 
1620df46c41aSBen Walker 	if (spdk_nvme_probe(NULL, NULL, probe_cb, attach_cb, NULL) != 0) {
162198416108SCunyin Chang 		fprintf(stderr, "spdk_nvme_probe() failed\n");
16229ec9c8b3SChangpeng Liu 		spdk_env_fini();
162398416108SCunyin Chang 		return 1;
162498416108SCunyin Chang 	}
162598416108SCunyin Chang 
16262e61a144SDaniel Verkamp 	qsort(devs, num_devs, sizeof(devs[0]), cmp_devs);
16272e61a144SDaniel Verkamp 
162898416108SCunyin Chang 	usage();
162998416108SCunyin Chang 
163098416108SCunyin Chang 	while (1) {
163198416108SCunyin Chang 		int cmd;
163298416108SCunyin Chang 		bool exit_flag = false;
163398416108SCunyin Chang 
163498416108SCunyin Chang 		if (!scanf("%d", &cmd)) {
16352716cd2aSlu fan 			printf("Invalid Command: command must be number 1-8\n");
163698416108SCunyin Chang 			while (getchar() != '\n');
16372716cd2aSlu fan 			usage();
16382716cd2aSlu fan 			continue;
163998416108SCunyin Chang 		}
164098416108SCunyin Chang 		switch (cmd) {
164198416108SCunyin Chang 		case 1:
164298416108SCunyin Chang 			display_controller_list();
164398416108SCunyin Chang 			break;
164498416108SCunyin Chang 		case 2:
164598416108SCunyin Chang 			add_ns();
164698416108SCunyin Chang 			break;
164798416108SCunyin Chang 		case 3:
164898416108SCunyin Chang 			delete_ns();
164998416108SCunyin Chang 			break;
165098416108SCunyin Chang 		case 4:
165198416108SCunyin Chang 			attach_and_detach_ns(SPDK_NVME_NS_CTRLR_ATTACH);
165298416108SCunyin Chang 			break;
165398416108SCunyin Chang 		case 5:
165498416108SCunyin Chang 			attach_and_detach_ns(SPDK_NVME_NS_CTRLR_DETACH);
165598416108SCunyin Chang 			break;
165698416108SCunyin Chang 		case 6:
1657eae68857SCunyin Chang 			format_nvm();
1658eae68857SCunyin Chang 			break;
1659eae68857SCunyin Chang 		case 7:
16600f805b36SCunyin Chang 			update_firmware_image();
16610f805b36SCunyin Chang 			break;
16620f805b36SCunyin Chang 		case 8:
166355f5b205SHui, Chunyang 			test_opal();
166455f5b205SHui, Chunyang 			break;
166555f5b205SHui, Chunyang 		case 9:
166698416108SCunyin Chang 			exit_flag = true;
166798416108SCunyin Chang 			break;
166898416108SCunyin Chang 		default:
166998416108SCunyin Chang 			printf("Invalid Command\n");
167098416108SCunyin Chang 			break;
167198416108SCunyin Chang 		}
167298416108SCunyin Chang 
167359970a89SDaniel Verkamp 		if (exit_flag) {
167498416108SCunyin Chang 			break;
167559970a89SDaniel Verkamp 		}
167698416108SCunyin Chang 
167798416108SCunyin Chang 		while (getchar() != '\n');
167898416108SCunyin Chang 		printf("press Enter to display cmd menu ...\n");
167998416108SCunyin Chang 		while (getchar() != '\n');
168098416108SCunyin Chang 		usage();
168198416108SCunyin Chang 	}
168298416108SCunyin Chang 
168398416108SCunyin Chang 	printf("Cleaning up...\n");
168498416108SCunyin Chang 
168547d4ead9SShuhei Matsumoto 	foreach_dev(dev) {
16860a903c91SShuhei Matsumoto 		spdk_nvme_detach_async(dev->ctrlr, &detach_ctx);
16870a903c91SShuhei Matsumoto 	}
16880a903c91SShuhei Matsumoto 
16894fe4040aSShuhei Matsumoto 	if (detach_ctx) {
16904fe4040aSShuhei Matsumoto 		spdk_nvme_detach_poll(detach_ctx);
169198416108SCunyin Chang 	}
169298416108SCunyin Chang 
16939ec9c8b3SChangpeng Liu 	spdk_env_fini();
16949ec9c8b3SChangpeng Liu 
169518d26e42SBen Walker 	return 0;
169698416108SCunyin Chang }
1697