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 (c) 2018, Joyent, Inc. 14 * Copyright 2021 Oxide Computer Company 15 */ 16 17 /* 18 * Basic testing of the SMBIOS 3.2 Slot extensions. 19 */ 20 21 #include "smbios_test.h" 22 23 static const char *smbios_test_name = "The One Slot"; 24 static uint8_t smbios_slot_bus = 0x42; 25 static uint8_t smbios_slot_df = 0x23; 26 static uint8_t smbios_slot_info = 0x65; 27 static uint16_t smbios_slot_pitch = 0x12af; 28 29 static size_t smbios_slot_34_contlen = offsetof(smb_slot_cont_t, smbsl_height); 30 31 static void 32 smbios_test_slot_fill(smb_slot_t *slot) 33 { 34 bzero(slot, sizeof (smb_slot_t)); 35 slot->smbsl_hdr.smbh_type = SMB_TYPE_SLOT; 36 slot->smbsl_hdr.smbh_len = sizeof (smb_slot_t); 37 slot->smbsl_name = 1; 38 slot->smbsl_type = SMB_SLT_PCIE3G16; 39 slot->smbsl_width = SMB_SLW_16X; 40 slot->smbsl_length = SMB_SLL_SHORT; 41 slot->smbsl_id = htole16(1); 42 slot->smbsl_ch1 = SMB_SLCH1_33V; 43 slot->smbsl_ch2 = SMB_SLCH2_PME; 44 slot->smbsl_sg = htole16(1); 45 slot->smbsl_bus = smbios_slot_bus; 46 slot->smbsl_df = smbios_slot_df; 47 slot->smbsl_dbw = SMB_SLW_16X; 48 } 49 50 boolean_t 51 smbios_test_slot_mktable(smbios_test_table_t *table) 52 { 53 smb_slot_t slot; 54 smb_slot_peer_t peers[2]; 55 56 smbios_test_slot_fill(&slot); 57 58 slot.smbsl_hdr.smbh_len += sizeof (peers); 59 slot.smbsl_npeers = 2; 60 61 peers[0].smbspb_group_no = htole16(1); 62 peers[0].smbspb_bus = 0x42; 63 peers[0].smbspb_df = 0x42; 64 peers[0].smbspb_width = SMB_SLW_8X; 65 66 peers[1].smbspb_group_no = htole16(1); 67 peers[1].smbspb_bus = 0x23; 68 peers[1].smbspb_df = 0x31; 69 peers[1].smbspb_width = SMB_SLW_8X; 70 71 (void) smbios_test_table_append(table, &slot, sizeof (slot)); 72 smbios_test_table_append_raw(table, peers, sizeof (peers)); 73 smbios_test_table_append_string(table, smbios_test_name); 74 smbios_test_table_str_fini(table); 75 76 smbios_test_table_append_eot(table); 77 78 return (B_TRUE); 79 } 80 81 static boolean_t 82 smbios_test_slot_mktable_nopeers(smbios_test_table_t *table, boolean_t is_35) 83 { 84 smb_slot_t slot; 85 smb_slot_cont_t cont; 86 size_t contlen; 87 88 if (is_35) { 89 contlen = sizeof (cont); 90 } else { 91 contlen = smbios_slot_34_contlen; 92 } 93 94 smbios_test_slot_fill(&slot); 95 slot.smbsl_hdr.smbh_len = SMB_SLOT_CONT_START + contlen; 96 97 cont.smbsl_info = smbios_slot_info; 98 cont.smbsl_pwidth = SMB_SLW_32X; 99 cont.smbsl_pitch = htole16(smbios_slot_pitch); 100 cont.smbsl_height = SMB_SLHT_LP; 101 102 (void) smbios_test_table_append(table, &slot, sizeof (slot)); 103 smbios_test_table_append_raw(table, &cont, contlen); 104 smbios_test_table_append_string(table, smbios_test_name); 105 smbios_test_table_str_fini(table); 106 smbios_test_table_append_eot(table); 107 108 return (B_TRUE); 109 } 110 111 /* 112 * 3.4 introduced additional data after peers. This version constructs a variant 113 * with no peers. 114 */ 115 boolean_t 116 smbios_test_slot_mktable_34_nopeers(smbios_test_table_t *table) 117 { 118 return (smbios_test_slot_mktable_nopeers(table, B_FALSE)); 119 } 120 121 boolean_t 122 smbios_test_slot_mktable_35(smbios_test_table_t *table) 123 { 124 return (smbios_test_slot_mktable_nopeers(table, B_TRUE)); 125 } 126 127 boolean_t 128 smbios_test_slot_mktable_34_peers(smbios_test_table_t *table) 129 { 130 smb_slot_t slot; 131 smb_slot_cont_t cont; 132 smb_slot_peer_t peers[1]; 133 134 smbios_test_slot_fill(&slot); 135 slot.smbsl_npeers = 1; 136 slot.smbsl_hdr.smbh_len = SMB_SLOT_CONT_START + 5 * slot.smbsl_npeers + 137 smbios_slot_34_contlen; 138 139 peers[0].smbspb_group_no = htole16(1); 140 peers[0].smbspb_bus = 0x42; 141 peers[0].smbspb_df = 0x9a; 142 peers[0].smbspb_width = SMB_SLW_8X; 143 144 cont.smbsl_info = smbios_slot_info; 145 cont.smbsl_pwidth = SMB_SLW_32X; 146 cont.smbsl_pitch = htole16(smbios_slot_pitch); 147 148 (void) smbios_test_table_append(table, &slot, sizeof (slot)); 149 smbios_test_table_append_raw(table, peers, sizeof (peers)); 150 smbios_test_table_append_raw(table, &cont, smbios_slot_34_contlen); 151 smbios_test_table_append_string(table, smbios_test_name); 152 smbios_test_table_str_fini(table); 153 smbios_test_table_append_eot(table); 154 return (B_TRUE); 155 } 156 157 static boolean_t 158 smbios_test_slot_common(smbios_slot_t *slot) 159 { 160 uint_t errs = 0; 161 162 if (strcmp(slot->smbl_name, smbios_test_name) != 0) { 163 warnx("slot name mismatch, expected %s, found %s", 164 smbios_test_name, slot->smbl_name); 165 errs++; 166 } 167 168 if (slot->smbl_type != SMB_SLT_PCIE3G16) { 169 warnx("incorrect slot type, found %u", slot->smbl_type); 170 errs++; 171 } 172 173 if (slot->smbl_width != SMB_SLW_16X) { 174 warnx("incorrect slot width, found %u", slot->smbl_width); 175 errs++; 176 } 177 178 if (slot->smbl_length != SMB_SLL_SHORT) { 179 warnx("incorrect slot length, found %u", slot->smbl_length); 180 errs++; 181 } 182 183 if (slot->smbl_dbw != SMB_SLW_16X) { 184 warnx("incorrect slot data bus width, found %u", 185 slot->smbl_dbw); 186 errs++; 187 } 188 189 if (slot->smbl_bus != smbios_slot_bus) { 190 warnx("incorrect slot bus id, found 0x%x\n", slot->smbl_bus); 191 } 192 193 if (slot->smbl_df != smbios_slot_df) { 194 warnx("incorrect slot df id, found 0x%x\n", slot->smbl_df); 195 } 196 197 if (errs > 0) { 198 return (B_FALSE); 199 } 200 201 return (B_TRUE); 202 } 203 204 boolean_t 205 smbios_test_slot_verify(smbios_hdl_t *hdl) 206 { 207 smbios_struct_t sp; 208 smbios_slot_t slot; 209 uint_t npeers; 210 smbios_slot_peer_t *peers; 211 uint_t errs = 0; 212 213 if (smbios_lookup_type(hdl, SMB_TYPE_SLOT, &sp) == -1) { 214 warnx("failed to lookup SMBIOS slot: %s", 215 smbios_errmsg(smbios_errno(hdl))); 216 return (B_FALSE); 217 } 218 219 if (smbios_info_slot(hdl, sp.smbstr_id, &slot) != 0) { 220 warnx("failed to get SMBIOS slot info: %s", 221 smbios_errmsg(smbios_errno(hdl))); 222 return (B_FALSE); 223 } 224 225 if (!smbios_test_slot_common(&slot)) { 226 errs++; 227 } 228 229 if (slot.smbl_npeers != 2) { 230 warnx("incorrect number of slot peers, found %u", 231 slot.smbl_npeers); 232 errs++; 233 } 234 235 if (smbios_info_slot_peers(hdl, sp.smbstr_id, &npeers, &peers) != 0) { 236 warnx("failed to get SMBIOS peer info: %s", 237 smbios_errmsg(smbios_errno(hdl))); 238 return (B_FALSE); 239 } 240 241 if (npeers != 2) { 242 warnx("got wrong number of slot peers: %u", npeers); 243 return (B_FALSE); 244 } 245 246 if (peers[0].smblp_group != 1) { 247 warnx("incorrect group for peer 0: %u", peers[0].smblp_group); 248 errs++; 249 } 250 251 if (peers[0].smblp_data_width != SMB_SLW_8X) { 252 warnx("incorrect data width for peer 0: %u", 253 peers[0].smblp_data_width); 254 errs++; 255 } 256 257 if (peers[0].smblp_device != (0x42 >> 3)) { 258 warnx("incorrect PCI device for peer 0: %u", 259 peers[0].smblp_device); 260 errs++; 261 } 262 263 if (peers[0].smblp_function != (0x42 & 0x7)) { 264 warnx("incorrect PCI function for peer 0: %u", 265 peers[0].smblp_function); 266 errs++; 267 } 268 269 if (peers[1].smblp_group != 1) { 270 warnx("incorrect group for peer 1: %u", peers[1].smblp_group); 271 errs++; 272 } 273 274 if (peers[1].smblp_device != (0x31 >> 3)) { 275 warnx("incorrect PCI device for peer 1: %u", 276 peers[1].smblp_device); 277 errs++; 278 } 279 280 if (peers[1].smblp_function != (0x31 & 0x7)) { 281 warnx("incorrect PCI function for peer 1: %u", 282 peers[1].smblp_function); 283 errs++; 284 } 285 286 if (peers[1].smblp_data_width != SMB_SLW_8X) { 287 warnx("incorrect data width for peer 1: %u", 288 peers[1].smblp_data_width); 289 errs++; 290 } 291 292 smbios_info_slot_peers_free(hdl, npeers, peers); 293 294 if (slot.smbl_info != 0) { 295 warnx("found wrong slot info: 0x%x", slot.smbl_info); 296 errs++; 297 } 298 299 if (slot.smbl_pwidth != 0) { 300 warnx("found wrong slot physical width: 0x%x", 301 slot.smbl_pwidth); 302 errs++; 303 } 304 305 if (slot.smbl_pitch != 0) { 306 warnx("found wrong slot pitch: 0x%x", slot.smbl_pitch); 307 errs++; 308 } 309 310 if (errs > 0) { 311 return (B_FALSE); 312 } 313 314 return (B_TRUE); 315 } 316 317 static boolean_t 318 smbios_test_slot_common_nopeers(smbios_hdl_t *hdl, smbios_struct_t *sp, 319 smbios_slot_t *slot) 320 { 321 uint_t errs = 0; 322 uint_t npeers; 323 smbios_slot_peer_t *peers; 324 325 if (slot->smbl_npeers != 0) { 326 warnx("incorrect number of slot peers, found %u", 327 slot->smbl_npeers); 328 errs++; 329 } 330 331 if (smbios_info_slot_peers(hdl, sp->smbstr_id, &npeers, &peers) != 0) { 332 warnx("failed to get SMBIOS peer info: %s", 333 smbios_errmsg(smbios_errno(hdl))); 334 return (B_FALSE); 335 } 336 337 if (npeers != 0) { 338 warnx("got wrong number of slot peers: %u", npeers); 339 errs++; 340 } 341 342 if (peers != NULL) { 343 warnx("expected NULL peers pointer, but found %p", peers); 344 errs++; 345 } 346 347 smbios_info_slot_peers_free(hdl, npeers, peers); 348 349 if (slot->smbl_info != smbios_slot_info) { 350 warnx("found wrong slot info: 0x%x, expected 0x%x", 351 slot->smbl_info, smbios_slot_info); 352 errs++; 353 } 354 355 if (slot->smbl_pwidth != SMB_SLW_32X) { 356 warnx("found wrong slot physical width: 0x%x, expected 0x%x", 357 slot->smbl_pwidth, SMB_SLW_32X); 358 errs++; 359 } 360 361 if (slot->smbl_pitch != smbios_slot_pitch) { 362 warnx("found wrong slot pitch: 0x%x, expected 0x%x", 363 slot->smbl_pitch, smbios_slot_pitch); 364 errs++; 365 } 366 367 return (errs == 0); 368 } 369 370 boolean_t 371 smbios_test_slot_verify_34_nopeers(smbios_hdl_t *hdl) 372 { 373 smbios_struct_t sp; 374 smbios_slot_t slot; 375 uint_t errs = 0; 376 377 if (smbios_lookup_type(hdl, SMB_TYPE_SLOT, &sp) == -1) { 378 warnx("failed to lookup SMBIOS slot: %s", 379 smbios_errmsg(smbios_errno(hdl))); 380 return (B_FALSE); 381 } 382 383 if (smbios_info_slot(hdl, sp.smbstr_id, &slot) != 0) { 384 warnx("failed to get SMBIOS slot info: %s", 385 smbios_errmsg(smbios_errno(hdl))); 386 return (B_FALSE); 387 } 388 389 if (!smbios_test_slot_common(&slot)) { 390 errs++; 391 } 392 393 if (!smbios_test_slot_common_nopeers(hdl, &sp, &slot)) { 394 errs++; 395 } 396 397 if (errs > 0) { 398 return (B_FALSE); 399 } 400 401 return (B_TRUE); 402 } 403 404 /* 405 * This is a variant of smbios_test_slot_verify_34_nopeers() that specifically 406 * uses an older library version and ensures that we don't overrun the 407 * smbios_slot_t. 408 */ 409 boolean_t 410 smbios_test_slot_verify_34_overrun(smbios_hdl_t *hdl) 411 { 412 smbios_struct_t sp; 413 smbios_slot_t slot; 414 uint_t errs = 0; 415 416 /* 417 * We purposefully set the values that are part of SMBIOS 3.5+ to bad 418 * values to make sure that we don't end up zeroing them. 419 */ 420 slot.smbl_height = 0xba; 421 422 if (smbios_lookup_type(hdl, SMB_TYPE_SLOT, &sp) == -1) { 423 warnx("failed to lookup SMBIOS slot: %s", 424 smbios_errmsg(smbios_errno(hdl))); 425 return (B_FALSE); 426 } 427 428 if (smbios_info_slot(hdl, sp.smbstr_id, &slot) != 0) { 429 warnx("failed to get SMBIOS slot info: %s", 430 smbios_errmsg(smbios_errno(hdl))); 431 return (B_FALSE); 432 } 433 434 if (slot.smbl_height != 0xba) { 435 warnx("smbios 3.4 slot structure was overrun, smbl_height " 436 "unexpectedly set to 0x%x", slot.smbl_height); 437 errs++; 438 } 439 440 if (!smbios_test_slot_common(&slot)) { 441 errs++; 442 } 443 444 if (!smbios_test_slot_common_nopeers(hdl, &sp, &slot)) { 445 errs++; 446 } 447 448 if (errs > 0) { 449 return (B_FALSE); 450 } 451 452 return (B_TRUE); 453 } 454 455 boolean_t 456 smbios_test_slot_verify_35(smbios_hdl_t *hdl) 457 { 458 smbios_struct_t sp; 459 smbios_slot_t slot; 460 uint_t errs = 0; 461 462 if (smbios_lookup_type(hdl, SMB_TYPE_SLOT, &sp) == -1) { 463 warnx("failed to lookup SMBIOS slot: %s", 464 smbios_errmsg(smbios_errno(hdl))); 465 return (B_FALSE); 466 } 467 468 if (smbios_info_slot(hdl, sp.smbstr_id, &slot) != 0) { 469 warnx("failed to get SMBIOS slot info: %s", 470 smbios_errmsg(smbios_errno(hdl))); 471 return (B_FALSE); 472 } 473 474 if (!smbios_test_slot_common(&slot)) { 475 errs++; 476 } 477 478 if (!smbios_test_slot_common_nopeers(hdl, &sp, &slot)) { 479 errs++; 480 } 481 482 if (slot.smbl_height != SMB_SLHT_LP) { 483 warnx("found wrong slot height: 0x%x, expected 0x%x", 484 slot.smbl_height, SMB_SLHT_LP); 485 errs++; 486 } 487 488 if (errs > 0) { 489 return (B_FALSE); 490 } 491 492 return (B_TRUE); 493 } 494 495 boolean_t 496 smbios_test_slot_verify_34_peers(smbios_hdl_t *hdl) 497 { 498 smbios_struct_t sp; 499 smbios_slot_t slot; 500 uint_t npeers; 501 smbios_slot_peer_t *peers; 502 uint_t errs = 0; 503 504 if (smbios_lookup_type(hdl, SMB_TYPE_SLOT, &sp) == -1) { 505 warnx("failed to lookup SMBIOS slot: %s", 506 smbios_errmsg(smbios_errno(hdl))); 507 return (B_FALSE); 508 } 509 510 if (smbios_info_slot(hdl, sp.smbstr_id, &slot) != 0) { 511 warnx("failed to get SMBIOS slot info: %s", 512 smbios_errmsg(smbios_errno(hdl))); 513 return (B_FALSE); 514 } 515 516 if (!smbios_test_slot_common(&slot)) { 517 errs++; 518 } 519 520 if (slot.smbl_npeers != 1) { 521 warnx("incorrect number of slot peers, found %u", 522 slot.smbl_npeers); 523 errs++; 524 } 525 526 if (smbios_info_slot_peers(hdl, sp.smbstr_id, &npeers, &peers) != 0) { 527 warnx("failed to get SMBIOS peer info: %s", 528 smbios_errmsg(smbios_errno(hdl))); 529 return (B_FALSE); 530 } 531 532 if (npeers != 1) { 533 warnx("got wrong number of slot peers: %u", npeers); 534 errs++; 535 } 536 537 if (peers[0].smblp_group != 1) { 538 warnx("incorrect group for peer 0: %u", peers[0].smblp_group); 539 errs++; 540 } 541 542 if (peers[0].smblp_data_width != SMB_SLW_8X) { 543 warnx("incorrect data width for peer 0: %u", 544 peers[0].smblp_data_width); 545 errs++; 546 } 547 548 if (peers[0].smblp_bus != 0x42) { 549 warnx("incorrect PCI bus for peer 0: %u", 550 peers[0].smblp_bus); 551 errs++; 552 } 553 554 if (peers[0].smblp_device != (0x9a >> 3)) { 555 warnx("incorrect PCI device for peer 0: %u", 556 peers[0].smblp_device); 557 errs++; 558 } 559 560 if (peers[0].smblp_function != (0x9a & 0x7)) { 561 warnx("incorrect PCI function for peer 0: %u", 562 peers[0].smblp_function); 563 errs++; 564 } 565 566 smbios_info_slot_peers_free(hdl, npeers, peers); 567 568 if (slot.smbl_info != smbios_slot_info) { 569 warnx("found wrong slot info: 0x%x, expected 0x%x", 570 slot.smbl_info, smbios_slot_info); 571 errs++; 572 } 573 574 if (slot.smbl_pwidth != SMB_SLW_32X) { 575 warnx("found wrong slot physical width: 0x%x, expected 0x%x", 576 slot.smbl_pwidth, SMB_SLW_32X); 577 errs++; 578 } 579 580 if (slot.smbl_pitch != smbios_slot_pitch) { 581 warnx("found wrong slot pitch: 0x%x, expected 0x%x", 582 slot.smbl_pitch, smbios_slot_pitch); 583 errs++; 584 } 585 586 if (errs > 0) { 587 return (B_FALSE); 588 } 589 590 return (B_TRUE); 591 } 592