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 a few different bits of the status code string generation and see that 18 * we get something expected. Note, we try to avoid using the existing constants 19 * that we have for the sct / sc when testing the corresponding entries so 20 * someone can more so copy and paste entries from the spec and be less tempted 21 * to copy data from the implementation. 22 */ 23 24 #include <stdbool.h> 25 #include <stdlib.h> 26 #include <err.h> 27 #include <stdio.h> 28 #include <strings.h> 29 #include <sys/sysmacros.h> 30 #include <libnvme.h> 31 32 typedef struct { 33 uint32_t st_code; 34 const char *st_str; 35 } sct_test_t; 36 37 static const sct_test_t sct_tests[] = { { 38 .st_code = 0, 39 .st_str = "generic command status", 40 }, { 41 .st_code = 7, 42 .st_str = "vendor specific" 43 }, { 44 .st_code = 0x23, 45 .st_str = "unknown status type" 46 }, { 47 .st_code = 0x169, 48 .st_str = "unknown status type" 49 } }; 50 51 typedef struct { 52 nvme_csi_t sc_csi; 53 uint32_t sc_sct; 54 uint32_t sc_sc; 55 const char *sc_str; 56 } sc_test_t; 57 58 static const sc_test_t sc_tests[] = { { 59 .sc_csi = NVME_CSI_NVM, 60 .sc_sct = NVME_CQE_SCT_GENERIC, 61 .sc_sc = 0x0, 62 .sc_str = "successful completion" 63 }, { 64 .sc_csi = NVME_CSI_NVM, 65 .sc_sct = NVME_CQE_SCT_GENERIC, 66 .sc_sc = 0x2, 67 .sc_str = "invalid field in command" 68 }, { 69 .sc_csi = NVME_CSI_NVM, 70 .sc_sct = NVME_CQE_SCT_GENERIC, 71 .sc_sc = 0xb, 72 .sc_str = "invalid namespace or format" 73 }, { 74 /* 75 * This is a purposefully bad CSI, but the CSI shouldn't matter for this 76 * code. 77 */ 78 .sc_csi = 0xff, 79 .sc_sct = NVME_CQE_SCT_GENERIC, 80 .sc_sc = 0xb, 81 .sc_str = "invalid namespace or format" 82 }, { 83 .sc_csi = NVME_CSI_NVM, 84 .sc_sct = NVME_CQE_SCT_GENERIC, 85 .sc_sc = 0x7f, 86 .sc_str = "unknown status code", 87 }, { 88 .sc_csi = NVME_CSI_NVM, 89 .sc_sct = NVME_CQE_SCT_GENERIC, 90 .sc_sc = 0x80, 91 .sc_str = "lba out of range" 92 }, { 93 .sc_csi = NVME_CSI_NVM, 94 .sc_sct = NVME_CQE_SCT_GENERIC, 95 .sc_sc = 0x82, 96 .sc_str = "namespace not ready" 97 }, { 98 .sc_csi = NVME_CSI_NVM, 99 .sc_sct = NVME_CQE_SCT_GENERIC, 100 .sc_sc = 0xbf, 101 .sc_str = "unknown command set specific general status code" 102 103 }, { 104 .sc_csi = NVME_CSI_NVM, 105 .sc_sct = NVME_CQE_SCT_GENERIC, 106 .sc_sc = 0xff, 107 .sc_str = "generic vendor specific status code" 108 }, { 109 .sc_csi = NVME_CSI_NVM, 110 .sc_sct = NVME_CQE_SCT_SPECIFIC, 111 .sc_sc = 0x6, 112 .sc_str = "invalid firmware slot" 113 }, { 114 .sc_csi = NVME_CSI_NVM, 115 .sc_sct = NVME_CQE_SCT_SPECIFIC, 116 .sc_sc = 0x9, 117 .sc_str = "invalid log page" 118 }, { 119 .sc_csi = NVME_CSI_NVM, 120 .sc_sct = NVME_CQE_SCT_SPECIFIC, 121 .sc_sc = 0x6f, 122 .sc_str = "unknown generic command status code" 123 }, { 124 .sc_csi = NVME_CSI_NVM, 125 .sc_sct = NVME_CQE_SCT_SPECIFIC, 126 .sc_sc = 0x80, 127 .sc_str = "conflicting attributes" 128 }, { 129 .sc_csi = NVME_CSI_NVM, 130 .sc_sct = NVME_CQE_SCT_SPECIFIC, 131 .sc_sc = 0xbf, 132 .sc_str = "unknown command specific, I/O command set specific status " 133 "code", 134 }, { 135 .sc_csi = NVME_CSI_NVM, 136 .sc_sct = NVME_CQE_SCT_SPECIFIC, 137 .sc_sc = 0xff, 138 .sc_str = "command specific vendor specific status code" 139 }, { 140 .sc_csi = NVME_CSI_NVM, 141 .sc_sct = NVME_CQE_SCT_INTEGRITY, 142 .sc_sc = 0x80, 143 .sc_str = "write fault" 144 }, { 145 .sc_csi = 0x23, 146 .sc_sct = NVME_CQE_SCT_INTEGRITY, 147 .sc_sc = 0x80, 148 .sc_str = "write fault" 149 }, { 150 .sc_csi = NVME_CSI_NVM, 151 .sc_sct = NVME_CQE_SCT_INTEGRITY, 152 .sc_sc = 0x0, 153 .sc_str = "unknown media and data integrity status code" 154 }, { 155 .sc_csi = NVME_CSI_NVM, 156 .sc_sct = NVME_CQE_SCT_INTEGRITY, 157 .sc_sc = 0xff, 158 .sc_str = "vendor specific media and data integrity status code" 159 } }; 160 161 static bool 162 sct_test_one(const sct_test_t *test) 163 { 164 const char *str = nvme_scttostr(NULL, test->st_code); 165 if (strcmp(str, test->st_str) != 0) { 166 warnx("TEST FAILED: sct 0x%x was translated to string %s, " 167 "not %s", test->st_code, str, test->st_str); 168 return (false); 169 } 170 171 (void) printf("TEST PASSED: sct 0x%x successfully translated\n", 172 test->st_code); 173 return (true); 174 } 175 176 static bool 177 sc_test_one(const sc_test_t *test) 178 { 179 const char *str = nvme_sctostr(NULL, test->sc_csi, test->sc_sct, 180 test->sc_sc); 181 if (strcmp(str, test->sc_str) != 0) { 182 warnx("TEST FAILED: csi/sct/sc 0x%x/0x%x/0x%x was translated " 183 "to string %s, not %s", test->sc_csi, test->sc_sct, 184 test->sc_sc, str, test->sc_str); 185 return (false); 186 } 187 188 (void) printf("TEST PASSED: csi/sct/sc 0x%x/0x%x/0x%x successfully " 189 "translated\n", test->sc_csi, test->sc_sct, test->sc_sc); 190 191 return (true); 192 } 193 194 int 195 main(void) 196 { 197 int ret = EXIT_SUCCESS; 198 199 for (size_t i = 0; i < ARRAY_SIZE(sct_tests); i++) { 200 if (!sct_test_one(&sct_tests[i])) { 201 ret = EXIT_FAILURE; 202 } 203 } 204 205 for (size_t i = 0; i < ARRAY_SIZE(sc_tests); i++) { 206 if (!sc_test_one(&sc_tests[i])) { 207 ret = EXIT_FAILURE; 208 } 209 } 210 211 return (ret); 212 } 213