1*564eeb7dSRobert Mustacchi /*
2*564eeb7dSRobert Mustacchi * This file and its contents are supplied under the terms of the
3*564eeb7dSRobert Mustacchi * Common Development and Distribution License ("CDDL"), version 1.0.
4*564eeb7dSRobert Mustacchi * You may only use this file in accordance with the terms of version
5*564eeb7dSRobert Mustacchi * 1.0 of the CDDL.
6*564eeb7dSRobert Mustacchi *
7*564eeb7dSRobert Mustacchi * A full copy of the text of the CDDL should have accompanied this
8*564eeb7dSRobert Mustacchi * source. A copy of the CDDL is also available via the Internet at
9*564eeb7dSRobert Mustacchi * http://www.illumos.org/license/CDDL.
10*564eeb7dSRobert Mustacchi */
11*564eeb7dSRobert Mustacchi
12*564eeb7dSRobert Mustacchi /*
13*564eeb7dSRobert Mustacchi * Copyright 2026 Oxide Computer Company
14*564eeb7dSRobert Mustacchi */
15*564eeb7dSRobert Mustacchi
16*564eeb7dSRobert Mustacchi /*
17*564eeb7dSRobert Mustacchi * Go through and test the basics of our set feature functionality. This is
18*564eeb7dSRobert Mustacchi * designed to be run against a device that supports the requisite OCP features:
19*564eeb7dSRobert Mustacchi *
20*564eeb7dSRobert Mustacchi * - Error Injection (0xc0)
21*564eeb7dSRobert Mustacchi * - PLP Health Check Interval (c6h)
22*564eeb7dSRobert Mustacchi *
23*564eeb7dSRobert Mustacchi * In this test we make sure that we can do:
24*564eeb7dSRobert Mustacchi *
25*564eeb7dSRobert Mustacchi * - Verify that we can't set a feature without the controller lock
26*564eeb7dSRobert Mustacchi * - Verify we aren't allowed to set a standard feature
27*564eeb7dSRobert Mustacchi * - A basic get feature / set feature loop without data
28*564eeb7dSRobert Mustacchi * - Test the missing fields and basics of the libnvme ocp error injection
29*564eeb7dSRobert Mustacchi * features which wraps set feature. This also gives us a basic set feature
30*564eeb7dSRobert Mustacchi * with data tests.
31*564eeb7dSRobert Mustacchi */
32*564eeb7dSRobert Mustacchi
33*564eeb7dSRobert Mustacchi #include <err.h>
34*564eeb7dSRobert Mustacchi #include <sys/sysmacros.h>
35*564eeb7dSRobert Mustacchi #include <sys/nvme/ocp.h>
36*564eeb7dSRobert Mustacchi
37*564eeb7dSRobert Mustacchi #include "libnvme_test_common.h"
38*564eeb7dSRobert Mustacchi
39*564eeb7dSRobert Mustacchi static void
set_feats_supported(nvme_ctrl_t * ctrl)40*564eeb7dSRobert Mustacchi set_feats_supported(nvme_ctrl_t *ctrl)
41*564eeb7dSRobert Mustacchi {
42*564eeb7dSRobert Mustacchi nvme_set_feat_req_t *req;
43*564eeb7dSRobert Mustacchi const char *feats[] = { "ocp/plphealth", "ocp/errinj" };
44*564eeb7dSRobert Mustacchi
45*564eeb7dSRobert Mustacchi for (size_t i = 0; i < ARRAY_SIZE(feats); i++) {
46*564eeb7dSRobert Mustacchi if (!nvme_set_feat_req_init_by_name(ctrl, feats[i], 0, NULL,
47*564eeb7dSRobert Mustacchi &req)) {
48*564eeb7dSRobert Mustacchi libnvme_test_ctrl_fatal(ctrl, "missing required "
49*564eeb7dSRobert Mustacchi "feature %s: test cannot proceed", feats[i]);
50*564eeb7dSRobert Mustacchi }
51*564eeb7dSRobert Mustacchi
52*564eeb7dSRobert Mustacchi nvme_set_feat_req_fini(req);
53*564eeb7dSRobert Mustacchi }
54*564eeb7dSRobert Mustacchi }
55*564eeb7dSRobert Mustacchi
56*564eeb7dSRobert Mustacchi static bool
set_feat_fail(nvme_ctrl_t * ctrl,const char * feat,const char * desc,uint32_t cdw11,nvme_err_t exp)57*564eeb7dSRobert Mustacchi set_feat_fail(nvme_ctrl_t *ctrl, const char *feat, const char *desc,
58*564eeb7dSRobert Mustacchi uint32_t cdw11, nvme_err_t exp)
59*564eeb7dSRobert Mustacchi {
60*564eeb7dSRobert Mustacchi nvme_err_t err;
61*564eeb7dSRobert Mustacchi bool ret = false;
62*564eeb7dSRobert Mustacchi nvme_set_feat_req_t *set = NULL;
63*564eeb7dSRobert Mustacchi
64*564eeb7dSRobert Mustacchi if (!nvme_set_feat_req_init_by_name(ctrl, feat, 0, NULL, &set)) {
65*564eeb7dSRobert Mustacchi libnvme_test_ctrl_warn(ctrl, "set feature %s: failed to "
66*564eeb7dSRobert Mustacchi "create %s request", desc, feat);
67*564eeb7dSRobert Mustacchi goto done;
68*564eeb7dSRobert Mustacchi }
69*564eeb7dSRobert Mustacchi
70*564eeb7dSRobert Mustacchi if (!nvme_set_feat_req_set_cdw11(set, cdw11)) {
71*564eeb7dSRobert Mustacchi libnvme_test_ctrl_warn(ctrl, "set feature %s: failed to set "
72*564eeb7dSRobert Mustacchi "%s cdw11 value", desc, feat);
73*564eeb7dSRobert Mustacchi goto done;
74*564eeb7dSRobert Mustacchi }
75*564eeb7dSRobert Mustacchi
76*564eeb7dSRobert Mustacchi if (nvme_set_feat_req_exec(set)) {
77*564eeb7dSRobert Mustacchi warnx("TEST FAILED: set feature %s unexpectedly passed: "
78*564eeb7dSRobert Mustacchi "expected failure", desc);
79*564eeb7dSRobert Mustacchi goto done;
80*564eeb7dSRobert Mustacchi }
81*564eeb7dSRobert Mustacchi
82*564eeb7dSRobert Mustacchi err = nvme_ctrl_err(ctrl);
83*564eeb7dSRobert Mustacchi if (err != exp) {
84*564eeb7dSRobert Mustacchi warnx("TEST FAILED: expected set feature %s to fail with %s "
85*564eeb7dSRobert Mustacchi "(0x%x), but found %s (0x%x)", desc,
86*564eeb7dSRobert Mustacchi nvme_ctrl_errtostr(ctrl, exp), exp,
87*564eeb7dSRobert Mustacchi nvme_ctrl_errtostr(ctrl, err), err);
88*564eeb7dSRobert Mustacchi goto done;
89*564eeb7dSRobert Mustacchi }
90*564eeb7dSRobert Mustacchi
91*564eeb7dSRobert Mustacchi ret = true;
92*564eeb7dSRobert Mustacchi (void) printf("TEST PASSED: set feature %s correctly failed with "
93*564eeb7dSRobert Mustacchi "%s\n", desc, nvme_ctrl_errtostr(ctrl, exp));
94*564eeb7dSRobert Mustacchi done:
95*564eeb7dSRobert Mustacchi nvme_set_feat_req_fini(set);
96*564eeb7dSRobert Mustacchi return (ret);
97*564eeb7dSRobert Mustacchi }
98*564eeb7dSRobert Mustacchi
99*564eeb7dSRobert Mustacchi static bool
get_plp(nvme_ctrl_t * ctrl,nvme_get_feat_req_t * get,uint32_t * valp)100*564eeb7dSRobert Mustacchi get_plp(nvme_ctrl_t *ctrl, nvme_get_feat_req_t *get, uint32_t *valp)
101*564eeb7dSRobert Mustacchi {
102*564eeb7dSRobert Mustacchi if (!nvme_get_feat_req_exec(get)) {
103*564eeb7dSRobert Mustacchi libnvme_test_ctrl_warn(ctrl, "failed to execute PLP get "
104*564eeb7dSRobert Mustacchi "feature request");
105*564eeb7dSRobert Mustacchi return (false);
106*564eeb7dSRobert Mustacchi }
107*564eeb7dSRobert Mustacchi
108*564eeb7dSRobert Mustacchi if (!nvme_get_feat_req_get_cdw0(get, valp)) {
109*564eeb7dSRobert Mustacchi libnvme_test_ctrl_warn(ctrl, "failed to get PLP cdw0 value");
110*564eeb7dSRobert Mustacchi return (false);
111*564eeb7dSRobert Mustacchi }
112*564eeb7dSRobert Mustacchi
113*564eeb7dSRobert Mustacchi *valp &= UINT16_MAX;
114*564eeb7dSRobert Mustacchi return (true);
115*564eeb7dSRobert Mustacchi }
116*564eeb7dSRobert Mustacchi
117*564eeb7dSRobert Mustacchi static bool
set_plp(nvme_ctrl_t * ctrl,nvme_set_feat_req_t * set,uint16_t val)118*564eeb7dSRobert Mustacchi set_plp(nvme_ctrl_t *ctrl, nvme_set_feat_req_t *set, uint16_t val)
119*564eeb7dSRobert Mustacchi {
120*564eeb7dSRobert Mustacchi /*
121*564eeb7dSRobert Mustacchi * The PLP value is actually in the upper 16 bits when one performs a
122*564eeb7dSRobert Mustacchi * GET FEATURE.
123*564eeb7dSRobert Mustacchi */
124*564eeb7dSRobert Mustacchi if (!nvme_set_feat_req_set_cdw11(set, val << 16)) {
125*564eeb7dSRobert Mustacchi libnvme_test_ctrl_warn(ctrl, "failed to set PLP cdw11 value");
126*564eeb7dSRobert Mustacchi return (false);
127*564eeb7dSRobert Mustacchi }
128*564eeb7dSRobert Mustacchi
129*564eeb7dSRobert Mustacchi if (!nvme_set_feat_req_exec(set)) {
130*564eeb7dSRobert Mustacchi libnvme_test_ctrl_warn(ctrl, "failed to execute PLP set "
131*564eeb7dSRobert Mustacchi "feature request");
132*564eeb7dSRobert Mustacchi return (false);
133*564eeb7dSRobert Mustacchi }
134*564eeb7dSRobert Mustacchi
135*564eeb7dSRobert Mustacchi return (true);
136*564eeb7dSRobert Mustacchi }
137*564eeb7dSRobert Mustacchi
138*564eeb7dSRobert Mustacchi /*
139*564eeb7dSRobert Mustacchi * Using the PLP Health Interval Checking, perform round-trip getting and
140*564eeb7dSRobert Mustacchi * setting of the feature and verify our values hold.
141*564eeb7dSRobert Mustacchi */
142*564eeb7dSRobert Mustacchi static bool
roundtrip_plp(nvme_ctrl_t * ctrl)143*564eeb7dSRobert Mustacchi roundtrip_plp(nvme_ctrl_t *ctrl)
144*564eeb7dSRobert Mustacchi {
145*564eeb7dSRobert Mustacchi nvme_get_feat_req_t *get = NULL;
146*564eeb7dSRobert Mustacchi nvme_set_feat_req_t *set = NULL;
147*564eeb7dSRobert Mustacchi bool ret = true;
148*564eeb7dSRobert Mustacchi uint32_t cdw0, new;
149*564eeb7dSRobert Mustacchi
150*564eeb7dSRobert Mustacchi if (!nvme_get_feat_req_init_by_name(ctrl, "ocp/plphealth", 0, NULL,
151*564eeb7dSRobert Mustacchi &get)) {
152*564eeb7dSRobert Mustacchi libnvme_test_ctrl_warn(ctrl, "failed to create PLP get feature "
153*564eeb7dSRobert Mustacchi "request");
154*564eeb7dSRobert Mustacchi ret = false;
155*564eeb7dSRobert Mustacchi goto done;
156*564eeb7dSRobert Mustacchi }
157*564eeb7dSRobert Mustacchi
158*564eeb7dSRobert Mustacchi if (!nvme_set_feat_req_init_by_name(ctrl, "ocp/plphealth", 0, NULL,
159*564eeb7dSRobert Mustacchi &set)) {
160*564eeb7dSRobert Mustacchi libnvme_test_ctrl_warn(ctrl, "failed to create PLP set feature "
161*564eeb7dSRobert Mustacchi "request");
162*564eeb7dSRobert Mustacchi ret = false;
163*564eeb7dSRobert Mustacchi goto done;
164*564eeb7dSRobert Mustacchi }
165*564eeb7dSRobert Mustacchi
166*564eeb7dSRobert Mustacchi if (!get_plp(ctrl, get, &cdw0)) {
167*564eeb7dSRobert Mustacchi ret = false;
168*564eeb7dSRobert Mustacchi goto done;
169*564eeb7dSRobert Mustacchi }
170*564eeb7dSRobert Mustacchi
171*564eeb7dSRobert Mustacchi if (!set_plp(ctrl, set, cdw0 + 1)) {
172*564eeb7dSRobert Mustacchi ret = false;
173*564eeb7dSRobert Mustacchi goto done;
174*564eeb7dSRobert Mustacchi }
175*564eeb7dSRobert Mustacchi
176*564eeb7dSRobert Mustacchi if (!get_plp(ctrl, get, &new)) {
177*564eeb7dSRobert Mustacchi ret = false;
178*564eeb7dSRobert Mustacchi goto done;
179*564eeb7dSRobert Mustacchi }
180*564eeb7dSRobert Mustacchi
181*564eeb7dSRobert Mustacchi if (cdw0 + 1 != new) {
182*564eeb7dSRobert Mustacchi warnx("setting ocp/plphealth didn't work, originally had 0x%x, "
183*564eeb7dSRobert Mustacchi "expected 0x%x, found 0x%x", cdw0, cdw0 + 1, new);
184*564eeb7dSRobert Mustacchi ret = false;
185*564eeb7dSRobert Mustacchi }
186*564eeb7dSRobert Mustacchi
187*564eeb7dSRobert Mustacchi if (!set_plp(ctrl, set, cdw0)) {
188*564eeb7dSRobert Mustacchi ret = false;
189*564eeb7dSRobert Mustacchi goto done;
190*564eeb7dSRobert Mustacchi }
191*564eeb7dSRobert Mustacchi
192*564eeb7dSRobert Mustacchi if (!get_plp(ctrl, get, &new)) {
193*564eeb7dSRobert Mustacchi ret = false;
194*564eeb7dSRobert Mustacchi goto done;
195*564eeb7dSRobert Mustacchi }
196*564eeb7dSRobert Mustacchi
197*564eeb7dSRobert Mustacchi if (cdw0 != new) {
198*564eeb7dSRobert Mustacchi warnx("TEST FAILED: failed to restore ocp/plphealth back to "
199*564eeb7dSRobert Mustacchi "0x%x: found 0x%x", cdw0, new);
200*564eeb7dSRobert Mustacchi ret = false;
201*564eeb7dSRobert Mustacchi }
202*564eeb7dSRobert Mustacchi
203*564eeb7dSRobert Mustacchi if (ret) {
204*564eeb7dSRobert Mustacchi (void) printf("TEST PASSED: ocp/plphealth set feature round "
205*564eeb7dSRobert Mustacchi "trip\n");
206*564eeb7dSRobert Mustacchi }
207*564eeb7dSRobert Mustacchi
208*564eeb7dSRobert Mustacchi done:
209*564eeb7dSRobert Mustacchi nvme_get_feat_req_fini(get);
210*564eeb7dSRobert Mustacchi nvme_set_feat_req_fini(set);
211*564eeb7dSRobert Mustacchi return (ret);
212*564eeb7dSRobert Mustacchi }
213*564eeb7dSRobert Mustacchi
214*564eeb7dSRobert Mustacchi static bool
errinj_req_fail(nvme_ctrl_t * ctrl,nvme_ocp_errinj_req_t * req,const char * desc,nvme_err_t exp)215*564eeb7dSRobert Mustacchi errinj_req_fail(nvme_ctrl_t *ctrl, nvme_ocp_errinj_req_t *req, const char *desc,
216*564eeb7dSRobert Mustacchi nvme_err_t exp)
217*564eeb7dSRobert Mustacchi {
218*564eeb7dSRobert Mustacchi const char *exps = nvme_ctrl_errtostr(ctrl, exp);
219*564eeb7dSRobert Mustacchi nvme_err_t err;
220*564eeb7dSRobert Mustacchi
221*564eeb7dSRobert Mustacchi if (nvme_ocp_errinj_req_exec(req)) {
222*564eeb7dSRobert Mustacchi warnx("TEST FAILED: %s unexpectedly succeeded, but expected %s",
223*564eeb7dSRobert Mustacchi desc, exps);
224*564eeb7dSRobert Mustacchi return (false);
225*564eeb7dSRobert Mustacchi }
226*564eeb7dSRobert Mustacchi
227*564eeb7dSRobert Mustacchi err = nvme_ctrl_err(ctrl);
228*564eeb7dSRobert Mustacchi if (err != exp) {
229*564eeb7dSRobert Mustacchi warnx("TEST FAILED: expected %s to fail with %s (0x%x), but "
230*564eeb7dSRobert Mustacchi "found %s (0x%x)", desc, nvme_ctrl_errtostr(ctrl, exp), exp,
231*564eeb7dSRobert Mustacchi nvme_ctrl_errtostr(ctrl, err), err);
232*564eeb7dSRobert Mustacchi return (false);
233*564eeb7dSRobert Mustacchi }
234*564eeb7dSRobert Mustacchi
235*564eeb7dSRobert Mustacchi
236*564eeb7dSRobert Mustacchi (void) printf("TEST PASSED: %s correctly failed with %s\n", desc, exps);
237*564eeb7dSRobert Mustacchi return (true);
238*564eeb7dSRobert Mustacchi }
239*564eeb7dSRobert Mustacchi
240*564eeb7dSRobert Mustacchi static bool
errinj_set_fail(nvme_ctrl_t * ctrl,const char * desc,nvme_err_t exp,bool res)241*564eeb7dSRobert Mustacchi errinj_set_fail(nvme_ctrl_t *ctrl, const char *desc, nvme_err_t exp, bool res)
242*564eeb7dSRobert Mustacchi {
243*564eeb7dSRobert Mustacchi if (res) {
244*564eeb7dSRobert Mustacchi warnx("TEST FAILED: setting error injection field %s to bad "
245*564eeb7dSRobert Mustacchi "value incorrectly worked: expected %s (0x%x)", desc,
246*564eeb7dSRobert Mustacchi nvme_ctrl_errtostr(ctrl, exp), exp);
247*564eeb7dSRobert Mustacchi return (false);
248*564eeb7dSRobert Mustacchi }
249*564eeb7dSRobert Mustacchi
250*564eeb7dSRobert Mustacchi nvme_err_t err = nvme_ctrl_err(ctrl);
251*564eeb7dSRobert Mustacchi if (err != exp) {
252*564eeb7dSRobert Mustacchi warnx("TEST FAILED: expected bad error injection field %s "
253*564eeb7dSRobert Mustacchi "value to fail with %s (0x%x): found %s (0x%x)", desc,
254*564eeb7dSRobert Mustacchi nvme_ctrl_errtostr(ctrl, exp), exp,
255*564eeb7dSRobert Mustacchi nvme_ctrl_errtostr(ctrl, err), err);
256*564eeb7dSRobert Mustacchi return (false);
257*564eeb7dSRobert Mustacchi }
258*564eeb7dSRobert Mustacchi
259*564eeb7dSRobert Mustacchi (void) printf("TEST PASSED: bad error injection field %s value "
260*564eeb7dSRobert Mustacchi "correctly failed with %s\n", desc, nvme_ctrl_errtostr(ctrl, exp));
261*564eeb7dSRobert Mustacchi return (true);
262*564eeb7dSRobert Mustacchi }
263*564eeb7dSRobert Mustacchi
264*564eeb7dSRobert Mustacchi /*
265*564eeb7dSRobert Mustacchi * Go through and verify that various different errors are caught:
266*564eeb7dSRobert Mustacchi *
267*564eeb7dSRobert Mustacchi * - Missing fields
268*564eeb7dSRobert Mustacchi * - Invalid values for type, number of reads, delay
269*564eeb7dSRobert Mustacchi * - Delay value unsupported
270*564eeb7dSRobert Mustacchi */
271*564eeb7dSRobert Mustacchi static bool
errinj_errors(nvme_ctrl_t * ctrl)272*564eeb7dSRobert Mustacchi errinj_errors(nvme_ctrl_t *ctrl)
273*564eeb7dSRobert Mustacchi {
274*564eeb7dSRobert Mustacchi bool ret = true;
275*564eeb7dSRobert Mustacchi nvme_ocp_errinj_req_t *req = NULL;
276*564eeb7dSRobert Mustacchi
277*564eeb7dSRobert Mustacchi if (!nvme_ocp_errinj_req_init(ctrl, &req)) {
278*564eeb7dSRobert Mustacchi libnvme_test_ctrl_warn(ctrl, "failed to create error injection "
279*564eeb7dSRobert Mustacchi "request");
280*564eeb7dSRobert Mustacchi ret = false;
281*564eeb7dSRobert Mustacchi goto done;
282*564eeb7dSRobert Mustacchi }
283*564eeb7dSRobert Mustacchi
284*564eeb7dSRobert Mustacchi if (!errinj_req_fail(ctrl, req, "error injection with missing fields",
285*564eeb7dSRobert Mustacchi NVME_ERR_OCP_ERRINJ_REQ_MISSING_FIELDS)) {
286*564eeb7dSRobert Mustacchi ret = false;
287*564eeb7dSRobert Mustacchi }
288*564eeb7dSRobert Mustacchi
289*564eeb7dSRobert Mustacchi if (!errinj_set_fail(ctrl, "type", NVME_ERR_OCP_ERRINJ_TYPE_RANGE,
290*564eeb7dSRobert Mustacchi nvme_ocp_errinj_req_set_type(req, 0xb22b7777)))
291*564eeb7dSRobert Mustacchi ret = false;
292*564eeb7dSRobert Mustacchi
293*564eeb7dSRobert Mustacchi if (!errinj_set_fail(ctrl, "nrtde", NVME_ERR_OCP_ERRINJ_NRTDE_RANGE,
294*564eeb7dSRobert Mustacchi nvme_ocp_errinj_req_set_nrtde(req, 0x12345)))
295*564eeb7dSRobert Mustacchi ret = false;
296*564eeb7dSRobert Mustacchi
297*564eeb7dSRobert Mustacchi /*
298*564eeb7dSRobert Mustacchi * Set us up for an unusable error on exec when we set an ld value with
299*564eeb7dSRobert Mustacchi * a different type.
300*564eeb7dSRobert Mustacchi */
301*564eeb7dSRobert Mustacchi if (!nvme_ocp_errinj_req_set_type(req, OCP_ERRINJ_T_CPU_HANG) ||
302*564eeb7dSRobert Mustacchi !nvme_ocp_errinj_req_set_ld(req, 0x23)) {
303*564eeb7dSRobert Mustacchi libnvme_test_ctrl_warn(ctrl, "failed to set fields for error "
304*564eeb7dSRobert Mustacchi "injection duration not settable");
305*564eeb7dSRobert Mustacchi ret = false;
306*564eeb7dSRobert Mustacchi } else if (!errinj_req_fail(ctrl, req, "error injection duration not "
307*564eeb7dSRobert Mustacchi "settable", NVME_ERR_OCP_ERRINJ_LD_UNUSE)) {
308*564eeb7dSRobert Mustacchi ret = false;
309*564eeb7dSRobert Mustacchi }
310*564eeb7dSRobert Mustacchi
311*564eeb7dSRobert Mustacchi done:
312*564eeb7dSRobert Mustacchi nvme_ocp_errinj_req_fini(req);
313*564eeb7dSRobert Mustacchi return (ret);
314*564eeb7dSRobert Mustacchi }
315*564eeb7dSRobert Mustacchi
316*564eeb7dSRobert Mustacchi /*
317*564eeb7dSRobert Mustacchi * Test error injection by creating something with a high rate of reads required
318*564eeb7dSRobert Mustacchi * that we shouldn't trigger. Verify we can see it with a GET FEATURE. Then
319*564eeb7dSRobert Mustacchi * clear it. Verify it's not there in a GET.
320*564eeb7dSRobert Mustacchi */
321*564eeb7dSRobert Mustacchi static bool
roundtrip_errinj(nvme_ctrl_t * ctrl)322*564eeb7dSRobert Mustacchi roundtrip_errinj(nvme_ctrl_t *ctrl)
323*564eeb7dSRobert Mustacchi {
324*564eeb7dSRobert Mustacchi bool ret = true;
325*564eeb7dSRobert Mustacchi nvme_ocp_errinj_req_t *req = NULL;
326*564eeb7dSRobert Mustacchi nvme_get_feat_req_t *get = NULL;
327*564eeb7dSRobert Mustacchi nvme_feat_disc_t *disc = NULL;
328*564eeb7dSRobert Mustacchi void *buf = NULL;
329*564eeb7dSRobert Mustacchi uint64_t len;
330*564eeb7dSRobert Mustacchi uint32_t cdw0;
331*564eeb7dSRobert Mustacchi
332*564eeb7dSRobert Mustacchi if (!nvme_get_feat_req_init_by_name(ctrl, "ocp/errinj", 0, &disc,
333*564eeb7dSRobert Mustacchi &get)) {
334*564eeb7dSRobert Mustacchi libnvme_test_ctrl_warn(ctrl, "failed to create error injection "
335*564eeb7dSRobert Mustacchi "get feature request");
336*564eeb7dSRobert Mustacchi ret = false;
337*564eeb7dSRobert Mustacchi goto done;
338*564eeb7dSRobert Mustacchi }
339*564eeb7dSRobert Mustacchi
340*564eeb7dSRobert Mustacchi len = nvme_feat_disc_data_size(disc);
341*564eeb7dSRobert Mustacchi buf = calloc(len, sizeof (uint8_t));
342*564eeb7dSRobert Mustacchi if (buf == NULL) {
343*564eeb7dSRobert Mustacchi err(EXIT_FAILURE, "INTERNAL TEST FAILED: failed to alloc %"
344*564eeb7dSRobert Mustacchi PRIu64 "bytes for error injection buffer", len);
345*564eeb7dSRobert Mustacchi }
346*564eeb7dSRobert Mustacchi if (!nvme_get_feat_req_set_output(get, buf, len)) {
347*564eeb7dSRobert Mustacchi libnvme_test_ctrl_warn(ctrl, "failed to set get feature output "
348*564eeb7dSRobert Mustacchi "buffer");
349*564eeb7dSRobert Mustacchi ret = false;
350*564eeb7dSRobert Mustacchi goto done;
351*564eeb7dSRobert Mustacchi }
352*564eeb7dSRobert Mustacchi
353*564eeb7dSRobert Mustacchi if (!nvme_ocp_errinj_req_init(ctrl, &req)) {
354*564eeb7dSRobert Mustacchi libnvme_test_ctrl_warn(ctrl, "failed to create error injection "
355*564eeb7dSRobert Mustacchi "request");
356*564eeb7dSRobert Mustacchi ret = false;
357*564eeb7dSRobert Mustacchi goto done;
358*564eeb7dSRobert Mustacchi }
359*564eeb7dSRobert Mustacchi
360*564eeb7dSRobert Mustacchi if (!nvme_ocp_errinj_req_set_type(req, OCP_ERRINJ_T_CPU_HANG) ||
361*564eeb7dSRobert Mustacchi !nvme_ocp_errinj_req_set_nrtde(req, 0x7777)) {
362*564eeb7dSRobert Mustacchi libnvme_test_ctrl_warn(ctrl, "failed to set basic error "
363*564eeb7dSRobert Mustacchi "injection fields");
364*564eeb7dSRobert Mustacchi ret = false;
365*564eeb7dSRobert Mustacchi goto done;
366*564eeb7dSRobert Mustacchi }
367*564eeb7dSRobert Mustacchi
368*564eeb7dSRobert Mustacchi if (!nvme_ocp_errinj_req_exec(req)) {
369*564eeb7dSRobert Mustacchi libnvme_test_ctrl_warn(ctrl, "failed to execute error "
370*564eeb7dSRobert Mustacchi "injection request");
371*564eeb7dSRobert Mustacchi ret = false;
372*564eeb7dSRobert Mustacchi goto done;
373*564eeb7dSRobert Mustacchi }
374*564eeb7dSRobert Mustacchi
375*564eeb7dSRobert Mustacchi if (!nvme_get_feat_req_exec(get) || !nvme_get_feat_req_get_cdw0(get,
376*564eeb7dSRobert Mustacchi &cdw0)) {
377*564eeb7dSRobert Mustacchi libnvme_test_ctrl_warn(ctrl, "failed to get error injection "
378*564eeb7dSRobert Mustacchi "request and data");
379*564eeb7dSRobert Mustacchi ret = false;
380*564eeb7dSRobert Mustacchi goto done;
381*564eeb7dSRobert Mustacchi }
382*564eeb7dSRobert Mustacchi
383*564eeb7dSRobert Mustacchi if (cdw0 != 1) {
384*564eeb7dSRobert Mustacchi warnx("TEST FAILED: error injection pending count is 0x%x, but "
385*564eeb7dSRobert Mustacchi "expected it to be 1", cdw0);
386*564eeb7dSRobert Mustacchi ret = false;
387*564eeb7dSRobert Mustacchi }
388*564eeb7dSRobert Mustacchi
389*564eeb7dSRobert Mustacchi const volatile ocp_vuf_errinj_t *err = buf;
390*564eeb7dSRobert Mustacchi if (err[0].oei_flags != (OCP_ERRINJ_F_ENABLE | OCP_ERRINJ_F_SINGLE)) {
391*564eeb7dSRobert Mustacchi warnx("TEST FAILED: found unexpected error flags 0x%x, "
392*564eeb7dSRobert Mustacchi "expected 0x%x", err[0].oei_flags, OCP_ERRINJ_F_ENABLE |
393*564eeb7dSRobert Mustacchi OCP_ERRINJ_F_SINGLE);
394*564eeb7dSRobert Mustacchi ret = false;
395*564eeb7dSRobert Mustacchi }
396*564eeb7dSRobert Mustacchi
397*564eeb7dSRobert Mustacchi if (err[0].oei_type != OCP_ERRINJ_T_CPU_HANG) {
398*564eeb7dSRobert Mustacchi warnx("TEST FAILED: found unexpected error type 0x%x, expected "
399*564eeb7dSRobert Mustacchi "0x%x", err[0].oei_type, OCP_ERRINJ_T_CPU_HANG);
400*564eeb7dSRobert Mustacchi ret = false;
401*564eeb7dSRobert Mustacchi }
402*564eeb7dSRobert Mustacchi
403*564eeb7dSRobert Mustacchi /*
404*564eeb7dSRobert Mustacchi * Assume that there is some number of reads potentially going on in the
405*564eeb7dSRobert Mustacchi * background, but hopefully not too much.
406*564eeb7dSRobert Mustacchi */
407*564eeb7dSRobert Mustacchi if (err[0].oei_nrtde < 0x6666) {
408*564eeb7dSRobert Mustacchi warnx("TEST FAILED: found unexpected nrtde value: 0x%x",
409*564eeb7dSRobert Mustacchi err[0].oei_nrtde);
410*564eeb7dSRobert Mustacchi ret = false;
411*564eeb7dSRobert Mustacchi }
412*564eeb7dSRobert Mustacchi
413*564eeb7dSRobert Mustacchi if (!nvme_ocp_errinj_clear(ctrl)) {
414*564eeb7dSRobert Mustacchi libnvme_test_ctrl_warn(ctrl, "failed to clear error injection "
415*564eeb7dSRobert Mustacchi "request");
416*564eeb7dSRobert Mustacchi ret = false;
417*564eeb7dSRobert Mustacchi goto done;
418*564eeb7dSRobert Mustacchi }
419*564eeb7dSRobert Mustacchi
420*564eeb7dSRobert Mustacchi if (!nvme_get_feat_req_exec(get) || !nvme_get_feat_req_get_cdw0(get,
421*564eeb7dSRobert Mustacchi &cdw0)) {
422*564eeb7dSRobert Mustacchi libnvme_test_ctrl_warn(ctrl, "failed to get error injection "
423*564eeb7dSRobert Mustacchi "request and data");
424*564eeb7dSRobert Mustacchi ret = false;
425*564eeb7dSRobert Mustacchi goto done;
426*564eeb7dSRobert Mustacchi }
427*564eeb7dSRobert Mustacchi
428*564eeb7dSRobert Mustacchi if (cdw0 != 0) {
429*564eeb7dSRobert Mustacchi warnx("TEST FAILED: error injection pending count is 0x%x "
430*564eeb7dSRobert Mustacchi "after clear, but expected 0", cdw0);
431*564eeb7dSRobert Mustacchi ret = false;
432*564eeb7dSRobert Mustacchi }
433*564eeb7dSRobert Mustacchi
434*564eeb7dSRobert Mustacchi if (err[0].oei_flags != 0) {
435*564eeb7dSRobert Mustacchi warnx("TEST FAILED: found unexpected error flags 0x%x after "
436*564eeb7dSRobert Mustacchi "clear, but expected 0", err[0].oei_flags);
437*564eeb7dSRobert Mustacchi ret = false;
438*564eeb7dSRobert Mustacchi }
439*564eeb7dSRobert Mustacchi
440*564eeb7dSRobert Mustacchi if (err[0].oei_type != 0) {
441*564eeb7dSRobert Mustacchi warnx("TEST FAILED: found unexpected error type 0x%x after "
442*564eeb7dSRobert Mustacchi "clear, but expected 0", err[0].oei_type);
443*564eeb7dSRobert Mustacchi ret = false;
444*564eeb7dSRobert Mustacchi }
445*564eeb7dSRobert Mustacchi
446*564eeb7dSRobert Mustacchi if (err[0].oei_nrtde != 0) {
447*564eeb7dSRobert Mustacchi warnx("TEST FAILED: found unexpected nrtde 0x%x after "
448*564eeb7dSRobert Mustacchi "clear, but expected 0", err[0].oei_nrtde);
449*564eeb7dSRobert Mustacchi ret = false;
450*564eeb7dSRobert Mustacchi }
451*564eeb7dSRobert Mustacchi
452*564eeb7dSRobert Mustacchi if (ret) {
453*564eeb7dSRobert Mustacchi (void) printf("TEST PASSED: error injection roundtrip\n");
454*564eeb7dSRobert Mustacchi }
455*564eeb7dSRobert Mustacchi
456*564eeb7dSRobert Mustacchi done:
457*564eeb7dSRobert Mustacchi nvme_ocp_errinj_req_fini(req);
458*564eeb7dSRobert Mustacchi free(buf);
459*564eeb7dSRobert Mustacchi nvme_feat_disc_free(disc);
460*564eeb7dSRobert Mustacchi nvme_get_feat_req_fini(get);
461*564eeb7dSRobert Mustacchi return (ret);
462*564eeb7dSRobert Mustacchi }
463*564eeb7dSRobert Mustacchi
464*564eeb7dSRobert Mustacchi int
main(void)465*564eeb7dSRobert Mustacchi main(void)
466*564eeb7dSRobert Mustacchi {
467*564eeb7dSRobert Mustacchi int ret = EXIT_SUCCESS;
468*564eeb7dSRobert Mustacchi
469*564eeb7dSRobert Mustacchi nvme_t *nvme;
470*564eeb7dSRobert Mustacchi nvme_ctrl_t *ctrl;
471*564eeb7dSRobert Mustacchi
472*564eeb7dSRobert Mustacchi libnvme_test_init(&nvme, &ctrl);
473*564eeb7dSRobert Mustacchi set_feats_supported(ctrl);
474*564eeb7dSRobert Mustacchi
475*564eeb7dSRobert Mustacchi /*
476*564eeb7dSRobert Mustacchi * Verify that if we try to set a feature without a lock this fails.
477*564eeb7dSRobert Mustacchi */
478*564eeb7dSRobert Mustacchi if (!set_feat_fail(ctrl, "ocp/plphealth", "without control lock", 0x23,
479*564eeb7dSRobert Mustacchi NVME_ERR_NEED_CTRL_WRLOCK)) {
480*564eeb7dSRobert Mustacchi ret = EXIT_FAILURE;
481*564eeb7dSRobert Mustacchi }
482*564eeb7dSRobert Mustacchi
483*564eeb7dSRobert Mustacchi /*
484*564eeb7dSRobert Mustacchi * Setting a standard feature should fail.
485*564eeb7dSRobert Mustacchi */
486*564eeb7dSRobert Mustacchi if (!set_feat_fail(ctrl, "queues", "standard feature", 0x7777,
487*564eeb7dSRobert Mustacchi NVME_ERR_NEED_CTRL_WRLOCK)) {
488*564eeb7dSRobert Mustacchi ret = EXIT_FAILURE;
489*564eeb7dSRobert Mustacchi }
490*564eeb7dSRobert Mustacchi
491*564eeb7dSRobert Mustacchi /*
492*564eeb7dSRobert Mustacchi * Take a controller lock for all the remaining tests.
493*564eeb7dSRobert Mustacchi */
494*564eeb7dSRobert Mustacchi if (!nvme_ctrl_lock(ctrl, NVME_LOCK_L_WRITE, 0)) {
495*564eeb7dSRobert Mustacchi libnvme_test_ctrl_fatal(ctrl, "failed to take a write lock: "
496*564eeb7dSRobert Mustacchi "cannot continue");
497*564eeb7dSRobert Mustacchi }
498*564eeb7dSRobert Mustacchi
499*564eeb7dSRobert Mustacchi if (!roundtrip_plp(ctrl))
500*564eeb7dSRobert Mustacchi ret = EXIT_FAILURE;
501*564eeb7dSRobert Mustacchi
502*564eeb7dSRobert Mustacchi if (!errinj_errors(ctrl))
503*564eeb7dSRobert Mustacchi ret = EXIT_FAILURE;
504*564eeb7dSRobert Mustacchi
505*564eeb7dSRobert Mustacchi if (!roundtrip_errinj(ctrl))
506*564eeb7dSRobert Mustacchi ret = EXIT_FAILURE;
507*564eeb7dSRobert Mustacchi
508*564eeb7dSRobert Mustacchi nvme_ctrl_unlock(ctrl);
509*564eeb7dSRobert Mustacchi nvme_ctrl_fini(ctrl);
510*564eeb7dSRobert Mustacchi nvme_fini(nvme);
511*564eeb7dSRobert Mustacchi
512*564eeb7dSRobert Mustacchi if (ret == EXIT_SUCCESS) {
513*564eeb7dSRobert Mustacchi (void) printf("All tests exited successfully\n");
514*564eeb7dSRobert Mustacchi }
515*564eeb7dSRobert Mustacchi
516*564eeb7dSRobert Mustacchi return (ret);
517*564eeb7dSRobert Mustacchi }
518