1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2024 Oxide Computer Company
14 */
15
16 /*
17 * Test various aspects of reading the persistent event log from a device and
18 * verify that we properly handle certain error conditions. In particular, we
19 * want to verify the following:
20 *
21 * 1) Issuing a reset context while it's already reset is fine.
22 * 2) Issuing a read without establish fails
23 * 3) Issuing an establish context with one fails
24 * 4) Otherwise basic read / establish / release works
25 *
26 * Because this requires device specific behavior is it not part of the default
27 * non-destructive run.
28 */
29
30 #include <err.h>
31
32 #include "libnvme_test_common.h"
33
34 static bool
pev_action(nvme_t * nvme,nvme_ctrl_t * ctrl,nvme_pev_log_lsp_t pev,bool exp,const char * desc)35 pev_action(nvme_t *nvme, nvme_ctrl_t *ctrl, nvme_pev_log_lsp_t pev, bool exp,
36 const char *desc)
37 {
38 nvme_log_disc_t *disc;
39 nvme_log_req_t *req;
40 uint8_t *buf;
41 size_t buflen = 512;
42 bool ret = true, lret;
43
44 if ((buf = calloc(buflen, sizeof (uint8_t))) == NULL) {
45 err(EXIT_FAILURE, "INTERNAL TEST FAILURE: failed to allocate "
46 "%zu bytes for internal buffer", buflen);
47 }
48
49 if (!nvme_log_req_init_by_name(ctrl, "pev", 0, &disc, &req)) {
50 libnvme_test_ctrl_fatal(ctrl, "%s: failed to initialize "
51 "persistent event log request", desc);
52 }
53
54 if (!nvme_log_req_set_output(req, buf, buflen)) {
55 libnvme_test_ctrl_warn(ctrl, "%s: failed to set output buffer",
56 desc);
57 ret = false;
58 goto done;
59 }
60
61 if (!nvme_log_req_set_lsp(req, pev)) {
62 libnvme_test_ctrl_warn(ctrl, "%s: failed to set lsp to 0x%x",
63 desc, pev);
64 ret = false;
65 goto done;
66 }
67
68 lret = nvme_log_req_exec(req);
69 if (exp && !lret) {
70 libnvme_test_ctrl_warn(ctrl, "%s: log request failed, but "
71 "expected success", desc);
72 ret = false;
73 } else if (!exp && lret) {
74 warnx("TEST FAILED: %s: log request succeeded, but expected "
75 "failure", desc);
76 ret = false;
77 } else if (!lret) {
78 nvme_err_t err;
79 uint32_t sct, sc;
80
81 err = nvme_ctrl_err(ctrl);
82 nvme_ctrl_deverr(ctrl, &sct, &sc);
83
84 if (err != NVME_ERR_CONTROLLER) {
85 warnx("TEST FAILED: %s: found controller error %s "
86 "(0x%x), but expected %s (0x%x)", desc,
87 nvme_errtostr(nvme, err), err,
88 nvme_errtostr(nvme, NVME_ERR_CONTROLLER),
89 NVME_ERR_CONTROLLER);
90 ret = false;
91 } else if (sct != NVME_CQE_SCT_GENERIC) {
92 warnx("TEST FAILED: %s: found device sct %s (0x%x), "
93 "but expected %s (0x%x)", desc,
94 nvme_scttostr(ctrl, sct), sct,
95 nvme_scttostr(ctrl, NVME_CQE_SCT_GENERIC),
96 NVME_CQE_SCT_GENERIC);
97 ret = false;
98 } else if (sc != NVME_CQE_SC_GEN_CMD_SEQ_ERR) {
99 warnx("TEST FAILED: %s: found device sc %s (0x%x), "
100 "but expected %s (0x%x)", desc,
101 nvme_sctostr(ctrl, NVME_CSI_NVM, sct, sc), sc,
102 nvme_sctostr(ctrl, NVME_CSI_NVM, sct,
103 NVME_CQE_SC_GEN_CMD_SEQ_ERR),
104 NVME_CQE_SC_GEN_CMD_SEQ_ERR);
105 ret = false;
106 }
107 } else if (pev == NVME_PEV_LSP_READ ||
108 pev == NVME_PEV_LSP_EST_CTX_READ) {
109 if (*buf != NVME_LOGPAGE_PEV) {
110 warnx("TEST FAILED: %s: returned data does not have "
111 "correct LID in byte 0, found 0x%x, expected 0x%x",
112 desc, *buf, NVME_LOGPAGE_PEV);
113 ret = false;
114 }
115 }
116
117 if (ret) {
118 (void) printf("TEST PASSED: %s\n", desc);
119 }
120 done:
121 nvme_log_disc_free(disc);
122 nvme_log_req_fini(req);
123 free(buf);
124 return (ret);
125 }
126
127 int
main(void)128 main(void)
129 {
130 int ret = EXIT_SUCCESS;
131 nvme_t *nvme;
132 nvme_ctrl_t *ctrl;
133
134 libnvme_test_init(&nvme, &ctrl);
135 if (!pev_action(nvme, ctrl, NVME_PEV_LSP_REL_CTX, true,
136 "initial release context works")) {
137 ret = EXIT_FAILURE;
138 }
139
140 if (!pev_action(nvme, ctrl, NVME_PEV_LSP_REL_CTX, true,
141 "second release context works")) {
142 ret = EXIT_FAILURE;
143 }
144
145 if (!pev_action(nvme, ctrl, NVME_PEV_LSP_READ, false,
146 "read without context fails")) {
147 ret = EXIT_FAILURE;
148 }
149
150 if (!pev_action(nvme, ctrl, NVME_PEV_LSP_EST_CTX_READ, true,
151 "establish context and read works")) {
152 ret = EXIT_FAILURE;
153 }
154
155 if (!pev_action(nvme, ctrl, NVME_PEV_LSP_EST_CTX_READ, false,
156 "second establish context and read fails")) {
157 ret = EXIT_FAILURE;
158 }
159
160 if (!pev_action(nvme, ctrl, NVME_PEV_LSP_READ, true,
161 "read with context works")) {
162 ret = EXIT_FAILURE;
163 }
164
165 if (!pev_action(nvme, ctrl, NVME_PEV_LSP_REL_CTX, true,
166 "release after read works")) {
167 ret = EXIT_FAILURE;
168 }
169
170 if (ret == EXIT_SUCCESS) {
171 (void) printf("All tests passed successfully\n");
172 }
173
174 return (ret);
175 }
176