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 * This test goes through the lifecycle of a namespace and verifies that when we
18*f5f0964cSRobert Mustacchi * try to take transitions that it does not support, we can generate the
19*f5f0964cSRobert Mustacchi * expected errors.
20*f5f0964cSRobert Mustacchi *
21*f5f0964cSRobert Mustacchi * This test expects to start from the device-empty profile.
22*f5f0964cSRobert Mustacchi */
23*f5f0964cSRobert Mustacchi
24*f5f0964cSRobert Mustacchi #include <err.h>
25*f5f0964cSRobert Mustacchi #include <stdlib.h>
26*f5f0964cSRobert Mustacchi #include <sys/sysmacros.h>
27*f5f0964cSRobert Mustacchi
28*f5f0964cSRobert Mustacchi #include "libnvme_test_common.h"
29*f5f0964cSRobert Mustacchi
30*f5f0964cSRobert Mustacchi /*
31*f5f0964cSRobert Mustacchi * We expect that we should always be issued NSID 1.
32*f5f0964cSRobert Mustacchi */
33*f5f0964cSRobert Mustacchi #define NS_LC_NSID 1
34*f5f0964cSRobert Mustacchi
35*f5f0964cSRobert Mustacchi /*
36*f5f0964cSRobert Mustacchi * This is a list of actions we can take in a given state against a namespace.
37*f5f0964cSRobert Mustacchi * There is no namespace create in this list as there is no way to specify a
38*f5f0964cSRobert Mustacchi * namespace to take action against.
39*f5f0964cSRobert Mustacchi */
40*f5f0964cSRobert Mustacchi typedef enum {
41*f5f0964cSRobert Mustacchi NS_ACT_NS_DELETE,
42*f5f0964cSRobert Mustacchi NS_ACT_CTRL_ATTACH,
43*f5f0964cSRobert Mustacchi NS_ACT_CTRL_DETACH,
44*f5f0964cSRobert Mustacchi NS_ACT_BD_ATTACH,
45*f5f0964cSRobert Mustacchi NS_ACT_BD_DETACH
46*f5f0964cSRobert Mustacchi } ns_act_t;
47*f5f0964cSRobert Mustacchi
48*f5f0964cSRobert Mustacchi #define NS_LC_NACTS (NS_ACT_BD_DETACH + 1)
49*f5f0964cSRobert Mustacchi
50*f5f0964cSRobert Mustacchi nvme_err_t nvme_unalloc_errs[NS_LC_NACTS] = {
51*f5f0964cSRobert Mustacchi [NS_ACT_NS_DELETE] = NVME_ERR_NS_UNALLOC,
52*f5f0964cSRobert Mustacchi [NS_ACT_CTRL_ATTACH] = NVME_ERR_NS_UNALLOC,
53*f5f0964cSRobert Mustacchi [NS_ACT_CTRL_DETACH] = NVME_ERR_NS_UNALLOC,
54*f5f0964cSRobert Mustacchi [NS_ACT_BD_ATTACH] = NVME_ERR_NS_UNALLOC,
55*f5f0964cSRobert Mustacchi [NS_ACT_BD_DETACH] = NVME_ERR_NS_UNALLOC
56*f5f0964cSRobert Mustacchi };
57*f5f0964cSRobert Mustacchi
58*f5f0964cSRobert Mustacchi nvme_err_t nvme_alloc_errs[NS_LC_NACTS] = {
59*f5f0964cSRobert Mustacchi [NS_ACT_NS_DELETE] = NVME_ERR_OK,
60*f5f0964cSRobert Mustacchi [NS_ACT_CTRL_ATTACH] = NVME_ERR_OK,
61*f5f0964cSRobert Mustacchi [NS_ACT_CTRL_DETACH] = NVME_ERR_NS_CTRL_NOT_ATTACHED,
62*f5f0964cSRobert Mustacchi [NS_ACT_BD_ATTACH] = NVME_ERR_NS_CTRL_NOT_ATTACHED,
63*f5f0964cSRobert Mustacchi [NS_ACT_BD_DETACH] = NVME_ERR_NS_CTRL_NOT_ATTACHED
64*f5f0964cSRobert Mustacchi };
65*f5f0964cSRobert Mustacchi
66*f5f0964cSRobert Mustacchi nvme_err_t nvme_attach_errs[NS_LC_NACTS] = {
67*f5f0964cSRobert Mustacchi [NS_ACT_NS_DELETE] = NVME_ERR_NS_CTRL_ATTACHED,
68*f5f0964cSRobert Mustacchi [NS_ACT_CTRL_ATTACH] = NVME_ERR_NS_CTRL_ATTACHED,
69*f5f0964cSRobert Mustacchi [NS_ACT_CTRL_DETACH] = NVME_ERR_OK,
70*f5f0964cSRobert Mustacchi [NS_ACT_BD_ATTACH] = NVME_ERR_OK,
71*f5f0964cSRobert Mustacchi [NS_ACT_BD_DETACH] = NVME_ERR_NS_CTRL_ATTACHED
72*f5f0964cSRobert Mustacchi };
73*f5f0964cSRobert Mustacchi
74*f5f0964cSRobert Mustacchi nvme_err_t nvme_blkdev_errs[NS_LC_NACTS] = {
75*f5f0964cSRobert Mustacchi [NS_ACT_NS_DELETE] = NVME_ERR_NS_BLKDEV_ATTACH,
76*f5f0964cSRobert Mustacchi [NS_ACT_CTRL_ATTACH] = NVME_ERR_NS_BLKDEV_ATTACH,
77*f5f0964cSRobert Mustacchi [NS_ACT_CTRL_DETACH] = NVME_ERR_NS_BLKDEV_ATTACH,
78*f5f0964cSRobert Mustacchi [NS_ACT_BD_ATTACH] = NVME_ERR_NS_BLKDEV_ATTACH,
79*f5f0964cSRobert Mustacchi [NS_ACT_BD_DETACH] = NVME_ERR_OK
80*f5f0964cSRobert Mustacchi };
81*f5f0964cSRobert Mustacchi
82*f5f0964cSRobert Mustacchi static bool
ns_life_err_comp(nvme_ctrl_t * ctrl,nvme_err_t exp,nvme_err_t act,const char * desc,const char * state)83*f5f0964cSRobert Mustacchi ns_life_err_comp(nvme_ctrl_t *ctrl, nvme_err_t exp, nvme_err_t act,
84*f5f0964cSRobert Mustacchi const char *desc, const char *state)
85*f5f0964cSRobert Mustacchi {
86*f5f0964cSRobert Mustacchi if (act != exp) {
87*f5f0964cSRobert Mustacchi warnx("TEST FAILED: %s in state %s returned %s (0x%x), but "
88*f5f0964cSRobert Mustacchi "expected %s (0x%x)", desc, state,
89*f5f0964cSRobert Mustacchi nvme_ctrl_errtostr(ctrl, act), act,
90*f5f0964cSRobert Mustacchi nvme_ctrl_errtostr(ctrl, exp), exp);
91*f5f0964cSRobert Mustacchi } else {
92*f5f0964cSRobert Mustacchi (void) printf("TEST PASSED: %s in state %s correctly returned "
93*f5f0964cSRobert Mustacchi "%s\n", desc, state, nvme_ctrl_errtostr(ctrl, act));
94*f5f0964cSRobert Mustacchi }
95*f5f0964cSRobert Mustacchi
96*f5f0964cSRobert Mustacchi return (act == exp);
97*f5f0964cSRobert Mustacchi }
98*f5f0964cSRobert Mustacchi
99*f5f0964cSRobert Mustacchi static bool
ns_life_ns_delete(nvme_ctrl_t * ctrl,uint32_t nsid,nvme_err_t exp,const char * state)100*f5f0964cSRobert Mustacchi ns_life_ns_delete(nvme_ctrl_t *ctrl, uint32_t nsid, nvme_err_t exp,
101*f5f0964cSRobert Mustacchi const char *state)
102*f5f0964cSRobert Mustacchi {
103*f5f0964cSRobert Mustacchi nvme_err_t act;
104*f5f0964cSRobert Mustacchi
105*f5f0964cSRobert Mustacchi if (!libnvme_test_ns_delete(ctrl, nsid, &act)) {
106*f5f0964cSRobert Mustacchi return (false);
107*f5f0964cSRobert Mustacchi }
108*f5f0964cSRobert Mustacchi
109*f5f0964cSRobert Mustacchi return (ns_life_err_comp(ctrl, exp, act, "namespace delete", state));
110*f5f0964cSRobert Mustacchi }
111*f5f0964cSRobert Mustacchi
112*f5f0964cSRobert Mustacchi static bool
ns_life_ctrl_attach(nvme_ctrl_t * ctrl,uint32_t nsid,nvme_err_t exp,const char * state)113*f5f0964cSRobert Mustacchi ns_life_ctrl_attach(nvme_ctrl_t *ctrl, uint32_t nsid, nvme_err_t exp,
114*f5f0964cSRobert Mustacchi const char *state)
115*f5f0964cSRobert Mustacchi {
116*f5f0964cSRobert Mustacchi nvme_err_t act;
117*f5f0964cSRobert Mustacchi
118*f5f0964cSRobert Mustacchi if (!libnvme_test_ctrl_attach(ctrl, nsid, NVME_NS_ATTACH_CTRL_ATTACH,
119*f5f0964cSRobert Mustacchi &act)) {
120*f5f0964cSRobert Mustacchi return (false);
121*f5f0964cSRobert Mustacchi }
122*f5f0964cSRobert Mustacchi
123*f5f0964cSRobert Mustacchi return (ns_life_err_comp(ctrl, exp, act, "controller attach", state));
124*f5f0964cSRobert Mustacchi }
125*f5f0964cSRobert Mustacchi
126*f5f0964cSRobert Mustacchi static bool
ns_life_ctrl_detach(nvme_ctrl_t * ctrl,uint32_t nsid,nvme_err_t exp,const char * state)127*f5f0964cSRobert Mustacchi ns_life_ctrl_detach(nvme_ctrl_t *ctrl, uint32_t nsid, nvme_err_t exp,
128*f5f0964cSRobert Mustacchi const char *state)
129*f5f0964cSRobert Mustacchi {
130*f5f0964cSRobert Mustacchi nvme_err_t act;
131*f5f0964cSRobert Mustacchi
132*f5f0964cSRobert Mustacchi if (!libnvme_test_ctrl_attach(ctrl, nsid, NVME_NS_ATTACH_CTRL_DETACH,
133*f5f0964cSRobert Mustacchi &act)) {
134*f5f0964cSRobert Mustacchi return (false);
135*f5f0964cSRobert Mustacchi }
136*f5f0964cSRobert Mustacchi
137*f5f0964cSRobert Mustacchi return (ns_life_err_comp(ctrl, exp, act, "controller detach", state));
138*f5f0964cSRobert Mustacchi }
139*f5f0964cSRobert Mustacchi
140*f5f0964cSRobert Mustacchi static bool
ns_life_blkdev_attach(nvme_ctrl_t * ctrl,uint32_t nsid,nvme_err_t exp,const char * state)141*f5f0964cSRobert Mustacchi ns_life_blkdev_attach(nvme_ctrl_t *ctrl, uint32_t nsid, nvme_err_t exp,
142*f5f0964cSRobert Mustacchi const char *state)
143*f5f0964cSRobert Mustacchi {
144*f5f0964cSRobert Mustacchi nvme_err_t act;
145*f5f0964cSRobert Mustacchi
146*f5f0964cSRobert Mustacchi if (!libnvme_test_ns_blkdev(ctrl, nsid, true, &act)) {
147*f5f0964cSRobert Mustacchi return (false);
148*f5f0964cSRobert Mustacchi }
149*f5f0964cSRobert Mustacchi
150*f5f0964cSRobert Mustacchi return (ns_life_err_comp(ctrl, exp, act, "blkdev attach", state));
151*f5f0964cSRobert Mustacchi }
152*f5f0964cSRobert Mustacchi
153*f5f0964cSRobert Mustacchi static bool
ns_life_blkdev_detach(nvme_ctrl_t * ctrl,uint32_t nsid,nvme_err_t exp,const char * state)154*f5f0964cSRobert Mustacchi ns_life_blkdev_detach(nvme_ctrl_t *ctrl, uint32_t nsid, nvme_err_t exp,
155*f5f0964cSRobert Mustacchi const char *state)
156*f5f0964cSRobert Mustacchi {
157*f5f0964cSRobert Mustacchi nvme_err_t act;
158*f5f0964cSRobert Mustacchi
159*f5f0964cSRobert Mustacchi if (!libnvme_test_ns_blkdev(ctrl, nsid, false, &act)) {
160*f5f0964cSRobert Mustacchi return (false);
161*f5f0964cSRobert Mustacchi }
162*f5f0964cSRobert Mustacchi
163*f5f0964cSRobert Mustacchi return (ns_life_err_comp(ctrl, exp, act, "blkdev detach", state));
164*f5f0964cSRobert Mustacchi }
165*f5f0964cSRobert Mustacchi
166*f5f0964cSRobert Mustacchi typedef bool (*ns_life_f)(nvme_ctrl_t *, uint32_t, nvme_err_t,
167*f5f0964cSRobert Mustacchi const char *);
168*f5f0964cSRobert Mustacchi
169*f5f0964cSRobert Mustacchi static const ns_life_f ns_lf_funcs[NS_LC_NACTS] = {
170*f5f0964cSRobert Mustacchi [NS_ACT_NS_DELETE] = ns_life_ns_delete,
171*f5f0964cSRobert Mustacchi [NS_ACT_CTRL_ATTACH] = ns_life_ctrl_attach,
172*f5f0964cSRobert Mustacchi [NS_ACT_CTRL_DETACH] = ns_life_ctrl_detach,
173*f5f0964cSRobert Mustacchi [NS_ACT_BD_ATTACH] = ns_life_blkdev_attach,
174*f5f0964cSRobert Mustacchi [NS_ACT_BD_DETACH] = ns_life_blkdev_detach
175*f5f0964cSRobert Mustacchi };
176*f5f0964cSRobert Mustacchi
177*f5f0964cSRobert Mustacchi typedef struct ns_life_test {
178*f5f0964cSRobert Mustacchi nvme_ns_disc_level_t nlt_disc;
179*f5f0964cSRobert Mustacchi const char *nlt_desc;
180*f5f0964cSRobert Mustacchi nvme_err_t *nlt_errs;
181*f5f0964cSRobert Mustacchi size_t nlt_nerrs;
182*f5f0964cSRobert Mustacchi } ns_life_test_t;
183*f5f0964cSRobert Mustacchi
184*f5f0964cSRobert Mustacchi static const ns_life_test_t ns_life_tests[] = { {
185*f5f0964cSRobert Mustacchi .nlt_disc = NVME_NS_DISC_F_ALL,
186*f5f0964cSRobert Mustacchi .nlt_desc = "unallocated",
187*f5f0964cSRobert Mustacchi .nlt_errs = nvme_unalloc_errs,
188*f5f0964cSRobert Mustacchi .nlt_nerrs = ARRAY_SIZE(nvme_unalloc_errs)
189*f5f0964cSRobert Mustacchi }, {
190*f5f0964cSRobert Mustacchi .nlt_disc = NVME_NS_DISC_F_ALLOCATED,
191*f5f0964cSRobert Mustacchi .nlt_desc = "allocated",
192*f5f0964cSRobert Mustacchi .nlt_errs = nvme_alloc_errs,
193*f5f0964cSRobert Mustacchi .nlt_nerrs = ARRAY_SIZE(nvme_alloc_errs)
194*f5f0964cSRobert Mustacchi }, {
195*f5f0964cSRobert Mustacchi .nlt_disc = NVME_NS_DISC_F_NOT_IGNORED,
196*f5f0964cSRobert Mustacchi .nlt_desc = "active",
197*f5f0964cSRobert Mustacchi .nlt_errs = nvme_attach_errs,
198*f5f0964cSRobert Mustacchi .nlt_nerrs = ARRAY_SIZE(nvme_attach_errs)
199*f5f0964cSRobert Mustacchi }, {
200*f5f0964cSRobert Mustacchi .nlt_disc = NVME_NS_DISC_F_BLKDEV,
201*f5f0964cSRobert Mustacchi .nlt_desc = "blkdev",
202*f5f0964cSRobert Mustacchi .nlt_errs = nvme_blkdev_errs,
203*f5f0964cSRobert Mustacchi .nlt_nerrs = ARRAY_SIZE(nvme_blkdev_errs)
204*f5f0964cSRobert Mustacchi } };
205*f5f0964cSRobert Mustacchi
206*f5f0964cSRobert Mustacchi static bool
ns_life_run_one(nvme_ctrl_t * ctrl,uint32_t lbaf,const ns_life_test_t * test)207*f5f0964cSRobert Mustacchi ns_life_run_one(nvme_ctrl_t *ctrl, uint32_t lbaf, const ns_life_test_t *test)
208*f5f0964cSRobert Mustacchi {
209*f5f0964cSRobert Mustacchi bool ret = true;
210*f5f0964cSRobert Mustacchi
211*f5f0964cSRobert Mustacchi for (size_t i = 0; i < test->nlt_nerrs; i++) {
212*f5f0964cSRobert Mustacchi if (!libnvme_test_setup_ns(ctrl, test->nlt_disc, NS_LC_NSID,
213*f5f0964cSRobert Mustacchi lbaf)) {
214*f5f0964cSRobert Mustacchi warnx("TEST FAILED: failed to transition ns to %s",
215*f5f0964cSRobert Mustacchi test->nlt_desc);
216*f5f0964cSRobert Mustacchi ret = false;
217*f5f0964cSRobert Mustacchi }
218*f5f0964cSRobert Mustacchi
219*f5f0964cSRobert Mustacchi if (!ns_lf_funcs[i](ctrl, NS_LC_NSID, test->nlt_errs[i],
220*f5f0964cSRobert Mustacchi test->nlt_desc)) {
221*f5f0964cSRobert Mustacchi ret = false;
222*f5f0964cSRobert Mustacchi }
223*f5f0964cSRobert Mustacchi }
224*f5f0964cSRobert Mustacchi
225*f5f0964cSRobert Mustacchi return (ret);
226*f5f0964cSRobert Mustacchi }
227*f5f0964cSRobert Mustacchi
228*f5f0964cSRobert Mustacchi int
main(void)229*f5f0964cSRobert Mustacchi main(void)
230*f5f0964cSRobert Mustacchi {
231*f5f0964cSRobert Mustacchi int ret = EXIT_SUCCESS;
232*f5f0964cSRobert Mustacchi nvme_t *nvme;
233*f5f0964cSRobert Mustacchi nvme_ctrl_t *ctrl;
234*f5f0964cSRobert Mustacchi nvme_ctrl_info_t *info;
235*f5f0964cSRobert Mustacchi uint32_t lbaf;
236*f5f0964cSRobert Mustacchi
237*f5f0964cSRobert Mustacchi libnvme_test_init(&nvme, &ctrl);
238*f5f0964cSRobert Mustacchi if (!nvme_ctrl_lock(ctrl, NVME_LOCK_L_WRITE, NVME_LOCK_F_DONT_BLOCK)) {
239*f5f0964cSRobert Mustacchi libnvme_test_ctrl_fatal(ctrl, "failed to obtain write lock");
240*f5f0964cSRobert Mustacchi }
241*f5f0964cSRobert Mustacchi
242*f5f0964cSRobert Mustacchi if (!nvme_ctrl_info_snap(ctrl, &info)) {
243*f5f0964cSRobert Mustacchi libnvme_test_ctrl_fatal(ctrl, "failed to get info snapshot");
244*f5f0964cSRobert Mustacchi }
245*f5f0964cSRobert Mustacchi
246*f5f0964cSRobert Mustacchi if (!libnvme_test_lbaf(info, NVME_TEST_LBA_SIZE, &lbaf)) {
247*f5f0964cSRobert Mustacchi errx(EXIT_FAILURE, "failed to find 4K LBA format, cannot "
248*f5f0964cSRobert Mustacchi "continue");
249*f5f0964cSRobert Mustacchi }
250*f5f0964cSRobert Mustacchi
251*f5f0964cSRobert Mustacchi for (size_t i = 0; i < ARRAY_SIZE(ns_life_tests); i++) {
252*f5f0964cSRobert Mustacchi if (!ns_life_run_one(ctrl, lbaf, &ns_life_tests[i]))
253*f5f0964cSRobert Mustacchi ret = EXIT_FAILURE;
254*f5f0964cSRobert Mustacchi }
255*f5f0964cSRobert Mustacchi
256*f5f0964cSRobert Mustacchi nvme_ctrl_info_free(info);
257*f5f0964cSRobert Mustacchi nvme_ctrl_unlock(ctrl);
258*f5f0964cSRobert Mustacchi nvme_ctrl_fini(ctrl);
259*f5f0964cSRobert Mustacchi nvme_fini(nvme);
260*f5f0964cSRobert Mustacchi
261*f5f0964cSRobert Mustacchi if (ret == EXIT_SUCCESS) {
262*f5f0964cSRobert Mustacchi (void) printf("All tests passed successfully\n");
263*f5f0964cSRobert Mustacchi }
264*f5f0964cSRobert Mustacchi
265*f5f0964cSRobert Mustacchi return (ret);
266*f5f0964cSRobert Mustacchi }
267