1*533affcbSRobert Mustacchi /*
2*533affcbSRobert Mustacchi  * This file and its contents are supplied under the terms of the
3*533affcbSRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4*533affcbSRobert Mustacchi  * You may only use this file in accordance with the terms of version
5*533affcbSRobert Mustacchi  * 1.0 of the CDDL.
6*533affcbSRobert Mustacchi  *
7*533affcbSRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8*533affcbSRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9*533affcbSRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10*533affcbSRobert Mustacchi  */
11*533affcbSRobert Mustacchi 
12*533affcbSRobert Mustacchi /*
13*533affcbSRobert Mustacchi  * Copyright 2024 Oxide Computer Company
14*533affcbSRobert Mustacchi  */
15*533affcbSRobert Mustacchi 
16*533affcbSRobert Mustacchi /*
17*533affcbSRobert Mustacchi  * Take a controller snapshot. Roundtrip it through a save and restore and make
18*533affcbSRobert Mustacchi  * sure that all the data is the same across the two.
19*533affcbSRobert Mustacchi  */
20*533affcbSRobert Mustacchi 
21*533affcbSRobert Mustacchi #include <err.h>
22*533affcbSRobert Mustacchi #include <string.h>
23*533affcbSRobert Mustacchi 
24*533affcbSRobert Mustacchi #include "libnvme_test_common.h"
25*533affcbSRobert Mustacchi 
26*533affcbSRobert Mustacchi static bool
info_roundtrip_pci(nvme_ctrl_info_t * info,nvme_ctrl_info_t * rest_info)27*533affcbSRobert Mustacchi info_roundtrip_pci(nvme_ctrl_info_t *info, nvme_ctrl_info_t *rest_info)
28*533affcbSRobert Mustacchi {
29*533affcbSRobert Mustacchi 	bool ret = true;
30*533affcbSRobert Mustacchi 	uint32_t id32, rest_id32;
31*533affcbSRobert Mustacchi 	uint16_t id16, rest_id16;
32*533affcbSRobert Mustacchi 	uint8_t id8, rest_id8;
33*533affcbSRobert Mustacchi 
34*533affcbSRobert Mustacchi 	if (!nvme_ctrl_info_pci_vid(info, &id16)) {
35*533affcbSRobert Mustacchi 		libnvme_test_ctrl_info_warn(info, "failed to get PCI vendor "
36*533affcbSRobert Mustacchi 		    "from original snapshot");
37*533affcbSRobert Mustacchi 		ret = false;
38*533affcbSRobert Mustacchi 	} else if (!nvme_ctrl_info_pci_vid(rest_info, &rest_id16)) {
39*533affcbSRobert Mustacchi 		libnvme_test_ctrl_info_warn(info, "failed to get PCI vendor "
40*533affcbSRobert Mustacchi 		    "from restored snapshot");
41*533affcbSRobert Mustacchi 		ret = false;
42*533affcbSRobert Mustacchi 	} else if (id16 != rest_id16) {
43*533affcbSRobert Mustacchi 		warnx("TEST FAILED: PCI vendor mismatch: was %u now %u",
44*533affcbSRobert Mustacchi 		    id16, rest_id16);
45*533affcbSRobert Mustacchi 		ret = false;
46*533affcbSRobert Mustacchi 	} else {
47*533affcbSRobert Mustacchi 		(void) printf("TEST PASSED: PCI vendor successfully "
48*533affcbSRobert Mustacchi 		    "restored\n");
49*533affcbSRobert Mustacchi 	}
50*533affcbSRobert Mustacchi 
51*533affcbSRobert Mustacchi 	if (!nvme_ctrl_info_pci_did(info, &id16)) {
52*533affcbSRobert Mustacchi 		libnvme_test_ctrl_info_warn(info, "failed to get PCI device "
53*533affcbSRobert Mustacchi 		    "from original snapshot");
54*533affcbSRobert Mustacchi 		ret = false;
55*533affcbSRobert Mustacchi 	} else if (!nvme_ctrl_info_pci_did(rest_info, &rest_id16)) {
56*533affcbSRobert Mustacchi 		libnvme_test_ctrl_info_warn(info, "failed to get PCI device "
57*533affcbSRobert Mustacchi 		    "from restored snapshot");
58*533affcbSRobert Mustacchi 		ret = false;
59*533affcbSRobert Mustacchi 	} else if (id16 != rest_id16) {
60*533affcbSRobert Mustacchi 		warnx("TEST FAILED: PCI device mismatch: was %u now %u",
61*533affcbSRobert Mustacchi 		    id16, rest_id16);
62*533affcbSRobert Mustacchi 		ret = false;
63*533affcbSRobert Mustacchi 	} else {
64*533affcbSRobert Mustacchi 		(void) printf("TEST PASSED: PCI device successfully "
65*533affcbSRobert Mustacchi 		    "restored\n");
66*533affcbSRobert Mustacchi 	}
67*533affcbSRobert Mustacchi 
68*533affcbSRobert Mustacchi 	if (!nvme_ctrl_info_pci_subvid(info, &id16)) {
69*533affcbSRobert Mustacchi 		libnvme_test_ctrl_info_warn(info, "failed to get PCI subsystem "
70*533affcbSRobert Mustacchi 		    "vendor from original snapshot");
71*533affcbSRobert Mustacchi 		ret = false;
72*533affcbSRobert Mustacchi 	} else if (!nvme_ctrl_info_pci_subvid(rest_info, &rest_id16)) {
73*533affcbSRobert Mustacchi 		libnvme_test_ctrl_info_warn(info, "failed to get PCI subsystem "
74*533affcbSRobert Mustacchi 		    "vendor from restored snapshot");
75*533affcbSRobert Mustacchi 		ret = false;
76*533affcbSRobert Mustacchi 	} else if (id16 != rest_id16) {
77*533affcbSRobert Mustacchi 		warnx("TEST FAILED: PCI subsystem vendor mismatch: was %u "
78*533affcbSRobert Mustacchi 		    "now %u", id16, rest_id16);
79*533affcbSRobert Mustacchi 		ret = false;
80*533affcbSRobert Mustacchi 	} else {
81*533affcbSRobert Mustacchi 		(void) printf("TEST PASSED: PCI subsystem vendor successfully "
82*533affcbSRobert Mustacchi 		    "restored\n");
83*533affcbSRobert Mustacchi 	}
84*533affcbSRobert Mustacchi 
85*533affcbSRobert Mustacchi 	if (!nvme_ctrl_info_pci_subsys(info, &id16)) {
86*533affcbSRobert Mustacchi 		libnvme_test_ctrl_info_warn(info, "failed to get PCI subsystem "
87*533affcbSRobert Mustacchi 		    "id from original snapshot");
88*533affcbSRobert Mustacchi 		ret = false;
89*533affcbSRobert Mustacchi 	} else if (!nvme_ctrl_info_pci_subsys(rest_info, &rest_id16)) {
90*533affcbSRobert Mustacchi 		libnvme_test_ctrl_info_warn(info, "failed to get PCI subsystem "
91*533affcbSRobert Mustacchi 		    "id from restored snapshot");
92*533affcbSRobert Mustacchi 		ret = false;
93*533affcbSRobert Mustacchi 	} else if (id16 != rest_id16) {
94*533affcbSRobert Mustacchi 		warnx("TEST FAILED: PCI subsystem id mismatch: was %u "
95*533affcbSRobert Mustacchi 		    "now %u", id16, rest_id16);
96*533affcbSRobert Mustacchi 		ret = false;
97*533affcbSRobert Mustacchi 	} else {
98*533affcbSRobert Mustacchi 		(void) printf("TEST PASSED: PCI subsystem id successfully "
99*533affcbSRobert Mustacchi 		    "restored\n");
100*533affcbSRobert Mustacchi 	}
101*533affcbSRobert Mustacchi 
102*533affcbSRobert Mustacchi 	if (!nvme_ctrl_info_pci_rev(info, &id8)) {
103*533affcbSRobert Mustacchi 		libnvme_test_ctrl_info_warn(info, "failed to get PCI revision "
104*533affcbSRobert Mustacchi 		    "from original snapshot");
105*533affcbSRobert Mustacchi 		ret = false;
106*533affcbSRobert Mustacchi 	} else if (!nvme_ctrl_info_pci_rev(rest_info, &rest_id8)) {
107*533affcbSRobert Mustacchi 		libnvme_test_ctrl_info_warn(info, "failed to get PCI revision "
108*533affcbSRobert Mustacchi 		    "from restored snapshot");
109*533affcbSRobert Mustacchi 		ret = false;
110*533affcbSRobert Mustacchi 	} else if (id8 != rest_id8) {
111*533affcbSRobert Mustacchi 		warnx("TEST FAILED: PCI revision mismatch: was %u now %u",
112*533affcbSRobert Mustacchi 		    id8, rest_id8);
113*533affcbSRobert Mustacchi 		ret = false;
114*533affcbSRobert Mustacchi 	} else {
115*533affcbSRobert Mustacchi 		(void) printf("TEST PASSED: PCI revision successfully "
116*533affcbSRobert Mustacchi 		    "restored\n");
117*533affcbSRobert Mustacchi 	}
118*533affcbSRobert Mustacchi 
119*533affcbSRobert Mustacchi 	if (!nvme_ctrl_info_pci_mps_min(info, &id32)) {
120*533affcbSRobert Mustacchi 		libnvme_test_ctrl_info_warn(info, "failed to get PCI MPS min "
121*533affcbSRobert Mustacchi 		    "from original snapshot");
122*533affcbSRobert Mustacchi 		ret = false;
123*533affcbSRobert Mustacchi 	} else if (!nvme_ctrl_info_pci_mps_min(rest_info, &rest_id32)) {
124*533affcbSRobert Mustacchi 		libnvme_test_ctrl_info_warn(info, "failed to get PCI MPS min "
125*533affcbSRobert Mustacchi 		    "from restored snapshot");
126*533affcbSRobert Mustacchi 		ret = false;
127*533affcbSRobert Mustacchi 	} else if (id32 != rest_id32) {
128*533affcbSRobert Mustacchi 		warnx("TEST FAILED: PCI MPS min mismatch: was %u now %u",
129*533affcbSRobert Mustacchi 		    id32, rest_id32);
130*533affcbSRobert Mustacchi 		ret = false;
131*533affcbSRobert Mustacchi 	} else {
132*533affcbSRobert Mustacchi 		(void) printf("TEST PASSED: PCI MPS min successfully "
133*533affcbSRobert Mustacchi 		    "restored\n");
134*533affcbSRobert Mustacchi 	}
135*533affcbSRobert Mustacchi 
136*533affcbSRobert Mustacchi 	if (!nvme_ctrl_info_pci_mps_max(info, &id32)) {
137*533affcbSRobert Mustacchi 		libnvme_test_ctrl_info_warn(info, "failed to get PCI MPS max "
138*533affcbSRobert Mustacchi 		    "from original snapshot");
139*533affcbSRobert Mustacchi 		ret = false;
140*533affcbSRobert Mustacchi 	} else if (!nvme_ctrl_info_pci_mps_max(rest_info, &rest_id32)) {
141*533affcbSRobert Mustacchi 		libnvme_test_ctrl_info_warn(info, "failed to get PCI MPS max "
142*533affcbSRobert Mustacchi 		    "from restored snapshot");
143*533affcbSRobert Mustacchi 		ret = false;
144*533affcbSRobert Mustacchi 	} else if (id32 != rest_id32) {
145*533affcbSRobert Mustacchi 		warnx("TEST FAILED: PCI MPS max mismatch: was %u now %u",
146*533affcbSRobert Mustacchi 		    id32, rest_id32);
147*533affcbSRobert Mustacchi 		ret = false;
148*533affcbSRobert Mustacchi 	} else {
149*533affcbSRobert Mustacchi 		(void) printf("TEST PASSED: PCI MPS max successfully "
150*533affcbSRobert Mustacchi 		    "restored\n");
151*533affcbSRobert Mustacchi 	}
152*533affcbSRobert Mustacchi 
153*533affcbSRobert Mustacchi 	if (!nvme_ctrl_info_pci_nintrs(info, &id32)) {
154*533affcbSRobert Mustacchi 		libnvme_test_ctrl_info_warn(info, "failed to get PCI intr "
155*533affcbSRobert Mustacchi 		    "count from original snapshot");
156*533affcbSRobert Mustacchi 		ret = false;
157*533affcbSRobert Mustacchi 	} else if (!nvme_ctrl_info_pci_nintrs(rest_info, &rest_id32)) {
158*533affcbSRobert Mustacchi 		libnvme_test_ctrl_info_warn(info, "failed to get PCI intr "
159*533affcbSRobert Mustacchi 		    "count from restored snapshot");
160*533affcbSRobert Mustacchi 		ret = false;
161*533affcbSRobert Mustacchi 	} else if (id32 != rest_id32) {
162*533affcbSRobert Mustacchi 		warnx("TEST FAILED: PCI intr count mismatch: was %u now %u",
163*533affcbSRobert Mustacchi 		    id32, rest_id32);
164*533affcbSRobert Mustacchi 		ret = false;
165*533affcbSRobert Mustacchi 	} else {
166*533affcbSRobert Mustacchi 		(void) printf("TEST PASSED: PCI intr count successfully "
167*533affcbSRobert Mustacchi 		    "restored\n");
168*533affcbSRobert Mustacchi 	}
169*533affcbSRobert Mustacchi 
170*533affcbSRobert Mustacchi 	return (ret);
171*533affcbSRobert Mustacchi }
172*533affcbSRobert Mustacchi 
173*533affcbSRobert Mustacchi static bool
info_roundtrip_ns(nvme_ctrl_info_t * info,nvme_ctrl_info_t * rest_info)174*533affcbSRobert Mustacchi info_roundtrip_ns(nvme_ctrl_info_t *info, nvme_ctrl_info_t *rest_info)
175*533affcbSRobert Mustacchi {
176*533affcbSRobert Mustacchi 	bool ret = true;
177*533affcbSRobert Mustacchi 	nvme_uint128_t u128, rest_u128;
178*533affcbSRobert Mustacchi 	const nvme_identify_nsid_t *idns, *rest_idns;
179*533affcbSRobert Mustacchi 
180*533affcbSRobert Mustacchi 	if (!nvme_ctrl_info_cap(info, &u128)) {
181*533affcbSRobert Mustacchi 		libnvme_test_ctrl_info_warn(info, "failed to get NVM capacity "
182*533affcbSRobert Mustacchi 		    "from original snapshot");
183*533affcbSRobert Mustacchi 		ret = false;
184*533affcbSRobert Mustacchi 	} else if (!nvme_ctrl_info_cap(rest_info, &rest_u128)) {
185*533affcbSRobert Mustacchi 		libnvme_test_ctrl_info_warn(info, "failed to get NVM capacity "
186*533affcbSRobert Mustacchi 		    "from restored snapshot");
187*533affcbSRobert Mustacchi 		ret = false;
188*533affcbSRobert Mustacchi 	} else if (memcmp(&u128, &rest_u128, sizeof (nvme_uint128_t)) != 0) {
189*533affcbSRobert Mustacchi 		warnx("TEST FAILED: NVM capacity mismatch");
190*533affcbSRobert Mustacchi 		ret = false;
191*533affcbSRobert Mustacchi 	} else {
192*533affcbSRobert Mustacchi 		(void) printf("TEST PASSED: NVM capacity successfully "
193*533affcbSRobert Mustacchi 		    "restored\n");
194*533affcbSRobert Mustacchi 	}
195*533affcbSRobert Mustacchi 
196*533affcbSRobert Mustacchi 	if (!nvme_ctrl_info_unalloc_cap(info, &u128)) {
197*533affcbSRobert Mustacchi 		libnvme_test_ctrl_info_warn(info, "failed to get NVM "
198*533affcbSRobert Mustacchi 		    "unallocated capacity from original snapshot");
199*533affcbSRobert Mustacchi 		ret = false;
200*533affcbSRobert Mustacchi 	} else if (!nvme_ctrl_info_unalloc_cap(rest_info, &rest_u128)) {
201*533affcbSRobert Mustacchi 		libnvme_test_ctrl_info_warn(info, "failed to get NVM "
202*533affcbSRobert Mustacchi 		    "unallocated capacity from restored snapshot");
203*533affcbSRobert Mustacchi 		ret = false;
204*533affcbSRobert Mustacchi 	} else if (memcmp(&u128, &rest_u128, sizeof (nvme_uint128_t)) != 0) {
205*533affcbSRobert Mustacchi 		warnx("TEST FAILED: NVM unallocated capacity mismatch");
206*533affcbSRobert Mustacchi 		ret = false;
207*533affcbSRobert Mustacchi 	} else {
208*533affcbSRobert Mustacchi 		(void) printf("TEST PASSED: NVM unallocated capacity "
209*533affcbSRobert Mustacchi 		    "successfully restored\n");
210*533affcbSRobert Mustacchi 	}
211*533affcbSRobert Mustacchi 
212*533affcbSRobert Mustacchi 	if (!nvme_ctrl_info_common_ns(info, &idns)) {
213*533affcbSRobert Mustacchi 		libnvme_test_ctrl_info_warn(info, "failed to get common ns "
214*533affcbSRobert Mustacchi 		    "from original snapshot");
215*533affcbSRobert Mustacchi 		ret = false;
216*533affcbSRobert Mustacchi 	} else if (!nvme_ctrl_info_common_ns(rest_info, &rest_idns)) {
217*533affcbSRobert Mustacchi 		libnvme_test_ctrl_info_warn(info, "failed to get common ns "
218*533affcbSRobert Mustacchi 		    "from restored snapshot");
219*533affcbSRobert Mustacchi 		ret = false;
220*533affcbSRobert Mustacchi 	} else if (memcmp(idns, rest_idns,
221*533affcbSRobert Mustacchi 	    sizeof (nvme_identify_nsid_t)) != 0) {
222*533affcbSRobert Mustacchi 		warnx("TEST FAILED: Common Identify Namespace mismatch");
223*533affcbSRobert Mustacchi 		ret = false;
224*533affcbSRobert Mustacchi 	} else {
225*533affcbSRobert Mustacchi 		(void) printf("TEST PASSED: common identify namespace "
226*533affcbSRobert Mustacchi 		    "successfully restored\n");
227*533affcbSRobert Mustacchi 	}
228*533affcbSRobert Mustacchi 
229*533affcbSRobert Mustacchi 	return (ret);
230*533affcbSRobert Mustacchi }
231*533affcbSRobert Mustacchi 
232*533affcbSRobert Mustacchi static bool
info_roundtrip_lba(nvme_ctrl_info_t * info,nvme_ctrl_info_t * rest_info)233*533affcbSRobert Mustacchi info_roundtrip_lba(nvme_ctrl_info_t *info, nvme_ctrl_info_t *rest_info)
234*533affcbSRobert Mustacchi {
235*533affcbSRobert Mustacchi 	bool ret = true;
236*533affcbSRobert Mustacchi 	const uint32_t nlbas = nvme_ctrl_info_nformats(info);
237*533affcbSRobert Mustacchi 
238*533affcbSRobert Mustacchi 	for (uint32_t i = 0; i < nlbas; i++) {
239*533affcbSRobert Mustacchi 		const nvme_nvm_lba_fmt_t *fmt, *rest_fmt;
240*533affcbSRobert Mustacchi 
241*533affcbSRobert Mustacchi 		if (!nvme_ctrl_info_format(info, i, &fmt)) {
242*533affcbSRobert Mustacchi 			/*
243*533affcbSRobert Mustacchi 			 * Some devices like the Kioxia KCD6XLUL3T84 have holes
244*533affcbSRobert Mustacchi 			 * in their LBA space. Skip such instances.
245*533affcbSRobert Mustacchi 			 */
246*533affcbSRobert Mustacchi 			if (nvme_ctrl_info_err(info) == NVME_INFO_ERR_BAD_FMT) {
247*533affcbSRobert Mustacchi 				continue;
248*533affcbSRobert Mustacchi 			}
249*533affcbSRobert Mustacchi 
250*533affcbSRobert Mustacchi 			libnvme_test_ctrl_info_warn(info, "failed to get "
251*533affcbSRobert Mustacchi 			    "LBA format %u from original snapshot", i);
252*533affcbSRobert Mustacchi 			ret = false;
253*533affcbSRobert Mustacchi 			continue;
254*533affcbSRobert Mustacchi 		}
255*533affcbSRobert Mustacchi 
256*533affcbSRobert Mustacchi 		if (!nvme_ctrl_info_format(rest_info, i, &rest_fmt)) {
257*533affcbSRobert Mustacchi 			libnvme_test_ctrl_info_warn(info, "failed to get "
258*533affcbSRobert Mustacchi 			    "LBA format %u from restored snapshot", i);
259*533affcbSRobert Mustacchi 			ret = false;
260*533affcbSRobert Mustacchi 			continue;
261*533affcbSRobert Mustacchi 		}
262*533affcbSRobert Mustacchi 
263*533affcbSRobert Mustacchi 		(void) printf("TEST PASSED: successfully got LBA format %u\n",
264*533affcbSRobert Mustacchi 		    i);
265*533affcbSRobert Mustacchi 		if (nvme_nvm_lba_fmt_id(fmt) != i) {
266*533affcbSRobert Mustacchi 			warnx("TEST FAILED: format %u from original snapshot "
267*533affcbSRobert Mustacchi 			    "has wrong format id: %u\n", i,
268*533affcbSRobert Mustacchi 			    nvme_nvm_lba_fmt_id(fmt));
269*533affcbSRobert Mustacchi 			ret = false;
270*533affcbSRobert Mustacchi 		}
271*533affcbSRobert Mustacchi 
272*533affcbSRobert Mustacchi 		if (nvme_nvm_lba_fmt_id(rest_fmt) != i) {
273*533affcbSRobert Mustacchi 			warnx("TEST FAILED: format %u from restored snapshot "
274*533affcbSRobert Mustacchi 			    "has wrong format id: %u\n", i,
275*533affcbSRobert Mustacchi 			    nvme_nvm_lba_fmt_id(rest_fmt));
276*533affcbSRobert Mustacchi 			ret = false;
277*533affcbSRobert Mustacchi 		}
278*533affcbSRobert Mustacchi 
279*533affcbSRobert Mustacchi 		if (nvme_nvm_lba_fmt_meta_size(fmt) !=
280*533affcbSRobert Mustacchi 		    nvme_nvm_lba_fmt_meta_size(rest_fmt)) {
281*533affcbSRobert Mustacchi 			warnx("TEST FAILED: LBA %u metadata size mismatch: "
282*533affcbSRobert Mustacchi 			    "was %u, now %u", i,
283*533affcbSRobert Mustacchi 			    nvme_nvm_lba_fmt_meta_size(fmt),
284*533affcbSRobert Mustacchi 			    nvme_nvm_lba_fmt_meta_size(rest_fmt));
285*533affcbSRobert Mustacchi 			ret = false;
286*533affcbSRobert Mustacchi 		} else {
287*533affcbSRobert Mustacchi 			(void) printf("TEST PASSED: LBA %u metadata "
288*533affcbSRobert Mustacchi 			    "successfully restored\n", i);
289*533affcbSRobert Mustacchi 		}
290*533affcbSRobert Mustacchi 
291*533affcbSRobert Mustacchi 		if (nvme_nvm_lba_fmt_data_size(fmt) !=
292*533affcbSRobert Mustacchi 		    nvme_nvm_lba_fmt_data_size(rest_fmt)) {
293*533affcbSRobert Mustacchi 			warnx("TEST FAILED: LBA %u data size mismatch: "
294*533affcbSRobert Mustacchi 			    "was %" PRIu64 ", now %" PRIu64, i,
295*533affcbSRobert Mustacchi 			    nvme_nvm_lba_fmt_data_size(fmt),
296*533affcbSRobert Mustacchi 			    nvme_nvm_lba_fmt_data_size(rest_fmt));
297*533affcbSRobert Mustacchi 			ret = false;
298*533affcbSRobert Mustacchi 		} else {
299*533affcbSRobert Mustacchi 			(void) printf("TEST PASSED: LBA %u data size "
300*533affcbSRobert Mustacchi 			    "successfully restored\n", i);
301*533affcbSRobert Mustacchi 		}
302*533affcbSRobert Mustacchi 
303*533affcbSRobert Mustacchi 		if (nvme_nvm_lba_fmt_rel_perf(fmt) !=
304*533affcbSRobert Mustacchi 		    nvme_nvm_lba_fmt_rel_perf(rest_fmt)) {
305*533affcbSRobert Mustacchi 			warnx("TEST FAILED: LBA %u relative perf mismatch: "
306*533affcbSRobert Mustacchi 			    "was %u, now %u", i,
307*533affcbSRobert Mustacchi 			    nvme_nvm_lba_fmt_rel_perf(fmt),
308*533affcbSRobert Mustacchi 			    nvme_nvm_lba_fmt_rel_perf(rest_fmt));
309*533affcbSRobert Mustacchi 			ret = false;
310*533affcbSRobert Mustacchi 		} else {
311*533affcbSRobert Mustacchi 			(void) printf("TEST PASSED: LBA %u relative perf "
312*533affcbSRobert Mustacchi 			    "successfully restored\n", i);
313*533affcbSRobert Mustacchi 		}
314*533affcbSRobert Mustacchi 	}
315*533affcbSRobert Mustacchi 
316*533affcbSRobert Mustacchi 	return (ret);
317*533affcbSRobert Mustacchi }
318*533affcbSRobert Mustacchi 
319*533affcbSRobert Mustacchi int
main(void)320*533affcbSRobert Mustacchi main(void)
321*533affcbSRobert Mustacchi {
322*533affcbSRobert Mustacchi 	int ret = EXIT_SUCCESS;
323*533affcbSRobert Mustacchi 	nvme_t *nvme;
324*533affcbSRobert Mustacchi 	nvme_ctrl_t *ctrl;
325*533affcbSRobert Mustacchi 	nvme_ctrl_info_t *info, *rest_info;
326*533affcbSRobert Mustacchi 	nvlist_t *nvl;
327*533affcbSRobert Mustacchi 	const nvme_identify_ctrl_t *ctrlid, *rest_ctrlid;
328*533affcbSRobert Mustacchi 	const nvme_version_t *vers, *rest_vers;
329*533affcbSRobert Mustacchi 
330*533affcbSRobert Mustacchi 	libnvme_test_init(&nvme, &ctrl);
331*533affcbSRobert Mustacchi 	if (!nvme_ctrl_info_snap(ctrl, &info)) {
332*533affcbSRobert Mustacchi 		libnvme_test_ctrl_fatal(ctrl, "failed to take a snapshot");
333*533affcbSRobert Mustacchi 	}
334*533affcbSRobert Mustacchi 
335*533affcbSRobert Mustacchi 	if (!nvme_ctrl_info_persist(info, &nvl)) {
336*533affcbSRobert Mustacchi 		libnvme_test_ctrl_info_fatal(info, "failed to persist the "
337*533affcbSRobert Mustacchi 		    "controller snapshot");
338*533affcbSRobert Mustacchi 	}
339*533affcbSRobert Mustacchi 
340*533affcbSRobert Mustacchi 	if (!nvme_ctrl_info_restore(nvme, nvl, &rest_info)) {
341*533affcbSRobert Mustacchi 		libnvme_test_hdl_fatal(nvme, "failed to restore controller "
342*533affcbSRobert Mustacchi 		    "snapshot");
343*533affcbSRobert Mustacchi 	}
344*533affcbSRobert Mustacchi 
345*533affcbSRobert Mustacchi 	if (nvme_ctrl_info_vendor(info) != nvme_ctrl_info_vendor(rest_info)) {
346*533affcbSRobert Mustacchi 		warnx("TEST FAILED: vendor mismatch: orig 0x%x, restored: 0x%x",
347*533affcbSRobert Mustacchi 		    nvme_ctrl_info_vendor(info),
348*533affcbSRobert Mustacchi 		    nvme_ctrl_info_vendor(rest_info));
349*533affcbSRobert Mustacchi 		ret = EXIT_FAILURE;
350*533affcbSRobert Mustacchi 	} else {
351*533affcbSRobert Mustacchi 		(void) printf("TEST PASSED: successfully matched vendor id\n");
352*533affcbSRobert Mustacchi 	}
353*533affcbSRobert Mustacchi 
354*533affcbSRobert Mustacchi 	ctrlid = nvme_ctrl_info_identify(info);
355*533affcbSRobert Mustacchi 	rest_ctrlid = nvme_ctrl_info_identify(rest_info);
356*533affcbSRobert Mustacchi 	if (memcmp(ctrlid, rest_ctrlid, sizeof (nvme_identify_ctrl_t)) != 0) {
357*533affcbSRobert Mustacchi 		warnx("TEST FAILED: Identify info mismatched after restore");
358*533affcbSRobert Mustacchi 		ret = EXIT_FAILURE;
359*533affcbSRobert Mustacchi 	} else {
360*533affcbSRobert Mustacchi 		(void) printf("TEST PASSED: identify controller successfully "
361*533affcbSRobert Mustacchi 		    "restored\n");
362*533affcbSRobert Mustacchi 	}
363*533affcbSRobert Mustacchi 
364*533affcbSRobert Mustacchi 	vers = nvme_ctrl_info_version(info);
365*533affcbSRobert Mustacchi 	rest_vers = nvme_ctrl_info_version(rest_info);
366*533affcbSRobert Mustacchi 	if (vers->v_major != rest_vers->v_major) {
367*533affcbSRobert Mustacchi 		warnx("TEST FAILED: mismatched major version: was %u, found %u",
368*533affcbSRobert Mustacchi 		    vers->v_major, rest_vers->v_major);
369*533affcbSRobert Mustacchi 		ret = EXIT_FAILURE;
370*533affcbSRobert Mustacchi 	} else {
371*533affcbSRobert Mustacchi 		(void) printf("TEST PASSED: major version successfully "
372*533affcbSRobert Mustacchi 		    "restored\n");
373*533affcbSRobert Mustacchi 	}
374*533affcbSRobert Mustacchi 
375*533affcbSRobert Mustacchi 	if (vers->v_minor != rest_vers->v_minor) {
376*533affcbSRobert Mustacchi 		warnx("TEST FAILED: mismatched minor version: was %u, found %u",
377*533affcbSRobert Mustacchi 		    vers->v_minor, rest_vers->v_minor);
378*533affcbSRobert Mustacchi 		ret = EXIT_FAILURE;
379*533affcbSRobert Mustacchi 	} else {
380*533affcbSRobert Mustacchi 		(void) printf("TEST PASSED: minor version successfully "
381*533affcbSRobert Mustacchi 		    "restored\n");
382*533affcbSRobert Mustacchi 	}
383*533affcbSRobert Mustacchi 
384*533affcbSRobert Mustacchi 	if (strcmp(nvme_ctrl_info_model(info),
385*533affcbSRobert Mustacchi 	    nvme_ctrl_info_model(rest_info)) != 0) {
386*533affcbSRobert Mustacchi 		warnx("TEST FAILED: model string mismatch");
387*533affcbSRobert Mustacchi 		ret = EXIT_FAILURE;
388*533affcbSRobert Mustacchi 	} else {
389*533affcbSRobert Mustacchi 		(void) printf("TEST PASSED: model successfully restored\n");
390*533affcbSRobert Mustacchi 	}
391*533affcbSRobert Mustacchi 
392*533affcbSRobert Mustacchi 	if (strcmp(nvme_ctrl_info_serial(info),
393*533affcbSRobert Mustacchi 	    nvme_ctrl_info_serial(rest_info)) != 0) {
394*533affcbSRobert Mustacchi 		warnx("TEST FAILED: serial string mismatch");
395*533affcbSRobert Mustacchi 		ret = EXIT_FAILURE;
396*533affcbSRobert Mustacchi 	} else {
397*533affcbSRobert Mustacchi 		(void) printf("TEST PASSED: serial successfully restored\n");
398*533affcbSRobert Mustacchi 	}
399*533affcbSRobert Mustacchi 
400*533affcbSRobert Mustacchi 	if (strcmp(nvme_ctrl_info_fwrev(info),
401*533affcbSRobert Mustacchi 	    nvme_ctrl_info_fwrev(rest_info)) != 0) {
402*533affcbSRobert Mustacchi 		warnx("TEST FAILED: fwrev string mismatch");
403*533affcbSRobert Mustacchi 		ret = EXIT_FAILURE;
404*533affcbSRobert Mustacchi 	} else {
405*533affcbSRobert Mustacchi 		(void) printf("TEST PASSED: fwrev successfully restored\n");
406*533affcbSRobert Mustacchi 	}
407*533affcbSRobert Mustacchi 
408*533affcbSRobert Mustacchi 	if (nvme_ctrl_info_nns(info) != nvme_ctrl_info_nns(rest_info)) {
409*533affcbSRobert Mustacchi 		warnx("TEST FAILED: number of namespaces mismatch: was %u, "
410*533affcbSRobert Mustacchi 		    "now %u", nvme_ctrl_info_nns(info),
411*533affcbSRobert Mustacchi 		    nvme_ctrl_info_nns(rest_info));
412*533affcbSRobert Mustacchi 		ret = EXIT_FAILURE;
413*533affcbSRobert Mustacchi 	} else {
414*533affcbSRobert Mustacchi 		(void) printf("TEST PASSED: number of namespaces successfully "
415*533affcbSRobert Mustacchi 		    "restored\n");
416*533affcbSRobert Mustacchi 	}
417*533affcbSRobert Mustacchi 
418*533affcbSRobert Mustacchi 	if (nvme_ctrl_info_type(info) != nvme_ctrl_info_type(rest_info)) {
419*533affcbSRobert Mustacchi 		warnx("TEST FAILED: controller type mismatch: was %u, "
420*533affcbSRobert Mustacchi 		    "now %u", nvme_ctrl_info_type(info),
421*533affcbSRobert Mustacchi 		    nvme_ctrl_info_type(rest_info));
422*533affcbSRobert Mustacchi 		ret = EXIT_FAILURE;
423*533affcbSRobert Mustacchi 	} else {
424*533affcbSRobert Mustacchi 		(void) printf("TEST PASSED: controller type successfully "
425*533affcbSRobert Mustacchi 		    "restored\n");
426*533affcbSRobert Mustacchi 	}
427*533affcbSRobert Mustacchi 
428*533affcbSRobert Mustacchi 	if (nvme_ctrl_info_transport(info) !=
429*533affcbSRobert Mustacchi 	    nvme_ctrl_info_transport(rest_info)) {
430*533affcbSRobert Mustacchi 		warnx("TEST FAILED: controller transport mismatch: was %u, "
431*533affcbSRobert Mustacchi 		    "now %u", nvme_ctrl_info_transport(info),
432*533affcbSRobert Mustacchi 		    nvme_ctrl_info_transport(rest_info));
433*533affcbSRobert Mustacchi 		ret = EXIT_FAILURE;
434*533affcbSRobert Mustacchi 	} else {
435*533affcbSRobert Mustacchi 		(void) printf("TEST PASSED: controller transport successfully "
436*533affcbSRobert Mustacchi 		    "restored\n");
437*533affcbSRobert Mustacchi 	}
438*533affcbSRobert Mustacchi 
439*533affcbSRobert Mustacchi 	if (nvme_ctrl_info_transport(info) == NVME_CTRL_TRANSPORT_PCI &&
440*533affcbSRobert Mustacchi 	    !info_roundtrip_pci(info, rest_info)) {
441*533affcbSRobert Mustacchi 		ret = EXIT_FAILURE;
442*533affcbSRobert Mustacchi 	}
443*533affcbSRobert Mustacchi 
444*533affcbSRobert Mustacchi 	if (ctrlid->id_oacs.oa_nsmgmt != 0 && !info_roundtrip_ns(info,
445*533affcbSRobert Mustacchi 	    rest_info)) {
446*533affcbSRobert Mustacchi 		ret = EXIT_FAILURE;
447*533affcbSRobert Mustacchi 	}
448*533affcbSRobert Mustacchi 
449*533affcbSRobert Mustacchi 	if (nvme_ctrl_info_nformats(info) !=
450*533affcbSRobert Mustacchi 	    nvme_ctrl_info_nformats(rest_info)) {
451*533affcbSRobert Mustacchi 		warnx("TEST FAILED: number of LBA formats mismatch: was %u, "
452*533affcbSRobert Mustacchi 		    "now %u", nvme_ctrl_info_nformats(info),
453*533affcbSRobert Mustacchi 		    nvme_ctrl_info_nformats(rest_info));
454*533affcbSRobert Mustacchi 		ret = EXIT_FAILURE;
455*533affcbSRobert Mustacchi 	} else {
456*533affcbSRobert Mustacchi 		(void) printf("TEST PASSED: number of LBA formats successfully "
457*533affcbSRobert Mustacchi 		    "restored\n");
458*533affcbSRobert Mustacchi 	}
459*533affcbSRobert Mustacchi 
460*533affcbSRobert Mustacchi 	if (nvme_ctrl_info_nformats(info) > 0 && !info_roundtrip_lba(info,
461*533affcbSRobert Mustacchi 	    rest_info)) {
462*533affcbSRobert Mustacchi 		ret = EXIT_FAILURE;
463*533affcbSRobert Mustacchi 	}
464*533affcbSRobert Mustacchi 
465*533affcbSRobert Mustacchi 	nvme_ctrl_info_free(rest_info);
466*533affcbSRobert Mustacchi 	nvme_ctrl_info_free(info);
467*533affcbSRobert Mustacchi 	nvme_ctrl_fini(ctrl);
468*533affcbSRobert Mustacchi 	nvme_fini(nvme);
469*533affcbSRobert Mustacchi 
470*533affcbSRobert Mustacchi 	if (ret == EXIT_SUCCESS) {
471*533affcbSRobert Mustacchi 		(void) printf("All tests exited successfully\n");
472*533affcbSRobert Mustacchi 	}
473*533affcbSRobert Mustacchi 
474*533affcbSRobert Mustacchi 	return (ret);
475*533affcbSRobert Mustacchi }
476