xref: /illumos-gate/usr/src/cmd/smbios/smbios.c (revision 3fe455549728ac525df3be56130ad8e075d645d7)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2015 OmniTI Computer Consulting, Inc.  All rights reserved.
24  * Copyright (c) 2017, Joyent, Inc.
25  * Copyright 2024 Oxide Computer Company
26  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
27  * Use is subject to license terms.
28  */
29 
30 #include <sys/sysmacros.h>
31 #include <sys/param.h>
32 #include <sys/bitext.h>
33 #include <sys/hexdump.h>
34 
35 #include <smbios.h>
36 #include <alloca.h>
37 #include <limits.h>
38 #include <unistd.h>
39 #include <strings.h>
40 #include <stdlib.h>
41 #include <stdarg.h>
42 #include <stdio.h>
43 #include <fcntl.h>
44 #include <errno.h>
45 #include <ctype.h>
46 #include <libjedec.h>
47 
48 #define	SMBIOS_SUCCESS	0
49 #define	SMBIOS_ERROR	1
50 #define	SMBIOS_USAGE	2
51 
52 static const char *g_pname;
53 static int g_hdr;
54 
55 static int opt_e;
56 static int opt_i = -1;
57 static int opt_O;
58 static int opt_s;
59 static int opt_t = -1;
60 static int opt_x;
61 
62 static boolean_t
63 smbios_vergteq(smbios_version_t *v, uint_t major, uint_t minor)
64 {
65 	if (v->smbv_major > major)
66 		return (B_TRUE);
67 	if (v->smbv_major == major &&
68 	    v->smbv_minor >= minor)
69 		return (B_TRUE);
70 	return (B_FALSE);
71 }
72 
73 static void __PRINTFLIKE(2)
74 smbios_warn(smbios_hdl_t *shp, const char *format, ...)
75 {
76 	va_list ap;
77 
78 	va_start(ap, format);
79 	(void) vfprintf(stderr, format, ap);
80 	va_end(ap);
81 
82 	if (shp != NULL) {
83 		(void) fprintf(stderr, ": %s",
84 		    smbios_errmsg(smbios_errno(shp)));
85 	}
86 
87 	(void) fprintf(stderr, "\n");
88 }
89 
90 static void __PRINTFLIKE(2)
91 oprintf(FILE *fp, const char *format, ...)
92 {
93 	va_list ap;
94 
95 	va_start(ap, format);
96 	(void) vfprintf(fp, format, ap);
97 	va_end(ap);
98 }
99 
100 static void __PRINTFLIKE(3)
101 desc_printf(const char *d, FILE *fp, const char *format, ...)
102 {
103 	va_list ap;
104 
105 	va_start(ap, format);
106 	(void) vfprintf(fp, format, ap);
107 	va_end(ap);
108 
109 	if (d != NULL)
110 		(void) fprintf(fp, " (%s)\n", d);
111 	else
112 		(void) fprintf(fp, "\n");
113 }
114 
115 static void
116 flag_printf(FILE *fp, const char *s, uint_t flags, size_t bits,
117     const char *(*flag_name)(uint_t), const char *(*flag_desc)(uint_t))
118 {
119 	size_t i;
120 
121 	oprintf(fp, "  %s: 0x%x\n", s, flags);
122 
123 	for (i = 0; i < bits; i++) {
124 		uint_t f = 1 << i;
125 		const char *n;
126 
127 		if (!(flags & f))
128 			continue;
129 
130 		if ((n = flag_name(f)) != NULL)
131 			desc_printf(flag_desc(f), fp, "\t%s", n);
132 		else
133 			desc_printf(flag_desc(f), fp, "\t0x%x", f);
134 	}
135 }
136 
137 static void
138 flag64_printf(FILE *fp, const char *s, uint64_t flags, size_t bits,
139     const char *(*flag_name)(uint64_t), const char *(*flag_desc)(uint64_t))
140 {
141 	size_t i;
142 
143 	oprintf(fp, "  %s: 0x%llx\n", s, (u_longlong_t)flags);
144 
145 	for (i = 0; i < bits; i++) {
146 		u_longlong_t f = 1ULL << i;
147 		const char *n;
148 
149 		if (!(flags & f))
150 			continue;
151 
152 		if ((n = flag_name(f)) != NULL)
153 			desc_printf(flag_desc(f), fp, "\t%s", n);
154 		else
155 			desc_printf(flag_desc(f), fp, "\t0x%llx", f);
156 	}
157 }
158 
159 static void
160 id_printf(FILE *fp, const char *s, id_t id)
161 {
162 	switch (id) {
163 	case SMB_ID_NONE:
164 		oprintf(fp, "%sNone\n", s);
165 		break;
166 	case SMB_ID_NOTSUP:
167 		oprintf(fp, "%sNot Supported\n", s);
168 		break;
169 	default:
170 		oprintf(fp, "%s%u\n", s, (uint_t)id);
171 	}
172 }
173 
174 static void
175 jedec_print(FILE *fp, const char *desc, uint_t id)
176 {
177 	const char *name;
178 	uint_t cont, vendor;
179 
180 	/*
181 	 * SMBIOS encodes data in the way that the underlying memory standard
182 	 * does. In this case, the upper byte indicates the vendor that we care
183 	 * about while the lower byte indicates the number of continuations that
184 	 * are needed. libjedec indexes this based on zero (e.g. table 1 is zero
185 	 * continuations), which is how the spec encodes it. We add one so that
186 	 * we can match how the spec describes it.
187 	 */
188 	vendor = id >> 8;
189 	cont = id & 0x7f;
190 	name = libjedec_vendor_string(cont, vendor);
191 	if (name == NULL) {
192 		oprintf(fp, "  %s: Bank: 0x%x Vendor: 0x%x\n", desc, cont + 1,
193 		    vendor);
194 	} else {
195 		oprintf(fp, "  %s: Bank: 0x%x Vendor: 0x%x (%s)\n", desc,
196 		    cont + 1, vendor, name);
197 	}
198 }
199 
200 /*
201  * Convert an SMBIOS encoded JEDEDC component revision into its actual form. In
202  * general, JEDEC revisions are single byte values; however, the SMBIOS fields
203  * are two bytes wide. The byte that we care about is the "first" byte which
204  * translates into the upper bits here. The revision is binary coded decimal
205  * (BCD) represented with each nibble as major.minor. The major is the upper
206  * nibble and the minor is the lower one.
207  */
208 static void
209 jedec_rev_print(FILE *fp, const char *desc, uint16_t raw_rev)
210 {
211 	uint8_t rev = (uint8_t)bitx16(raw_rev, 15, 8);
212 	uint8_t maj = bitx8(rev, 7, 4);
213 	uint8_t min = bitx8(rev, 3, 0);
214 	oprintf(fp, "  %s: %x.%x\n", desc, maj, min);
215 }
216 
217 /*
218  * Print a 128-bit data as a series of 16 hex digits.
219  */
220 static void
221 u128_print(FILE *fp, const char *desc, const uint8_t *data)
222 {
223 	uint_t i;
224 
225 	oprintf(fp, "%s: ", desc);
226 	for (i = 0; i < 16; i++) {
227 		oprintf(fp, " %02x", data[i]);
228 	}
229 	oprintf(fp, "\n");
230 }
231 
232 /*
233  * Print a string that came from an SMBIOS table. We do this character by
234  * character so we can potentially escape strings.
235  */
236 static void
237 str_print_label(FILE *fp, const char *header, const char *str, boolean_t label)
238 {
239 	const char *c;
240 
241 	oprintf(fp, header);
242 	if (label) {
243 		oprintf(fp, ": ");
244 	}
245 
246 	for (c = str; *c != '\0'; c++) {
247 		if (isprint(*c)) {
248 			oprintf(fp, "%c", *c);
249 		} else {
250 			oprintf(fp, "\\x%02x", *c);
251 		}
252 	}
253 
254 	oprintf(fp, "\n");
255 }
256 
257 static void
258 str_print_nolabel(FILE *fp, const char *ws, const char *str)
259 {
260 	return (str_print_label(fp, ws, str, B_FALSE));
261 }
262 
263 static void
264 str_print(FILE *fp, const char *header, const char *str)
265 {
266 	return (str_print_label(fp, header, str, B_TRUE));
267 }
268 
269 static int
270 check_oem(smbios_hdl_t *shp)
271 {
272 	int i;
273 	int cnt;
274 	int rv;
275 	id_t oem_id;
276 	smbios_struct_t s;
277 	const char **oem_str;
278 
279 	rv = smbios_lookup_type(shp, SMB_TYPE_OEMSTR, &s);
280 	if (rv != 0) {
281 		return (-1);
282 	}
283 
284 	oem_id = s.smbstr_id;
285 
286 	cnt = smbios_info_strtab(shp, oem_id, 0, NULL);
287 	if (cnt > 0) {
288 		oem_str =  alloca(sizeof (char *) * cnt);
289 		(void) smbios_info_strtab(shp, oem_id, cnt, oem_str);
290 
291 		for (i = 0; i < cnt; i++) {
292 			if (strncmp(oem_str[i], SMB_PRMS1,
293 			    strlen(SMB_PRMS1) + 1) == 0) {
294 				return (0);
295 			}
296 		}
297 	}
298 
299 	return (-1);
300 }
301 
302 static void
303 print_smbios_21(smbios_21_entry_t *ep, FILE *fp)
304 {
305 	int i;
306 
307 	oprintf(fp, "Entry Point Anchor Tag: %*.*s\n",
308 	    (int)sizeof (ep->smbe_eanchor), (int)sizeof (ep->smbe_eanchor),
309 	    ep->smbe_eanchor);
310 
311 	oprintf(fp, "Entry Point Checksum: 0x%x\n", ep->smbe_ecksum);
312 	oprintf(fp, "Entry Point Length: %u\n", ep->smbe_elen);
313 	oprintf(fp, "Entry Point Version: %u.%u\n",
314 	    ep->smbe_major, ep->smbe_minor);
315 	oprintf(fp, "Max Structure Size: %u\n", ep->smbe_maxssize);
316 	oprintf(fp, "Entry Point Revision: 0x%x\n", ep->smbe_revision);
317 
318 	oprintf(fp, "Entry Point Revision Data:");
319 	for (i = 0; i < sizeof (ep->smbe_format); i++)
320 		oprintf(fp, " 0x%02x", ep->smbe_format[i]);
321 	oprintf(fp, "\n");
322 
323 	oprintf(fp, "Intermediate Anchor Tag: %*.*s\n",
324 	    (int)sizeof (ep->smbe_ianchor), (int)sizeof (ep->smbe_ianchor),
325 	    ep->smbe_ianchor);
326 
327 	oprintf(fp, "Intermediate Checksum: 0x%x\n", ep->smbe_icksum);
328 	oprintf(fp, "Structure Table Length: %u\n", ep->smbe_stlen);
329 	oprintf(fp, "Structure Table Address: 0x%x\n", ep->smbe_staddr);
330 	oprintf(fp, "Structure Table Entries: %u\n", ep->smbe_stnum);
331 	oprintf(fp, "DMI BCD Revision: 0x%x\n", ep->smbe_bcdrev);
332 }
333 
334 static void
335 print_smbios_30(smbios_30_entry_t *ep, FILE *fp)
336 {
337 	oprintf(fp, "Entry Point Anchor Tag: %*.*s\n",
338 	    (int)sizeof (ep->smbe_eanchor), (int)sizeof (ep->smbe_eanchor),
339 	    ep->smbe_eanchor);
340 
341 	oprintf(fp, "Entry Point Checksum: 0x%x\n", ep->smbe_ecksum);
342 	oprintf(fp, "Entry Point Length: %u\n", ep->smbe_elen);
343 	oprintf(fp, "SMBIOS Version: %u.%u\n",
344 	    ep->smbe_major, ep->smbe_minor);
345 	oprintf(fp, "SMBIOS DocRev: 0x%x\n", ep->smbe_docrev);
346 	oprintf(fp, "Entry Point Revision: 0x%x\n", ep->smbe_revision);
347 
348 	oprintf(fp, "Structure Table Length: %u\n", ep->smbe_stlen);
349 	oprintf(fp, "Structure Table Address: 0x%" PRIx64 "\n",
350 	    ep->smbe_staddr);
351 }
352 
353 static void
354 print_smbios(smbios_hdl_t *shp, FILE *fp)
355 {
356 	smbios_entry_t ep;
357 
358 	switch (smbios_info_smbios(shp, &ep)) {
359 	case SMBIOS_ENTRY_POINT_21:
360 		print_smbios_21(&ep.ep21, fp);
361 		break;
362 	case SMBIOS_ENTRY_POINT_30:
363 		print_smbios_30(&ep.ep30, fp);
364 		break;
365 	}
366 }
367 
368 static void
369 print_common(const smbios_info_t *ip, FILE *fp)
370 {
371 	if (ip->smbi_manufacturer[0] != '\0')
372 		str_print(fp, "  Manufacturer", ip->smbi_manufacturer);
373 	if (ip->smbi_product[0] != '\0')
374 		str_print(fp, "  Product", ip->smbi_product);
375 	if (ip->smbi_version[0] != '\0')
376 		str_print(fp, "  Version", ip->smbi_version);
377 	if (ip->smbi_serial[0] != '\0')
378 		str_print(fp, "  Serial Number", ip->smbi_serial);
379 	if (ip->smbi_asset[0] != '\0')
380 		str_print(fp, "  Asset Tag", ip->smbi_asset);
381 	if (ip->smbi_location[0] != '\0')
382 		str_print(fp, "  Location Tag", ip->smbi_location);
383 	if (ip->smbi_part[0] != '\0')
384 		str_print(fp, "  Part Number", ip->smbi_part);
385 }
386 
387 static void
388 print_bios(smbios_hdl_t *shp, FILE *fp)
389 {
390 	smbios_bios_t b;
391 
392 	if (smbios_info_bios(shp, &b) == -1) {
393 		smbios_warn(shp, "failed to read BIOS information");
394 		return;
395 	}
396 
397 	str_print(fp, "  Vendor", b.smbb_vendor);
398 	str_print(fp, "  Version String", b.smbb_version);
399 	str_print(fp, "  Release Date", b.smbb_reldate);
400 	oprintf(fp, "  Address Segment: 0x%x\n", b.smbb_segment);
401 	oprintf(fp, "  ROM Size: %" PRIu64 " bytes\n", b.smbb_extromsize);
402 	oprintf(fp, "  Image Size: %u bytes\n", b.smbb_runsize);
403 
404 	flag64_printf(fp, "Characteristics",
405 	    b.smbb_cflags, sizeof (b.smbb_cflags) * NBBY,
406 	    smbios_bios_flag_name, smbios_bios_flag_desc);
407 
408 	if (b.smbb_nxcflags > SMB_BIOSXB_1) {
409 		flag_printf(fp, "Characteristics Extension Byte 1",
410 		    b.smbb_xcflags[SMB_BIOSXB_1],
411 		    sizeof (b.smbb_xcflags[SMB_BIOSXB_1]) * NBBY,
412 		    smbios_bios_xb1_name, smbios_bios_xb1_desc);
413 	}
414 
415 	if (b.smbb_nxcflags > SMB_BIOSXB_2) {
416 		flag_printf(fp, "Characteristics Extension Byte 2",
417 		    b.smbb_xcflags[SMB_BIOSXB_2],
418 		    sizeof (b.smbb_xcflags[SMB_BIOSXB_2]) * NBBY,
419 		    smbios_bios_xb2_name, smbios_bios_xb2_desc);
420 	}
421 
422 	if (b.smbb_nxcflags > SMB_BIOSXB_BIOS_MIN) {
423 		oprintf(fp, "  Version Number: %u.%u\n",
424 		    b.smbb_biosv.smbv_major, b.smbb_biosv.smbv_minor);
425 	}
426 
427 	/*
428 	 * If the major and minor versions are 0xff then that indicates that the
429 	 * embedded controller does not exist.
430 	 */
431 	if (b.smbb_nxcflags > SMB_BIOSXB_ECFW_MIN &&
432 	    b.smbb_ecfwv.smbv_major != 0xff &&
433 	    b.smbb_ecfwv.smbv_minor != 0xff) {
434 		oprintf(fp, "  Embedded Ctlr Firmware Version Number: %u.%u\n",
435 		    b.smbb_ecfwv.smbv_major, b.smbb_ecfwv.smbv_minor);
436 	}
437 }
438 
439 static void
440 print_system(smbios_hdl_t *shp, FILE *fp)
441 {
442 	smbios_system_t s;
443 	uint_t i;
444 
445 	if (smbios_info_system(shp, &s) == -1) {
446 		smbios_warn(shp, "failed to read system information");
447 		return;
448 	}
449 
450 	oprintf(fp, "  UUID: ");
451 	for (i = 0; i < s.smbs_uuidlen; i++) {
452 		oprintf(fp, "%02x", s.smbs_uuid[i]);
453 		if (i == 3 || i == 5 || i == 7 || i == 9)
454 			oprintf(fp, "-");
455 	}
456 	oprintf(fp, "\n");
457 
458 	desc_printf(smbios_system_wakeup_desc(s.smbs_wakeup),
459 	    fp, "  Wake-Up Event: 0x%x", s.smbs_wakeup);
460 
461 	str_print(fp, "  SKU Number", s.smbs_sku);
462 	str_print(fp, "  Family", s.smbs_family);
463 }
464 
465 static void
466 print_bboard(smbios_hdl_t *shp, id_t id, FILE *fp)
467 {
468 	smbios_bboard_t b;
469 	int chdl_cnt;
470 
471 	if (smbios_info_bboard(shp, id, &b) != 0) {
472 		smbios_warn(shp, "failed to read baseboard information");
473 		return;
474 	}
475 
476 	oprintf(fp, "  Chassis: %u\n", (uint_t)b.smbb_chassis);
477 
478 	flag_printf(fp, "Flags", b.smbb_flags, sizeof (b.smbb_flags) * NBBY,
479 	    smbios_bboard_flag_name, smbios_bboard_flag_desc);
480 
481 	desc_printf(smbios_bboard_type_desc(b.smbb_type),
482 	    fp, "  Board Type: 0x%x", b.smbb_type);
483 
484 	chdl_cnt = b.smbb_contn;
485 	if (chdl_cnt != 0) {
486 		id_t *chdl;
487 		uint16_t hdl;
488 		int i, n, cnt;
489 
490 		chdl = alloca(chdl_cnt * sizeof (id_t));
491 		cnt = smbios_info_contains(shp, id, chdl_cnt, chdl);
492 		if (cnt > SMB_CONT_MAX)
493 			return;
494 		n = MIN(chdl_cnt, cnt);
495 
496 		oprintf(fp, "\n");
497 		for (i = 0; i < n; i++) {
498 			hdl = (uint16_t)chdl[i];
499 			oprintf(fp, "  Contained Handle: %u\n", hdl);
500 		}
501 	}
502 }
503 
504 static void
505 print_chassis(smbios_hdl_t *shp, id_t id, FILE *fp)
506 {
507 	smbios_chassis_t c;
508 	smbios_chassis_entry_t *elts;
509 	uint_t nelts, i;
510 
511 	if (smbios_info_chassis(shp, id, &c) != 0) {
512 		smbios_warn(shp, "failed to read chassis information");
513 		return;
514 	}
515 
516 	oprintf(fp, "  OEM Data: 0x%x\n", c.smbc_oemdata);
517 	str_print(fp, "  SKU Number",
518 	    c.smbc_sku[0] == '\0' ? "<unknown>" : c.smbc_sku);
519 	oprintf(fp, "  Lock Present: %s\n", c.smbc_lock ? "Y" : "N");
520 
521 	desc_printf(smbios_chassis_type_desc(c.smbc_type),
522 	    fp, "  Chassis Type: 0x%x", c.smbc_type);
523 
524 	desc_printf(smbios_chassis_state_desc(c.smbc_bustate),
525 	    fp, "  Boot-Up State: 0x%x", c.smbc_bustate);
526 
527 	desc_printf(smbios_chassis_state_desc(c.smbc_psstate),
528 	    fp, "  Power Supply State: 0x%x", c.smbc_psstate);
529 
530 	desc_printf(smbios_chassis_state_desc(c.smbc_thstate),
531 	    fp, "  Thermal State: 0x%x", c.smbc_thstate);
532 
533 	oprintf(fp, "  Chassis Height: %uu\n", c.smbc_uheight);
534 	oprintf(fp, "  Power Cords: %u\n", c.smbc_cords);
535 
536 	oprintf(fp, "  Element Records: %u\n", c.smbc_elems);
537 
538 	if (c.smbc_elems == 0) {
539 		return;
540 	}
541 
542 	if (smbios_info_chassis_elts(shp, id, &nelts, &elts) != 0) {
543 		smbios_warn(shp, "failed to read chassis elements");
544 		return;
545 	}
546 
547 	oprintf(fp, "\n");
548 
549 	for (i = 0; i < nelts; i++) {
550 		switch (elts[i].smbce_type) {
551 		case SMB_CELT_BBOARD:
552 			desc_printf(smbios_bboard_type_desc(elts[i].smbce_elt),
553 			    fp, "  Contained SMBIOS Base Board Type: 0x%x",
554 			    elts[i].smbce_elt);
555 			break;
556 		case SMB_CELT_SMBIOS:
557 			desc_printf(smbios_type_name(elts[i].smbce_elt), fp,
558 			    "  Contained SMBIOS structure Type: %u",
559 			    elts[i].smbce_elt);
560 			break;
561 		default:
562 			oprintf(fp, "  Unknown contained Type: %u/%u\n",
563 			    elts[i].smbce_type, elts[i].smbce_elt);
564 			break;
565 		}
566 		oprintf(fp, "    Minimum number: %u\n", elts[i].smbce_min);
567 		oprintf(fp, "    Maximum number: %u\n", elts[i].smbce_max);
568 	}
569 }
570 
571 static void
572 print_processor(smbios_hdl_t *shp, id_t id, FILE *fp)
573 {
574 	smbios_processor_t p;
575 	uint_t status;
576 
577 	if (smbios_info_processor(shp, id, &p) != 0) {
578 		smbios_warn(shp, "failed to read processor information");
579 		return;
580 	}
581 	status = SMB_PRSTATUS_STATUS(p.smbp_status);
582 
583 	desc_printf(smbios_processor_family_desc(p.smbp_family),
584 	    fp, "  Family: %u", p.smbp_family);
585 
586 	oprintf(fp, "  CPUID: 0x%llx\n", (u_longlong_t)p.smbp_cpuid);
587 
588 	desc_printf(smbios_processor_type_desc(p.smbp_type),
589 	    fp, "  Type: %u", p.smbp_type);
590 
591 	desc_printf(smbios_processor_upgrade_desc(p.smbp_upgrade),
592 	    fp, "  Socket Upgrade: %u", p.smbp_upgrade);
593 
594 	oprintf(fp, "  Socket Status: %s\n",
595 	    SMB_PRSTATUS_PRESENT(p.smbp_status) ?
596 	    "Populated" : "Not Populated");
597 
598 	desc_printf(smbios_processor_status_desc(status),
599 	    fp, "  Processor Status: %u", status);
600 
601 	if (SMB_PRV_LEGACY(p.smbp_voltage)) {
602 		oprintf(fp, "  Supported Voltages:");
603 		switch (p.smbp_voltage) {
604 		case SMB_PRV_5V:
605 			oprintf(fp, " 5.0V");
606 			break;
607 		case SMB_PRV_33V:
608 			oprintf(fp, " 3.3V");
609 			break;
610 		case SMB_PRV_29V:
611 			oprintf(fp, " 2.9V");
612 			break;
613 		}
614 		oprintf(fp, "\n");
615 	} else {
616 		oprintf(fp, "  Supported Voltages: %.1fV\n",
617 		    (float)SMB_PRV_VOLTAGE(p.smbp_voltage) / 10);
618 	}
619 
620 	if (p.smbp_corecount != 0) {
621 		oprintf(fp, "  Core Count: %u\n", p.smbp_corecount);
622 	} else {
623 		oprintf(fp, "  Core Count: Unknown\n");
624 	}
625 
626 	if (p.smbp_coresenabled != 0) {
627 		oprintf(fp, "  Cores Enabled: %u\n", p.smbp_coresenabled);
628 	} else {
629 		oprintf(fp, "  Cores Enabled: Unknown\n");
630 	}
631 
632 	if (p.smbp_threadcount != 0) {
633 		oprintf(fp, "  Thread Count: %u\n", p.smbp_threadcount);
634 	} else {
635 		oprintf(fp, "  Thread Count: Unknown\n");
636 	}
637 
638 	if (p.smbp_cflags) {
639 		flag_printf(fp, "Processor Characteristics",
640 		    p.smbp_cflags, sizeof (p.smbp_cflags) * NBBY,
641 		    smbios_processor_core_flag_name,
642 		    smbios_processor_core_flag_desc);
643 	}
644 
645 	if (p.smbp_clkspeed != 0)
646 		oprintf(fp, "  External Clock Speed: %uMHz\n", p.smbp_clkspeed);
647 	else
648 		oprintf(fp, "  External Clock Speed: Unknown\n");
649 
650 	if (p.smbp_maxspeed != 0)
651 		oprintf(fp, "  Maximum Speed: %uMHz\n", p.smbp_maxspeed);
652 	else
653 		oprintf(fp, "  Maximum Speed: Unknown\n");
654 
655 	if (p.smbp_curspeed != 0)
656 		oprintf(fp, "  Current Speed: %uMHz\n", p.smbp_curspeed);
657 	else
658 		oprintf(fp, "  Current Speed: Unknown\n");
659 
660 	id_printf(fp, "  L1 Cache Handle: ", p.smbp_l1cache);
661 	id_printf(fp, "  L2 Cache Handle: ", p.smbp_l2cache);
662 	id_printf(fp, "  L3 Cache Handle: ", p.smbp_l3cache);
663 
664 	if (p.smbp_threadsenabled != 0) {
665 		oprintf(fp, "  Threads Enabled: %u\n", p.smbp_threadsenabled);
666 	} else {
667 		oprintf(fp, "  Threads Enabled: Unknown\n");
668 	}
669 
670 	/*
671 	 * The Socket Type string overlaps with the upgrade string. Only print
672 	 * something if we have a valid value.
673 	 */
674 	if (*p.smbp_socktype != '\0') {
675 		str_print(fp, "  Socket Type", p.smbp_socktype);
676 	}
677 }
678 
679 static void
680 print_cache(smbios_hdl_t *shp, id_t id, FILE *fp)
681 {
682 	smbios_cache_t c;
683 
684 	if (smbios_info_cache(shp, id, &c) != 0) {
685 		smbios_warn(shp, "failed to read cache information");
686 		return;
687 	}
688 
689 	oprintf(fp, "  Level: %u\n", c.smba_level);
690 	oprintf(fp, "  Maximum Installed Size: %" PRIu64 " bytes\n",
691 	    c.smba_maxsize2);
692 
693 	if (c.smba_size2 != 0) {
694 		oprintf(fp, "  Installed Size: %" PRIu64 " bytes\n",
695 		    c.smba_size2);
696 	} else {
697 		oprintf(fp, "  Installed Size: Not Installed\n");
698 	}
699 
700 	if (c.smba_speed != 0)
701 		oprintf(fp, "  Speed: %uns\n", c.smba_speed);
702 	else
703 		oprintf(fp, "  Speed: Unknown\n");
704 
705 	flag_printf(fp, "Supported SRAM Types",
706 	    c.smba_stype, sizeof (c.smba_stype) * NBBY,
707 	    smbios_cache_ctype_name, smbios_cache_ctype_desc);
708 
709 	desc_printf(smbios_cache_ctype_desc(c.smba_ctype),
710 	    fp, "  Current SRAM Type: 0x%x", c.smba_ctype);
711 
712 	desc_printf(smbios_cache_ecc_desc(c.smba_etype),
713 	    fp, "  Error Correction Type: %u", c.smba_etype);
714 
715 	desc_printf(smbios_cache_logical_desc(c.smba_ltype),
716 	    fp, "  Logical Cache Type: %u", c.smba_ltype);
717 
718 	desc_printf(smbios_cache_assoc_desc(c.smba_assoc),
719 	    fp, "  Associativity: %u", c.smba_assoc);
720 
721 	desc_printf(smbios_cache_mode_desc(c.smba_mode),
722 	    fp, "  Mode: %u", c.smba_mode);
723 
724 	desc_printf(smbios_cache_loc_desc(c.smba_location),
725 	    fp, "  Location: %u", c.smba_location);
726 
727 	flag_printf(fp, "Flags", c.smba_flags, sizeof (c.smba_flags) * NBBY,
728 	    smbios_cache_flag_name, smbios_cache_flag_desc);
729 }
730 
731 static void
732 print_port(smbios_hdl_t *shp, id_t id, FILE *fp)
733 {
734 	smbios_port_t p;
735 
736 	if (smbios_info_port(shp, id, &p) != 0) {
737 		smbios_warn(shp, "failed to read port information");
738 		return;
739 	}
740 
741 	str_print(fp, "  Internal Reference Designator", p.smbo_iref);
742 	str_print(fp, "  External Reference Designator", p.smbo_eref);
743 
744 	desc_printf(smbios_port_conn_desc(p.smbo_itype),
745 	    fp, "  Internal Connector Type: %u", p.smbo_itype);
746 
747 	desc_printf(smbios_port_conn_desc(p.smbo_etype),
748 	    fp, "  External Connector Type: %u", p.smbo_etype);
749 
750 	desc_printf(smbios_port_type_desc(p.smbo_ptype),
751 	    fp, "  Port Type: %u", p.smbo_ptype);
752 }
753 
754 static void
755 print_slot(smbios_hdl_t *shp, id_t id, FILE *fp)
756 {
757 	smbios_slot_t s;
758 	smbios_version_t v;
759 
760 	if (smbios_info_slot(shp, id, &s) != 0) {
761 		smbios_warn(shp, "failed to read slot information");
762 		return;
763 	}
764 	smbios_info_smbios_version(shp, &v);
765 
766 	str_print(fp, "  Reference Designator", s.smbl_name);
767 	oprintf(fp, "  Slot ID: 0x%x\n", s.smbl_id);
768 
769 	desc_printf(smbios_slot_type_desc(s.smbl_type),
770 	    fp, "  Type: 0x%x", s.smbl_type);
771 
772 	desc_printf(smbios_slot_width_desc(s.smbl_width),
773 	    fp, "  Width: 0x%x", s.smbl_width);
774 
775 	desc_printf(smbios_slot_usage_desc(s.smbl_usage),
776 	    fp, "  Usage: 0x%x", s.smbl_usage);
777 
778 	desc_printf(smbios_slot_length_desc(s.smbl_length),
779 	    fp, "  Length: 0x%x", s.smbl_length);
780 
781 	flag_printf(fp, "Slot Characteristics 1",
782 	    s.smbl_ch1, sizeof (s.smbl_ch1) * NBBY,
783 	    smbios_slot_ch1_name, smbios_slot_ch1_desc);
784 
785 	flag_printf(fp, "Slot Characteristics 2",
786 	    s.smbl_ch2, sizeof (s.smbl_ch2) * NBBY,
787 	    smbios_slot_ch2_name, smbios_slot_ch2_desc);
788 
789 	if (check_oem(shp) != 0 && !smbios_vergteq(&v, 2, 6))
790 		return;
791 
792 	oprintf(fp, "  Segment Group: %u\n", s.smbl_sg);
793 	oprintf(fp, "  Bus Number: %u\n", s.smbl_bus);
794 	oprintf(fp, "  Device/Function Number: %u/%u\n", s.smbl_df >> 3,
795 	    s.smbl_df & 0x7);
796 
797 	if (s.smbl_dbw != 0) {
798 		oprintf(fp, "  Data Bus Width: %d\n", s.smbl_dbw);
799 	}
800 
801 	if (s.smbl_npeers > 0) {
802 		smbios_slot_peer_t *peer;
803 		uint_t i, npeers;
804 
805 		if (smbios_info_slot_peers(shp, id, &npeers, &peer) != 0) {
806 			smbios_warn(shp, "failed to read slot peer "
807 			    "information");
808 			return;
809 		}
810 
811 		for (i = 0; i < npeers; i++) {
812 			oprintf(fp, "  Slot Peer %u:\n", i);
813 			oprintf(fp, "    Segment group: %u\n",
814 			    peer[i].smblp_group);
815 			oprintf(fp, "    Bus/Device/Function: %u/%u/%u\n",
816 			    peer[i].smblp_bus, peer[i].smblp_device,
817 			    peer[i].smblp_function);
818 			oprintf(fp, "    Electrical width: %u\n",
819 			    peer[i].smblp_data_width);
820 		}
821 
822 		smbios_info_slot_peers_free(shp, npeers, peer);
823 	}
824 
825 	if (s.smbl_info != 0) {
826 		if (s.smbl_type >= SMB_SLT_PCIE &&
827 		    s.smbl_type <= SMB_SLT_PCIEG6P) {
828 			oprintf(fp, "  PCIe Generation: %d\n", s.smbl_info);
829 		} else {
830 			oprintf(fp, "  Slot Type: 0x%x\n", s.smbl_info);
831 		}
832 	}
833 
834 	if (s.smbl_pwidth != 0) {
835 		desc_printf(smbios_slot_width_desc(s.smbl_pwidth),
836 		    fp, "  Physical Width: 0x%x", s.smbl_pwidth);
837 	}
838 
839 	if (s.smbl_pitch != 0) {
840 		oprintf(fp, "  Slot Pitch: %u.%u mm\n", s.smbl_pitch / 100,
841 		    s.smbl_pitch % 100);
842 	}
843 
844 	/*
845 	 * The slot height was introduced in SMBIOS 3.5. However, a value of
846 	 * zero here does not mean that it is unknown, but rather that the
847 	 * concept is not applicable. Therefore we cannot use a standard check
848 	 * against zero for this and instead use the version.
849 	 */
850 	if (smbios_vergteq(&v, 3, 5)) {
851 		desc_printf(smbios_slot_height_desc(s.smbl_height), fp,
852 		    "  Height: 0x%x", s.smbl_height);
853 	} else {
854 		oprintf(fp, "  Height:  unknown\n");
855 	}
856 }
857 
858 static void
859 print_obdevs_ext(smbios_hdl_t *shp, id_t id, FILE *fp)
860 {
861 	boolean_t enabled;
862 	smbios_obdev_ext_t oe;
863 	const char *type;
864 
865 	if (smbios_info_obdevs_ext(shp, id, &oe) != 0) {
866 		smbios_warn(shp, "failed to read extended on-board devices "
867 		    "information");
868 		return;
869 	}
870 
871 	/*
872 	 * Bit 7 is always whether or not the device is enabled while bits 0:6
873 	 * are the actual device type.
874 	 */
875 	enabled = oe.smboe_dtype >> 7;
876 	type = smbios_onboard_ext_type_desc(oe.smboe_dtype & 0x7f);
877 
878 	str_print(fp, "  Reference Designator", oe.smboe_name);
879 	oprintf(fp, "  Device Enabled: %s\n", enabled == B_TRUE ? "true" :
880 	    "false");
881 	oprintf(fp, "  Device Type: %s\n", type);
882 	oprintf(fp, "  Device Type Instance: %u\n", oe.smboe_dti);
883 	oprintf(fp, "  Segment Group Number: %u\n", oe.smboe_sg);
884 	oprintf(fp, "  Bus Number: %u\n", oe.smboe_bus);
885 	oprintf(fp, "  Device/Function Number: %u\n", oe.smboe_df);
886 }
887 
888 static void
889 print_obdevs(smbios_hdl_t *shp, id_t id, FILE *fp)
890 {
891 	smbios_obdev_t *argv;
892 	int i, argc;
893 
894 	if ((argc = smbios_info_obdevs(shp, id, 0, NULL)) > 0) {
895 		argv = alloca(sizeof (smbios_obdev_t) * argc);
896 		if (smbios_info_obdevs(shp, id, argc, argv) == -1) {
897 			smbios_warn(shp, "failed to read on-board device "
898 			    "information");
899 			return;
900 		}
901 		for (i = 0; i < argc; i++)
902 			str_print_nolabel(fp, "  ", argv[i].smbd_name);
903 	}
904 }
905 
906 static void
907 print_strtab(smbios_hdl_t *shp, id_t id, FILE *fp)
908 {
909 	const char **argv;
910 	int i, argc;
911 
912 	if ((argc = smbios_info_strtab(shp, id, 0, NULL)) > 0) {
913 		argv = alloca(sizeof (char *) * argc);
914 		if (smbios_info_strtab(shp, id, argc, argv) == -1) {
915 			smbios_warn(shp, "failed to read string table "
916 			    "information");
917 			return;
918 		}
919 		for (i = 0; i < argc; i++)
920 			str_print_nolabel(fp, "  ", argv[i]);
921 	}
922 }
923 
924 static void
925 print_lang(smbios_hdl_t *shp, id_t id, FILE *fp)
926 {
927 	smbios_lang_t l;
928 
929 	if (smbios_info_lang(shp, &l) == -1) {
930 		smbios_warn(shp, "failed to read language information");
931 		return;
932 	}
933 
934 	str_print(fp, "  Current Language", l.smbla_cur);
935 	oprintf(fp, "  Language String Format: %u\n", l.smbla_fmt);
936 	oprintf(fp, "  Number of Installed Languages: %u\n", l.smbla_num);
937 	oprintf(fp, "  Installed Languages:\n");
938 
939 	print_strtab(shp, id, fp);
940 }
941 
942 /*ARGSUSED*/
943 static void
944 print_evlog(smbios_hdl_t *shp, id_t id, FILE *fp)
945 {
946 	smbios_evlog_t ev;
947 	uint32_t i;
948 
949 	if (smbios_info_eventlog(shp, &ev) == -1) {
950 		smbios_warn(shp, "failed to read event log information");
951 		return;
952 	}
953 
954 	oprintf(fp, "  Log Area Size: %lu bytes\n", (ulong_t)ev.smbev_size);
955 	oprintf(fp, "  Header Offset: %lu\n", (ulong_t)ev.smbev_hdr);
956 	oprintf(fp, "  Data Offset: %lu\n", (ulong_t)ev.smbev_data);
957 
958 	desc_printf(smbios_evlog_method_desc(ev.smbev_method),
959 	    fp, "  Data Access Method: %u", ev.smbev_method);
960 
961 	flag_printf(fp, "Log Flags",
962 	    ev.smbev_flags, sizeof (ev.smbev_flags) * NBBY,
963 	    smbios_evlog_flag_name, smbios_evlog_flag_desc);
964 
965 	desc_printf(smbios_evlog_format_desc(ev.smbev_format),
966 	    fp, "  Log Header Format: %u", ev.smbev_format);
967 
968 	oprintf(fp, "  Update Token: 0x%x\n", ev.smbev_token);
969 	oprintf(fp, "  Data Access Address: ");
970 
971 	switch (ev.smbev_method) {
972 	case SMB_EVM_1x1i_1x1d:
973 	case SMB_EVM_2x1i_1x1d:
974 	case SMB_EVM_1x2i_1x1d:
975 		oprintf(fp, "Index Address 0x%x, Data Address 0x%x\n",
976 		    ev.smbev_addr.eva_io.evi_iaddr,
977 		    ev.smbev_addr.eva_io.evi_daddr);
978 		break;
979 	case SMB_EVM_GPNV:
980 		oprintf(fp, "0x%x\n", ev.smbev_addr.eva_gpnv);
981 		break;
982 	default:
983 		oprintf(fp, "0x%x\n", ev.smbev_addr.eva_addr);
984 	}
985 
986 	oprintf(fp, "  Type Descriptors:\n");
987 
988 	for (i = 0; i < ev.smbev_typec; i++) {
989 		oprintf(fp, "  %u: Log Type 0x%x, Data Type 0x%x\n", i,
990 		    ev.smbev_typev[i].smbevt_ltype,
991 		    ev.smbev_typev[i].smbevt_dtype);
992 	}
993 }
994 
995 static void
996 print_bytes(const uint8_t *data, size_t size, FILE *fp)
997 {
998 	hexdump_t h;
999 
1000 	hexdump_init(&h);
1001 	hexdump_set_grouping(&h, 4);
1002 	hexdump_set_indent(&h, 2);
1003 
1004 	(void) fprintf(fp, "\n");
1005 	(void) hexdump_fileh(&h, data, size, HDF_DEFAULT, fp);
1006 	(void) fprintf(fp, "\n");
1007 
1008 	hexdump_fini(&h);
1009 }
1010 
1011 static void
1012 print_memarray(smbios_hdl_t *shp, id_t id, FILE *fp)
1013 {
1014 	smbios_memarray_t ma;
1015 
1016 	if (smbios_info_memarray(shp, id, &ma) != 0) {
1017 		smbios_warn(shp, "failed to read memarray information");
1018 		return;
1019 	}
1020 
1021 	desc_printf(smbios_memarray_loc_desc(ma.smbma_location),
1022 	    fp, "  Location: %u", ma.smbma_location);
1023 
1024 	desc_printf(smbios_memarray_use_desc(ma.smbma_use),
1025 	    fp, "  Use: %u", ma.smbma_use);
1026 
1027 	desc_printf(smbios_memarray_ecc_desc(ma.smbma_ecc),
1028 	    fp, "  ECC: %u", ma.smbma_ecc);
1029 
1030 	oprintf(fp, "  Number of Slots/Sockets: %u\n", ma.smbma_ndevs);
1031 	id_printf(fp, "  Memory Error Data: ", ma.smbma_err);
1032 	oprintf(fp, "  Max Capacity: %llu bytes\n",
1033 	    (u_longlong_t)ma.smbma_size);
1034 }
1035 
1036 static void
1037 print_memdevice(smbios_hdl_t *shp, id_t id, FILE *fp)
1038 {
1039 	smbios_memdevice_t md;
1040 
1041 	if (smbios_info_memdevice(shp, id, &md) != 0) {
1042 		smbios_warn(shp, "failed to read memory device information");
1043 		return;
1044 	}
1045 
1046 	id_printf(fp, "  Physical Memory Array: ", md.smbmd_array);
1047 	id_printf(fp, "  Memory Error Data: ", md.smbmd_error);
1048 
1049 	if (md.smbmd_twidth != -1u)
1050 		oprintf(fp, "  Total Width: %u bits\n", md.smbmd_twidth);
1051 	else
1052 		oprintf(fp, "  Total Width: Unknown\n");
1053 
1054 	if (md.smbmd_dwidth != -1u)
1055 		oprintf(fp, "  Data Width: %u bits\n", md.smbmd_dwidth);
1056 	else
1057 		oprintf(fp, "  Data Width: Unknown\n");
1058 
1059 	switch (md.smbmd_size) {
1060 	case -1ull:
1061 		oprintf(fp, "  Size: Unknown\n");
1062 		break;
1063 	case 0:
1064 		oprintf(fp, "  Size: Not Populated\n");
1065 		break;
1066 	default:
1067 		oprintf(fp, "  Size: %llu bytes\n",
1068 		    (u_longlong_t)md.smbmd_size);
1069 	}
1070 
1071 	desc_printf(smbios_memdevice_form_desc(md.smbmd_form),
1072 	    fp, "  Form Factor: %u", md.smbmd_form);
1073 
1074 	if (md.smbmd_set == 0)
1075 		oprintf(fp, "  Set: None\n");
1076 	else if (md.smbmd_set == (uint8_t)-1u)
1077 		oprintf(fp, "  Set: Unknown\n");
1078 	else
1079 		oprintf(fp, "  Set: %u\n", md.smbmd_set);
1080 
1081 	if (md.smbmd_rank != 0) {
1082 		desc_printf(smbios_memdevice_rank_desc(md.smbmd_rank),
1083 		    fp, "  Rank: %u", md.smbmd_rank);
1084 	} else {
1085 		oprintf(fp, "  Rank: Unknown\n");
1086 	}
1087 
1088 	desc_printf(smbios_memdevice_type_desc(md.smbmd_type),
1089 	    fp, "  Memory Type: %u", md.smbmd_type);
1090 
1091 	flag_printf(fp, "Flags", md.smbmd_flags, sizeof (md.smbmd_flags) * NBBY,
1092 	    smbios_memdevice_flag_name, smbios_memdevice_flag_desc);
1093 
1094 	if (md.smbmd_extspeed != 0) {
1095 		oprintf(fp, "  Speed: %" PRIu64 " MT/s\n", md.smbmd_extspeed);
1096 	} else {
1097 		oprintf(fp, "  Speed: Unknown\n");
1098 	}
1099 
1100 	if (md.smbmd_extclkspeed != 0) {
1101 		oprintf(fp, "  Configured Speed: %" PRIu64 " MT/s\n",
1102 		    md.smbmd_extclkspeed);
1103 	} else {
1104 		oprintf(fp, "  Configured Speed: Unknown\n");
1105 	}
1106 
1107 	str_print(fp, "  Device Locator", md.smbmd_dloc);
1108 	str_print(fp, "  Bank Locator", md.smbmd_bloc);
1109 
1110 	if (md.smbmd_minvolt != 0) {
1111 		oprintf(fp, "  Minimum Voltage: %.2fV\n",
1112 		    md.smbmd_minvolt / 1000.0);
1113 	} else {
1114 		oprintf(fp, "  Minimum Voltage: Unknown\n");
1115 	}
1116 
1117 	if (md.smbmd_maxvolt != 0) {
1118 		oprintf(fp, "  Maximum Voltage: %.2fV\n",
1119 		    md.smbmd_maxvolt / 1000.0);
1120 	} else {
1121 		oprintf(fp, "  Maximum Voltage: Unknown\n");
1122 	}
1123 
1124 	if (md.smbmd_confvolt != 0) {
1125 		oprintf(fp, "  Configured Voltage: %.2fV\n",
1126 		    md.smbmd_confvolt / 1000.0);
1127 	} else {
1128 		oprintf(fp, "  Configured Voltage: Unknown\n");
1129 	}
1130 
1131 	if (md.smbmd_memtech != 0) {
1132 		desc_printf(smbios_memdevice_memtech_desc(md.smbmd_memtech),
1133 		    fp, "  Memory Technology: %u", md.smbmd_memtech);
1134 	}
1135 
1136 	if (md.smbmd_opcap_flags != 0) {
1137 		flag_printf(fp, "Operating Mode Capabilities",
1138 		    md.smbmd_opcap_flags, sizeof (md.smbmd_opcap_flags) * NBBY,
1139 		    smbios_memdevice_op_capab_name,
1140 		    smbios_memdevice_op_capab_desc);
1141 	}
1142 
1143 	if (md.smbmd_firmware_rev[0] != '\0') {
1144 		str_print(fp, "  Firmware Revision", md.smbmd_firmware_rev);
1145 	}
1146 
1147 	if (md.smbmd_modmfg_id != SMB_MD_MFG_UNKNOWN) {
1148 		jedec_print(fp, "Module Manufacturer ID", md.smbmd_modmfg_id);
1149 	}
1150 
1151 	if (md.smbmd_modprod_id  != 0) {
1152 		jedec_print(fp, "Module Product ID", md.smbmd_modprod_id);
1153 	}
1154 
1155 	if (md.smbmd_cntrlmfg_id != SMB_MD_MFG_UNKNOWN) {
1156 		jedec_print(fp, "Memory Subsystem Controller Manufacturer ID",
1157 		    md.smbmd_cntrlmfg_id);
1158 	}
1159 
1160 	if (md.smbmd_cntrlprod_id != 0) {
1161 		jedec_print(fp, "Memory Subsystem Controller Product ID",
1162 		    md.smbmd_cntrlprod_id);
1163 	}
1164 
1165 	if (md.smbmd_nvsize == UINT64_MAX) {
1166 		oprintf(fp, "  Non-volatile Size: Unknown\n");
1167 	} else if (md.smbmd_nvsize != 0) {
1168 		oprintf(fp, "  Non-volatile Size: %llu bytes\n",
1169 		    (u_longlong_t)md.smbmd_nvsize);
1170 	}
1171 
1172 	if (md.smbmd_volatile_size == UINT64_MAX) {
1173 		oprintf(fp, "  Volatile Size: Unknown\n");
1174 	} else if (md.smbmd_volatile_size != 0) {
1175 		oprintf(fp, "  Volatile Size: %llu bytes\n",
1176 		    (u_longlong_t)md.smbmd_volatile_size);
1177 	}
1178 
1179 	if (md.smbmd_cache_size == UINT64_MAX) {
1180 		oprintf(fp, "  Cache Size: Unknown\n");
1181 	} else if (md.smbmd_cache_size != 0) {
1182 		oprintf(fp, "  Cache Size: %llu bytes\n",
1183 		    (u_longlong_t)md.smbmd_cache_size);
1184 	}
1185 
1186 	if (md.smbmd_logical_size == UINT64_MAX) {
1187 		oprintf(fp, "  Logical Size: Unknown\n");
1188 	} else if (md.smbmd_logical_size != 0) {
1189 		oprintf(fp, "  Logical Size: %llu bytes\n",
1190 		    (u_longlong_t)md.smbmd_logical_size);
1191 	}
1192 
1193 	if (md.smbmd_pmic0_mfgid != SMB_MD_MFG_UNKNOWN) {
1194 		jedec_print(fp, "PMIC0 Manufacturer ID", md.smbmd_pmic0_mfgid);
1195 	}
1196 
1197 	if (md.smbmd_pmic0_rev != SMB_MD_REV_UNKNOWN) {
1198 		jedec_rev_print(fp, "PMIC0 Revision", md.smbmd_pmic0_rev);
1199 	}
1200 
1201 	if (md.smbmd_rcd_mfgid != SMB_MD_MFG_UNKNOWN) {
1202 		jedec_print(fp, "RCD Manufacturer ID", md.smbmd_rcd_mfgid);
1203 	}
1204 
1205 	if (md.smbmd_rcd_rev != SMB_MD_REV_UNKNOWN) {
1206 		jedec_rev_print(fp, "RCD Revision", md.smbmd_rcd_rev);
1207 	}
1208 }
1209 
1210 static void
1211 print_memarrmap(smbios_hdl_t *shp, id_t id, FILE *fp)
1212 {
1213 	smbios_memarrmap_t ma;
1214 
1215 	if (smbios_info_memarrmap(shp, id, &ma) != 0) {
1216 		smbios_warn(shp, "failed to read memory array map information");
1217 		return;
1218 	}
1219 
1220 	id_printf(fp, "  Physical Memory Array: ", ma.smbmam_array);
1221 	oprintf(fp, "  Devices per Row: %u\n", ma.smbmam_width);
1222 
1223 	oprintf(fp, "  Physical Address: 0x%llx\n  Size: %llu bytes\n",
1224 	    (u_longlong_t)ma.smbmam_addr, (u_longlong_t)ma.smbmam_size);
1225 }
1226 
1227 static void
1228 print_memdevmap(smbios_hdl_t *shp, id_t id, FILE *fp)
1229 {
1230 	smbios_memdevmap_t md;
1231 
1232 	if (smbios_info_memdevmap(shp, id, &md) != 0) {
1233 		smbios_warn(shp, "failed to read memory device map "
1234 		    "information");
1235 		return;
1236 	}
1237 
1238 	id_printf(fp, "  Memory Device: ", md.smbmdm_device);
1239 	id_printf(fp, "  Memory Array Mapped Address: ", md.smbmdm_arrmap);
1240 
1241 	oprintf(fp, "  Physical Address: 0x%llx\n  Size: %llu bytes\n",
1242 	    (u_longlong_t)md.smbmdm_addr, (u_longlong_t)md.smbmdm_size);
1243 
1244 	oprintf(fp, "  Partition Row Position: %u\n", md.smbmdm_rpos);
1245 	oprintf(fp, "  Interleave Position: %u\n", md.smbmdm_ipos);
1246 	oprintf(fp, "  Interleave Data Depth: %u\n", md.smbmdm_idepth);
1247 }
1248 
1249 static void
1250 print_hwsec(smbios_hdl_t *shp, FILE *fp)
1251 {
1252 	smbios_hwsec_t h;
1253 
1254 	if (smbios_info_hwsec(shp, &h) == -1) {
1255 		smbios_warn(shp, "failed to read hwsec information");
1256 		return;
1257 	}
1258 
1259 	desc_printf(smbios_hwsec_desc(h.smbh_pwr_ps),
1260 	    fp, "  Power-On Password Status: %u", h.smbh_pwr_ps);
1261 	desc_printf(smbios_hwsec_desc(h.smbh_kbd_ps),
1262 	    fp, "  Keyboard Password Status: %u", h.smbh_kbd_ps);
1263 	desc_printf(smbios_hwsec_desc(h.smbh_adm_ps),
1264 	    fp, "  Administrator Password Status: %u", h.smbh_adm_ps);
1265 	desc_printf(smbios_hwsec_desc(h.smbh_pan_ps),
1266 	    fp, "  Front Panel Reset Status: %u", h.smbh_pan_ps);
1267 }
1268 
1269 static void
1270 print_vprobe(smbios_hdl_t *shp, id_t id, FILE *fp)
1271 {
1272 	smbios_vprobe_t vp;
1273 
1274 	if (smbios_info_vprobe(shp, id, &vp) != 0) {
1275 		smbios_warn(shp, "failed to read voltage probe information");
1276 		return;
1277 	}
1278 
1279 	str_print(fp, "  Description", vp.smbvp_description != NULL ?
1280 	    vp.smbvp_description : "unknown");
1281 	desc_printf(smbios_vprobe_loc_desc(vp.smbvp_location),
1282 	    fp, "  Location: %u", vp.smbvp_location);
1283 	desc_printf(smbios_vprobe_status_desc(vp.smbvp_status),
1284 	    fp, "  Status: %u", vp.smbvp_status);
1285 
1286 	if (vp.smbvp_maxval != SMB_PROBE_UNKNOWN_VALUE) {
1287 		oprintf(fp, "  Maximum Possible Voltage: %u mV\n",
1288 		    vp.smbvp_maxval);
1289 	} else {
1290 		oprintf(fp, "  Maximum Possible Voltage: unknown\n");
1291 	}
1292 
1293 	if (vp.smbvp_minval != SMB_PROBE_UNKNOWN_VALUE) {
1294 		oprintf(fp, "  Minimum Possible Voltage: %u mV\n",
1295 		    vp.smbvp_minval);
1296 	} else {
1297 		oprintf(fp, "  Minimum Possible Voltage: unknown\n");
1298 	}
1299 
1300 	if (vp.smbvp_resolution != SMB_PROBE_UNKNOWN_VALUE) {
1301 		oprintf(fp, "  Probe Resolution: %u.%u mV\n",
1302 		    vp.smbvp_resolution / 10,
1303 		    vp.smbvp_resolution % 10);
1304 	} else {
1305 		oprintf(fp, "  Probe Resolution: unknown\n");
1306 	}
1307 
1308 	if (vp.smbvp_tolerance != SMB_PROBE_UNKNOWN_VALUE) {
1309 		oprintf(fp, "  Probe Tolerance: +/-%u mV\n",
1310 		    vp.smbvp_tolerance);
1311 	} else {
1312 		oprintf(fp, "  Probe Tolerance: unknown\n");
1313 	}
1314 
1315 	if (vp.smbvp_accuracy != SMB_PROBE_UNKNOWN_VALUE) {
1316 		oprintf(fp, "  Probe Accuracy: +/-%u.%02u%%\n",
1317 		    vp.smbvp_accuracy / 100,
1318 		    vp.smbvp_accuracy % 100);
1319 	} else {
1320 		oprintf(fp, "  Probe Accuracy: unknown\n");
1321 	}
1322 
1323 	oprintf(fp, "  OEM- or BIOS- defined value: 0x%x\n", vp.smbvp_oem);
1324 
1325 	if (vp.smbvp_nominal != SMB_PROBE_UNKNOWN_VALUE) {
1326 		oprintf(fp, "  Probe Nominal Value: %u mV\n", vp.smbvp_nominal);
1327 	} else {
1328 		oprintf(fp, "  Probe Nominal Value: unknown\n");
1329 	}
1330 }
1331 
1332 static void
1333 print_cooldev(smbios_hdl_t *shp, id_t id, FILE *fp)
1334 {
1335 	smbios_cooldev_t cd;
1336 
1337 	if (smbios_info_cooldev(shp, id, &cd) != 0) {
1338 		smbios_warn(shp, "failed to read cooling device "
1339 		    "information");
1340 		return;
1341 	}
1342 
1343 	id_printf(fp, "  Temperature Probe Handle: ", cd.smbcd_tprobe);
1344 	desc_printf(smbios_cooldev_type_desc(cd.smbcd_type),
1345 	    fp, "  Device Type: %u", cd.smbcd_type);
1346 	desc_printf(smbios_cooldev_status_desc(cd.smbcd_status),
1347 	    fp, "  Status: %u", cd.smbcd_status);
1348 	oprintf(fp, "  Cooling Unit Group: %u\n", cd.smbcd_group);
1349 	oprintf(fp, "  OEM- or BIOS- defined data: 0x%x\n", cd.smbcd_oem);
1350 	if (cd.smbcd_nominal != SMB_PROBE_UNKNOWN_VALUE) {
1351 		oprintf(fp, "  Nominal Speed: %u RPM\n", cd.smbcd_nominal);
1352 	} else {
1353 		oprintf(fp, "  Nominal Speed: unknown\n");
1354 	}
1355 
1356 	if (cd.smbcd_descr != NULL && cd.smbcd_descr[0] != '\0') {
1357 		str_print(fp, "  Description", cd.smbcd_descr);
1358 	}
1359 }
1360 
1361 static void
1362 print_tprobe(smbios_hdl_t *shp, id_t id, FILE *fp)
1363 {
1364 	smbios_tprobe_t tp;
1365 
1366 	if (smbios_info_tprobe(shp, id, &tp) != 0) {
1367 		smbios_warn(shp, "failed to read temperature probe "
1368 		    "information");
1369 		return;
1370 	}
1371 
1372 	str_print(fp, "  Description", tp.smbtp_description != NULL ?
1373 	    tp.smbtp_description : "unknown");
1374 	desc_printf(smbios_tprobe_loc_desc(tp.smbtp_location),
1375 	    fp, "  Location: %u", tp.smbtp_location);
1376 	desc_printf(smbios_tprobe_status_desc(tp.smbtp_status),
1377 	    fp, "  Status: %u", tp.smbtp_status);
1378 
1379 	if (tp.smbtp_maxval != SMB_PROBE_UNKNOWN_VALUE) {
1380 		oprintf(fp, "  Maximum Possible Temperature: %u.%u C\n",
1381 		    tp.smbtp_maxval / 10, tp.smbtp_maxval % 10);
1382 	} else {
1383 		oprintf(fp, "  Maximum Possible Temperature: unknown\n");
1384 	}
1385 
1386 	if (tp.smbtp_minval != SMB_PROBE_UNKNOWN_VALUE) {
1387 		oprintf(fp, "  Minimum Possible Temperature: %u.%u C\n",
1388 		    tp.smbtp_minval / 10, tp.smbtp_minval % 10);
1389 	} else {
1390 		oprintf(fp, "  Minimum Possible Temperature: unknown\n");
1391 	}
1392 
1393 	if (tp.smbtp_resolution != SMB_PROBE_UNKNOWN_VALUE) {
1394 		oprintf(fp, "  Probe Resolution: %u.%03u C\n",
1395 		    tp.smbtp_resolution / 1000,
1396 		    tp.smbtp_resolution % 1000);
1397 	} else {
1398 		oprintf(fp, "  Probe Resolution: unknown\n");
1399 	}
1400 
1401 	if (tp.smbtp_tolerance != SMB_PROBE_UNKNOWN_VALUE) {
1402 		oprintf(fp, "  Probe Tolerance: +/-%u.%u C\n",
1403 		    tp.smbtp_tolerance / 10, tp.smbtp_tolerance % 10);
1404 	} else {
1405 		oprintf(fp, "  Probe Tolerance: unknown\n");
1406 	}
1407 
1408 	if (tp.smbtp_accuracy != SMB_PROBE_UNKNOWN_VALUE) {
1409 		oprintf(fp, "  Probe Accuracy: +/-%u.%02u%%\n",
1410 		    tp.smbtp_accuracy / 100,
1411 		    tp.smbtp_accuracy % 100);
1412 	} else {
1413 		oprintf(fp, "  Probe Accuracy: unknown\n");
1414 	}
1415 
1416 	oprintf(fp, "  OEM- or BIOS- defined value: 0x%x\n", tp.smbtp_oem);
1417 
1418 	if (tp.smbtp_nominal != SMB_PROBE_UNKNOWN_VALUE) {
1419 		oprintf(fp, "  Probe Nominal Value: %u.%u C\n",
1420 		    tp.smbtp_nominal / 10, tp.smbtp_nominal % 10);
1421 	} else {
1422 		oprintf(fp, "  Probe Nominal Value: unknown\n");
1423 	}
1424 }
1425 
1426 static void
1427 print_iprobe(smbios_hdl_t *shp, id_t id, FILE *fp)
1428 {
1429 	smbios_iprobe_t ip;
1430 
1431 	if (smbios_info_iprobe(shp, id, &ip) != 0) {
1432 		smbios_warn(shp, "failed to read current probe information");
1433 		return;
1434 	}
1435 
1436 	str_print(fp, "  Description", ip.smbip_description != NULL ?
1437 	    ip.smbip_description : "unknown");
1438 	desc_printf(smbios_iprobe_loc_desc(ip.smbip_location),
1439 	    fp, "  Location: %u", ip.smbip_location);
1440 	desc_printf(smbios_iprobe_status_desc(ip.smbip_status),
1441 	    fp, "  Status: %u", ip.smbip_status);
1442 
1443 	if (ip.smbip_maxval != SMB_PROBE_UNKNOWN_VALUE) {
1444 		oprintf(fp, "  Maximum Possible Current: %u mA\n",
1445 		    ip.smbip_maxval);
1446 	} else {
1447 		oprintf(fp, "  Maximum Possible Current: unknown\n");
1448 	}
1449 
1450 	if (ip.smbip_minval != SMB_PROBE_UNKNOWN_VALUE) {
1451 		oprintf(fp, "  Minimum Possible Current: %u mA\n",
1452 		    ip.smbip_minval);
1453 	} else {
1454 		oprintf(fp, "  Minimum Possible Current: unknown\n");
1455 	}
1456 
1457 	if (ip.smbip_resolution != SMB_PROBE_UNKNOWN_VALUE) {
1458 		oprintf(fp, "  Probe Resolution: %u.%u mA\n",
1459 		    ip.smbip_resolution / 10,
1460 		    ip.smbip_resolution % 10);
1461 	} else {
1462 		oprintf(fp, "  Probe Resolution: unknown\n");
1463 	}
1464 
1465 	if (ip.smbip_tolerance != SMB_PROBE_UNKNOWN_VALUE) {
1466 		oprintf(fp, "  Probe Tolerance: +/-%u mA\n",
1467 		    ip.smbip_tolerance);
1468 	} else {
1469 		oprintf(fp, "  Probe Tolerance: unknown\n");
1470 	}
1471 
1472 	if (ip.smbip_accuracy != SMB_PROBE_UNKNOWN_VALUE) {
1473 		oprintf(fp, "  Probe Accuracy: +/-%u.%02u%%\n",
1474 		    ip.smbip_accuracy / 100,
1475 		    ip.smbip_accuracy % 100);
1476 	} else {
1477 		oprintf(fp, "  Probe Accuracy: unknown\n");
1478 	}
1479 
1480 	oprintf(fp, "  OEM- or BIOS- defined value: 0x%x\n", ip.smbip_oem);
1481 
1482 	if (ip.smbip_nominal != SMB_PROBE_UNKNOWN_VALUE) {
1483 		oprintf(fp, "  Probe Nominal Value: %u mA\n", ip.smbip_nominal);
1484 	} else {
1485 		oprintf(fp, "  Probe Nominal Value: unknown\n");
1486 	}
1487 }
1488 
1489 static void
1490 print_boot(smbios_hdl_t *shp, FILE *fp)
1491 {
1492 	smbios_boot_t b;
1493 
1494 	if (smbios_info_boot(shp, &b) == -1) {
1495 		smbios_warn(shp, "failed to read boot information");
1496 		return;
1497 	}
1498 
1499 	desc_printf(smbios_boot_desc(b.smbt_status),
1500 	    fp, "  Boot Status Code: 0x%x", b.smbt_status);
1501 
1502 	if (b.smbt_size != 0) {
1503 		oprintf(fp, "  Boot Data (%lu bytes):\n", (ulong_t)b.smbt_size);
1504 		print_bytes(b.smbt_data, b.smbt_size, fp);
1505 	}
1506 }
1507 
1508 static void
1509 print_ipmi(smbios_hdl_t *shp, FILE *fp)
1510 {
1511 	smbios_ipmi_t i;
1512 
1513 	if (smbios_info_ipmi(shp, &i) == -1) {
1514 		smbios_warn(shp, "failed to read ipmi information");
1515 		return;
1516 	}
1517 
1518 	desc_printf(smbios_ipmi_type_desc(i.smbip_type),
1519 	    fp, "  Type: %u", i.smbip_type);
1520 
1521 	oprintf(fp, "  BMC IPMI Version: %u.%u\n",
1522 	    i.smbip_vers.smbv_major, i.smbip_vers.smbv_minor);
1523 
1524 	oprintf(fp, "  i2c Bus Slave Address: 0x%x\n", i.smbip_i2c);
1525 	oprintf(fp, "  NV Storage Device Bus ID: 0x%x\n", i.smbip_bus);
1526 	oprintf(fp, "  BMC Base Address: 0x%llx\n", (u_longlong_t)i.smbip_addr);
1527 	oprintf(fp, "  Interrupt Number: %u\n", i.smbip_intr);
1528 	oprintf(fp, "  Register Spacing: %u\n", i.smbip_regspacing);
1529 
1530 	flag_printf(fp, "Flags", i.smbip_flags, sizeof (i.smbip_flags) * NBBY,
1531 	    smbios_ipmi_flag_name, smbios_ipmi_flag_desc);
1532 }
1533 
1534 static void
1535 print_powersup(smbios_hdl_t *shp, id_t id, FILE *fp)
1536 {
1537 	smbios_powersup_t p;
1538 
1539 	if (smbios_info_powersup(shp, id, &p) != 0) {
1540 		smbios_warn(shp, "failed to read power supply information");
1541 		return;
1542 	}
1543 
1544 	oprintf(fp, "  Power Supply Group: %u\n", p.smbps_group);
1545 	if (p.smbps_maxout != 0x8000) {
1546 		oprintf(fp, "  Maximum Output: %" PRIu64 " mW\n",
1547 		    p.smbps_maxout);
1548 	} else {
1549 		oprintf(fp, "  Maximum Output: unknown\n");
1550 	}
1551 
1552 	flag_printf(fp, "Characteristics", p.smbps_flags,
1553 	    sizeof (p.smbps_flags) * NBBY, smbios_powersup_flag_name,
1554 	    smbios_powersup_flag_desc);
1555 
1556 	desc_printf(smbios_powersup_input_desc(p.smbps_ivrs),
1557 	    fp, "  Input Voltage Range Switching: %u", p.smbps_ivrs);
1558 	desc_printf(smbios_powersup_status_desc(p.smbps_status),
1559 	    fp, "  Status: %u", p.smbps_status);
1560 	desc_printf(smbios_powersup_type_desc(p.smbps_pstype),
1561 	    fp, "  Type: %u", p.smbps_pstype);
1562 
1563 	if (p.smbps_vprobe != 0xffff) {
1564 		oprintf(fp, "  Voltage Probe Handle: %" _PRIuID "\n",
1565 		    p.smbps_vprobe);
1566 	}
1567 
1568 	if (p.smbps_cooldev != 0xffff) {
1569 		oprintf(fp, "  Cooling Device Handle: %" _PRIuID "\n",
1570 		    p.smbps_cooldev);
1571 	}
1572 
1573 	if (p.smbps_iprobe != 0xffff) {
1574 		oprintf(fp, "  Current Probe Handle: %" _PRIuID "\n",
1575 		    p.smbps_iprobe);
1576 	}
1577 }
1578 
1579 static void
1580 print_addinfo(smbios_hdl_t *shp, id_t id, FILE *fp)
1581 {
1582 	uint_t nents, i;
1583 
1584 	if (smbios_info_addinfo_nents(shp, id, &nents) != 0) {
1585 		smbios_warn(shp, "failed to read additional information");
1586 		return;
1587 	}
1588 
1589 	oprintf(fp, "  Number of Additional Information Entries: %u\n", nents);
1590 	for (i = 0; i < nents; i++) {
1591 		smbios_addinfo_ent_t *ent;
1592 
1593 		oprintf(fp, "  Additional Information Entry %u\n", i);
1594 		if (smbios_info_addinfo_ent(shp, id, i, &ent) != 0) {
1595 			smbios_warn(shp, "failed to read additional "
1596 			    "information entry %u", i);
1597 			continue;
1598 		}
1599 
1600 		oprintf(fp, "    Referenced handle: %" _PRIuID "\n",
1601 		    ent->smbai_ref);
1602 		oprintf(fp, "    Handle offset: %u\n", ent->smbai_ref_off);
1603 		if (ent->smbai_str != NULL) {
1604 			str_print(fp, "    Information String", ent->smbai_str);
1605 		}
1606 
1607 		/*
1608 		 * As of SMBIOS 3.7, there are no extra data entries strictly
1609 		 * defined in the spec, but there may be something. If we find
1610 		 * something that's a standard integer size, then we'll
1611 		 * interpret it and print it as a hex value. In theory this is
1612 		 * supposed to refer back to some field, but hard to say how
1613 		 * this'll actually be used. The first time we encountered it
1614 		 * was just an additional string entry.
1615 		 */
1616 		if (ent->smbai_dlen > 0) {
1617 			oprintf(fp, "    Data Length: %u\n", ent->smbai_dlen);
1618 			switch (ent->smbai_dlen) {
1619 			case 1:
1620 				oprintf(fp, "    Data: 0x%x\n",
1621 				    *(uint8_t *)ent->smbai_data);
1622 				break;
1623 			case 2:
1624 				oprintf(fp, "    Data: 0x%x\n",
1625 				    *(uint16_t *)ent->smbai_data);
1626 				break;
1627 			case 4:
1628 				oprintf(fp, "    Data: 0x%x\n",
1629 				    *(uint32_t *)ent->smbai_data);
1630 				break;
1631 			case 8:
1632 				oprintf(fp, "    Data: 0x%" PRIx64 "\n",
1633 				    *(uint64_t *)ent->smbai_data);
1634 				break;
1635 			default:
1636 				break;
1637 			}
1638 		}
1639 
1640 		smbios_info_addinfo_ent_free(shp, ent);
1641 	}
1642 }
1643 
1644 
1645 static void
1646 print_processor_info_riscv(smbios_hdl_t *shp, id_t id, FILE *fp)
1647 {
1648 	smbios_processor_info_riscv_t rv;
1649 
1650 	if (smbios_info_processor_riscv(shp, id, &rv) != 0) {
1651 		smbios_warn(shp, "failed to read RISC-V specific processor "
1652 		    "information");
1653 		return;
1654 	}
1655 
1656 	if (rv.smbpirv_boothart != 0) {
1657 		oprintf(fp, "    Boot Hart\n");
1658 	}
1659 	u128_print(fp, "    Hart ID", rv.smbpirv_hartid);
1660 	u128_print(fp, "    Vendor ID", rv.smbpirv_vendid);
1661 	u128_print(fp, "    Architecture ID", rv.smbpirv_archid);
1662 	u128_print(fp, "    Implementation ID", rv.smbpirv_machid);
1663 	flag64_printf(fp, "  ISA", rv.smbpirv_isa,
1664 	    sizeof (rv.smbpirv_isa) * NBBY, smbios_riscv_isa_name,
1665 	    smbios_riscv_isa_desc);
1666 	flag_printf(fp, "  Privilege Levels", rv.smbpirv_privlvl,
1667 	    sizeof (rv.smbpirv_privlvl) * NBBY, smbios_riscv_priv_name,
1668 	    smbios_riscv_priv_desc);
1669 	u128_print(fp, "    Machine Exception Trap Delegation",
1670 	    rv.smbpirv_metdi);
1671 	u128_print(fp, "    Machine Interrupt Trap Delegation",
1672 	    rv.smbpirv_mitdi);
1673 	desc_printf(smbios_riscv_width_desc(rv.smbpirv_xlen),
1674 	    fp, "    Register Width: 0x%x", rv.smbpirv_xlen);
1675 	desc_printf(smbios_riscv_width_desc(rv.smbpirv_mxlen),
1676 	    fp, "    M-Mode Register Width: 0x%x", rv.smbpirv_mxlen);
1677 	desc_printf(smbios_riscv_width_desc(rv.smbpirv_sxlen),
1678 	    fp, "    S-Mode Register Width: 0x%x", rv.smbpirv_sxlen);
1679 	desc_printf(smbios_riscv_width_desc(rv.smbpirv_uxlen),
1680 	    fp, "    U-Mode Register Width: 0x%x", rv.smbpirv_uxlen);
1681 }
1682 
1683 static void
1684 print_processor_info(smbios_hdl_t *shp, id_t id, FILE *fp)
1685 {
1686 	smbios_processor_info_t p;
1687 
1688 	if (smbios_info_processor_info(shp, id, &p) != 0) {
1689 		smbios_warn(shp, "failed to read processor additional "
1690 		    "information");
1691 		return;
1692 	}
1693 
1694 	id_printf(fp, "  Processor Handle: ", p.smbpi_processor);
1695 	desc_printf(smbios_processor_info_type_desc(p.smbpi_ptype),
1696 	    fp, "  Processor Type: %u", p.smbpi_ptype);
1697 
1698 	switch (p.smbpi_ptype) {
1699 	case SMB_PROCINFO_T_RV32:
1700 	case SMB_PROCINFO_T_RV64:
1701 	case SMB_PROCINFO_T_RV128:
1702 		oprintf(fp, "  RISC-V Additional Processor Information:\n");
1703 		print_processor_info_riscv(shp, id, fp);
1704 		break;
1705 	default:
1706 		break;
1707 	}
1708 }
1709 
1710 static void
1711 print_battery(smbios_hdl_t *shp, id_t id, FILE *fp)
1712 {
1713 	smbios_battery_t bat;
1714 
1715 	if (smbios_info_battery(shp, id, &bat) != 0) {
1716 		smbios_warn(shp, "failed to read battery information");
1717 		return;
1718 	}
1719 
1720 	if (bat.smbb_date != NULL) {
1721 		str_print(fp, "  Manufacture Date", bat.smbb_date);
1722 	}
1723 
1724 	if (bat.smbb_serial != NULL) {
1725 		str_print(fp, "  Serial Number", bat.smbb_serial);
1726 	}
1727 
1728 	if (bat.smbb_chem != SMB_BDC_UNKNOWN) {
1729 		desc_printf(smbios_battery_chem_desc(bat.smbb_chem),
1730 		    fp, "  Battery Chemistry: 0x%x", bat.smbb_chem);
1731 	}
1732 
1733 	if (bat.smbb_cap != 0) {
1734 		oprintf(fp, "  Design Capacity: %u mWh\n", bat.smbb_cap);
1735 	} else {
1736 		oprintf(fp, "  Design Capacity: unknown\n");
1737 	}
1738 
1739 	if (bat.smbb_volt != 0) {
1740 		oprintf(fp, "  Design Voltage: %u mV\n", bat.smbb_volt);
1741 	} else {
1742 		oprintf(fp, "  Design Voltage: unknown\n");
1743 	}
1744 
1745 	str_print(fp, "  SBDS Version Number", bat.smbb_version);
1746 	if (bat.smbb_err != UINT8_MAX) {
1747 		oprintf(fp, "  Maximum Error: %u\n", bat.smbb_err);
1748 	} else {
1749 		oprintf(fp, "  Maximum Error: unknown\n");
1750 	}
1751 	oprintf(fp, "  SBDS Serial Number: %04x\n", bat.smbb_ssn);
1752 	oprintf(fp, "  SBDS Manufacture Date: %u-%02u-%02u\n", bat.smbb_syear,
1753 	    bat.smbb_smonth, bat.smbb_sday);
1754 	str_print(fp, "  SBDS Device Chemistry", bat.smbb_schem);
1755 	oprintf(fp, "  OEM-specific Information: 0x%08x\n", bat.smbb_oemdata);
1756 }
1757 
1758 static void
1759 print_pointdev(smbios_hdl_t *shp, id_t id, FILE *fp)
1760 {
1761 	smbios_pointdev_t pd;
1762 
1763 	if (smbios_info_pointdev(shp, id, &pd) != 0) {
1764 		smbios_warn(shp, "failed to read pointer device information");
1765 		return;
1766 	}
1767 
1768 	desc_printf(smbios_pointdev_type_desc(pd.smbpd_type),
1769 	    fp, "  Type: %u", pd.smbpd_type);
1770 	desc_printf(smbios_pointdev_iface_desc(pd.smbpd_iface),
1771 	    fp, "  Interface: %u", pd.smbpd_iface);
1772 	oprintf(fp, "  Buttons: %u\n", pd.smbpd_nbuttons);
1773 }
1774 
1775 static void
1776 print_extprocessor(smbios_hdl_t *shp, id_t id, FILE *fp)
1777 {
1778 	int i;
1779 	smbios_processor_ext_t ep;
1780 
1781 	if (check_oem(shp) != 0)
1782 		return;
1783 
1784 	if (smbios_info_extprocessor(shp, id, &ep) != 0) {
1785 		smbios_warn(shp, "failed to read extended processor "
1786 		    "information");
1787 		return;
1788 	}
1789 
1790 	oprintf(fp, "  Processor: %u\n", ep.smbpe_processor);
1791 	oprintf(fp, "  FRU: %u\n", ep.smbpe_fru);
1792 	oprintf(fp, "  Initial APIC ID count: %u\n\n", ep.smbpe_n);
1793 
1794 	for (i = 0; i < ep.smbpe_n; i++) {
1795 		oprintf(fp, "  Logical Strand %u: Initial APIC ID: %u\n", i,
1796 		    ep.smbpe_apicid[i]);
1797 	}
1798 }
1799 
1800 static void
1801 print_extport(smbios_hdl_t *shp, id_t id, FILE *fp)
1802 {
1803 	smbios_port_ext_t epo;
1804 
1805 	if (check_oem(shp) != 0)
1806 		return;
1807 
1808 	if (smbios_info_extport(shp, id, &epo) != 0) {
1809 		smbios_warn(shp, "failed to read extended port information");
1810 		return;
1811 	}
1812 
1813 	oprintf(fp, "  Chassis Handle: %u\n", epo.smbporte_chassis);
1814 	oprintf(fp, "  Port Connector Handle: %u\n", epo.smbporte_port);
1815 	oprintf(fp, "  Device Type: %u\n", epo.smbporte_dtype);
1816 	oprintf(fp, "  Device Handle: %u\n", epo.smbporte_devhdl);
1817 	oprintf(fp, "  PHY: %u\n", epo.smbporte_phy);
1818 }
1819 
1820 static void
1821 print_pciexrc(smbios_hdl_t *shp, id_t id, FILE *fp)
1822 {
1823 	smbios_pciexrc_t pcie;
1824 
1825 	if (check_oem(shp) != 0)
1826 		return;
1827 
1828 	if (smbios_info_pciexrc(shp, id, &pcie) != 0) {
1829 		smbios_warn(shp, "failed to read pciexrc information");
1830 		return;
1831 	}
1832 
1833 	oprintf(fp, "  Component ID: %u\n", pcie.smbpcie_bb);
1834 	oprintf(fp, "  BDF: 0x%x\n", pcie.smbpcie_bdf);
1835 }
1836 
1837 static void
1838 print_extmemarray(smbios_hdl_t *shp, id_t id, FILE *fp)
1839 {
1840 	smbios_memarray_ext_t em;
1841 
1842 	if (check_oem(shp) != 0)
1843 		return;
1844 
1845 	if (smbios_info_extmemarray(shp, id, &em) != 0) {
1846 		smbios_warn(shp, "failed to read extmemarray information");
1847 		return;
1848 	}
1849 
1850 	oprintf(fp, "  Physical Memory Array Handle: %u\n", em.smbmae_ma);
1851 	oprintf(fp, "  Component Parent Handle: %u\n", em.smbmae_comp);
1852 	oprintf(fp, "  BDF: 0x%x\n", em.smbmae_bdf);
1853 }
1854 
1855 static void
1856 print_extmemdevice(smbios_hdl_t *shp, id_t id, FILE *fp)
1857 {
1858 	uint_t i, ncs;
1859 	uint8_t *cs;
1860 	smbios_memdevice_ext_t emd;
1861 
1862 	if (check_oem(shp) != 0)
1863 		return;
1864 
1865 	if (smbios_info_extmemdevice(shp, id, &emd) != 0) {
1866 		smbios_warn(shp, "failed to read extmemdevice information");
1867 		return;
1868 	}
1869 
1870 	oprintf(fp, "  Memory Device Handle: %u\n", emd.smbmdeve_md);
1871 	oprintf(fp, "  DRAM Channel: %u\n", emd.smbmdeve_drch);
1872 	oprintf(fp, "  Number of Chip Selects: %u\n", emd.smbmdeve_ncs);
1873 
1874 	if (emd.smbmdeve_ncs == 0)
1875 		return;
1876 
1877 	if (smbios_info_extmemdevice_cs(shp, id, &ncs, &cs) != 0) {
1878 		smbios_warn(shp, "failed to read extmemdevice cs information");
1879 		return;
1880 	}
1881 
1882 	for (i = 0; i < ncs; i++) {
1883 		oprintf(fp, "  Chip Select: %u\n", cs[i]);
1884 	}
1885 	smbios_info_extmemdevice_cs_free(shp, ncs, cs);
1886 }
1887 
1888 static void
1889 print_strprop_info(smbios_hdl_t *shp, id_t id, FILE *fp)
1890 {
1891 	smbios_strprop_t prop;
1892 
1893 	if (smbios_info_strprop(shp, id, &prop) != 0) {
1894 		smbios_warn(shp, "failed to read string property information");
1895 		return;
1896 	}
1897 
1898 	desc_printf(smbios_strprop_id_desc(prop.smbsp_prop_id), fp,
1899 	    "  Property ID: %u", prop.smbsp_prop_id);
1900 	if (prop.smbsp_prop_val != NULL) {
1901 		str_print(fp, "  Property Value", prop.smbsp_prop_val);
1902 	}
1903 	id_printf(fp, "  Parent Handle: ", prop.smbsp_parent);
1904 }
1905 
1906 static void
1907 print_fwinfo(smbios_hdl_t *shp, id_t id, FILE *fp)
1908 {
1909 	smbios_fwinfo_t fw;
1910 	smbios_fwinfo_comp_t *comps;
1911 	uint_t ncomps, i;
1912 
1913 	if (smbios_info_fwinfo(shp, id, &fw) != 0) {
1914 		smbios_warn(shp, "failed to read firmware inventory");
1915 		return;
1916 	}
1917 
1918 	str_print(fp, "  Component Name", fw.smbfw_name);
1919 	str_print(fp, "  ID", fw.smbfw_id);
1920 	str_print(fp, "  Release Date", fw.smbfw_reldate);
1921 	str_print(fp, "  Lowest Supported Version", fw.smbfw_lsv);
1922 	desc_printf(smbios_fwinfo_vers_desc(fw.smbfw_vers_fmt), fp,
1923 	    "  Version Format: %u", fw.smbfw_vers_fmt);
1924 	desc_printf(smbios_fwinfo_id_desc(fw.smbfw_id_fmt), fp,
1925 	    "  ID Format: %u", fw.smbfw_id_fmt);
1926 	if (fw.smbfw_imgsz != UINT64_MAX) {
1927 		oprintf(fp, "  Image Size: %" PRIu64 "\n", fw.smbfw_imgsz);
1928 	} else {
1929 		oprintf(fp, "  Image Size: unknown\n");
1930 	}
1931 
1932 	flag_printf(fp, "Characteristics", fw.smbfw_chars,
1933 	    sizeof (fw.smbfw_chars) * NBBY, smbios_fwinfo_ch_name,
1934 	    smbios_fwinfo_ch_desc);
1935 
1936 	desc_printf(smbios_fwinfo_state_desc(fw.smbfw_state), fp, "  State: %u",
1937 	    fw.smbfw_state);
1938 	oprintf(fp, "  Number of Associated Components: %u\n",
1939 	    fw.smbfw_ncomps);
1940 
1941 	if (fw.smbfw_ncomps == 0)
1942 		return;
1943 
1944 	if (smbios_info_fwinfo_comps(shp, id, &ncomps, &comps) == -1) {
1945 		smbios_warn(shp, "failed to read firmware inventory "
1946 		    "components");
1947 		return;
1948 	}
1949 
1950 	oprintf(fp, "\n  Component Handles:\n");
1951 	for (i = 0; i < ncomps; i++) {
1952 		oprintf(fp, "    %" _PRIdID "\n", comps[i].smbfwe_id);
1953 	}
1954 }
1955 
1956 static int
1957 print_struct(smbios_hdl_t *shp, const smbios_struct_t *sp, void *fp)
1958 {
1959 	smbios_info_t info;
1960 	int hex = opt_x;
1961 	const char *s;
1962 
1963 	if (opt_t != -1 && opt_t != sp->smbstr_type)
1964 		return (0); /* skip struct if type doesn't match -t */
1965 
1966 	if (!opt_O && (sp->smbstr_type == SMB_TYPE_MEMCTL ||
1967 	    sp->smbstr_type == SMB_TYPE_MEMMOD))
1968 		return (0); /* skip struct if type is obsolete */
1969 
1970 	if (g_hdr++ == 0 || !opt_s)
1971 		oprintf(fp, "%-5s %-4s %s\n", "ID", "SIZE", "TYPE");
1972 
1973 	oprintf(fp, "%-5u %-4lu",
1974 	    (uint_t)sp->smbstr_id, (ulong_t)sp->smbstr_size);
1975 
1976 	if ((s = smbios_type_name(sp->smbstr_type)) != NULL)
1977 		oprintf(fp, " %s (type %u)", s, sp->smbstr_type);
1978 	else if (sp->smbstr_type > SMB_TYPE_OEM_LO &&
1979 	    sp->smbstr_type < SMB_TYPE_OEM_HI)
1980 		oprintf(fp, " %s+%u (type %u)", "SMB_TYPE_OEM_LO",
1981 		    sp->smbstr_type - SMB_TYPE_OEM_LO, sp->smbstr_type);
1982 	else
1983 		oprintf(fp, " %u", sp->smbstr_type);
1984 
1985 	if ((s = smbios_type_desc(sp->smbstr_type)) != NULL)
1986 		oprintf(fp, " (%s)\n", s);
1987 	else
1988 		oprintf(fp, "\n");
1989 
1990 	if (opt_s)
1991 		return (0); /* only print header line if -s specified */
1992 
1993 	if (smbios_info_common(shp, sp->smbstr_id, &info) == 0) {
1994 		oprintf(fp, "\n");
1995 		print_common(&info, fp);
1996 	}
1997 
1998 	switch (sp->smbstr_type) {
1999 	case SMB_TYPE_BIOS:
2000 		oprintf(fp, "\n");
2001 		print_bios(shp, fp);
2002 		break;
2003 	case SMB_TYPE_SYSTEM:
2004 		oprintf(fp, "\n");
2005 		print_system(shp, fp);
2006 		break;
2007 	case SMB_TYPE_BASEBOARD:
2008 		oprintf(fp, "\n");
2009 		print_bboard(shp, sp->smbstr_id, fp);
2010 		break;
2011 	case SMB_TYPE_CHASSIS:
2012 		oprintf(fp, "\n");
2013 		print_chassis(shp, sp->smbstr_id, fp);
2014 		break;
2015 	case SMB_TYPE_PROCESSOR:
2016 		oprintf(fp, "\n");
2017 		print_processor(shp, sp->smbstr_id, fp);
2018 		break;
2019 	case SMB_TYPE_CACHE:
2020 		oprintf(fp, "\n");
2021 		print_cache(shp, sp->smbstr_id, fp);
2022 		break;
2023 	case SMB_TYPE_PORT:
2024 		oprintf(fp, "\n");
2025 		print_port(shp, sp->smbstr_id, fp);
2026 		break;
2027 	case SMB_TYPE_SLOT:
2028 		oprintf(fp, "\n");
2029 		print_slot(shp, sp->smbstr_id, fp);
2030 		break;
2031 	case SMB_TYPE_OBDEVS:
2032 		oprintf(fp, "\n");
2033 		print_obdevs(shp, sp->smbstr_id, fp);
2034 		break;
2035 	case SMB_TYPE_OEMSTR:
2036 	case SMB_TYPE_SYSCONFSTR:
2037 		oprintf(fp, "\n");
2038 		print_strtab(shp, sp->smbstr_id, fp);
2039 		break;
2040 	case SMB_TYPE_LANG:
2041 		oprintf(fp, "\n");
2042 		print_lang(shp, sp->smbstr_id, fp);
2043 		break;
2044 	case SMB_TYPE_EVENTLOG:
2045 		oprintf(fp, "\n");
2046 		print_evlog(shp, sp->smbstr_id, fp);
2047 		break;
2048 	case SMB_TYPE_MEMARRAY:
2049 		oprintf(fp, "\n");
2050 		print_memarray(shp, sp->smbstr_id, fp);
2051 		break;
2052 	case SMB_TYPE_MEMDEVICE:
2053 		oprintf(fp, "\n");
2054 		print_memdevice(shp, sp->smbstr_id, fp);
2055 		break;
2056 	case SMB_TYPE_MEMARRAYMAP:
2057 		oprintf(fp, "\n");
2058 		print_memarrmap(shp, sp->smbstr_id, fp);
2059 		break;
2060 	case SMB_TYPE_MEMDEVICEMAP:
2061 		oprintf(fp, "\n");
2062 		print_memdevmap(shp, sp->smbstr_id, fp);
2063 		break;
2064 	case SMB_TYPE_BATTERY:
2065 		oprintf(fp, "\n");
2066 		print_battery(shp, sp->smbstr_id, fp);
2067 		break;
2068 	case SMB_TYPE_POINTDEV:
2069 		oprintf(fp, "\n");
2070 		print_pointdev(shp, sp->smbstr_id, fp);
2071 		break;
2072 	case SMB_TYPE_SECURITY:
2073 		oprintf(fp, "\n");
2074 		print_hwsec(shp, fp);
2075 		break;
2076 	case SMB_TYPE_VPROBE:
2077 		oprintf(fp, "\n");
2078 		print_vprobe(shp, sp->smbstr_id, fp);
2079 		break;
2080 	case SMB_TYPE_COOLDEV:
2081 		oprintf(fp, "\n");
2082 		print_cooldev(shp, sp->smbstr_id, fp);
2083 		break;
2084 	case SMB_TYPE_TPROBE:
2085 		oprintf(fp, "\n");
2086 		print_tprobe(shp, sp->smbstr_id, fp);
2087 		break;
2088 	case SMB_TYPE_IPROBE:
2089 		oprintf(fp, "\n");
2090 		print_iprobe(shp, sp->smbstr_id, fp);
2091 		break;
2092 	case SMB_TYPE_BOOT:
2093 		oprintf(fp, "\n");
2094 		print_boot(shp, fp);
2095 		break;
2096 	case SMB_TYPE_IPMIDEV:
2097 		oprintf(fp, "\n");
2098 		print_ipmi(shp, fp);
2099 		break;
2100 	case SMB_TYPE_POWERSUP:
2101 		oprintf(fp, "\n");
2102 		print_powersup(shp, sp->smbstr_id, fp);
2103 		break;
2104 	case SMB_TYPE_ADDINFO:
2105 		oprintf(fp, "\n");
2106 		print_addinfo(shp, sp->smbstr_id, fp);
2107 		break;
2108 	case SMB_TYPE_OBDEVEXT:
2109 		oprintf(fp, "\n");
2110 		print_obdevs_ext(shp, sp->smbstr_id, fp);
2111 		break;
2112 	case SMB_TYPE_PROCESSOR_INFO:
2113 		oprintf(fp, "\n");
2114 		print_processor_info(shp, sp->smbstr_id, fp);
2115 		break;
2116 	case SMB_TYPE_STRPROP:
2117 		oprintf(fp, "\n");
2118 		print_strprop_info(shp, sp->smbstr_id, fp);
2119 		break;
2120 	case SMB_TYPE_FWINFO:
2121 		oprintf(fp, "\n");
2122 		print_fwinfo(shp, sp->smbstr_id, fp);
2123 		break;
2124 	case SUN_OEM_EXT_PROCESSOR:
2125 		oprintf(fp, "\n");
2126 		print_extprocessor(shp, sp->smbstr_id, fp);
2127 		break;
2128 	case SUN_OEM_EXT_PORT:
2129 		oprintf(fp, "\n");
2130 		print_extport(shp, sp->smbstr_id, fp);
2131 		break;
2132 	case SUN_OEM_PCIEXRC:
2133 		oprintf(fp, "\n");
2134 		print_pciexrc(shp, sp->smbstr_id, fp);
2135 		break;
2136 	case SUN_OEM_EXT_MEMARRAY:
2137 		oprintf(fp, "\n");
2138 		print_extmemarray(shp, sp->smbstr_id, fp);
2139 		break;
2140 	case SUN_OEM_EXT_MEMDEVICE:
2141 		oprintf(fp, "\n");
2142 		print_extmemdevice(shp, sp->smbstr_id, fp);
2143 		break;
2144 	default:
2145 		hex++;
2146 	}
2147 
2148 	if (hex)
2149 		print_bytes(sp->smbstr_data, sp->smbstr_size, fp);
2150 	else
2151 		oprintf(fp, "\n");
2152 
2153 	return (0);
2154 }
2155 
2156 static uint16_t
2157 getu16(const char *name, const char *s)
2158 {
2159 	u_longlong_t val;
2160 	char *p;
2161 
2162 	errno = 0;
2163 	val = strtoull(s, &p, 0);
2164 
2165 	if (errno != 0 || p == s || *p != '\0' || val > UINT16_MAX) {
2166 		(void) fprintf(stderr, "%s: invalid %s argument -- %s\n",
2167 		    g_pname, name, s);
2168 		exit(SMBIOS_USAGE);
2169 	}
2170 
2171 	return ((uint16_t)val);
2172 }
2173 
2174 static uint16_t
2175 getstype(const char *name, const char *s)
2176 {
2177 	const char *ts;
2178 	uint16_t t;
2179 
2180 	for (t = 0; t < SMB_TYPE_OEM_LO; t++) {
2181 		if ((ts = smbios_type_name(t)) != NULL && strcmp(s, ts) == 0)
2182 			return (t);
2183 	}
2184 
2185 	(void) fprintf(stderr, "%s: invalid %s argument -- %s\n",
2186 	    g_pname, name, s);
2187 
2188 	exit(SMBIOS_USAGE);
2189 	/*NOTREACHED*/
2190 }
2191 
2192 static int
2193 usage(FILE *fp)
2194 {
2195 	(void) fprintf(fp, "Usage: %s "
2196 	    "[-BeOsx] [-i id] [-t type] [-w file] [file]\n\n", g_pname);
2197 
2198 	(void) fprintf(fp,
2199 	    "\t-B disable header validation for broken BIOSes\n"
2200 	    "\t-e display SMBIOS entry point information\n"
2201 	    "\t-i display only the specified structure\n"
2202 	    "\t-O display obsolete structure types\n"
2203 	    "\t-s display only a summary of structure identifiers and types\n"
2204 	    "\t-t display only the specified structure type\n"
2205 	    "\t-w write the raw data to the specified file\n"
2206 	    "\t-x display raw data for structures\n");
2207 
2208 	return (SMBIOS_USAGE);
2209 }
2210 
2211 int
2212 main(int argc, char *argv[])
2213 {
2214 	const char *ifile = NULL;
2215 	const char *ofile = NULL;
2216 	int oflags = 0;
2217 
2218 	smbios_hdl_t *shp;
2219 	smbios_struct_t s;
2220 	int err, fd, c;
2221 	char *p;
2222 
2223 	if ((p = strrchr(argv[0], '/')) == NULL)
2224 		g_pname = argv[0];
2225 	else
2226 		g_pname = p + 1;
2227 
2228 	while (optind < argc) {
2229 		while ((c = getopt(argc, argv, "Bei:Ost:w:xZ")) != EOF) {
2230 			switch (c) {
2231 			case 'B':
2232 				oflags |= SMB_O_NOCKSUM | SMB_O_NOVERS;
2233 				break;
2234 			case 'e':
2235 				opt_e++;
2236 				break;
2237 			case 'i':
2238 				opt_i = getu16("struct ID", optarg);
2239 				break;
2240 			case 'O':
2241 				opt_O++;
2242 				break;
2243 			case 's':
2244 				opt_s++;
2245 				break;
2246 			case 't':
2247 				if (isdigit(optarg[0]))
2248 					opt_t = getu16("struct type", optarg);
2249 				else
2250 					opt_t = getstype("struct type", optarg);
2251 				break;
2252 			case 'w':
2253 				ofile = optarg;
2254 				break;
2255 			case 'x':
2256 				opt_x++;
2257 				break;
2258 			case 'Z':
2259 				oflags |= SMB_O_ZIDS; /* undocumented */
2260 				break;
2261 			default:
2262 				return (usage(stderr));
2263 			}
2264 		}
2265 
2266 		if (optind < argc) {
2267 			if (ifile != NULL) {
2268 				(void) fprintf(stderr, "%s: illegal "
2269 				    "argument -- %s\n", g_pname, argv[optind]);
2270 				return (SMBIOS_USAGE);
2271 			}
2272 			ifile = argv[optind++];
2273 		}
2274 	}
2275 
2276 	if ((shp = smbios_open(ifile, SMB_VERSION, oflags, &err)) == NULL) {
2277 		(void) fprintf(stderr, "%s: failed to load SMBIOS: %s\n",
2278 		    g_pname, smbios_errmsg(err));
2279 		return (SMBIOS_ERROR);
2280 	}
2281 
2282 	if (opt_i == -1 && opt_t == -1 && opt_e == 0 &&
2283 	    smbios_truncated(shp))
2284 		(void) fprintf(stderr, "%s: SMBIOS table is truncated\n",
2285 		    g_pname);
2286 
2287 	if (ofile != NULL) {
2288 		if ((fd = open(ofile, O_WRONLY|O_CREAT|O_TRUNC, 0666)) == -1) {
2289 			(void) fprintf(stderr, "%s: failed to open %s: %s\n",
2290 			    g_pname, ofile, strerror(errno));
2291 			err = SMBIOS_ERROR;
2292 		} else if (smbios_write(shp, fd) != 0) {
2293 			(void) fprintf(stderr, "%s: failed to write %s: %s\n",
2294 			    g_pname, ofile, smbios_errmsg(smbios_errno(shp)));
2295 			err = SMBIOS_ERROR;
2296 		}
2297 		smbios_close(shp);
2298 		return (err);
2299 	}
2300 
2301 	if (opt_e) {
2302 		print_smbios(shp, stdout);
2303 		smbios_close(shp);
2304 		return (SMBIOS_SUCCESS);
2305 	}
2306 
2307 	if (opt_O && (opt_i != -1 || opt_t != -1))
2308 		opt_O++; /* -i or -t imply displaying obsolete records */
2309 
2310 	if (opt_i != -1)
2311 		err = smbios_lookup_id(shp, opt_i, &s);
2312 	else
2313 		err = smbios_iter(shp, print_struct, stdout);
2314 
2315 	if (err != 0) {
2316 		(void) fprintf(stderr, "%s: failed to access SMBIOS: %s\n",
2317 		    g_pname, smbios_errmsg(smbios_errno(shp)));
2318 		smbios_close(shp);
2319 		return (SMBIOS_ERROR);
2320 	}
2321 
2322 	if (opt_i != -1)
2323 		(void) print_struct(shp, &s, stdout);
2324 
2325 	smbios_close(shp);
2326 	return (SMBIOS_SUCCESS);
2327 }
2328