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 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 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