xref: /illumos-gate/usr/src/test/nvme-tests/tests/libnvme/format.c (revision f5f0964ce91892f7482efc86903b0ec7c7b6ba66)
1*f5f0964cSRobert Mustacchi /*
2*f5f0964cSRobert Mustacchi  * This file and its contents are supplied under the terms of the
3*f5f0964cSRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4*f5f0964cSRobert Mustacchi  * You may only use this file in accordance with the terms of version
5*f5f0964cSRobert Mustacchi  * 1.0 of the CDDL.
6*f5f0964cSRobert Mustacchi  *
7*f5f0964cSRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8*f5f0964cSRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9*f5f0964cSRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10*f5f0964cSRobert Mustacchi  */
11*f5f0964cSRobert Mustacchi 
12*f5f0964cSRobert Mustacchi /*
13*f5f0964cSRobert Mustacchi  * Copyright 2025 Oxide Computer Company
14*f5f0964cSRobert Mustacchi  */
15*f5f0964cSRobert Mustacchi 
16*f5f0964cSRobert Mustacchi /*
17*f5f0964cSRobert Mustacchi  * Test basic features around formatting namespaces and secure erase. In
18*f5f0964cSRobert Mustacchi  * particular we want to make sure that we can do the following:
19*f5f0964cSRobert Mustacchi  *
20*f5f0964cSRobert Mustacchi  *  - Format a single namespace
21*f5f0964cSRobert Mustacchi  *  - Broadcast format all active namespaces
22*f5f0964cSRobert Mustacchi  *  - Secure erase (whether broadcast or serially)
23*f5f0964cSRobert Mustacchi  *
24*f5f0964cSRobert Mustacchi  * We create two 1 GiB namespaces that we use for this. The namespace size
25*f5f0964cSRobert Mustacchi  * hopefully keeps format and secure erase timing reasonable. We end up writing
26*f5f0964cSRobert Mustacchi  * a message to sector 0 of each namespace to try to verify data was actually
27*f5f0964cSRobert Mustacchi  * erased.
28*f5f0964cSRobert Mustacchi  *
29*f5f0964cSRobert Mustacchi  * This test starts from the device-empty profile so we can control the size and
30*f5f0964cSRobert Mustacchi  * space of namespaces.
31*f5f0964cSRobert Mustacchi  */
32*f5f0964cSRobert Mustacchi 
33*f5f0964cSRobert Mustacchi #include <err.h>
34*f5f0964cSRobert Mustacchi #include <stdlib.h>
35*f5f0964cSRobert Mustacchi #include <stdio.h>
36*f5f0964cSRobert Mustacchi #include <string.h>
37*f5f0964cSRobert Mustacchi #include <libdevinfo.h>
38*f5f0964cSRobert Mustacchi #include <fcntl.h>
39*f5f0964cSRobert Mustacchi #include <unistd.h>
40*f5f0964cSRobert Mustacchi 
41*f5f0964cSRobert Mustacchi #include "libnvme_test_common.h"
42*f5f0964cSRobert Mustacchi 
43*f5f0964cSRobert Mustacchi #define	NSID_BASE	1
44*f5f0964cSRobert Mustacchi #define	NNSIDS		2
45*f5f0964cSRobert Mustacchi 
46*f5f0964cSRobert Mustacchi /*
47*f5f0964cSRobert Mustacchi  * Because we use the raw block device, our size needs to be a multiple of both
48*f5f0964cSRobert Mustacchi  * of the sector sizes we use (4k, 512), which gives us a 4k buffer.
49*f5f0964cSRobert Mustacchi  */
50*f5f0964cSRobert Mustacchi #define	FMT_BUF_SIZE	4096
51*f5f0964cSRobert Mustacchi 
52*f5f0964cSRobert Mustacchi static const char *format_msgs[NNSIDS] = {
53*f5f0964cSRobert Mustacchi 	"Those Who Fight Further",
54*f5f0964cSRobert Mustacchi 	"Those Who Deny the Dawn"
55*f5f0964cSRobert Mustacchi };
56*f5f0964cSRobert Mustacchi 
57*f5f0964cSRobert Mustacchi /*
58*f5f0964cSRobert Mustacchi  * Check the results of a format / erase namespace and verify that our old data
59*f5f0964cSRobert Mustacchi  * is gone. Write new data.
60*f5f0964cSRobert Mustacchi  */
61*f5f0964cSRobert Mustacchi static bool
format_io_verify(int fd,uint32_t nsid)62*f5f0964cSRobert Mustacchi format_io_verify(int fd, uint32_t nsid)
63*f5f0964cSRobert Mustacchi {
64*f5f0964cSRobert Mustacchi 	uint8_t buf[FMT_BUF_SIZE];
65*f5f0964cSRobert Mustacchi 	const char *msg = format_msgs[nsid - 1];
66*f5f0964cSRobert Mustacchi 	size_t msglen = strlen(msg) + 1;
67*f5f0964cSRobert Mustacchi 
68*f5f0964cSRobert Mustacchi 	if (pread(fd, buf, sizeof (buf), 0) != sizeof (buf)) {
69*f5f0964cSRobert Mustacchi 		warn("TEST FAILED: failed to read from nsid %u", nsid);
70*f5f0964cSRobert Mustacchi 		return (false);
71*f5f0964cSRobert Mustacchi 	}
72*f5f0964cSRobert Mustacchi 
73*f5f0964cSRobert Mustacchi 	/*
74*f5f0964cSRobert Mustacchi 	 * These contents should never match our message.
75*f5f0964cSRobert Mustacchi 	 */
76*f5f0964cSRobert Mustacchi 	if (memcmp(buf, msg, msglen) != 0) {
77*f5f0964cSRobert Mustacchi 		(void) printf("TEST PASSED: namespace %u data successfully "
78*f5f0964cSRobert Mustacchi 		    "cleared\n", nsid);
79*f5f0964cSRobert Mustacchi 	} else {
80*f5f0964cSRobert Mustacchi 		warnx("TEST FAILED: nsid %u data was not successfully erased",
81*f5f0964cSRobert Mustacchi 		    nsid);
82*f5f0964cSRobert Mustacchi 		(void) printf("Unexpected data: found\n");
83*f5f0964cSRobert Mustacchi 		for (size_t i = 0; i < msglen; i++) {
84*f5f0964cSRobert Mustacchi 			(void) printf("buf[%u]: %02x\n", i, buf[i]);
85*f5f0964cSRobert Mustacchi 		}
86*f5f0964cSRobert Mustacchi 
87*f5f0964cSRobert Mustacchi 		return (false);
88*f5f0964cSRobert Mustacchi 	}
89*f5f0964cSRobert Mustacchi 
90*f5f0964cSRobert Mustacchi 	(void) memset(buf, 0x77, sizeof (buf));
91*f5f0964cSRobert Mustacchi 	(void) memcpy(buf, msg, msglen);
92*f5f0964cSRobert Mustacchi 	if (pwrite(fd, buf, sizeof (buf), 0) != sizeof (buf)) {
93*f5f0964cSRobert Mustacchi 		warnx("TEST FAILED: failed to write updated buffer to nsid "
94*f5f0964cSRobert Mustacchi 		    "%u", nsid);
95*f5f0964cSRobert Mustacchi 		return (false);
96*f5f0964cSRobert Mustacchi 	}
97*f5f0964cSRobert Mustacchi 
98*f5f0964cSRobert Mustacchi 	if (fsync(fd) != 0) {
99*f5f0964cSRobert Mustacchi 		warn("TEST FAILED: failed to synchronize raw device write "
100*f5f0964cSRobert Mustacchi 		    "to ns %u", nsid);
101*f5f0964cSRobert Mustacchi 	}
102*f5f0964cSRobert Mustacchi 
103*f5f0964cSRobert Mustacchi 	(void) memset(buf, 0, sizeof (buf));
104*f5f0964cSRobert Mustacchi 	if (pread(fd, buf, sizeof (buf), 0) != sizeof (buf)) {
105*f5f0964cSRobert Mustacchi 		warnx("TEST FAILED: failed to read back data written to %u",
106*f5f0964cSRobert Mustacchi 		    nsid);
107*f5f0964cSRobert Mustacchi 		return (false);
108*f5f0964cSRobert Mustacchi 	}
109*f5f0964cSRobert Mustacchi 
110*f5f0964cSRobert Mustacchi 	if (memcmp(buf, msg, msglen) != 0) {
111*f5f0964cSRobert Mustacchi 		warnx("TEST FAILED: did not get back data written to nsid %u",
112*f5f0964cSRobert Mustacchi 		    nsid);
113*f5f0964cSRobert Mustacchi 		(void) printf("Mismatched data: found/expected\n");
114*f5f0964cSRobert Mustacchi 		for (size_t i = 0; i < msglen; i++) {
115*f5f0964cSRobert Mustacchi 			(void) printf("buf[%u]: %02x/%02x\n", i, buf[i],
116*f5f0964cSRobert Mustacchi 			    msg[i]);
117*f5f0964cSRobert Mustacchi 		}
118*f5f0964cSRobert Mustacchi 		return (false);
119*f5f0964cSRobert Mustacchi 	}
120*f5f0964cSRobert Mustacchi 
121*f5f0964cSRobert Mustacchi 	(void) printf("TEST PASSED: successfully wrote message to nsid %u\n",
122*f5f0964cSRobert Mustacchi 	    nsid);
123*f5f0964cSRobert Mustacchi 	return (true);
124*f5f0964cSRobert Mustacchi }
125*f5f0964cSRobert Mustacchi 
126*f5f0964cSRobert Mustacchi /*
127*f5f0964cSRobert Mustacchi  * Used after another namespace has been formatted to check that the other is
128*f5f0964cSRobert Mustacchi  * still okay and its data hasn't been overwritten.
129*f5f0964cSRobert Mustacchi  */
130*f5f0964cSRobert Mustacchi static bool
format_io_check(int fd,uint32_t nsid)131*f5f0964cSRobert Mustacchi format_io_check(int fd, uint32_t nsid)
132*f5f0964cSRobert Mustacchi {
133*f5f0964cSRobert Mustacchi 	uint8_t buf[FMT_BUF_SIZE];
134*f5f0964cSRobert Mustacchi 	const char *msg = format_msgs[nsid - 1];
135*f5f0964cSRobert Mustacchi 	size_t msglen = strlen(msg) + 1;
136*f5f0964cSRobert Mustacchi 
137*f5f0964cSRobert Mustacchi 	if (pread(fd, buf, sizeof (buf), 0) != sizeof (buf)) {
138*f5f0964cSRobert Mustacchi 		warnx("TEST FAILED: failed to read back data on nsid %u",
139*f5f0964cSRobert Mustacchi 		    nsid);
140*f5f0964cSRobert Mustacchi 		return (false);
141*f5f0964cSRobert Mustacchi 	}
142*f5f0964cSRobert Mustacchi 
143*f5f0964cSRobert Mustacchi 	if (memcmp(buf, msg, msglen) != 0) {
144*f5f0964cSRobert Mustacchi 		warnx("TEST FAILED: data on nsid %u changed after format of "
145*f5f0964cSRobert Mustacchi 		    "other namespace", nsid);
146*f5f0964cSRobert Mustacchi 		(void) printf("Mismatched data: found/expected\n");
147*f5f0964cSRobert Mustacchi 		for (size_t i = 0; i < msglen; i++) {
148*f5f0964cSRobert Mustacchi 			(void) printf("buf[%u]: %02x/%02x\n", i, buf[i],
149*f5f0964cSRobert Mustacchi 			    msg[i]);
150*f5f0964cSRobert Mustacchi 		}
151*f5f0964cSRobert Mustacchi 		return (false);
152*f5f0964cSRobert Mustacchi 	}
153*f5f0964cSRobert Mustacchi 
154*f5f0964cSRobert Mustacchi 	(void) printf("TEST PASSED: verified prior message on nsid %u\n",
155*f5f0964cSRobert Mustacchi 	    nsid);
156*f5f0964cSRobert Mustacchi 	return (true);
157*f5f0964cSRobert Mustacchi }
158*f5f0964cSRobert Mustacchi 
159*f5f0964cSRobert Mustacchi /*
160*f5f0964cSRobert Mustacchi  * Get the file descripto that corresponds to the raw whole disk device which is
161*f5f0964cSRobert Mustacchi  * generally s2 or 'c,raw'.
162*f5f0964cSRobert Mustacchi  */
163*f5f0964cSRobert Mustacchi static int
format_blkdev_fd(const char * bd_addr)164*f5f0964cSRobert Mustacchi format_blkdev_fd(const char *bd_addr)
165*f5f0964cSRobert Mustacchi {
166*f5f0964cSRobert Mustacchi 	int fd = -1;
167*f5f0964cSRobert Mustacchi 	di_node_t root;
168*f5f0964cSRobert Mustacchi 
169*f5f0964cSRobert Mustacchi 	root = di_init("/", DINFOCPYALL);
170*f5f0964cSRobert Mustacchi 	if (root == DI_NODE_NIL) {
171*f5f0964cSRobert Mustacchi 		warnx("failed to take devinfo snapshot");
172*f5f0964cSRobert Mustacchi 		return (-1);
173*f5f0964cSRobert Mustacchi 	}
174*f5f0964cSRobert Mustacchi 
175*f5f0964cSRobert Mustacchi 	for (di_node_t n = di_drv_first_node("blkdev", root); n != DI_NODE_NIL;
176*f5f0964cSRobert Mustacchi 	    n = di_drv_next_node(n)) {
177*f5f0964cSRobert Mustacchi 		char *devfs, path[PATH_MAX];
178*f5f0964cSRobert Mustacchi 		const char *addr = di_bus_addr(n);
179*f5f0964cSRobert Mustacchi 
180*f5f0964cSRobert Mustacchi 		if (addr == NULL) {
181*f5f0964cSRobert Mustacchi 			continue;
182*f5f0964cSRobert Mustacchi 		}
183*f5f0964cSRobert Mustacchi 
184*f5f0964cSRobert Mustacchi 		if (strcmp(bd_addr, addr) != 0)
185*f5f0964cSRobert Mustacchi 			continue;
186*f5f0964cSRobert Mustacchi 
187*f5f0964cSRobert Mustacchi 		devfs = di_devfs_path(n);
188*f5f0964cSRobert Mustacchi 		if (devfs == NULL) {
189*f5f0964cSRobert Mustacchi 			warn("failed to get devfs path for blkdev %s", bd_addr);
190*f5f0964cSRobert Mustacchi 			goto out;
191*f5f0964cSRobert Mustacchi 		}
192*f5f0964cSRobert Mustacchi 
193*f5f0964cSRobert Mustacchi 		if (snprintf(path, sizeof (path), "/devices/%s:c,raw", devfs) >=
194*f5f0964cSRobert Mustacchi 		    sizeof (path)) {
195*f5f0964cSRobert Mustacchi 			di_devfs_path_free(devfs);
196*f5f0964cSRobert Mustacchi 			warnx("Construction of blkdev %s minor path exceeded "
197*f5f0964cSRobert Mustacchi 			    "internal buffer", bd_addr);
198*f5f0964cSRobert Mustacchi 			goto out;
199*f5f0964cSRobert Mustacchi 		}
200*f5f0964cSRobert Mustacchi 
201*f5f0964cSRobert Mustacchi 		/*
202*f5f0964cSRobert Mustacchi 		 * We need to use O_NDELAY here to convince the system that it's
203*f5f0964cSRobert Mustacchi 		 * okay that there isn't valid CMLB information yet, which is
204*f5f0964cSRobert Mustacchi 		 * fine because we're trashing this device.
205*f5f0964cSRobert Mustacchi 		 */
206*f5f0964cSRobert Mustacchi 		di_devfs_path_free(devfs);
207*f5f0964cSRobert Mustacchi 		fd = open(path, O_RDWR | O_NDELAY);
208*f5f0964cSRobert Mustacchi 		if (fd < 0) {
209*f5f0964cSRobert Mustacchi 			warn("failed to open %s", path);
210*f5f0964cSRobert Mustacchi 			goto out;
211*f5f0964cSRobert Mustacchi 		}
212*f5f0964cSRobert Mustacchi 	}
213*f5f0964cSRobert Mustacchi 
214*f5f0964cSRobert Mustacchi 	if (fd == -1) {
215*f5f0964cSRobert Mustacchi 		warnx("failed to find di_node_t that matches %s", bd_addr);
216*f5f0964cSRobert Mustacchi 	}
217*f5f0964cSRobert Mustacchi 
218*f5f0964cSRobert Mustacchi out:
219*f5f0964cSRobert Mustacchi 	di_fini(root);
220*f5f0964cSRobert Mustacchi 	return (fd);
221*f5f0964cSRobert Mustacchi }
222*f5f0964cSRobert Mustacchi 
223*f5f0964cSRobert Mustacchi /*
224*f5f0964cSRobert Mustacchi  * Leave a message in sector 0 of each device that we can later verify is there
225*f5f0964cSRobert Mustacchi  * or not.
226*f5f0964cSRobert Mustacchi  */
227*f5f0964cSRobert Mustacchi static bool
format_nsid_io(nvme_ctrl_t * ctrl,uint32_t nsid,bool (* cb)(int,uint32_t))228*f5f0964cSRobert Mustacchi format_nsid_io(nvme_ctrl_t *ctrl, uint32_t nsid, bool (*cb)(int, uint32_t))
229*f5f0964cSRobert Mustacchi {
230*f5f0964cSRobert Mustacchi 	int fd;
231*f5f0964cSRobert Mustacchi 	nvme_ns_info_t *ns = NULL;
232*f5f0964cSRobert Mustacchi 	const char *bd_addr;
233*f5f0964cSRobert Mustacchi 	bool ret = false;
234*f5f0964cSRobert Mustacchi 
235*f5f0964cSRobert Mustacchi 	if (!libnvme_test_setup_ns(ctrl, NVME_NS_DISC_F_BLKDEV, nsid,
236*f5f0964cSRobert Mustacchi 	    UINT32_MAX)) {
237*f5f0964cSRobert Mustacchi 		libnvme_test_ctrl_warn(ctrl, "failed to attach blkdev to "
238*f5f0964cSRobert Mustacchi 		    "nsid %u", nsid);
239*f5f0964cSRobert Mustacchi 		return (false);
240*f5f0964cSRobert Mustacchi 	}
241*f5f0964cSRobert Mustacchi 
242*f5f0964cSRobert Mustacchi 	if (!nvme_ctrl_ns_info_snap(ctrl, nsid, &ns)) {
243*f5f0964cSRobert Mustacchi 		libnvme_test_ctrl_warn(ctrl, "failed to take namespace %u "
244*f5f0964cSRobert Mustacchi 		    "info snapshot", nsid);
245*f5f0964cSRobert Mustacchi 		goto out;
246*f5f0964cSRobert Mustacchi 	}
247*f5f0964cSRobert Mustacchi 
248*f5f0964cSRobert Mustacchi 	if (!nvme_ns_info_bd_addr(ns, &bd_addr)) {
249*f5f0964cSRobert Mustacchi 		libnvme_test_ctrl_warn(ctrl, "failed to get blkdev address "
250*f5f0964cSRobert Mustacchi 		    "for namespace %u", nsid);
251*f5f0964cSRobert Mustacchi 		goto out;
252*f5f0964cSRobert Mustacchi 	}
253*f5f0964cSRobert Mustacchi 
254*f5f0964cSRobert Mustacchi 	if ((fd = format_blkdev_fd(bd_addr)) < 0) {
255*f5f0964cSRobert Mustacchi 		warnx("TEST FAILED: failed to acquire blkdev fd for nsid %u "
256*f5f0964cSRobert Mustacchi 		    "to write data", nsid);
257*f5f0964cSRobert Mustacchi 		goto out;
258*f5f0964cSRobert Mustacchi 	}
259*f5f0964cSRobert Mustacchi 
260*f5f0964cSRobert Mustacchi 	ret = cb(fd, nsid);
261*f5f0964cSRobert Mustacchi 	VERIFY0(close(fd));
262*f5f0964cSRobert Mustacchi 
263*f5f0964cSRobert Mustacchi out:
264*f5f0964cSRobert Mustacchi 	if (!libnvme_test_setup_ns(ctrl, NVME_NS_DISC_F_NOT_IGNORED, nsid,
265*f5f0964cSRobert Mustacchi 	    UINT32_MAX)) {
266*f5f0964cSRobert Mustacchi 		libnvme_test_ctrl_warn(ctrl, "failed to detach blkdev from "
267*f5f0964cSRobert Mustacchi 		    "nsid %u", nsid);
268*f5f0964cSRobert Mustacchi 		ret = false;
269*f5f0964cSRobert Mustacchi 	}
270*f5f0964cSRobert Mustacchi 
271*f5f0964cSRobert Mustacchi 	nvme_ns_info_free(ns);
272*f5f0964cSRobert Mustacchi 	return (ret);
273*f5f0964cSRobert Mustacchi }
274*f5f0964cSRobert Mustacchi 
275*f5f0964cSRobert Mustacchi /*
276*f5f0964cSRobert Mustacchi  * Verify that a given namespace has the expected LBA format.
277*f5f0964cSRobert Mustacchi  */
278*f5f0964cSRobert Mustacchi static bool
format_check_lbaf(nvme_ctrl_t * ctrl,uint32_t nsid,uint32_t lbaf)279*f5f0964cSRobert Mustacchi format_check_lbaf(nvme_ctrl_t *ctrl, uint32_t nsid, uint32_t lbaf)
280*f5f0964cSRobert Mustacchi {
281*f5f0964cSRobert Mustacchi 	bool ret = false;
282*f5f0964cSRobert Mustacchi 	nvme_ns_info_t *info;
283*f5f0964cSRobert Mustacchi 	const nvme_nvm_lba_fmt_t *lba;
284*f5f0964cSRobert Mustacchi 
285*f5f0964cSRobert Mustacchi 	if (!nvme_ctrl_ns_info_snap(ctrl, nsid, &info)) {
286*f5f0964cSRobert Mustacchi 		libnvme_test_ctrl_warn(ctrl, "failed to take namespace %u "
287*f5f0964cSRobert Mustacchi 		    "info snapshot", nsid);
288*f5f0964cSRobert Mustacchi 		return (false);
289*f5f0964cSRobert Mustacchi 	}
290*f5f0964cSRobert Mustacchi 
291*f5f0964cSRobert Mustacchi 	if (!nvme_ns_info_curformat(info, &lba)) {
292*f5f0964cSRobert Mustacchi 		libnvme_test_ctrl_warn(ctrl, "failed to get namespace %u "
293*f5f0964cSRobert Mustacchi 		    "current lba format", nsid);
294*f5f0964cSRobert Mustacchi 		goto out;
295*f5f0964cSRobert Mustacchi 	}
296*f5f0964cSRobert Mustacchi 
297*f5f0964cSRobert Mustacchi 	if (nvme_nvm_lba_fmt_id(lba) == lbaf) {
298*f5f0964cSRobert Mustacchi 		(void) printf("TEST PASSED: Succesfully formatted namespace %u "
299*f5f0964cSRobert Mustacchi 		    "to format %u (0x%" PRIx64 ")\n", nsid, lbaf,
300*f5f0964cSRobert Mustacchi 		    nvme_nvm_lba_fmt_data_size(lba));
301*f5f0964cSRobert Mustacchi 		ret = true;
302*f5f0964cSRobert Mustacchi 	} else {
303*f5f0964cSRobert Mustacchi 		warnx("TEST FAILED: Formatted namespace %u ended up with LBA "
304*f5f0964cSRobert Mustacchi 		    "format %u (0x%" PRIx64 " bytes), not %u", nsid,
305*f5f0964cSRobert Mustacchi 		    nvme_nvm_lba_fmt_id(lba), nvme_nvm_lba_fmt_data_size(lba),
306*f5f0964cSRobert Mustacchi 		    lbaf);
307*f5f0964cSRobert Mustacchi 	}
308*f5f0964cSRobert Mustacchi 
309*f5f0964cSRobert Mustacchi out:
310*f5f0964cSRobert Mustacchi 	nvme_ns_info_free(info);
311*f5f0964cSRobert Mustacchi 	return (ret);
312*f5f0964cSRobert Mustacchi }
313*f5f0964cSRobert Mustacchi 
314*f5f0964cSRobert Mustacchi static bool
format_ns(nvme_ctrl_t * ctrl,uint32_t nsid,uint32_t ses,uint32_t lbaf)315*f5f0964cSRobert Mustacchi format_ns(nvme_ctrl_t *ctrl, uint32_t nsid, uint32_t ses, uint32_t lbaf)
316*f5f0964cSRobert Mustacchi {
317*f5f0964cSRobert Mustacchi 	bool ret = true;
318*f5f0964cSRobert Mustacchi 	nvme_format_req_t *req;
319*f5f0964cSRobert Mustacchi 
320*f5f0964cSRobert Mustacchi 	if (!nvme_format_req_init(ctrl, &req)) {
321*f5f0964cSRobert Mustacchi 		libnvme_test_ctrl_warn(ctrl, "failed to initialize format "
322*f5f0964cSRobert Mustacchi 		    "request");
323*f5f0964cSRobert Mustacchi 		ret = false;
324*f5f0964cSRobert Mustacchi 		goto done;
325*f5f0964cSRobert Mustacchi 	}
326*f5f0964cSRobert Mustacchi 
327*f5f0964cSRobert Mustacchi 	if (!nvme_format_req_set_lbaf(req, lbaf)) {
328*f5f0964cSRobert Mustacchi 		libnvme_test_ctrl_warn(ctrl, "failed to set format lbaf to "
329*f5f0964cSRobert Mustacchi 		    "0x%x", lbaf);
330*f5f0964cSRobert Mustacchi 		ret = false;
331*f5f0964cSRobert Mustacchi 		goto done;
332*f5f0964cSRobert Mustacchi 	}
333*f5f0964cSRobert Mustacchi 
334*f5f0964cSRobert Mustacchi 	if (!nvme_format_req_set_ses(req, ses)) {
335*f5f0964cSRobert Mustacchi 		libnvme_test_ctrl_warn(ctrl, "failed to set format ses to 0x%x",
336*f5f0964cSRobert Mustacchi 		    ses);
337*f5f0964cSRobert Mustacchi 		ret = false;
338*f5f0964cSRobert Mustacchi 		goto done;
339*f5f0964cSRobert Mustacchi 	}
340*f5f0964cSRobert Mustacchi 
341*f5f0964cSRobert Mustacchi 	if (!nvme_format_req_set_nsid(req, nsid)) {
342*f5f0964cSRobert Mustacchi 		libnvme_test_ctrl_warn(ctrl, "failed to set format nsid to "
343*f5f0964cSRobert Mustacchi 		    "0x%x", nsid);
344*f5f0964cSRobert Mustacchi 		ret = false;
345*f5f0964cSRobert Mustacchi 		goto done;
346*f5f0964cSRobert Mustacchi 	}
347*f5f0964cSRobert Mustacchi 
348*f5f0964cSRobert Mustacchi 	if (!nvme_format_req_exec(req)) {
349*f5f0964cSRobert Mustacchi 		libnvme_test_ctrl_warn(ctrl, "failed to execute format "
350*f5f0964cSRobert Mustacchi 		    "namespace for nsid %u", nsid);
351*f5f0964cSRobert Mustacchi 		ret = false;
352*f5f0964cSRobert Mustacchi 		goto done;
353*f5f0964cSRobert Mustacchi 	}
354*f5f0964cSRobert Mustacchi 
355*f5f0964cSRobert Mustacchi 	for (uint32_t i = 0; i < NNSIDS; i++) {
356*f5f0964cSRobert Mustacchi 		if (nsid == NVME_NSID_BCAST || nsid == (NSID_BASE + i)) {
357*f5f0964cSRobert Mustacchi 			if (!format_check_lbaf(ctrl, NSID_BASE + i, lbaf)) {
358*f5f0964cSRobert Mustacchi 				ret = false;
359*f5f0964cSRobert Mustacchi 			}
360*f5f0964cSRobert Mustacchi 		}
361*f5f0964cSRobert Mustacchi 	}
362*f5f0964cSRobert Mustacchi 
363*f5f0964cSRobert Mustacchi done:
364*f5f0964cSRobert Mustacchi 	nvme_format_req_fini(req);
365*f5f0964cSRobert Mustacchi 	return (ret);
366*f5f0964cSRobert Mustacchi }
367*f5f0964cSRobert Mustacchi 
368*f5f0964cSRobert Mustacchi int
main(void)369*f5f0964cSRobert Mustacchi main(void)
370*f5f0964cSRobert Mustacchi {
371*f5f0964cSRobert Mustacchi 	int ret = EXIT_SUCCESS;
372*f5f0964cSRobert Mustacchi 	nvme_t *nvme;
373*f5f0964cSRobert Mustacchi 	nvme_ctrl_t *ctrl;
374*f5f0964cSRobert Mustacchi 	nvme_ctrl_info_t *info;
375*f5f0964cSRobert Mustacchi 	uint32_t lbaf_4k, lbaf_512, ses;
376*f5f0964cSRobert Mustacchi 	const nvme_identify_ctrl_t *id;
377*f5f0964cSRobert Mustacchi 
378*f5f0964cSRobert Mustacchi 	libnvme_test_init(&nvme, &ctrl);
379*f5f0964cSRobert Mustacchi 	if (!nvme_ctrl_lock(ctrl, NVME_LOCK_L_WRITE, NVME_LOCK_F_DONT_BLOCK)) {
380*f5f0964cSRobert Mustacchi 		libnvme_test_ctrl_fatal(ctrl, "failed to obtain write lock");
381*f5f0964cSRobert Mustacchi 	}
382*f5f0964cSRobert Mustacchi 
383*f5f0964cSRobert Mustacchi 	if (!nvme_ctrl_info_snap(ctrl, &info)) {
384*f5f0964cSRobert Mustacchi 		libnvme_test_ctrl_fatal(ctrl, "failed to get info snapshot");
385*f5f0964cSRobert Mustacchi 	}
386*f5f0964cSRobert Mustacchi 
387*f5f0964cSRobert Mustacchi 	if (!libnvme_test_lbaf(info, 4096, &lbaf_4k)) {
388*f5f0964cSRobert Mustacchi 		errx(EXIT_FAILURE, "failed to find 4K LBA format, cannot "
389*f5f0964cSRobert Mustacchi 		    "continue");
390*f5f0964cSRobert Mustacchi 	}
391*f5f0964cSRobert Mustacchi 
392*f5f0964cSRobert Mustacchi 	if (!libnvme_test_lbaf(info, 512, &lbaf_512)) {
393*f5f0964cSRobert Mustacchi 		errx(EXIT_FAILURE, "failed to find 512 byte LBA format, cannot "
394*f5f0964cSRobert Mustacchi 		    "continue");
395*f5f0964cSRobert Mustacchi 	}
396*f5f0964cSRobert Mustacchi 	(void) printf("LBA indexes: 512/4k %u/%u\n", lbaf_512, lbaf_4k);
397*f5f0964cSRobert Mustacchi 
398*f5f0964cSRobert Mustacchi 	/*
399*f5f0964cSRobert Mustacchi 	 * Start by creating a single 512 byte namespace. We only create a
400*f5f0964cSRobert Mustacchi 	 * single one for now because we expect that many devices don't like
401*f5f0964cSRobert Mustacchi 	 * having namespaces with different LBA formats despite indicating in
402*f5f0964cSRobert Mustacchi 	 * the format NVM attributes that namespaces are independent.
403*f5f0964cSRobert Mustacchi 	 */
404*f5f0964cSRobert Mustacchi 	if (!libnvme_test_setup_ns(ctrl, NVME_NS_DISC_F_ACTIVE, 1, lbaf_512)) {
405*f5f0964cSRobert Mustacchi 		libnvme_test_ctrl_fatal(ctrl, "failed to create initial "
406*f5f0964cSRobert Mustacchi 		    "namespaces");
407*f5f0964cSRobert Mustacchi 	}
408*f5f0964cSRobert Mustacchi 
409*f5f0964cSRobert Mustacchi 	/*
410*f5f0964cSRobert Mustacchi 	 * Because the namespaces was created as part of this (we assume we
411*f5f0964cSRobert Mustacchi 	 * started from the empty device-reset profile), nothing should be here.
412*f5f0964cSRobert Mustacchi 	 */
413*f5f0964cSRobert Mustacchi 	if (!format_nsid_io(ctrl, 1, format_io_verify))
414*f5f0964cSRobert Mustacchi 		ret = EXIT_FAILURE;
415*f5f0964cSRobert Mustacchi 
416*f5f0964cSRobert Mustacchi 	/*
417*f5f0964cSRobert Mustacchi 	 * Format it to itself and make sure that data is gone.
418*f5f0964cSRobert Mustacchi 	 */
419*f5f0964cSRobert Mustacchi 	if (!format_ns(ctrl, 1, NVME_FRMT_SES_NONE, lbaf_512))
420*f5f0964cSRobert Mustacchi 		ret = EXIT_FAILURE;
421*f5f0964cSRobert Mustacchi 
422*f5f0964cSRobert Mustacchi 	if (!format_nsid_io(ctrl, 1, format_io_verify))
423*f5f0964cSRobert Mustacchi 		ret = EXIT_FAILURE;
424*f5f0964cSRobert Mustacchi 
425*f5f0964cSRobert Mustacchi 	/*
426*f5f0964cSRobert Mustacchi 	 * Transform it to 4K now.
427*f5f0964cSRobert Mustacchi 	 */
428*f5f0964cSRobert Mustacchi 	if (!format_ns(ctrl, 1, NVME_FRMT_SES_NONE, lbaf_4k))
429*f5f0964cSRobert Mustacchi 		ret = EXIT_FAILURE;
430*f5f0964cSRobert Mustacchi 	if (!format_nsid_io(ctrl, 1, format_io_verify))
431*f5f0964cSRobert Mustacchi 		ret = EXIT_FAILURE;
432*f5f0964cSRobert Mustacchi 
433*f5f0964cSRobert Mustacchi 	/*
434*f5f0964cSRobert Mustacchi 	 * Now create a second namespace. At this point we are constrained to
435*f5f0964cSRobert Mustacchi 	 * 4k.
436*f5f0964cSRobert Mustacchi 	 */
437*f5f0964cSRobert Mustacchi 	if (!libnvme_test_setup_ns(ctrl, NVME_NS_DISC_F_ACTIVE, 2, lbaf_4k)) {
438*f5f0964cSRobert Mustacchi 		libnvme_test_ctrl_fatal(ctrl, "failed to create second "
439*f5f0964cSRobert Mustacchi 		    "namespace");
440*f5f0964cSRobert Mustacchi 	}
441*f5f0964cSRobert Mustacchi 
442*f5f0964cSRobert Mustacchi 	if (!format_nsid_io(ctrl, 2, format_io_verify))
443*f5f0964cSRobert Mustacchi 		ret = EXIT_FAILURE;
444*f5f0964cSRobert Mustacchi 	if (!format_nsid_io(ctrl, 1, format_io_check))
445*f5f0964cSRobert Mustacchi 		ret = EXIT_FAILURE;
446*f5f0964cSRobert Mustacchi 
447*f5f0964cSRobert Mustacchi 	/*
448*f5f0964cSRobert Mustacchi 	 * Now reformat 1 and make sure its data is gone and 2's data is intact.
449*f5f0964cSRobert Mustacchi 	 */
450*f5f0964cSRobert Mustacchi 	if (!format_ns(ctrl, 2, NVME_FRMT_SES_NONE, lbaf_4k))
451*f5f0964cSRobert Mustacchi 		ret = EXIT_FAILURE;
452*f5f0964cSRobert Mustacchi 	if (!format_nsid_io(ctrl, 1, format_io_check))
453*f5f0964cSRobert Mustacchi 		ret = EXIT_FAILURE;
454*f5f0964cSRobert Mustacchi 	if (!format_nsid_io(ctrl, 2, format_io_verify))
455*f5f0964cSRobert Mustacchi 		ret = EXIT_FAILURE;
456*f5f0964cSRobert Mustacchi 
457*f5f0964cSRobert Mustacchi 	/*
458*f5f0964cSRobert Mustacchi 	 * Perform a broadcast format back to 512.
459*f5f0964cSRobert Mustacchi 	 */
460*f5f0964cSRobert Mustacchi 	if (!format_ns(ctrl, NVME_NSID_BCAST, NVME_FRMT_SES_NONE, lbaf_512))
461*f5f0964cSRobert Mustacchi 		ret = EXIT_FAILURE;
462*f5f0964cSRobert Mustacchi 
463*f5f0964cSRobert Mustacchi 	if (!format_nsid_io(ctrl, 1, format_io_verify))
464*f5f0964cSRobert Mustacchi 		ret = EXIT_FAILURE;
465*f5f0964cSRobert Mustacchi 	if (!format_nsid_io(ctrl, 2, format_io_verify))
466*f5f0964cSRobert Mustacchi 		ret = EXIT_FAILURE;
467*f5f0964cSRobert Mustacchi 
468*f5f0964cSRobert Mustacchi 	/*
469*f5f0964cSRobert Mustacchi 	 * All devices that support format in theory support secure-erase. Check
470*f5f0964cSRobert Mustacchi 	 * to see if they support cryptographic secure erase as that should
471*f5f0964cSRobert Mustacchi 	 * speed things up due to per-key usage. Secure erase may only work
472*f5f0964cSRobert Mustacchi 	 * globally or operate per-namespace. Regardless of this, we assume that
473*f5f0964cSRobert Mustacchi 	 * if we're changing the format, that has to be done globally.
474*f5f0964cSRobert Mustacchi 	 */
475*f5f0964cSRobert Mustacchi 	id = nvme_ctrl_info_identify(info);
476*f5f0964cSRobert Mustacchi 	if (id->id_fna.fn_crypt_erase != 0) {
477*f5f0964cSRobert Mustacchi 		ses = NVME_FRMT_SES_CRYPTO;
478*f5f0964cSRobert Mustacchi 	} else {
479*f5f0964cSRobert Mustacchi 		ses = NVME_FRMT_SES_USER;
480*f5f0964cSRobert Mustacchi 	}
481*f5f0964cSRobert Mustacchi 
482*f5f0964cSRobert Mustacchi 	if (!format_ns(ctrl, NVME_NSID_BCAST, ses, lbaf_4k))
483*f5f0964cSRobert Mustacchi 		ret = EXIT_FAILURE;
484*f5f0964cSRobert Mustacchi 	if (!format_nsid_io(ctrl, 1, format_io_verify))
485*f5f0964cSRobert Mustacchi 		ret = EXIT_FAILURE;
486*f5f0964cSRobert Mustacchi 	if (!format_nsid_io(ctrl, 2, format_io_verify))
487*f5f0964cSRobert Mustacchi 		ret = EXIT_FAILURE;
488*f5f0964cSRobert Mustacchi 
489*f5f0964cSRobert Mustacchi 	if (id->id_fna.fn_sec_erase == 0) {
490*f5f0964cSRobert Mustacchi 		if (!format_ns(ctrl, 1, ses, lbaf_4k))
491*f5f0964cSRobert Mustacchi 			ret = EXIT_FAILURE;
492*f5f0964cSRobert Mustacchi 		if (!format_nsid_io(ctrl, 2, format_io_check))
493*f5f0964cSRobert Mustacchi 			ret = EXIT_FAILURE;
494*f5f0964cSRobert Mustacchi 		if (!format_nsid_io(ctrl, 1, format_io_verify))
495*f5f0964cSRobert Mustacchi 			ret = EXIT_FAILURE;
496*f5f0964cSRobert Mustacchi 
497*f5f0964cSRobert Mustacchi 		if (!format_ns(ctrl, 2, ses, lbaf_4k))
498*f5f0964cSRobert Mustacchi 			ret = EXIT_FAILURE;
499*f5f0964cSRobert Mustacchi 		if (!format_nsid_io(ctrl, 2, format_io_verify))
500*f5f0964cSRobert Mustacchi 			ret = EXIT_FAILURE;
501*f5f0964cSRobert Mustacchi 		if (!format_nsid_io(ctrl, 1, format_io_check))
502*f5f0964cSRobert Mustacchi 			ret = EXIT_FAILURE;
503*f5f0964cSRobert Mustacchi 	}
504*f5f0964cSRobert Mustacchi 
505*f5f0964cSRobert Mustacchi 	nvme_ctrl_info_free(info);
506*f5f0964cSRobert Mustacchi 	nvme_ctrl_unlock(ctrl);
507*f5f0964cSRobert Mustacchi 	nvme_ctrl_fini(ctrl);
508*f5f0964cSRobert Mustacchi 	nvme_fini(nvme);
509*f5f0964cSRobert Mustacchi 
510*f5f0964cSRobert Mustacchi 	if (ret == EXIT_SUCCESS) {
511*f5f0964cSRobert Mustacchi 		(void) printf("All tests passed successfully\n");
512*f5f0964cSRobert Mustacchi 	}
513*f5f0964cSRobert Mustacchi 
514*f5f0964cSRobert Mustacchi 	return (ret);
515*f5f0964cSRobert Mustacchi }
516