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 2019 Joyent, Inc. 14 */ 15 16 #include <string.h> 17 #include <stdio.h> 18 #include <stdarg.h> 19 #include <stdlib.h> 20 #include <err.h> 21 22 #include "imc_test.h" 23 24 /* 25 * Test runner for the IMC driver and its decoder. This operates by creating 26 * fake topologies and then building a copy of the decoder into this. 27 */ 28 29 static void 30 imc_print(const char *fmt, ...) 31 { 32 va_list ap; 33 34 va_start(ap, fmt); 35 (void) vfprintf(stdout, fmt, ap); 36 va_end(ap); 37 } 38 39 static const char * 40 imc_test_strerror(imc_decode_failure_t fail) 41 { 42 switch (fail) { 43 case IMC_DECODE_F_NONE: 44 return ("Actually succeeded"); 45 case IMC_DECODE_F_LEGACY_RANGE: 46 return ("Asked to decode legacy address"); 47 case IMC_DECODE_F_BAD_SOCKET: 48 return ("BAD socket data"); 49 case IMC_DECODE_F_BAD_SAD: 50 return ("BAD SAD data"); 51 case IMC_DECODE_F_OUTSIDE_DRAM: 52 return ("Address not DRAM"); 53 case IMC_DECODE_F_NO_SAD_RULE: 54 return ("No valid SAD rule"); 55 case IMC_DECODE_F_BAD_SAD_INTERLEAVE: 56 return ("SAD bad interleave target"); 57 case IMC_DECODE_F_BAD_REMOTE_MC_ROUTE: 58 return ("SAD MC_ROUTE refers to non-existent socket"); 59 case IMC_DECODE_F_SAD_SEARCH_LOOP: 60 return ("SAD search looped"); 61 case IMC_DECODE_F_SAD_BAD_MOD: 62 return ("SAD has a bad mod rule"); 63 case IMC_DECODE_F_SAD_BAD_SOCKET: 64 return ("SAD has a bad Socket target"); 65 case IMC_DECODE_F_SAD_BAD_TAD: 66 return ("SAD has a bad TAD target"); 67 case IMC_DECODE_F_NO_TAD_RULE: 68 return ("No valid TAD rule"); 69 case IMC_DECODE_F_TAD_3_ILEAVE: 70 return ("Unsupported 3-way channel interleave"); 71 case IMC_DECODE_F_TAD_BAD_TARGET_INDEX: 72 return ("Bad TAD target index"); 73 case IMC_DECODE_F_BAD_CHANNEL_ID: 74 return ("Bad channel ID"); 75 case IMC_DECODE_F_BAD_CHANNEL_TAD_OFFSET: 76 return ("Bad channel tad offset"); 77 case IMC_DECODE_F_NO_RIR_RULE: 78 return ("No valid rank interleave rule"); 79 case IMC_DECODE_F_BAD_RIR_ILEAVE_TARGET: 80 return ("Bad rank interleave target"); 81 case IMC_DECODE_F_BAD_DIMM_INDEX: 82 return ("Bad DIMM target index"); 83 case IMC_DECODE_F_DIMM_NOT_PRESENT: 84 return ("DIMM not present"); 85 case IMC_DECODE_F_BAD_DIMM_RANK: 86 return ("Bad DIMM rank"); 87 case IMC_DECODE_F_CHANOFF_UNDERFLOW: 88 return ("Channel address offset calculation underflow"); 89 case IMC_DECODE_F_RANKOFF_UNDERFLOW: 90 return ("Rank address offset calculation underflow"); 91 default: 92 return ("<unknown>"); 93 } 94 } 95 96 static const char * 97 imc_test_strenum(imc_decode_failure_t fail) 98 { 99 switch (fail) { 100 case IMC_DECODE_F_NONE: 101 return ("IMC_DECODE_F_NONE"); 102 case IMC_DECODE_F_LEGACY_RANGE: 103 return ("IMC_DECODE_F_LEGACY_RANGE"); 104 case IMC_DECODE_F_BAD_SOCKET: 105 return ("IMC_DECODE_F_BAD_SOCKET"); 106 case IMC_DECODE_F_BAD_SAD: 107 return ("IMC_DECODE_F_BAD_SAD"); 108 case IMC_DECODE_F_OUTSIDE_DRAM: 109 return ("IMC_DECODE_F_OUTSIDE_DRAM"); 110 case IMC_DECODE_F_NO_SAD_RULE: 111 return ("IMC_DECODE_F_NO_SAD_RULE"); 112 case IMC_DECODE_F_BAD_SAD_INTERLEAVE: 113 return ("IMC_DECODE_F_BAD_SAD_INTERLEAVE"); 114 case IMC_DECODE_F_BAD_REMOTE_MC_ROUTE: 115 return ("IMC_DECODE_F_BAD_REMOTE_MC_ROUTE"); 116 case IMC_DECODE_F_SAD_SEARCH_LOOP: 117 return ("IMC_DECODE_F_SAD_SEARCH_LOOP"); 118 case IMC_DECODE_F_SAD_BAD_MOD: 119 return ("IMC_DECODE_F_SAD_BAD_MOD"); 120 case IMC_DECODE_F_SAD_BAD_SOCKET: 121 return ("IMC_DECODE_F_SAD_BAD_SOCKET"); 122 case IMC_DECODE_F_SAD_BAD_TAD: 123 return ("IMC_DECODE_F_SAD_BAD_TAD"); 124 case IMC_DECODE_F_NO_TAD_RULE: 125 return ("IMC_DECODE_F_NO_TAD_RULE"); 126 case IMC_DECODE_F_TAD_3_ILEAVE: 127 return ("IMC_DECODE_F_TAD_3_ILEAVE"); 128 case IMC_DECODE_F_TAD_BAD_TARGET_INDEX: 129 return ("IMC_DECODE_F_TAD_BAD_TARGET_INDEX"); 130 case IMC_DECODE_F_BAD_CHANNEL_ID: 131 return ("IMC_DECODE_F_BAD_CHANNEL_ID"); 132 case IMC_DECODE_F_BAD_CHANNEL_TAD_OFFSET: 133 return ("IMC_DECODE_F_BAD_CHANNEL_TAD_OFFSET"); 134 case IMC_DECODE_F_NO_RIR_RULE: 135 return ("IMC_DECODE_F_NO_RIR_RULE"); 136 case IMC_DECODE_F_BAD_RIR_ILEAVE_TARGET: 137 return ("IMC_DECODE_F_BAD_RIR_ILEAVE_TARGET"); 138 case IMC_DECODE_F_BAD_DIMM_INDEX: 139 return ("IMC_DECODE_F_BAD_DIMM_INDEX"); 140 case IMC_DECODE_F_DIMM_NOT_PRESENT: 141 return ("IMC_DECODE_F_DIMM_NOT_PRESENT"); 142 case IMC_DECODE_F_BAD_DIMM_RANK: 143 return ("IMC_DECODE_F_BAD_DIMM_RANK"); 144 case IMC_DECODE_F_CHANOFF_UNDERFLOW: 145 return ("IMC_DECODE_F_CHANOFF_UNDERFLOW"); 146 case IMC_DECODE_F_RANKOFF_UNDERFLOW: 147 return ("IMC_DECODE_F_RANKOFF_UNDERFLOW"); 148 default: 149 return ("<unknown>"); 150 } 151 } 152 153 static uint_t 154 imc_test_run_one(const imc_test_case_t *test) 155 { 156 imc_decode_state_t dec; 157 boolean_t pass; 158 159 imc_print("Running test: %s\n", test->itc_desc); 160 imc_print("\tDecoding address: 0x%" PRIx64 "\n", test->itc_pa); 161 162 (void) memset(&dec, '\0', sizeof (dec)); 163 pass = imc_decode_pa(test->itc_imc, test->itc_pa, &dec); 164 if (pass && !test->itc_pass) { 165 imc_print("\tdecode unexpectedly succeeded\n"); 166 imc_print("\texpected error '%s' (%s/0x%x)\n", 167 imc_test_strerror(test->itc_fail), 168 imc_test_strenum(test->itc_fail), 169 test->itc_fail); 170 imc_print("\t\tdecoded socket: %u\n", dec.ids_nodeid); 171 imc_print("\t\tdecoded tad: %u\n", dec.ids_tadid); 172 imc_print("\t\tdecoded channel: %u\n", 173 dec.ids_channelid); 174 imc_print("\t\tdecoded channel address: 0x%" PRIx64 "\n", 175 dec.ids_chanaddr); 176 imc_print("\t\tdecoded rank: %u\n", dec.ids_rankid); 177 imc_print("\t\tdecoded rank address: 0x%" PRIx64 "\n", 178 dec.ids_rankaddr); 179 imc_print("\ttest failed\n"); 180 181 return (1); 182 } else if (pass) { 183 uint_t err = 0; 184 185 if (test->itc_nodeid != UINT32_MAX && 186 test->itc_nodeid != dec.ids_nodeid) { 187 imc_print("\tsocket mismatch\n" 188 "\t\texpected %u\n\t\tfound %u\n", 189 test->itc_nodeid, dec.ids_nodeid); 190 err |= 1; 191 } 192 193 if (test->itc_tadid != UINT32_MAX && 194 test->itc_tadid != dec.ids_tadid) { 195 imc_print("\tTAD mismatch\n" 196 "\t\texpected %u\n\t\tfound %u\n", 197 test->itc_tadid, dec.ids_tadid); 198 err |= 1; 199 } 200 201 if (test->itc_channelid != UINT32_MAX && 202 test->itc_channelid != dec.ids_channelid) { 203 imc_print("\tchannel mismatch\n" 204 "\t\texpected %u\n\t\tfound %u\n", 205 test->itc_channelid, dec.ids_channelid); 206 err |= 1; 207 } 208 209 if (test->itc_chanaddr != UINT64_MAX && 210 test->itc_chanaddr != dec.ids_chanaddr) { 211 imc_print("\tchannel address mismatch\n" 212 "\t\texpected 0x%" PRIx64 "\n\t\t" 213 "found 0x%" PRIx64 "\n", 214 test->itc_chanaddr, dec.ids_chanaddr); 215 err |= 1; 216 } 217 218 if (test->itc_dimmid != UINT32_MAX && 219 test->itc_dimmid != dec.ids_dimmid) { 220 imc_print("\tDIMM mismatch\n" 221 "\t\texpected %u\n\t\tfound %u\n", 222 test->itc_dimmid, dec.ids_dimmid); 223 err |= 1; 224 } 225 226 if (test->itc_rankid != UINT32_MAX && 227 test->itc_rankid != dec.ids_rankid) { 228 imc_print("\trank mismatch\n" 229 "\t\texpected %u\n\t\tfound %u\n", 230 test->itc_rankid, dec.ids_rankid); 231 err |= 1; 232 } 233 234 if (test->itc_rankaddr != UINT64_MAX && 235 test->itc_rankaddr != dec.ids_rankaddr) { 236 imc_print("\trank address mismatch\n" 237 "\t\texpected 0x%" PRIx64 "\n\t\t" 238 "found 0x%" PRIx64 "\n", 239 test->itc_rankaddr, dec.ids_rankaddr); 240 err |= 1; 241 } 242 243 if (err) { 244 imc_print("\tDecoding failed\n"); 245 } else { 246 imc_print("\tDecoded successfully\n"); 247 } 248 249 return (err); 250 } else if (!pass && !test->itc_pass) { 251 if (dec.ids_fail != test->itc_fail) { 252 imc_print("\terror mismatch\n" 253 "\t\texpected '%s' (%s/0x%x)\n\t\tfound '%s' " 254 "(%s/0x%x)\n", imc_test_strerror(test->itc_fail), 255 imc_test_strenum(test->itc_fail), test->itc_fail, 256 imc_test_strerror(dec.ids_fail), 257 imc_test_strenum(dec.ids_fail), dec.ids_fail); 258 return (1); 259 } 260 261 imc_print("\tCorrect decoding error generated\n"); 262 return (0); 263 } else { 264 imc_print("\tdecode failed with '%s' (%s/0x%x)\n", 265 imc_test_strerror(dec.ids_fail), 266 imc_test_strenum(dec.ids_fail), 267 dec.ids_fail); 268 if (test->itc_nodeid != UINT32_MAX) { 269 imc_print("\t\texpected socket: %u\n", 270 test->itc_nodeid); 271 } 272 273 if (test->itc_tadid != UINT32_MAX) { 274 imc_print("\t\texpected tad: %u\n", test->itc_tadid); 275 } 276 277 if (test->itc_channelid != UINT32_MAX) { 278 imc_print("\t\texpected channel: %u\n", 279 test->itc_channelid); 280 } 281 282 if (test->itc_chanaddr != UINT64_MAX) { 283 imc_print("\t\texpected channel address: 0x%" PRIx64 284 "\n", test->itc_chanaddr); 285 } 286 287 if (test->itc_rankid != UINT32_MAX) { 288 imc_print("\t\texpected rank: %u\n", 289 test->itc_rankid); 290 } 291 292 if (test->itc_rankaddr != UINT64_MAX) { 293 imc_print("\t\texpected rank address: 0x%" PRIx64 "\n", 294 test->itc_rankaddr); 295 } 296 297 imc_print("\tdecode failed, expected pass\n"); 298 299 return (1); 300 } 301 } 302 303 static void 304 imc_test_run(const imc_test_case_t *tests, uint_t *ntests, uint_t *nfail) 305 { 306 while (tests[0].itc_desc != NULL) { 307 *nfail += imc_test_run_one(tests); 308 *ntests += 1; 309 tests++; 310 } 311 } 312 313 int 314 main(int argc, char *argv[]) 315 { 316 uint_t ntests = 0, nfail = 0; 317 int i; 318 319 if (argc > 1) { 320 for (i = 1; i < argc; i++) { 321 if (strcmp(argv[i], "basic") == 0) { 322 imc_test_run(imc_test_basics, &ntests, &nfail); 323 } else if (strcmp(argv[i], "badaddr") == 0) { 324 imc_test_run(imc_test_badaddr, &ntests, &nfail); 325 } else if (strcmp(argv[i], "sad") == 0) { 326 imc_test_run(imc_test_sad, &ntests, &nfail); 327 } else if (strcmp(argv[i], "skx_loop") == 0) { 328 imc_test_run(imc_test_skx_loop, &ntests, 329 &nfail); 330 } else if (strcmp(argv[i], "tad") == 0) { 331 imc_test_run(imc_test_tad, &ntests, &nfail); 332 } else if (strcmp(argv[i], "rir") == 0) { 333 imc_test_run(imc_test_rir, &ntests, &nfail); 334 } else if (strcmp(argv[i], "fail") == 0) { 335 imc_test_run(imc_test_fail, &ntests, &nfail); 336 } else { 337 errx(EXIT_FAILURE, "Unknown test argument %s", 338 argv[i]); 339 } 340 } 341 } else { 342 imc_test_run(imc_test_basics, &ntests, &nfail); 343 imc_test_run(imc_test_badaddr, &ntests, &nfail); 344 imc_test_run(imc_test_skx_loop, &ntests, &nfail); 345 imc_test_run(imc_test_rir, &ntests, &nfail); 346 imc_test_run(imc_test_tad, &ntests, &nfail); 347 imc_test_run(imc_test_sad, &ntests, &nfail); 348 imc_test_run(imc_test_fail, &ntests, &nfail); 349 } 350 351 imc_print("%u/%u tests passed\n", ntests - nfail, ntests); 352 return (nfail > 0); 353 } 354