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
smbios_test_slot_fill(smb_slot_t * slot)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
smbios_test_slot_mktable(smbios_test_table_t * table)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
smbios_test_slot_mktable_nopeers(smbios_test_table_t * table,boolean_t is_35)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
smbios_test_slot_mktable_34_nopeers(smbios_test_table_t * table)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
smbios_test_slot_mktable_35(smbios_test_table_t * table)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
smbios_test_slot_mktable_34_peers(smbios_test_table_t * table)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
smbios_test_slot_common(smbios_slot_t * slot)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
smbios_test_slot_verify(smbios_hdl_t * hdl)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
smbios_test_slot_common_nopeers(smbios_hdl_t * hdl,smbios_struct_t * sp,smbios_slot_t * slot)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
smbios_test_slot_verify_34_nopeers(smbios_hdl_t * hdl)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
smbios_test_slot_verify_34_overrun(smbios_hdl_t * hdl)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
smbios_test_slot_verify_35(smbios_hdl_t * hdl)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
smbios_test_slot_verify_34_peers(smbios_hdl_t * hdl)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