xref: /spdk/test/nvme/boot_partition/boot_partition.c (revision cc6920a4763d4b9a43aa40583c8397d8f14fa100)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright (c) Samsung Electronics Co., Ltd.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Samsung Electronics Co., Ltd. nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include "spdk/stdinc.h"
35 #include "spdk/nvme.h"
36 #include "spdk/util.h"
37 #include "spdk/env.h"
38 
39 struct ctrlr {
40 	struct spdk_nvme_transport_id trid;
41 	struct spdk_nvme_ctrlr	*ctrlr;
42 	char			*write_buf;
43 	char			*read_buf;
44 	int			write_completed;
45 };
46 
47 static struct ctrlr g_ctrlr;
48 
49 static void cleanup(void);
50 
51 static void
52 fill_pattern(char *buf, size_t num_bytes, char pattern)
53 {
54 	size_t	i;
55 
56 	for (i = 0; i < num_bytes; i++) {
57 		buf[i] = pattern;
58 	}
59 }
60 
61 static void
62 write_complete(void *arg, const struct spdk_nvme_cpl *completion)
63 {
64 	printf("Boot Partition Write - SCT : %d, SC : %d\n",
65 	       completion->status.sct, completion->status.sc);
66 	g_ctrlr.write_completed = 1;
67 }
68 
69 static int
70 boot_partition_test(void)
71 {
72 	struct spdk_nvme_ctrlr			*ctrlr;
73 	union spdk_nvme_cap_register		cap;
74 	int					rc;
75 	union spdk_nvme_bpinfo_register		bpinfo;
76 	unsigned int				bpsize;
77 	unsigned int				bpsize_in_4k;
78 
79 	ctrlr = g_ctrlr.ctrlr;
80 
81 	cap = spdk_nvme_ctrlr_get_regs_cap(ctrlr);
82 
83 	if (cap.bits.bps) {
84 		printf("Boot Partitions are Supported by the Controller\n");
85 	} else {
86 		printf("Boot Partitions are Not Supported by the Controller\n");
87 		return -ENOTSUP;
88 	}
89 
90 	bpinfo = spdk_nvme_ctrlr_get_regs_bpinfo(ctrlr);
91 	bpsize = bpinfo.bits.bpsz * 131072;
92 	bpsize_in_4k = bpsize / 4096;
93 
94 	printf("Boot Partition Info\n");
95 	printf("Active Boot Partition ID : %d\n", bpinfo.bits.abpid);
96 	printf("Boot Read Status : %d\n", bpinfo.bits.brs);
97 	printf("Boot Partition Size : %d bytes\n", bpsize);
98 
99 	g_ctrlr.write_buf = spdk_zmalloc(bpsize, 0x1000, NULL,
100 					 SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
101 
102 	if (g_ctrlr.write_buf == NULL) {
103 		printf("Error - could not allocate write buffer for test\n");
104 		cleanup();
105 		return -ENOMEM;
106 	}
107 
108 	g_ctrlr.read_buf = spdk_memzone_reserve("boot_partition", bpsize,
109 						SPDK_ENV_SOCKET_ID_ANY, 0);
110 
111 	if (g_ctrlr.read_buf == NULL) {
112 		printf("Error - could not allocate read buffer for test\n");
113 		cleanup();
114 		return -ENOMEM;
115 	}
116 
117 	fill_pattern(g_ctrlr.write_buf, bpsize, 0xDE);
118 
119 	g_ctrlr.write_completed = 0;
120 	rc = spdk_nvme_ctrlr_write_boot_partition(ctrlr, g_ctrlr.write_buf,
121 			bpsize, 0, write_complete, NULL);
122 	if (rc) {
123 		printf("Error - Boot Partition write failure. rc: %d", rc);
124 		cleanup();
125 		return rc;
126 	}
127 
128 	while (!g_ctrlr.write_completed) {
129 		spdk_nvme_ctrlr_process_admin_completions(ctrlr);
130 	}
131 
132 	rc = spdk_nvme_ctrlr_read_boot_partition_start(ctrlr, g_ctrlr.read_buf,
133 			bpsize_in_4k, 0, 0);
134 
135 	if (rc) {
136 		printf("Error - Boot Partition read start failure. rc: %d", rc);
137 		cleanup();
138 		return rc;
139 	}
140 
141 	do {
142 		rc = spdk_nvme_ctrlr_read_boot_partition_poll(ctrlr);
143 	} while (rc == -EAGAIN);
144 
145 	if (rc != 0) {
146 		printf("Error - Boot Partition read poll failure. rc: %d", rc);
147 		cleanup();
148 		return rc;
149 	}
150 
151 	rc = memcmp(g_ctrlr.write_buf, g_ctrlr.read_buf, bpsize);
152 	if (rc) {
153 		printf("Error - Boot Partition written data does not match Boot Partition read data, rc: %d\n", rc);
154 		cleanup();
155 		return rc;
156 	}
157 
158 	printf("Boot Partition 0 written data matches Boot Partition 0 read data\n");
159 
160 	fill_pattern(g_ctrlr.write_buf, bpsize, 0xAD);
161 
162 	g_ctrlr.write_completed = 0;
163 	rc = spdk_nvme_ctrlr_write_boot_partition(ctrlr, g_ctrlr.write_buf,
164 			bpsize, 1, write_complete, NULL);
165 	if (rc) {
166 		printf("Error - Boot Partition write failure. rc: %d", rc);
167 		cleanup();
168 		return rc;
169 	}
170 
171 	while (!g_ctrlr.write_completed) {
172 		spdk_nvme_ctrlr_process_admin_completions(ctrlr);
173 	}
174 
175 	rc = spdk_nvme_ctrlr_read_boot_partition_start(ctrlr, g_ctrlr.read_buf,
176 			bpsize_in_4k, 0, 1);
177 
178 	if (rc) {
179 		printf("Error - Boot Partition read start failure. rc: %d", rc);
180 		cleanup();
181 		return rc;
182 	}
183 
184 	do {
185 		rc = spdk_nvme_ctrlr_read_boot_partition_poll(ctrlr);
186 	} while (rc == -EAGAIN);
187 
188 	if (rc != 0) {
189 		printf("Error - Boot Partition read poll failure. rc: %d", rc);
190 		cleanup();
191 		return rc;
192 	}
193 
194 	rc = memcmp(g_ctrlr.write_buf, g_ctrlr.read_buf, bpsize);
195 	if (rc) {
196 		printf("Error - Boot Partition written data does not match Boot Partition read data, rc: %d\n", rc);
197 		cleanup();
198 		return rc;
199 	}
200 
201 	printf("Boot Partition 1 written data matches Boot Partition 1 read data\n");
202 
203 	cleanup();
204 
205 	return 0;
206 }
207 
208 static void
209 cleanup(void)
210 {
211 	spdk_memzone_free("boot_partition");
212 	spdk_free(g_ctrlr.write_buf);
213 	spdk_nvme_detach(g_ctrlr.ctrlr);
214 }
215 
216 static void
217 usage(char *program_name)
218 {
219 	printf("%s Option (Mandatory)", program_name);
220 	printf("\n");
221 	printf("\t[-p PCIe address of the NVMe Device with Boot Partition support]\n");
222 	printf("\n");
223 }
224 
225 static int
226 parse_args(int argc, char **argv)
227 {
228 	int op;
229 	unsigned num_args = 0;
230 
231 	while ((op = getopt(argc, argv, "p:")) != -1) {
232 		switch (op) {
233 		case 'p':
234 			snprintf(&g_ctrlr.trid.traddr[0], SPDK_NVMF_TRADDR_MAX_LEN + 1,
235 				 "%s", optarg);
236 
237 			g_ctrlr.trid.trtype = SPDK_NVME_TRANSPORT_PCIE;
238 
239 			spdk_nvme_transport_id_populate_trstring(&g_ctrlr.trid,
240 					spdk_nvme_transport_id_trtype_str(g_ctrlr.trid.trtype));
241 
242 			num_args++;
243 			break;
244 		default:
245 			usage(argv[0]);
246 			return 1;
247 		}
248 	}
249 
250 	if (num_args != 1) {
251 		usage(argv[0]);
252 		return 1;
253 	}
254 
255 	return 0;
256 }
257 
258 int main(int argc, char **argv)
259 {
260 	int			rc;
261 	struct spdk_env_opts	opts;
262 
263 	/*
264 	 * Parse the input arguments. For now we use the following
265 	 * format list:
266 	 *
267 	 * -p <pci id>
268 	 *
269 	 */
270 	rc = parse_args(argc, argv);
271 	if (rc) {
272 		fprintf(stderr, "Error in parse_args(): %d\n", rc);
273 		return rc;
274 	}
275 
276 	spdk_env_opts_init(&opts);
277 	opts.name = "boot_partition";
278 	opts.shm_id = 0;
279 	if (spdk_env_init(&opts) < 0) {
280 		fprintf(stderr, "Unable to initialize SPDK env\n");
281 		return 1;
282 	}
283 
284 	printf("Initializing NVMe Controller\n");
285 
286 	g_ctrlr.ctrlr = spdk_nvme_connect(&g_ctrlr.trid, NULL, 0);
287 	if (!g_ctrlr.ctrlr) {
288 		fprintf(stderr, "spdk_nvme_connect() failed\n");
289 		return 1;
290 	}
291 
292 	printf("Initialization complete.\n");
293 	rc = boot_partition_test();
294 	return rc;
295 }
296