xref: /spdk/examples/nvme/hello_world/hello_world.c (revision 307b8c112ffd90a26d53dd15fad67bd9038ef526)
1  /*   SPDX-License-Identifier: BSD-3-Clause
2   *   Copyright (c) Intel Corporation.
3   *   All rights reserved.
4   */
5  
6  #include "spdk/stdinc.h"
7  
8  #include "spdk/nvme.h"
9  #include "spdk/vmd.h"
10  #include "spdk/nvme_zns.h"
11  #include "spdk/env.h"
12  #include "spdk/string.h"
13  #include "spdk/log.h"
14  
15  struct ctrlr_entry {
16  	struct spdk_nvme_ctrlr		*ctrlr;
17  	TAILQ_ENTRY(ctrlr_entry)	link;
18  	char				name[1024];
19  };
20  
21  struct ns_entry {
22  	struct spdk_nvme_ctrlr	*ctrlr;
23  	struct spdk_nvme_ns	*ns;
24  	TAILQ_ENTRY(ns_entry)	link;
25  	struct spdk_nvme_qpair	*qpair;
26  };
27  
28  static TAILQ_HEAD(, ctrlr_entry) g_controllers = TAILQ_HEAD_INITIALIZER(g_controllers);
29  static TAILQ_HEAD(, ns_entry) g_namespaces = TAILQ_HEAD_INITIALIZER(g_namespaces);
30  static struct spdk_nvme_transport_id g_trid = {};
31  
32  static bool g_vmd = false;
33  
34  static void
35  register_ns(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_ns *ns)
36  {
37  	struct ns_entry *entry;
38  
39  	if (!spdk_nvme_ns_is_active(ns)) {
40  		return;
41  	}
42  
43  	entry = malloc(sizeof(struct ns_entry));
44  	if (entry == NULL) {
45  		perror("ns_entry malloc");
46  		exit(1);
47  	}
48  
49  	entry->ctrlr = ctrlr;
50  	entry->ns = ns;
51  	TAILQ_INSERT_TAIL(&g_namespaces, entry, link);
52  
53  	printf("  Namespace ID: %d size: %juGB\n", spdk_nvme_ns_get_id(ns),
54  	       spdk_nvme_ns_get_size(ns) / 1000000000);
55  }
56  
57  struct hello_world_sequence {
58  	struct ns_entry	*ns_entry;
59  	char		*buf;
60  	unsigned        using_cmb_io;
61  	int		is_completed;
62  };
63  
64  static void
65  read_complete(void *arg, const struct spdk_nvme_cpl *completion)
66  {
67  	struct hello_world_sequence *sequence = arg;
68  
69  	/* Assume the I/O was successful */
70  	sequence->is_completed = 1;
71  	/* See if an error occurred. If so, display information
72  	 * about it, and set completion value so that I/O
73  	 * caller is aware that an error occurred.
74  	 */
75  	if (spdk_nvme_cpl_is_error(completion)) {
76  		spdk_nvme_qpair_print_completion(sequence->ns_entry->qpair, (struct spdk_nvme_cpl *)completion);
77  		fprintf(stderr, "I/O error status: %s\n", spdk_nvme_cpl_get_status_string(&completion->status));
78  		fprintf(stderr, "Read I/O failed, aborting run\n");
79  		sequence->is_completed = 2;
80  		exit(1);
81  	}
82  
83  	/*
84  	 * The read I/O has completed.  Print the contents of the
85  	 *  buffer, free the buffer, then mark the sequence as
86  	 *  completed.  This will trigger the hello_world() function
87  	 *  to exit its polling loop.
88  	 */
89  	printf("%s", sequence->buf);
90  	spdk_free(sequence->buf);
91  }
92  
93  static void
94  write_complete(void *arg, const struct spdk_nvme_cpl *completion)
95  {
96  	struct hello_world_sequence	*sequence = arg;
97  	struct ns_entry			*ns_entry = sequence->ns_entry;
98  	int				rc;
99  
100  	/* See if an error occurred. If so, display information
101  	 * about it, and set completion value so that I/O
102  	 * caller is aware that an error occurred.
103  	 */
104  	if (spdk_nvme_cpl_is_error(completion)) {
105  		spdk_nvme_qpair_print_completion(sequence->ns_entry->qpair, (struct spdk_nvme_cpl *)completion);
106  		fprintf(stderr, "I/O error status: %s\n", spdk_nvme_cpl_get_status_string(&completion->status));
107  		fprintf(stderr, "Write I/O failed, aborting run\n");
108  		sequence->is_completed = 2;
109  		exit(1);
110  	}
111  	/*
112  	 * The write I/O has completed.  Free the buffer associated with
113  	 *  the write I/O and allocate a new zeroed buffer for reading
114  	 *  the data back from the NVMe namespace.
115  	 */
116  	if (sequence->using_cmb_io) {
117  		spdk_nvme_ctrlr_unmap_cmb(ns_entry->ctrlr);
118  	} else {
119  		spdk_free(sequence->buf);
120  	}
121  	sequence->buf = spdk_zmalloc(0x1000, 0x1000, NULL, SPDK_ENV_SOCKET_ID_ANY, SPDK_MALLOC_DMA);
122  
123  	rc = spdk_nvme_ns_cmd_read(ns_entry->ns, ns_entry->qpair, sequence->buf,
124  				   0, /* LBA start */
125  				   1, /* number of LBAs */
126  				   read_complete, (void *)sequence, 0);
127  	if (rc != 0) {
128  		fprintf(stderr, "starting read I/O failed\n");
129  		exit(1);
130  	}
131  }
132  
133  static void
134  reset_zone_complete(void *arg, const struct spdk_nvme_cpl *completion)
135  {
136  	struct hello_world_sequence *sequence = arg;
137  
138  	/* Assume the I/O was successful */
139  	sequence->is_completed = 1;
140  	/* See if an error occurred. If so, display information
141  	 * about it, and set completion value so that I/O
142  	 * caller is aware that an error occurred.
143  	 */
144  	if (spdk_nvme_cpl_is_error(completion)) {
145  		spdk_nvme_qpair_print_completion(sequence->ns_entry->qpair, (struct spdk_nvme_cpl *)completion);
146  		fprintf(stderr, "I/O error status: %s\n", spdk_nvme_cpl_get_status_string(&completion->status));
147  		fprintf(stderr, "Reset zone I/O failed, aborting run\n");
148  		sequence->is_completed = 2;
149  		exit(1);
150  	}
151  }
152  
153  static void
154  reset_zone_and_wait_for_completion(struct hello_world_sequence *sequence)
155  {
156  	if (spdk_nvme_zns_reset_zone(sequence->ns_entry->ns, sequence->ns_entry->qpair,
157  				     0, /* starting LBA of the zone to reset */
158  				     false, /* don't reset all zones */
159  				     reset_zone_complete,
160  				     sequence)) {
161  		fprintf(stderr, "starting reset zone I/O failed\n");
162  		exit(1);
163  	}
164  	while (!sequence->is_completed) {
165  		spdk_nvme_qpair_process_completions(sequence->ns_entry->qpair, 0);
166  	}
167  	sequence->is_completed = 0;
168  }
169  
170  static void
171  hello_world(void)
172  {
173  	struct ns_entry			*ns_entry;
174  	struct hello_world_sequence	sequence;
175  	int				rc;
176  	size_t				sz;
177  
178  	TAILQ_FOREACH(ns_entry, &g_namespaces, link) {
179  		/*
180  		 * Allocate an I/O qpair that we can use to submit read/write requests
181  		 *  to namespaces on the controller.  NVMe controllers typically support
182  		 *  many qpairs per controller.  Any I/O qpair allocated for a controller
183  		 *  can submit I/O to any namespace on that controller.
184  		 *
185  		 * The SPDK NVMe driver provides no synchronization for qpair accesses -
186  		 *  the application must ensure only a single thread submits I/O to a
187  		 *  qpair, and that same thread must also check for completions on that
188  		 *  qpair.  This enables extremely efficient I/O processing by making all
189  		 *  I/O operations completely lockless.
190  		 */
191  		ns_entry->qpair = spdk_nvme_ctrlr_alloc_io_qpair(ns_entry->ctrlr, NULL, 0);
192  		if (ns_entry->qpair == NULL) {
193  			printf("ERROR: spdk_nvme_ctrlr_alloc_io_qpair() failed\n");
194  			return;
195  		}
196  
197  		/*
198  		 * Use spdk_dma_zmalloc to allocate a 4KB zeroed buffer.  This memory
199  		 * will be pinned, which is required for data buffers used for SPDK NVMe
200  		 * I/O operations.
201  		 */
202  		sequence.using_cmb_io = 1;
203  		sequence.buf = spdk_nvme_ctrlr_map_cmb(ns_entry->ctrlr, &sz);
204  		if (sequence.buf == NULL || sz < 0x1000) {
205  			sequence.using_cmb_io = 0;
206  			sequence.buf = spdk_zmalloc(0x1000, 0x1000, NULL, SPDK_ENV_SOCKET_ID_ANY, SPDK_MALLOC_DMA);
207  		}
208  		if (sequence.buf == NULL) {
209  			printf("ERROR: write buffer allocation failed\n");
210  			return;
211  		}
212  		if (sequence.using_cmb_io) {
213  			printf("INFO: using controller memory buffer for IO\n");
214  		} else {
215  			printf("INFO: using host memory buffer for IO\n");
216  		}
217  		sequence.is_completed = 0;
218  		sequence.ns_entry = ns_entry;
219  
220  		/*
221  		 * If the namespace is a Zoned Namespace, rather than a regular
222  		 * NVM namespace, we need to reset the first zone, before we
223  		 * write to it. This not needed for regular NVM namespaces.
224  		 */
225  		if (spdk_nvme_ns_get_csi(ns_entry->ns) == SPDK_NVME_CSI_ZNS) {
226  			reset_zone_and_wait_for_completion(&sequence);
227  		}
228  
229  		/*
230  		 * Print "Hello world!" to sequence.buf.  We will write this data to LBA
231  		 *  0 on the namespace, and then later read it back into a separate buffer
232  		 *  to demonstrate the full I/O path.
233  		 */
234  		snprintf(sequence.buf, 0x1000, "%s", "Hello world!\n");
235  
236  		/*
237  		 * Write the data buffer to LBA 0 of this namespace.  "write_complete" and
238  		 *  "&sequence" are specified as the completion callback function and
239  		 *  argument respectively.  write_complete() will be called with the
240  		 *  value of &sequence as a parameter when the write I/O is completed.
241  		 *  This allows users to potentially specify different completion
242  		 *  callback routines for each I/O, as well as pass a unique handle
243  		 *  as an argument so the application knows which I/O has completed.
244  		 *
245  		 * Note that the SPDK NVMe driver will only check for completions
246  		 *  when the application calls spdk_nvme_qpair_process_completions().
247  		 *  It is the responsibility of the application to trigger the polling
248  		 *  process.
249  		 */
250  		rc = spdk_nvme_ns_cmd_write(ns_entry->ns, ns_entry->qpair, sequence.buf,
251  					    0, /* LBA start */
252  					    1, /* number of LBAs */
253  					    write_complete, &sequence, 0);
254  		if (rc != 0) {
255  			fprintf(stderr, "starting write I/O failed\n");
256  			exit(1);
257  		}
258  
259  		/*
260  		 * Poll for completions.  0 here means process all available completions.
261  		 *  In certain usage models, the caller may specify a positive integer
262  		 *  instead of 0 to signify the maximum number of completions it should
263  		 *  process.  This function will never block - if there are no
264  		 *  completions pending on the specified qpair, it will return immediately.
265  		 *
266  		 * When the write I/O completes, write_complete() will submit a new I/O
267  		 *  to read LBA 0 into a separate buffer, specifying read_complete() as its
268  		 *  completion routine.  When the read I/O completes, read_complete() will
269  		 *  print the buffer contents and set sequence.is_completed = 1.  That will
270  		 *  break this loop and then exit the program.
271  		 */
272  		while (!sequence.is_completed) {
273  			spdk_nvme_qpair_process_completions(ns_entry->qpair, 0);
274  		}
275  
276  		/*
277  		 * Free the I/O qpair.  This typically is done when an application exits.
278  		 *  But SPDK does support freeing and then reallocating qpairs during
279  		 *  operation.  It is the responsibility of the caller to ensure all
280  		 *  pending I/O are completed before trying to free the qpair.
281  		 */
282  		spdk_nvme_ctrlr_free_io_qpair(ns_entry->qpair);
283  	}
284  }
285  
286  static bool
287  probe_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
288  	 struct spdk_nvme_ctrlr_opts *opts)
289  {
290  	printf("Attaching to %s\n", trid->traddr);
291  
292  	return true;
293  }
294  
295  static void
296  attach_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
297  	  struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_ctrlr_opts *opts)
298  {
299  	int nsid;
300  	struct ctrlr_entry *entry;
301  	struct spdk_nvme_ns *ns;
302  	const struct spdk_nvme_ctrlr_data *cdata;
303  
304  	entry = malloc(sizeof(struct ctrlr_entry));
305  	if (entry == NULL) {
306  		perror("ctrlr_entry malloc");
307  		exit(1);
308  	}
309  
310  	printf("Attached to %s\n", trid->traddr);
311  
312  	/*
313  	 * spdk_nvme_ctrlr is the logical abstraction in SPDK for an NVMe
314  	 *  controller.  During initialization, the IDENTIFY data for the
315  	 *  controller is read using an NVMe admin command, and that data
316  	 *  can be retrieved using spdk_nvme_ctrlr_get_data() to get
317  	 *  detailed information on the controller.  Refer to the NVMe
318  	 *  specification for more details on IDENTIFY for NVMe controllers.
319  	 */
320  	cdata = spdk_nvme_ctrlr_get_data(ctrlr);
321  
322  	snprintf(entry->name, sizeof(entry->name), "%-20.20s (%-20.20s)", cdata->mn, cdata->sn);
323  
324  	entry->ctrlr = ctrlr;
325  	TAILQ_INSERT_TAIL(&g_controllers, entry, link);
326  
327  	/*
328  	 * Each controller has one or more namespaces.  An NVMe namespace is basically
329  	 *  equivalent to a SCSI LUN.  The controller's IDENTIFY data tells us how
330  	 *  many namespaces exist on the controller.  For Intel(R) P3X00 controllers,
331  	 *  it will just be one namespace.
332  	 *
333  	 * Note that in NVMe, namespace IDs start at 1, not 0.
334  	 */
335  	for (nsid = spdk_nvme_ctrlr_get_first_active_ns(ctrlr); nsid != 0;
336  	     nsid = spdk_nvme_ctrlr_get_next_active_ns(ctrlr, nsid)) {
337  		ns = spdk_nvme_ctrlr_get_ns(ctrlr, nsid);
338  		if (ns == NULL) {
339  			continue;
340  		}
341  		register_ns(ctrlr, ns);
342  	}
343  }
344  
345  static void
346  cleanup(void)
347  {
348  	struct ns_entry *ns_entry, *tmp_ns_entry;
349  	struct ctrlr_entry *ctrlr_entry, *tmp_ctrlr_entry;
350  	struct spdk_nvme_detach_ctx *detach_ctx = NULL;
351  
352  	TAILQ_FOREACH_SAFE(ns_entry, &g_namespaces, link, tmp_ns_entry) {
353  		TAILQ_REMOVE(&g_namespaces, ns_entry, link);
354  		free(ns_entry);
355  	}
356  
357  	TAILQ_FOREACH_SAFE(ctrlr_entry, &g_controllers, link, tmp_ctrlr_entry) {
358  		TAILQ_REMOVE(&g_controllers, ctrlr_entry, link);
359  		spdk_nvme_detach_async(ctrlr_entry->ctrlr, &detach_ctx);
360  		free(ctrlr_entry);
361  	}
362  
363  	if (detach_ctx) {
364  		spdk_nvme_detach_poll(detach_ctx);
365  	}
366  }
367  
368  static void
369  usage(const char *program_name)
370  {
371  	printf("%s [options]", program_name);
372  	printf("\t\n");
373  	printf("options:\n");
374  	printf("\t[-d DPDK huge memory size in MB]\n");
375  	printf("\t[-g use single file descriptor for DPDK memory segments]\n");
376  	printf("\t[-i shared memory group ID]\n");
377  	printf("\t[-r remote NVMe over Fabrics target address]\n");
378  	printf("\t[-V enumerate VMD]\n");
379  #ifdef DEBUG
380  	printf("\t[-L enable debug logging]\n");
381  #else
382  	printf("\t[-L enable debug logging (flag disabled, must reconfigure with --enable-debug)]\n");
383  #endif
384  }
385  
386  static int
387  parse_args(int argc, char **argv, struct spdk_env_opts *env_opts)
388  {
389  	int op, rc;
390  
391  	spdk_nvme_trid_populate_transport(&g_trid, SPDK_NVME_TRANSPORT_PCIE);
392  	snprintf(g_trid.subnqn, sizeof(g_trid.subnqn), "%s", SPDK_NVMF_DISCOVERY_NQN);
393  
394  	while ((op = getopt(argc, argv, "d:gi:r:L:V")) != -1) {
395  		switch (op) {
396  		case 'V':
397  			g_vmd = true;
398  			break;
399  		case 'i':
400  			env_opts->shm_id = spdk_strtol(optarg, 10);
401  			if (env_opts->shm_id < 0) {
402  				fprintf(stderr, "Invalid shared memory ID\n");
403  				return env_opts->shm_id;
404  			}
405  			break;
406  		case 'g':
407  			env_opts->hugepage_single_segments = true;
408  			break;
409  		case 'r':
410  			if (spdk_nvme_transport_id_parse(&g_trid, optarg) != 0) {
411  				fprintf(stderr, "Error parsing transport address\n");
412  				return 1;
413  			}
414  			break;
415  		case 'd':
416  			env_opts->mem_size = spdk_strtol(optarg, 10);
417  			if (env_opts->mem_size < 0) {
418  				fprintf(stderr, "Invalid DPDK memory size\n");
419  				return env_opts->mem_size;
420  			}
421  			break;
422  		case 'L':
423  			rc = spdk_log_set_flag(optarg);
424  			if (rc < 0) {
425  				fprintf(stderr, "unknown flag\n");
426  				usage(argv[0]);
427  				exit(EXIT_FAILURE);
428  			}
429  #ifdef DEBUG
430  			spdk_log_set_print_level(SPDK_LOG_DEBUG);
431  #endif
432  			break;
433  		default:
434  			usage(argv[0]);
435  			return 1;
436  		}
437  	}
438  
439  	return 0;
440  }
441  
442  int
443  main(int argc, char **argv)
444  {
445  	int rc;
446  	struct spdk_env_opts opts;
447  
448  	/*
449  	 * SPDK relies on an abstraction around the local environment
450  	 * named env that handles memory allocation and PCI device operations.
451  	 * This library must be initialized first.
452  	 *
453  	 */
454  	spdk_env_opts_init(&opts);
455  	rc = parse_args(argc, argv, &opts);
456  	if (rc != 0) {
457  		return rc;
458  	}
459  
460  	opts.name = "hello_world";
461  	if (spdk_env_init(&opts) < 0) {
462  		fprintf(stderr, "Unable to initialize SPDK env\n");
463  		return 1;
464  	}
465  
466  	printf("Initializing NVMe Controllers\n");
467  
468  	if (g_vmd && spdk_vmd_init()) {
469  		fprintf(stderr, "Failed to initialize VMD."
470  			" Some NVMe devices can be unavailable.\n");
471  	}
472  
473  	/*
474  	 * Start the SPDK NVMe enumeration process.  probe_cb will be called
475  	 *  for each NVMe controller found, giving our application a choice on
476  	 *  whether to attach to each controller.  attach_cb will then be
477  	 *  called for each controller after the SPDK NVMe driver has completed
478  	 *  initializing the controller we chose to attach.
479  	 */
480  	rc = spdk_nvme_probe(&g_trid, NULL, probe_cb, attach_cb, NULL);
481  	if (rc != 0) {
482  		fprintf(stderr, "spdk_nvme_probe() failed\n");
483  		rc = 1;
484  		goto exit;
485  	}
486  
487  	if (TAILQ_EMPTY(&g_controllers)) {
488  		fprintf(stderr, "no NVMe controllers found\n");
489  		rc = 1;
490  		goto exit;
491  	}
492  
493  	printf("Initialization complete.\n");
494  	hello_world();
495  	cleanup();
496  	if (g_vmd) {
497  		spdk_vmd_fini();
498  	}
499  
500  exit:
501  	cleanup();
502  	spdk_env_fini();
503  	return rc;
504  }
505