xref: /spdk/examples/nvme/pmr_persistence/pmr_persistence.c (revision 186b109dd3a723612e3df79bb3d97699173d39e3)
1488570ebSJim Harris /*   SPDX-License-Identifier: BSD-3-Clause
2e04da24cSKrishna Kanth Reddy  *   Copyright (c) Samsung Electronics Co., Ltd.
3e04da24cSKrishna Kanth Reddy  *   All rights reserved.
4e04da24cSKrishna Kanth Reddy  */
5e04da24cSKrishna Kanth Reddy 
6e04da24cSKrishna Kanth Reddy #include "spdk/stdinc.h"
7e04da24cSKrishna Kanth Reddy 
8e04da24cSKrishna Kanth Reddy #include "spdk/env.h"
9e04da24cSKrishna Kanth Reddy #include "spdk/nvme.h"
10e04da24cSKrishna Kanth Reddy #include "spdk/string.h"
11e04da24cSKrishna Kanth Reddy 
12e04da24cSKrishna Kanth Reddy struct nvme_io {
13e04da24cSKrishna Kanth Reddy 	struct spdk_nvme_ctrlr *ctrlr;
14e04da24cSKrishna Kanth Reddy 	struct spdk_nvme_transport_id trid;
15e04da24cSKrishna Kanth Reddy 	struct spdk_nvme_ns *ns;
16e04da24cSKrishna Kanth Reddy 	unsigned nsid;
17e04da24cSKrishna Kanth Reddy 	unsigned rlba;
18e04da24cSKrishna Kanth Reddy 	unsigned nlbas;
19e04da24cSKrishna Kanth Reddy 	unsigned wlba;
20e04da24cSKrishna Kanth Reddy 	uint32_t lba_size;
21e04da24cSKrishna Kanth Reddy 	unsigned done;
22e04da24cSKrishna Kanth Reddy };
23e04da24cSKrishna Kanth Reddy 
24e04da24cSKrishna Kanth Reddy struct config {
25e04da24cSKrishna Kanth Reddy 	struct nvme_io pmr_dev;
26e04da24cSKrishna Kanth Reddy 	size_t         copy_size;
27e04da24cSKrishna Kanth Reddy };
28e04da24cSKrishna Kanth Reddy 
29e04da24cSKrishna Kanth Reddy static struct config g_config;
30e04da24cSKrishna Kanth Reddy 
31e04da24cSKrishna Kanth Reddy /* Namespaces index from 1. Return 0 to invoke an error */
32e04da24cSKrishna Kanth Reddy static unsigned
33e04da24cSKrishna Kanth Reddy get_nsid(const struct spdk_nvme_transport_id *trid)
34e04da24cSKrishna Kanth Reddy {
35e04da24cSKrishna Kanth Reddy 	if (!strcmp(trid->traddr, g_config.pmr_dev.trid.traddr)) {
36e04da24cSKrishna Kanth Reddy 		return g_config.pmr_dev.nsid;
37e04da24cSKrishna Kanth Reddy 	}
38e04da24cSKrishna Kanth Reddy 	return 0;
39e04da24cSKrishna Kanth Reddy }
40e04da24cSKrishna Kanth Reddy 
41e04da24cSKrishna Kanth Reddy static void
42e04da24cSKrishna Kanth Reddy check_io(void *arg, const struct spdk_nvme_cpl *completion)
43e04da24cSKrishna Kanth Reddy {
44e04da24cSKrishna Kanth Reddy 	g_config.pmr_dev.done = 1;
45e04da24cSKrishna Kanth Reddy }
46e04da24cSKrishna Kanth Reddy 
47e04da24cSKrishna Kanth Reddy static int
48e04da24cSKrishna Kanth Reddy pmr_persistence(void)
49e04da24cSKrishna Kanth Reddy {
50e04da24cSKrishna Kanth Reddy 	int rc = 0;
51e04da24cSKrishna Kanth Reddy 	void *pmr_buf, *buf;
52e04da24cSKrishna Kanth Reddy 	size_t sz;
53e04da24cSKrishna Kanth Reddy 	struct spdk_nvme_qpair	*qpair;
54e04da24cSKrishna Kanth Reddy 
55e04da24cSKrishna Kanth Reddy 	/* Allocate Queue Pair for the Controller with PMR */
56e04da24cSKrishna Kanth Reddy 	qpair = spdk_nvme_ctrlr_alloc_io_qpair(g_config.pmr_dev.ctrlr, NULL, 0);
57e04da24cSKrishna Kanth Reddy 	if (qpair == NULL) {
58e04da24cSKrishna Kanth Reddy 		printf("ERROR: spdk_nvme_ctrlr_alloc_io_qpair() failed\n");
59e04da24cSKrishna Kanth Reddy 		return -ENOMEM;
60e04da24cSKrishna Kanth Reddy 	}
61e04da24cSKrishna Kanth Reddy 
62e04da24cSKrishna Kanth Reddy 	/* Enable the PMR */
63e04da24cSKrishna Kanth Reddy 	rc = spdk_nvme_ctrlr_enable_pmr(g_config.pmr_dev.ctrlr);
64e04da24cSKrishna Kanth Reddy 	if (rc) {
65e04da24cSKrishna Kanth Reddy 		printf("ERROR: Enabling PMR failed\n");
66e04da24cSKrishna Kanth Reddy 		printf("Are you sure %s has a valid PMR?\n",
67e04da24cSKrishna Kanth Reddy 		       g_config.pmr_dev.trid.traddr);
68e04da24cSKrishna Kanth Reddy 		goto free_qpair;
69e04da24cSKrishna Kanth Reddy 	}
70e04da24cSKrishna Kanth Reddy 
71e04da24cSKrishna Kanth Reddy 	/* Allocate buffer from PMR */
72e04da24cSKrishna Kanth Reddy 	pmr_buf = spdk_nvme_ctrlr_map_pmr(g_config.pmr_dev.ctrlr, &sz);
73e04da24cSKrishna Kanth Reddy 	if (pmr_buf == NULL || sz < g_config.copy_size) {
74e04da24cSKrishna Kanth Reddy 		printf("ERROR: PMR buffer allocation failed\n");
75e04da24cSKrishna Kanth Reddy 		rc = -ENOMEM;
76e04da24cSKrishna Kanth Reddy 		goto disable_pmr;
77e04da24cSKrishna Kanth Reddy 	}
78e04da24cSKrishna Kanth Reddy 
79e04da24cSKrishna Kanth Reddy 	/* Clear the done flag */
80e04da24cSKrishna Kanth Reddy 	g_config.pmr_dev.done = 0;
81e04da24cSKrishna Kanth Reddy 
82e04da24cSKrishna Kanth Reddy 	/* Do the write to the PMR IO buffer, reading from rlba */
83e04da24cSKrishna Kanth Reddy 	rc = spdk_nvme_ns_cmd_read(g_config.pmr_dev.ns, qpair, pmr_buf,
84e04da24cSKrishna Kanth Reddy 				   g_config.pmr_dev.rlba, g_config.pmr_dev.nlbas,
85e04da24cSKrishna Kanth Reddy 				   check_io, NULL, 0);
86e04da24cSKrishna Kanth Reddy 	if (rc != 0) {
87e04da24cSKrishna Kanth Reddy 		fprintf(stderr, "Read I/O to PMR failed\n");
88e04da24cSKrishna Kanth Reddy 		rc = -EIO;
89e04da24cSKrishna Kanth Reddy 		goto unmap_pmr;
90e04da24cSKrishna Kanth Reddy 	}
91e04da24cSKrishna Kanth Reddy 	while (!g_config.pmr_dev.done) {
92e04da24cSKrishna Kanth Reddy 		spdk_nvme_qpair_process_completions(qpair, 0);
93e04da24cSKrishna Kanth Reddy 	}
94e04da24cSKrishna Kanth Reddy 
95e04da24cSKrishna Kanth Reddy 	/* Clear the done flag */
96e04da24cSKrishna Kanth Reddy 	g_config.pmr_dev.done = 0;
97e04da24cSKrishna Kanth Reddy 
98e04da24cSKrishna Kanth Reddy 	pmr_buf = NULL;
99e04da24cSKrishna Kanth Reddy 
100e04da24cSKrishna Kanth Reddy 	/* Free PMR buffer */
101e04da24cSKrishna Kanth Reddy 	rc = spdk_nvme_ctrlr_unmap_pmr(g_config.pmr_dev.ctrlr);
102e04da24cSKrishna Kanth Reddy 	if (rc) {
103e04da24cSKrishna Kanth Reddy 		printf("ERROR: Unmapping PMR failed\n");
104e04da24cSKrishna Kanth Reddy 		goto disable_pmr;
105e04da24cSKrishna Kanth Reddy 	}
106e04da24cSKrishna Kanth Reddy 
107e04da24cSKrishna Kanth Reddy 	/* Disable the PMR */
108e04da24cSKrishna Kanth Reddy 	rc = spdk_nvme_ctrlr_disable_pmr(g_config.pmr_dev.ctrlr);
109e04da24cSKrishna Kanth Reddy 	if (rc) {
110e04da24cSKrishna Kanth Reddy 		printf("ERROR: Disabling PMR failed\n");
111e04da24cSKrishna Kanth Reddy 		goto free_qpair;
112e04da24cSKrishna Kanth Reddy 	}
113e04da24cSKrishna Kanth Reddy 
114e04da24cSKrishna Kanth Reddy 	/* Free the queue */
115e04da24cSKrishna Kanth Reddy 	spdk_nvme_ctrlr_free_io_qpair(qpair);
116e04da24cSKrishna Kanth Reddy 
117e04da24cSKrishna Kanth Reddy 	rc = spdk_nvme_ctrlr_reset(g_config.pmr_dev.ctrlr);
118e04da24cSKrishna Kanth Reddy 	if (rc) {
119e04da24cSKrishna Kanth Reddy 		printf("ERROR: Resetting Controller failed\n");
120e04da24cSKrishna Kanth Reddy 		return rc;
121e04da24cSKrishna Kanth Reddy 	}
122e04da24cSKrishna Kanth Reddy 
123e04da24cSKrishna Kanth Reddy 	/* Allocate Queue Pair for the Controller with PMR */
124e04da24cSKrishna Kanth Reddy 	qpair = spdk_nvme_ctrlr_alloc_io_qpair(g_config.pmr_dev.ctrlr, NULL, 0);
125e04da24cSKrishna Kanth Reddy 	if (qpair == NULL) {
126e04da24cSKrishna Kanth Reddy 		printf("ERROR: spdk_nvme_ctrlr_alloc_io_qpair() failed\n");
127e04da24cSKrishna Kanth Reddy 		return -ENOMEM;
128e04da24cSKrishna Kanth Reddy 	}
129e04da24cSKrishna Kanth Reddy 
130e04da24cSKrishna Kanth Reddy 	/* Enable the PMR */
131e04da24cSKrishna Kanth Reddy 	rc = spdk_nvme_ctrlr_enable_pmr(g_config.pmr_dev.ctrlr);
132e04da24cSKrishna Kanth Reddy 	if (rc) {
133e04da24cSKrishna Kanth Reddy 		printf("ERROR: Enabling PMR failed\n");
134e04da24cSKrishna Kanth Reddy 		goto free_qpair;
135e04da24cSKrishna Kanth Reddy 	}
136e04da24cSKrishna Kanth Reddy 
137e04da24cSKrishna Kanth Reddy 	/* Allocate buffer from PMR */
138e04da24cSKrishna Kanth Reddy 	pmr_buf = spdk_nvme_ctrlr_map_pmr(g_config.pmr_dev.ctrlr, &sz);
139e04da24cSKrishna Kanth Reddy 	if (pmr_buf == NULL || sz < g_config.copy_size) {
140e04da24cSKrishna Kanth Reddy 		printf("ERROR: PMR buffer allocation failed\n");
141e04da24cSKrishna Kanth Reddy 		rc = -ENOMEM;
142e04da24cSKrishna Kanth Reddy 		goto disable_pmr;
143e04da24cSKrishna Kanth Reddy 	}
144e04da24cSKrishna Kanth Reddy 
145e04da24cSKrishna Kanth Reddy 	/* Do the read from the PMR IO buffer, write to wlba */
146e04da24cSKrishna Kanth Reddy 	rc = spdk_nvme_ns_cmd_write(g_config.pmr_dev.ns, qpair, pmr_buf,
147e04da24cSKrishna Kanth Reddy 				    g_config.pmr_dev.wlba, g_config.pmr_dev.nlbas,
148e04da24cSKrishna Kanth Reddy 				    check_io, NULL, 0);
149e04da24cSKrishna Kanth Reddy 	if (rc != 0) {
150e04da24cSKrishna Kanth Reddy 		fprintf(stderr, "Read I/O from PMR failed\n");
151e04da24cSKrishna Kanth Reddy 		rc = -EIO;
152e04da24cSKrishna Kanth Reddy 		goto unmap_pmr;
153e04da24cSKrishna Kanth Reddy 	}
154e04da24cSKrishna Kanth Reddy 	while (!g_config.pmr_dev.done) {
155e04da24cSKrishna Kanth Reddy 		spdk_nvme_qpair_process_completions(qpair, 0);
156e04da24cSKrishna Kanth Reddy 	}
157e04da24cSKrishna Kanth Reddy 
158e04da24cSKrishna Kanth Reddy 	/* Clear the done flag */
159e04da24cSKrishna Kanth Reddy 	g_config.pmr_dev.done = 0;
160e04da24cSKrishna Kanth Reddy 
161*186b109dSJim Harris 	buf = spdk_zmalloc(g_config.copy_size, 0x1000, NULL, SPDK_ENV_NUMA_ID_ANY, SPDK_MALLOC_DMA);
162e04da24cSKrishna Kanth Reddy 	if (buf == NULL) {
163e04da24cSKrishna Kanth Reddy 		printf("ERROR: Buffer allocation failed\n");
164e04da24cSKrishna Kanth Reddy 		rc = -ENOMEM;
165e04da24cSKrishna Kanth Reddy 		goto unmap_pmr;
166e04da24cSKrishna Kanth Reddy 	}
167e04da24cSKrishna Kanth Reddy 
168e04da24cSKrishna Kanth Reddy 	/* Do the read from wlba to a buffer */
169e04da24cSKrishna Kanth Reddy 	rc = spdk_nvme_ns_cmd_read(g_config.pmr_dev.ns, qpair, buf,
170e04da24cSKrishna Kanth Reddy 				   g_config.pmr_dev.wlba, g_config.pmr_dev.nlbas,
171e04da24cSKrishna Kanth Reddy 				   check_io, NULL, 0);
172e04da24cSKrishna Kanth Reddy 	if (rc != 0) {
173e04da24cSKrishna Kanth Reddy 		fprintf(stderr, "Read I/O from WLBA failed\n");
174e04da24cSKrishna Kanth Reddy 		rc = -EIO;
175e04da24cSKrishna Kanth Reddy 		goto free_buf;
176e04da24cSKrishna Kanth Reddy 	}
177e04da24cSKrishna Kanth Reddy 	while (!g_config.pmr_dev.done) {
178e04da24cSKrishna Kanth Reddy 		spdk_nvme_qpair_process_completions(qpair, 0);
179e04da24cSKrishna Kanth Reddy 	}
180e04da24cSKrishna Kanth Reddy 
181e04da24cSKrishna Kanth Reddy 	/* Clear the done flag */
182e04da24cSKrishna Kanth Reddy 	g_config.pmr_dev.done = 0;
183e04da24cSKrishna Kanth Reddy 
184e04da24cSKrishna Kanth Reddy 	/* Compare the data in the read buffer to the PMR buffer */
185e04da24cSKrishna Kanth Reddy 	if (memcmp(buf, pmr_buf, g_config.copy_size)) {
186e04da24cSKrishna Kanth Reddy 		printf("PMR Data Not Persistent, after Controller Reset\n");
187e04da24cSKrishna Kanth Reddy 		rc = -EIO;
188e04da24cSKrishna Kanth Reddy 	} else {
189e04da24cSKrishna Kanth Reddy 		printf("PMR Data is Persistent across Controller Reset\n");
190e04da24cSKrishna Kanth Reddy 	}
191e04da24cSKrishna Kanth Reddy 
192e04da24cSKrishna Kanth Reddy free_buf:
193e04da24cSKrishna Kanth Reddy 	spdk_free(buf);
194e04da24cSKrishna Kanth Reddy 
195e04da24cSKrishna Kanth Reddy unmap_pmr:
196e04da24cSKrishna Kanth Reddy 	/* Free PMR buffer */
197e04da24cSKrishna Kanth Reddy 	spdk_nvme_ctrlr_unmap_pmr(g_config.pmr_dev.ctrlr);
198e04da24cSKrishna Kanth Reddy 
199e04da24cSKrishna Kanth Reddy disable_pmr:
200e04da24cSKrishna Kanth Reddy 	/* Disable the PMR */
201e04da24cSKrishna Kanth Reddy 	spdk_nvme_ctrlr_disable_pmr(g_config.pmr_dev.ctrlr);
202e04da24cSKrishna Kanth Reddy 
203e04da24cSKrishna Kanth Reddy free_qpair:
204e04da24cSKrishna Kanth Reddy 	/* Free the queue */
205e04da24cSKrishna Kanth Reddy 	spdk_nvme_ctrlr_free_io_qpair(qpair);
206e04da24cSKrishna Kanth Reddy 
207e04da24cSKrishna Kanth Reddy 	return rc;
208e04da24cSKrishna Kanth Reddy }
209e04da24cSKrishna Kanth Reddy 
210e04da24cSKrishna Kanth Reddy static bool
211e04da24cSKrishna Kanth Reddy probe_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
212e04da24cSKrishna Kanth Reddy 	 struct spdk_nvme_ctrlr_opts *opts)
213e04da24cSKrishna Kanth Reddy {
214e04da24cSKrishna Kanth Reddy 	/* We will only attach to the Controller specified by the user */
215e04da24cSKrishna Kanth Reddy 	if (spdk_nvme_transport_id_compare(trid, &g_config.pmr_dev.trid)) {
216e04da24cSKrishna Kanth Reddy 		printf("%s - not probed %s!\n", __func__, trid->traddr);
217e04da24cSKrishna Kanth Reddy 		return 0;
218e04da24cSKrishna Kanth Reddy 	}
219e04da24cSKrishna Kanth Reddy 
220e04da24cSKrishna Kanth Reddy 	printf("%s - probed %s!\n", __func__, trid->traddr);
221e04da24cSKrishna Kanth Reddy 	return 1;
222e04da24cSKrishna Kanth Reddy }
223e04da24cSKrishna Kanth Reddy 
224e04da24cSKrishna Kanth Reddy static void
225e04da24cSKrishna Kanth Reddy attach_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
226e04da24cSKrishna Kanth Reddy 	  struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_ctrlr_opts *opts)
227e04da24cSKrishna Kanth Reddy {
228e04da24cSKrishna Kanth Reddy 	struct spdk_nvme_ns *ns;
229e04da24cSKrishna Kanth Reddy 
230e04da24cSKrishna Kanth Reddy 	ns = spdk_nvme_ctrlr_get_ns(ctrlr, get_nsid(trid));
231e04da24cSKrishna Kanth Reddy 	if (ns == NULL) {
232e04da24cSKrishna Kanth Reddy 		fprintf(stderr, "Could not locate namespace %d on controller %s.\n",
233e04da24cSKrishna Kanth Reddy 			get_nsid(trid), trid->traddr);
234e04da24cSKrishna Kanth Reddy 		exit(-1);
235e04da24cSKrishna Kanth Reddy 	}
236e04da24cSKrishna Kanth Reddy 
237e04da24cSKrishna Kanth Reddy 	g_config.pmr_dev.ctrlr    = ctrlr;
238e04da24cSKrishna Kanth Reddy 	g_config.pmr_dev.ns       = ns;
239e04da24cSKrishna Kanth Reddy 	g_config.pmr_dev.lba_size = spdk_nvme_ns_get_sector_size(ns);
240e04da24cSKrishna Kanth Reddy 
241e04da24cSKrishna Kanth Reddy 	printf("%s - attached %s!\n", __func__, trid->traddr);
242e04da24cSKrishna Kanth Reddy }
243e04da24cSKrishna Kanth Reddy 
244e04da24cSKrishna Kanth Reddy static void
245e04da24cSKrishna Kanth Reddy usage(char *program_name)
246e04da24cSKrishna Kanth Reddy {
247e04da24cSKrishna Kanth Reddy 	printf("%s options (all mandatory)", program_name);
248e04da24cSKrishna Kanth Reddy 	printf("\n");
249e04da24cSKrishna Kanth Reddy 	printf("\t[-p PCIe address of the NVMe Device with PMR support]\n");
250e04da24cSKrishna Kanth Reddy 	printf("\t[-n Namespace ID]\n");
251e04da24cSKrishna Kanth Reddy 	printf("\t[-r Read LBA]\n");
252e04da24cSKrishna Kanth Reddy 	printf("\t[-l Number of LBAs to read]\n");
253e04da24cSKrishna Kanth Reddy 	printf("\t[-w Write LBA]\n");
254e04da24cSKrishna Kanth Reddy 	printf("\n");
255e04da24cSKrishna Kanth Reddy }
256e04da24cSKrishna Kanth Reddy 
257e04da24cSKrishna Kanth Reddy static int
258e04da24cSKrishna Kanth Reddy parse_args(int argc, char **argv)
259e04da24cSKrishna Kanth Reddy {
260e04da24cSKrishna Kanth Reddy 	int op;
261e04da24cSKrishna Kanth Reddy 	unsigned num_args = 0;
262e04da24cSKrishna Kanth Reddy 	long int val;
263e04da24cSKrishna Kanth Reddy 
264e04da24cSKrishna Kanth Reddy 	while ((op = getopt(argc, argv, "p:n:r:l:w:")) != -1) {
265e04da24cSKrishna Kanth Reddy 		switch (op) {
266e04da24cSKrishna Kanth Reddy 		case 'p':
267e04da24cSKrishna Kanth Reddy 			snprintf(&g_config.pmr_dev.trid.traddr[0], SPDK_NVMF_TRADDR_MAX_LEN + 1,
268e04da24cSKrishna Kanth Reddy 				 "%s", optarg);
269e04da24cSKrishna Kanth Reddy 
270e04da24cSKrishna Kanth Reddy 			g_config.pmr_dev.trid.trtype = SPDK_NVME_TRANSPORT_PCIE;
271e04da24cSKrishna Kanth Reddy 
272e04da24cSKrishna Kanth Reddy 			spdk_nvme_transport_id_populate_trstring(&g_config.pmr_dev.trid,
273e04da24cSKrishna Kanth Reddy 					spdk_nvme_transport_id_trtype_str(g_config.pmr_dev.trid.trtype));
274e04da24cSKrishna Kanth Reddy 
275e04da24cSKrishna Kanth Reddy 			num_args++;
276e04da24cSKrishna Kanth Reddy 			break;
277e04da24cSKrishna Kanth Reddy 		case 'n':
278e04da24cSKrishna Kanth Reddy 		case 'r':
279e04da24cSKrishna Kanth Reddy 		case 'l':
280e04da24cSKrishna Kanth Reddy 		case 'w':
281e04da24cSKrishna Kanth Reddy 			val = spdk_strtol(optarg, 10);
282e04da24cSKrishna Kanth Reddy 			if (val < 0) {
283e04da24cSKrishna Kanth Reddy 				fprintf(stderr, "Converting a string to integer failed\n");
284e04da24cSKrishna Kanth Reddy 				return val;
285e04da24cSKrishna Kanth Reddy 			}
286e04da24cSKrishna Kanth Reddy 			switch (op) {
287e04da24cSKrishna Kanth Reddy 			case 'n':
288e04da24cSKrishna Kanth Reddy 				g_config.pmr_dev.nsid = (unsigned)val;
289e04da24cSKrishna Kanth Reddy 				num_args++;
290e04da24cSKrishna Kanth Reddy 				break;
291e04da24cSKrishna Kanth Reddy 			case 'r':
292e04da24cSKrishna Kanth Reddy 				g_config.pmr_dev.rlba = (unsigned)val;
293e04da24cSKrishna Kanth Reddy 				num_args++;
294e04da24cSKrishna Kanth Reddy 				break;
295e04da24cSKrishna Kanth Reddy 			case 'l':
296e04da24cSKrishna Kanth Reddy 				g_config.pmr_dev.nlbas = (unsigned)val;
297e04da24cSKrishna Kanth Reddy 				num_args++;
298e04da24cSKrishna Kanth Reddy 				break;
299e04da24cSKrishna Kanth Reddy 			case 'w':
300e04da24cSKrishna Kanth Reddy 				g_config.pmr_dev.wlba = (unsigned)val;
301e04da24cSKrishna Kanth Reddy 				num_args++;
302e04da24cSKrishna Kanth Reddy 				break;
303e04da24cSKrishna Kanth Reddy 			}
304e04da24cSKrishna Kanth Reddy 			break;
305e04da24cSKrishna Kanth Reddy 		default:
306e04da24cSKrishna Kanth Reddy 			usage(argv[0]);
307e04da24cSKrishna Kanth Reddy 			return 1;
308e04da24cSKrishna Kanth Reddy 		}
309e04da24cSKrishna Kanth Reddy 	}
310e04da24cSKrishna Kanth Reddy 
311e04da24cSKrishna Kanth Reddy 	if (num_args != 5) {
312e04da24cSKrishna Kanth Reddy 		usage(argv[0]);
313e04da24cSKrishna Kanth Reddy 		return 1;
314e04da24cSKrishna Kanth Reddy 	}
315e04da24cSKrishna Kanth Reddy 
316e04da24cSKrishna Kanth Reddy 	return 0;
317e04da24cSKrishna Kanth Reddy }
318e04da24cSKrishna Kanth Reddy 
319e04da24cSKrishna Kanth Reddy static void
320e04da24cSKrishna Kanth Reddy cleanup(void)
321e04da24cSKrishna Kanth Reddy {
322e04da24cSKrishna Kanth Reddy 	struct spdk_nvme_detach_ctx *detach_ctx = NULL;
323e04da24cSKrishna Kanth Reddy 
324e04da24cSKrishna Kanth Reddy 	spdk_nvme_detach_async(g_config.pmr_dev.ctrlr, &detach_ctx);
325e04da24cSKrishna Kanth Reddy 
3264fe4040aSShuhei Matsumoto 	if (detach_ctx) {
3274fe4040aSShuhei Matsumoto 		spdk_nvme_detach_poll(detach_ctx);
328e04da24cSKrishna Kanth Reddy 	}
329e04da24cSKrishna Kanth Reddy }
330e04da24cSKrishna Kanth Reddy 
3318dd1cd21SBen Walker int
3328dd1cd21SBen Walker main(int argc, char **argv)
333e04da24cSKrishna Kanth Reddy {
334e04da24cSKrishna Kanth Reddy 	int rc = 0;
335e04da24cSKrishna Kanth Reddy 	struct spdk_env_opts opts;
336e04da24cSKrishna Kanth Reddy 
337e04da24cSKrishna Kanth Reddy 	/*
338e04da24cSKrishna Kanth Reddy 	 * Parse the input arguments. For now we use the following
339e04da24cSKrishna Kanth Reddy 	 * format list:
340e04da24cSKrishna Kanth Reddy 	 *
341e04da24cSKrishna Kanth Reddy 	 * -p <pci id> -n <namespace> -r <Read LBA> -l <number of LBAs> -w <Write LBA>
342e04da24cSKrishna Kanth Reddy 	 *
343e04da24cSKrishna Kanth Reddy 	 */
344e04da24cSKrishna Kanth Reddy 	rc = parse_args(argc, argv);
345e04da24cSKrishna Kanth Reddy 	if (rc) {
346e04da24cSKrishna Kanth Reddy 		fprintf(stderr, "Error in parse_args(): %d\n", rc);
347e04da24cSKrishna Kanth Reddy 		return rc;
348e04da24cSKrishna Kanth Reddy 	}
349e04da24cSKrishna Kanth Reddy 
350e04da24cSKrishna Kanth Reddy 	/*
351e04da24cSKrishna Kanth Reddy 	 * SPDK relies on an abstraction around the local environment
352e04da24cSKrishna Kanth Reddy 	 * named env that handles memory allocation and PCI device operations.
353e04da24cSKrishna Kanth Reddy 	 * This library must be initialized first.
354e04da24cSKrishna Kanth Reddy 	 *
355e04da24cSKrishna Kanth Reddy 	 */
35657fd99b9SJim Harris 	opts.opts_size = sizeof(opts);
357e04da24cSKrishna Kanth Reddy 	spdk_env_opts_init(&opts);
358e04da24cSKrishna Kanth Reddy 	opts.name = "pmr_persistence";
359e04da24cSKrishna Kanth Reddy 	opts.shm_id = 0;
360e04da24cSKrishna Kanth Reddy 	if (spdk_env_init(&opts) < 0) {
361e04da24cSKrishna Kanth Reddy 		fprintf(stderr, "Unable to initialize SPDK env\n");
362e04da24cSKrishna Kanth Reddy 		return 1;
363e04da24cSKrishna Kanth Reddy 	}
364e04da24cSKrishna Kanth Reddy 
365e04da24cSKrishna Kanth Reddy 	/*
366e04da24cSKrishna Kanth Reddy 	 * PMRs only apply to PCIe attached NVMe controllers so we
367e04da24cSKrishna Kanth Reddy 	 * only probe the PCIe bus. This is the default when we pass
368e04da24cSKrishna Kanth Reddy 	 * in NULL for the first argument.
369e04da24cSKrishna Kanth Reddy 	 */
370e04da24cSKrishna Kanth Reddy 
371e04da24cSKrishna Kanth Reddy 	rc = spdk_nvme_probe(NULL, NULL, probe_cb, attach_cb, NULL);
372e04da24cSKrishna Kanth Reddy 	if (rc) {
373e04da24cSKrishna Kanth Reddy 		fprintf(stderr, "Error in spdk_nvme_probe(): %d\n", rc);
374e04da24cSKrishna Kanth Reddy 		cleanup();
375e04da24cSKrishna Kanth Reddy 		return rc;
376e04da24cSKrishna Kanth Reddy 	}
377e04da24cSKrishna Kanth Reddy 
378e04da24cSKrishna Kanth Reddy 	g_config.copy_size = g_config.pmr_dev.nlbas * g_config.pmr_dev.lba_size;
379e04da24cSKrishna Kanth Reddy 
380e04da24cSKrishna Kanth Reddy 	/*
381e04da24cSKrishna Kanth Reddy 	 * Call the pmr_persistence() function which performs the data copy
382e04da24cSKrishna Kanth Reddy 	 * to PMR region, resets the Controller and verifies the data persistence
383e04da24cSKrishna Kanth Reddy 	 * or returns an error code if it fails.
384e04da24cSKrishna Kanth Reddy 	 */
385e04da24cSKrishna Kanth Reddy 	rc = pmr_persistence();
386e04da24cSKrishna Kanth Reddy 	if (rc) {
387e04da24cSKrishna Kanth Reddy 		fprintf(stderr, "Error in pmr_persistence(): %d\n", rc);
388e04da24cSKrishna Kanth Reddy 	}
389e04da24cSKrishna Kanth Reddy 
390e04da24cSKrishna Kanth Reddy 	cleanup();
391e04da24cSKrishna Kanth Reddy 
392e04da24cSKrishna Kanth Reddy 	return rc;
393e04da24cSKrishna Kanth Reddy }
394