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 * This file contains several synthetic controllers that we plan to use 18 * throughout the rest of our various unit tests. We define rather minimal bits 19 * of the identify controller data structures here. The relevant bits for these 20 * tests are generally the following: 21 * 22 * - Firmware Commit and Download -- id_oacs.oa_firmware (1.0) 23 * - Firmware Update Granularity -- ap_fwug (1.3) 24 * - Format NVM Support -- id_oacs.oa_format (1.0) 25 * - Volatile Write Cache Present -- id_vwc.vwc_present (1.0) 26 * - Autonomous Power State Suport -- id_apsta.ap_sup (1.1) 27 * - Namespace Count -- id_nn (1.0) 28 * - Namespace Management -- id_oacs.oa_nsmgmt (1.2) 29 * - Save/Select in Get/Set Feat -- id_oncs.on_save (1.1) 30 * - Extended Get Log Page -- id_lpa.lp_extsup (1.2) 31 * - Smart/Health Info per NS -- id_lpa.lp_smart (1.0) 32 * - Error Log Page Entries -- id_elpe (1.0) (Z) 33 * - Namespace Change Notices -- id_oaes.oaes_nsan (1.2) 34 * 35 * Note, we skip adding the controller version mostly because our common code 36 * doesn't use it and that way we can reuse entries more often. Items that the 37 * spec defines as zeros based are indicated with a trailing Z. That means that 38 * software will treat the value as what's there + 1. 39 */ 40 41 #include <err.h> 42 #include <stdio.h> 43 44 #include "nvme_unit.h" 45 46 /* 47 * We start with a basic controller. This has a single namespace and supports 48 * the optional format and firmware commands. It doesn't have a volatile write 49 * cache. 50 */ 51 static const nvme_identify_ctrl_t nvme_ctrl_base = { 52 .id_oacs = { 53 .oa_firmware = 1, 54 .oa_format = 1 55 }, 56 .id_nn = 1, 57 .id_frmw = { 58 .fw_nslot = 1 59 }, 60 .id_elpe = 3 61 }; 62 63 const nvme_valid_ctrl_data_t nvme_ctrl_base_1v0 = { 64 .vcd_vers = &nvme_vers_1v0, 65 .vcd_id = &nvme_ctrl_base 66 }; 67 68 const nvme_valid_ctrl_data_t nvme_ctrl_base_1v1 = { 69 .vcd_vers = &nvme_vers_1v1, 70 .vcd_id = &nvme_ctrl_base 71 }; 72 73 const nvme_valid_ctrl_data_t nvme_ctrl_base_1v2 = { 74 .vcd_vers = &nvme_vers_1v2, 75 .vcd_id = &nvme_ctrl_base 76 }; 77 78 const nvme_valid_ctrl_data_t nvme_ctrl_base_2v0 = { 79 .vcd_vers = &nvme_vers_2v0, 80 .vcd_id = &nvme_ctrl_base 81 }; 82 83 84 /* 85 * An NVMe 1.0 version of the base controller with per-NS Health. 86 */ 87 static const nvme_identify_ctrl_t nvme_ctrl_base_health = { 88 .id_oacs = { 89 .oa_firmware = 1, 90 .oa_format = 1 91 }, 92 .id_lpa = { 93 .lp_smart = 1 94 }, 95 .id_nn = 1, 96 .id_frmw = { 97 .fw_nslot = 1 98 }, 99 .id_elpe = 3 100 }; 101 102 const nvme_valid_ctrl_data_t nvme_ctrl_health_1v0 = { 103 .vcd_vers = &nvme_vers_1v0, 104 .vcd_id = &nvme_ctrl_base_health 105 }; 106 107 /* 108 * Next, a more complex controller that has all the current optional features. 109 * It has namespace support with 128 namespaces. 110 */ 111 static const nvme_identify_ctrl_t nvme_ctrl_fancy = { 112 .id_oacs = { 113 .oa_firmware = 1, 114 .oa_format = 1, 115 .oa_nsmgmt = 1 116 }, 117 .id_oncs = { 118 .on_save = 1, 119 }, 120 .id_vwc = { 121 .vwc_present = 1 122 }, 123 .id_apsta = { 124 .ap_sup = 1 125 }, 126 .id_nn = 128, 127 .id_frmw = { 128 .fw_nslot = 1 129 }, 130 .id_lpa = { 131 .lp_extsup = 1, 132 .lp_smart = 1 133 }, 134 .id_oaes = { 135 .oaes_nsan = 1 136 } 137 }; 138 139 const nvme_valid_ctrl_data_t nvme_ctrl_ns_1v2 = { 140 .vcd_vers = &nvme_vers_1v2, 141 .vcd_id = &nvme_ctrl_fancy 142 }; 143 144 const nvme_valid_ctrl_data_t nvme_ctrl_ns_1v3 = { 145 .vcd_vers = &nvme_vers_1v3, 146 .vcd_id = &nvme_ctrl_fancy 147 }; 148 149 const nvme_valid_ctrl_data_t nvme_ctrl_ns_1v4 = { 150 .vcd_vers = &nvme_vers_1v4, 151 .vcd_id = &nvme_ctrl_fancy 152 }; 153 154 const nvme_valid_ctrl_data_t nvme_ctrl_ns_2v0 = { 155 .vcd_vers = &nvme_vers_2v0, 156 .vcd_id = &nvme_ctrl_fancy 157 }; 158 159 /* 160 * This next controller is designed to help test log size and offset properties. 161 * A log offset is only allowed if the corresponding LPA is set. Similarly, the 162 * length changes from 12 bits to 32 bits of dwords when that is present. 163 */ 164 static const nvme_identify_ctrl_t nvme_ctrl_nolpa = { 165 .id_oacs = { 166 .oa_firmware = 1, 167 .oa_format = 1, 168 .oa_nsmgmt = 1 169 }, 170 .id_oncs = { 171 .on_save = 1, 172 }, 173 .id_vwc = { 174 .vwc_present = 1 175 }, 176 .id_apsta = { 177 .ap_sup = 1 178 }, 179 .id_nn = 128, 180 .id_frmw = { 181 .fw_nslot = 1 182 }, 183 .id_oaes = { 184 .oaes_nsan = 1 185 } 186 }; 187 188 const nvme_valid_ctrl_data_t nvme_ctrl_nolpa_1v4 = { 189 .vcd_vers = &nvme_vers_1v4, 190 .vcd_id = &nvme_ctrl_nolpa 191 }; 192 193 /* 194 * A variant on the fancy controller without namespace management. 195 */ 196 static const nvme_identify_ctrl_t nvme_ctrl_nons = { 197 .id_oacs = { 198 .oa_firmware = 1, 199 .oa_format = 1, 200 }, 201 .id_oncs = { 202 .on_save = 1, 203 }, 204 .id_vwc = { 205 .vwc_present = 1 206 }, 207 .id_apsta = { 208 .ap_sup = 1 209 }, 210 .id_nn = 1, 211 .id_frmw = { 212 .fw_nslot = 1 213 }, 214 .id_lpa = { 215 .lp_extsup = 1, 216 .lp_smart = 1 217 }, 218 .id_oaes = { 219 .oaes_nsan = 1 220 } 221 }; 222 223 const nvme_valid_ctrl_data_t nvme_ctrl_nons_1v3 = { 224 .vcd_vers = &nvme_vers_1v3, 225 .vcd_id = &nvme_ctrl_nons 226 }; 227 228 const nvme_valid_ctrl_data_t nvme_ctrl_nons_1v4 = { 229 .vcd_vers = &nvme_vers_1v4, 230 .vcd_id = &nvme_ctrl_nons 231 }; 232 233 const nvme_valid_ctrl_data_t nvme_ctrl_nons_2v0 = { 234 .vcd_vers = &nvme_vers_2v0, 235 .vcd_id = &nvme_ctrl_nons 236 }; 237 238 /* 239 * This is a controller that supports none of the optional features at all. 240 */ 241 static const nvme_identify_ctrl_t nvme_ctrl_nocmds = { 242 .id_nn = 1, 243 .id_frmw = { 244 .fw_nslot = 1 245 }, 246 }; 247 248 const nvme_valid_ctrl_data_t nvme_ctrl_nocmds_1v0 = { 249 .vcd_vers = &nvme_vers_1v0, 250 .vcd_id = &nvme_ctrl_nocmds 251 }; 252 253 /* 254 * Controllers with explicitly no granularity and one with 8k. 255 */ 256 static const nvme_identify_ctrl_t nvme_ctrl_nogran = { 257 .id_oacs = { 258 .oa_firmware = 1, 259 .oa_format = 1, 260 }, 261 .id_oncs = { 262 .on_save = 1 263 }, 264 .id_frmw = { 265 .fw_nslot = 3 266 }, 267 .id_nn = 1, 268 .ap_fwug = 0xff 269 }; 270 271 static const nvme_identify_ctrl_t nvme_ctrl_8kgran = { 272 .id_oacs = { 273 .oa_firmware = 1, 274 .oa_format = 1, 275 }, 276 .id_oncs = { 277 .on_save = 1 278 }, 279 .id_frmw = { 280 .fw_nslot = 7 281 }, 282 .id_nn = 1, 283 .ap_fwug = 0x2 284 }; 285 286 const nvme_valid_ctrl_data_t nvme_ctrl_nogran_1v3 = { 287 .vcd_vers = &nvme_vers_1v3, 288 .vcd_id = &nvme_ctrl_nogran 289 }; 290 291 const nvme_valid_ctrl_data_t nvme_ctrl_8kgran_1v3 = { 292 .vcd_vers = &nvme_vers_1v3, 293 .vcd_id = &nvme_ctrl_8kgran 294 }; 295 296 static const char * 297 nvme_field_error_to_str(nvme_field_error_t err) 298 { 299 switch (err) { 300 case NVME_FIELD_ERR_OK: 301 return ("NVME_FIELD_ERR_OK"); 302 case NVME_FIELD_ERR_UNSUP_VERSION: 303 return ("NVME_FIELD_ERR_UNSUP_VERSION"); 304 case NVME_FIELD_ERR_UNSUP_FIELD: 305 return ("NVME_FIELD_ERR_UNSUP_FIELD"); 306 case NVME_FIELD_ERR_BAD_VALUE: 307 return ("NVME_FIELD_ERR_BAD_VALUE"); 308 default: 309 return ("unknown"); 310 } 311 } 312 313 static bool 314 nvme_unit_field_test_one(const nvme_unit_field_test_t *test) 315 { 316 char buf[128]; 317 const nvme_field_info_t *field; 318 nvme_field_error_t err; 319 320 buf[0] = '\0'; 321 field = &test->nu_fields[test->nu_index]; 322 err = nvme_field_validate(field, test->nu_data, test->nu_value, buf, 323 sizeof (buf)); 324 325 if (err != test->nu_ret) { 326 warnx("TEST FAILED: %s: found wrong return value %s (%u), " 327 "expected %s (%u)", test->nu_desc, 328 nvme_field_error_to_str(err), err, 329 nvme_field_error_to_str(test->nu_ret), test->nu_ret); 330 return (false); 331 } 332 333 (void) printf("TEST PASSED: %s: got correct return value\n", 334 test->nu_desc); 335 if (err != NVME_FIELD_ERR_OK && buf[0] == '\0') { 336 warnx("TEST FAILED: %s: error buffer was empty", test->nu_desc); 337 return (false); 338 } else if (err == NVME_FIELD_ERR_OK && buf[0] != '\0') { 339 warnx("TEST FAILED: %s: error buffer was not empty", 340 test->nu_desc); 341 return (false); 342 } 343 344 (void) printf("TEST PASSED: %s: error buffer properly formed\n", 345 test->nu_desc); 346 return (true); 347 } 348 349 bool 350 nvme_unit_field_test(const nvme_unit_field_test_t *tests, size_t ntests) 351 { 352 bool ret = true; 353 354 for (size_t i = 0; i < ntests; i++) { 355 if (!nvme_unit_field_test_one(&tests[i])) { 356 ret = false; 357 } 358 } 359 360 return (ret); 361 } 362