xref: /spdk/test/nvme/boot_partition/boot_partition.c (revision 30afc27748e69257ca50f7e3a4b4ca6466ffc26b)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (c) Samsung Electronics Co., Ltd.
3  *   All rights reserved.
4  */
5 
6 #include "spdk/stdinc.h"
7 #include "spdk/nvme.h"
8 #include "spdk/util.h"
9 #include "spdk/env.h"
10 
11 struct ctrlr {
12 	struct spdk_nvme_transport_id trid;
13 	struct spdk_nvme_ctrlr	*ctrlr;
14 	char			*write_buf;
15 	char			*read_buf;
16 	int			write_completed;
17 };
18 
19 static struct ctrlr g_ctrlr;
20 
21 static void cleanup(void);
22 
23 static void
24 fill_pattern(char *buf, size_t num_bytes, char pattern)
25 {
26 	size_t	i;
27 
28 	for (i = 0; i < num_bytes; i++) {
29 		buf[i] = pattern;
30 	}
31 }
32 
33 static void
34 write_complete(void *arg, const struct spdk_nvme_cpl *completion)
35 {
36 	printf("Boot Partition Write - SCT : %d, SC : %d\n",
37 	       completion->status.sct, completion->status.sc);
38 	g_ctrlr.write_completed = 1;
39 }
40 
41 static int
42 boot_partition_test(void)
43 {
44 	struct spdk_nvme_ctrlr			*ctrlr;
45 	union spdk_nvme_cap_register		cap;
46 	int					rc;
47 	union spdk_nvme_bpinfo_register		bpinfo;
48 	unsigned int				bpsize;
49 	unsigned int				bpsize_in_4k;
50 
51 	ctrlr = g_ctrlr.ctrlr;
52 
53 	cap = spdk_nvme_ctrlr_get_regs_cap(ctrlr);
54 
55 	if (cap.bits.bps) {
56 		printf("Boot Partitions are Supported by the Controller\n");
57 	} else {
58 		printf("Boot Partitions are Not Supported by the Controller\n");
59 		return -ENOTSUP;
60 	}
61 
62 	bpinfo = spdk_nvme_ctrlr_get_regs_bpinfo(ctrlr);
63 	bpsize = bpinfo.bits.bpsz * 131072;
64 	bpsize_in_4k = bpsize / 4096;
65 
66 	printf("Boot Partition Info\n");
67 	printf("Active Boot Partition ID : %d\n", bpinfo.bits.abpid);
68 	printf("Boot Read Status : %d\n", bpinfo.bits.brs);
69 	printf("Boot Partition Size : %d bytes\n", bpsize);
70 
71 	g_ctrlr.write_buf = spdk_zmalloc(bpsize, 0x1000, NULL,
72 					 SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
73 
74 	if (g_ctrlr.write_buf == NULL) {
75 		printf("Error - could not allocate write buffer for test\n");
76 		cleanup();
77 		return -ENOMEM;
78 	}
79 
80 	g_ctrlr.read_buf = spdk_memzone_reserve("boot_partition", bpsize,
81 						SPDK_ENV_NUMA_ID_ANY, 0);
82 
83 	if (g_ctrlr.read_buf == NULL) {
84 		printf("Error - could not allocate read buffer for test\n");
85 		cleanup();
86 		return -ENOMEM;
87 	}
88 
89 	fill_pattern(g_ctrlr.write_buf, bpsize, 0xDE);
90 
91 	g_ctrlr.write_completed = 0;
92 	rc = spdk_nvme_ctrlr_write_boot_partition(ctrlr, g_ctrlr.write_buf,
93 			bpsize, 0, write_complete, NULL);
94 	if (rc) {
95 		printf("Error - Boot Partition write failure. rc: %d", rc);
96 		cleanup();
97 		return rc;
98 	}
99 
100 	while (!g_ctrlr.write_completed) {
101 		spdk_nvme_ctrlr_process_admin_completions(ctrlr);
102 	}
103 
104 	rc = spdk_nvme_ctrlr_read_boot_partition_start(ctrlr, g_ctrlr.read_buf,
105 			bpsize_in_4k, 0, 0);
106 
107 	if (rc) {
108 		printf("Error - Boot Partition read start failure. rc: %d", rc);
109 		cleanup();
110 		return rc;
111 	}
112 
113 	do {
114 		rc = spdk_nvme_ctrlr_read_boot_partition_poll(ctrlr);
115 	} while (rc == -EAGAIN);
116 
117 	if (rc != 0) {
118 		printf("Error - Boot Partition read poll failure. rc: %d", rc);
119 		cleanup();
120 		return rc;
121 	}
122 
123 	rc = memcmp(g_ctrlr.write_buf, g_ctrlr.read_buf, bpsize);
124 	if (rc) {
125 		printf("Error - Boot Partition written data does not match Boot Partition read data, rc: %d\n", rc);
126 		cleanup();
127 		return rc;
128 	}
129 
130 	printf("Boot Partition 0 written data matches Boot Partition 0 read data\n");
131 
132 	fill_pattern(g_ctrlr.write_buf, bpsize, 0xAD);
133 
134 	g_ctrlr.write_completed = 0;
135 	rc = spdk_nvme_ctrlr_write_boot_partition(ctrlr, g_ctrlr.write_buf,
136 			bpsize, 1, write_complete, NULL);
137 	if (rc) {
138 		printf("Error - Boot Partition write failure. rc: %d", rc);
139 		cleanup();
140 		return rc;
141 	}
142 
143 	while (!g_ctrlr.write_completed) {
144 		spdk_nvme_ctrlr_process_admin_completions(ctrlr);
145 	}
146 
147 	rc = spdk_nvme_ctrlr_read_boot_partition_start(ctrlr, g_ctrlr.read_buf,
148 			bpsize_in_4k, 0, 1);
149 
150 	if (rc) {
151 		printf("Error - Boot Partition read start failure. rc: %d", rc);
152 		cleanup();
153 		return rc;
154 	}
155 
156 	do {
157 		rc = spdk_nvme_ctrlr_read_boot_partition_poll(ctrlr);
158 	} while (rc == -EAGAIN);
159 
160 	if (rc != 0) {
161 		printf("Error - Boot Partition read poll failure. rc: %d", rc);
162 		cleanup();
163 		return rc;
164 	}
165 
166 	rc = memcmp(g_ctrlr.write_buf, g_ctrlr.read_buf, bpsize);
167 	if (rc) {
168 		printf("Error - Boot Partition written data does not match Boot Partition read data, rc: %d\n", rc);
169 		cleanup();
170 		return rc;
171 	}
172 
173 	printf("Boot Partition 1 written data matches Boot Partition 1 read data\n");
174 
175 	cleanup();
176 
177 	return 0;
178 }
179 
180 static void
181 cleanup(void)
182 {
183 	spdk_memzone_free("boot_partition");
184 	spdk_free(g_ctrlr.write_buf);
185 	spdk_nvme_detach(g_ctrlr.ctrlr);
186 }
187 
188 static void
189 usage(char *program_name)
190 {
191 	printf("%s Option (Mandatory)", program_name);
192 	printf("\n");
193 	printf("\t[-p PCIe address of the NVMe Device with Boot Partition support]\n");
194 	printf("\n");
195 }
196 
197 static int
198 parse_args(int argc, char **argv)
199 {
200 	int op;
201 	unsigned num_args = 0;
202 
203 	while ((op = getopt(argc, argv, "p:")) != -1) {
204 		switch (op) {
205 		case 'p':
206 			snprintf(&g_ctrlr.trid.traddr[0], SPDK_NVMF_TRADDR_MAX_LEN + 1,
207 				 "%s", optarg);
208 
209 			g_ctrlr.trid.trtype = SPDK_NVME_TRANSPORT_PCIE;
210 
211 			spdk_nvme_transport_id_populate_trstring(&g_ctrlr.trid,
212 					spdk_nvme_transport_id_trtype_str(g_ctrlr.trid.trtype));
213 
214 			num_args++;
215 			break;
216 		default:
217 			usage(argv[0]);
218 			return 1;
219 		}
220 	}
221 
222 	if (num_args != 1) {
223 		usage(argv[0]);
224 		return 1;
225 	}
226 
227 	return 0;
228 }
229 
230 int
231 main(int argc, char **argv)
232 {
233 	int			rc;
234 	struct spdk_env_opts	opts;
235 
236 	/*
237 	 * Parse the input arguments. For now we use the following
238 	 * format list:
239 	 *
240 	 * -p <pci id>
241 	 *
242 	 */
243 	rc = parse_args(argc, argv);
244 	if (rc) {
245 		fprintf(stderr, "Error in parse_args(): %d\n", rc);
246 		return rc;
247 	}
248 
249 	opts.opts_size = sizeof(opts);
250 	spdk_env_opts_init(&opts);
251 	opts.name = "boot_partition";
252 	opts.shm_id = 0;
253 	if (spdk_env_init(&opts) < 0) {
254 		fprintf(stderr, "Unable to initialize SPDK env\n");
255 		return 1;
256 	}
257 
258 	printf("Initializing NVMe Controller\n");
259 
260 	g_ctrlr.ctrlr = spdk_nvme_connect(&g_ctrlr.trid, NULL, 0);
261 	if (!g_ctrlr.ctrlr) {
262 		fprintf(stderr, "spdk_nvme_connect() failed\n");
263 		return 1;
264 	}
265 
266 	printf("Initialization complete.\n");
267 	rc = boot_partition_test();
268 	return rc;
269 }
270