xref: /illumos-gate/usr/src/cmd/smbios/smbios.c (revision cd61ae21816e53b94bc1673f3f1aa651fc3115e8)
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 2010 Sun Microsystems, Inc.  All rights reserved.
26  * Use is subject to license terms.
27  */
28 
29 #include <sys/sysmacros.h>
30 #include <sys/param.h>
31 
32 #include <smbios.h>
33 #include <alloca.h>
34 #include <limits.h>
35 #include <unistd.h>
36 #include <strings.h>
37 #include <stdlib.h>
38 #include <stdarg.h>
39 #include <stdio.h>
40 #include <fcntl.h>
41 #include <errno.h>
42 #include <ctype.h>
43 #include <libjedec.h>
44 
45 #define	SMBIOS_SUCCESS	0
46 #define	SMBIOS_ERROR	1
47 #define	SMBIOS_USAGE	2
48 
49 static const char *g_pname;
50 static int g_hdr;
51 
52 static int opt_e;
53 static int opt_i = -1;
54 static int opt_O;
55 static int opt_s;
56 static int opt_t = -1;
57 static int opt_x;
58 
59 static boolean_t
60 smbios_vergteq(smbios_version_t *v, uint_t major, uint_t minor)
61 {
62 	if (v->smbv_major > major)
63 		return (B_TRUE);
64 	if (v->smbv_major == major &&
65 	    v->smbv_minor >= minor)
66 		return (B_TRUE);
67 	return (B_FALSE);
68 }
69 
70 /*PRINTFLIKE2*/
71 static void
72 smbios_warn(smbios_hdl_t *shp, const char *format, ...)
73 {
74 	va_list ap;
75 
76 	va_start(ap, format);
77 	(void) vfprintf(stderr, format, ap);
78 	va_end(ap);
79 
80 	if (shp != NULL) {
81 		(void) fprintf(stderr, ": %s",
82 		    smbios_errmsg(smbios_errno(shp)));
83 	}
84 
85 	(void) fprintf(stderr, "\n");
86 }
87 
88 /*PRINTFLIKE2*/
89 static void
90 oprintf(FILE *fp, const char *format, ...)
91 {
92 	va_list ap;
93 
94 	va_start(ap, format);
95 	(void) vfprintf(fp, format, ap);
96 	va_end(ap);
97 }
98 
99 /*PRINTFLIKE3*/
100 static void
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  * Print a 128-bit data as a series of 16 hex digits.
202  */
203 static void
204 u128_print(FILE *fp, const char *desc, const uint8_t *data)
205 {
206 	uint_t i;
207 
208 	oprintf(fp, "%s: ", desc);
209 	for (i = 0; i < 16; i++) {
210 		oprintf(fp, " %02x", data[i]);
211 	}
212 	oprintf(fp, "\n");
213 }
214 
215 static int
216 check_oem(smbios_hdl_t *shp)
217 {
218 	int i;
219 	int cnt;
220 	int rv;
221 	id_t oem_id;
222 	smbios_struct_t s;
223 	const char **oem_str;
224 
225 	rv = smbios_lookup_type(shp, SMB_TYPE_OEMSTR, &s);
226 	if (rv != 0) {
227 		return (-1);
228 	}
229 
230 	oem_id = s.smbstr_id;
231 
232 	cnt = smbios_info_strtab(shp, oem_id, 0, NULL);
233 	if (cnt > 0) {
234 		oem_str =  alloca(sizeof (char *) * cnt);
235 		(void) smbios_info_strtab(shp, oem_id, cnt, oem_str);
236 
237 		for (i = 0; i < cnt; i++) {
238 			if (strncmp(oem_str[i], SMB_PRMS1,
239 			    strlen(SMB_PRMS1) + 1) == 0) {
240 				return (0);
241 			}
242 		}
243 	}
244 
245 	return (-1);
246 }
247 
248 static void
249 print_smbios_21(smbios_21_entry_t *ep, FILE *fp)
250 {
251 	int i;
252 
253 	oprintf(fp, "Entry Point Anchor Tag: %*.*s\n",
254 	    (int)sizeof (ep->smbe_eanchor), (int)sizeof (ep->smbe_eanchor),
255 	    ep->smbe_eanchor);
256 
257 	oprintf(fp, "Entry Point Checksum: 0x%x\n", ep->smbe_ecksum);
258 	oprintf(fp, "Entry Point Length: %u\n", ep->smbe_elen);
259 	oprintf(fp, "Entry Point Version: %u.%u\n",
260 	    ep->smbe_major, ep->smbe_minor);
261 	oprintf(fp, "Max Structure Size: %u\n", ep->smbe_maxssize);
262 	oprintf(fp, "Entry Point Revision: 0x%x\n", ep->smbe_revision);
263 
264 	oprintf(fp, "Entry Point Revision Data:");
265 	for (i = 0; i < sizeof (ep->smbe_format); i++)
266 		oprintf(fp, " 0x%02x", ep->smbe_format[i]);
267 	oprintf(fp, "\n");
268 
269 	oprintf(fp, "Intermediate Anchor Tag: %*.*s\n",
270 	    (int)sizeof (ep->smbe_ianchor), (int)sizeof (ep->smbe_ianchor),
271 	    ep->smbe_ianchor);
272 
273 	oprintf(fp, "Intermediate Checksum: 0x%x\n", ep->smbe_icksum);
274 	oprintf(fp, "Structure Table Length: %u\n", ep->smbe_stlen);
275 	oprintf(fp, "Structure Table Address: 0x%x\n", ep->smbe_staddr);
276 	oprintf(fp, "Structure Table Entries: %u\n", ep->smbe_stnum);
277 	oprintf(fp, "DMI BCD Revision: 0x%x\n", ep->smbe_bcdrev);
278 }
279 
280 static void
281 print_smbios_30(smbios_30_entry_t *ep, FILE *fp)
282 {
283 	oprintf(fp, "Entry Point Anchor Tag: %*.*s\n",
284 	    (int)sizeof (ep->smbe_eanchor), (int)sizeof (ep->smbe_eanchor),
285 	    ep->smbe_eanchor);
286 
287 	oprintf(fp, "Entry Point Checksum: 0x%x\n", ep->smbe_ecksum);
288 	oprintf(fp, "Entry Point Length: %u\n", ep->smbe_elen);
289 	oprintf(fp, "SMBIOS Version: %u.%u\n",
290 	    ep->smbe_major, ep->smbe_minor);
291 	oprintf(fp, "SMBIOS DocRev: 0x%x\n", ep->smbe_docrev);
292 	oprintf(fp, "Entry Point Revision: 0x%x\n", ep->smbe_revision);
293 
294 	oprintf(fp, "Structure Table Length: %u\n", ep->smbe_stlen);
295 	oprintf(fp, "Structure Table Address: 0x%" PRIx64 "\n",
296 	    ep->smbe_staddr);
297 }
298 
299 static void
300 print_smbios(smbios_hdl_t *shp, FILE *fp)
301 {
302 	smbios_entry_t ep;
303 
304 	switch (smbios_info_smbios(shp, &ep)) {
305 	case SMBIOS_ENTRY_POINT_21:
306 		print_smbios_21(&ep.ep21, fp);
307 		break;
308 	case SMBIOS_ENTRY_POINT_30:
309 		print_smbios_30(&ep.ep30, fp);
310 		break;
311 	}
312 }
313 
314 static void
315 print_common(const smbios_info_t *ip, FILE *fp)
316 {
317 	if (ip->smbi_manufacturer[0] != '\0')
318 		oprintf(fp, "  Manufacturer: %s\n", ip->smbi_manufacturer);
319 	if (ip->smbi_product[0] != '\0')
320 		oprintf(fp, "  Product: %s\n", ip->smbi_product);
321 	if (ip->smbi_version[0] != '\0')
322 		oprintf(fp, "  Version: %s\n", ip->smbi_version);
323 	if (ip->smbi_serial[0] != '\0')
324 		oprintf(fp, "  Serial Number: %s\n", ip->smbi_serial);
325 	if (ip->smbi_asset[0] != '\0')
326 		oprintf(fp, "  Asset Tag: %s\n", ip->smbi_asset);
327 	if (ip->smbi_location[0] != '\0')
328 		oprintf(fp, "  Location Tag: %s\n", ip->smbi_location);
329 	if (ip->smbi_part[0] != '\0')
330 		oprintf(fp, "  Part Number: %s\n", ip->smbi_part);
331 }
332 
333 static void
334 print_bios(smbios_hdl_t *shp, FILE *fp)
335 {
336 	smbios_bios_t b;
337 
338 	(void) smbios_info_bios(shp, &b);
339 
340 	oprintf(fp, "  Vendor: %s\n", b.smbb_vendor);
341 	oprintf(fp, "  Version String: %s\n", b.smbb_version);
342 	oprintf(fp, "  Release Date: %s\n", b.smbb_reldate);
343 	oprintf(fp, "  Address Segment: 0x%x\n", b.smbb_segment);
344 	oprintf(fp, "  ROM Size: %" PRIu64 " bytes\n", b.smbb_extromsize);
345 	oprintf(fp, "  Image Size: %u bytes\n", b.smbb_runsize);
346 
347 	flag64_printf(fp, "Characteristics",
348 	    b.smbb_cflags, sizeof (b.smbb_cflags) * NBBY,
349 	    smbios_bios_flag_name, smbios_bios_flag_desc);
350 
351 	if (b.smbb_nxcflags > SMB_BIOSXB_1) {
352 		flag_printf(fp, "Characteristics Extension Byte 1",
353 		    b.smbb_xcflags[SMB_BIOSXB_1],
354 		    sizeof (b.smbb_xcflags[SMB_BIOSXB_1]) * NBBY,
355 		    smbios_bios_xb1_name, smbios_bios_xb1_desc);
356 	}
357 
358 	if (b.smbb_nxcflags > SMB_BIOSXB_2) {
359 		flag_printf(fp, "Characteristics Extension Byte 2",
360 		    b.smbb_xcflags[SMB_BIOSXB_2],
361 		    sizeof (b.smbb_xcflags[SMB_BIOSXB_2]) * NBBY,
362 		    smbios_bios_xb2_name, smbios_bios_xb2_desc);
363 	}
364 
365 	if (b.smbb_nxcflags > SMB_BIOSXB_BIOS_MIN) {
366 		oprintf(fp, "  Version Number: %u.%u\n",
367 		    b.smbb_biosv.smbv_major, b.smbb_biosv.smbv_minor);
368 	}
369 
370 	/*
371 	 * If the major and minor versions are 0xff then that indicates that the
372 	 * embedded controller does not exist.
373 	 */
374 	if (b.smbb_nxcflags > SMB_BIOSXB_ECFW_MIN &&
375 	    b.smbb_ecfwv.smbv_major != 0xff &&
376 	    b.smbb_ecfwv.smbv_minor != 0xff) {
377 		oprintf(fp, "  Embedded Ctlr Firmware Version Number: %u.%u\n",
378 		    b.smbb_ecfwv.smbv_major, b.smbb_ecfwv.smbv_minor);
379 	}
380 }
381 
382 static void
383 print_system(smbios_hdl_t *shp, FILE *fp)
384 {
385 	smbios_system_t s;
386 	uint_t i;
387 
388 	(void) smbios_info_system(shp, &s);
389 
390 	oprintf(fp, "  UUID: ");
391 	for (i = 0; i < s.smbs_uuidlen; i++) {
392 		oprintf(fp, "%02x", s.smbs_uuid[i]);
393 		if (i == 3 || i == 5 || i == 7 || i == 9)
394 			oprintf(fp, "-");
395 	}
396 	oprintf(fp, "\n");
397 
398 	desc_printf(smbios_system_wakeup_desc(s.smbs_wakeup),
399 	    fp, "  Wake-Up Event: 0x%x", s.smbs_wakeup);
400 
401 	oprintf(fp, "  SKU Number: %s\n", s.smbs_sku);
402 	oprintf(fp, "  Family: %s\n", s.smbs_family);
403 }
404 
405 static void
406 print_bboard(smbios_hdl_t *shp, id_t id, FILE *fp)
407 {
408 	smbios_bboard_t b;
409 	int chdl_cnt;
410 
411 	(void) smbios_info_bboard(shp, id, &b);
412 
413 	oprintf(fp, "  Chassis: %u\n", (uint_t)b.smbb_chassis);
414 
415 	flag_printf(fp, "Flags", b.smbb_flags, sizeof (b.smbb_flags) * NBBY,
416 	    smbios_bboard_flag_name, smbios_bboard_flag_desc);
417 
418 	desc_printf(smbios_bboard_type_desc(b.smbb_type),
419 	    fp, "  Board Type: 0x%x", b.smbb_type);
420 
421 	chdl_cnt = b.smbb_contn;
422 	if (chdl_cnt != 0) {
423 		id_t *chdl;
424 		uint16_t hdl;
425 		int i, n, cnt;
426 
427 		chdl = alloca(chdl_cnt * sizeof (id_t));
428 		cnt = smbios_info_contains(shp, id, chdl_cnt, chdl);
429 		if (cnt > SMB_CONT_MAX)
430 			return;
431 		n = MIN(chdl_cnt, cnt);
432 
433 		oprintf(fp, "\n");
434 		for (i = 0; i < n; i++) {
435 			hdl = (uint16_t)chdl[i];
436 			oprintf(fp, "  Contained Handle: %u\n", hdl);
437 		}
438 	}
439 }
440 
441 static void
442 print_chassis(smbios_hdl_t *shp, id_t id, FILE *fp)
443 {
444 	smbios_chassis_t c;
445 	int elem_cnt;
446 
447 	(void) smbios_info_chassis(shp, id, &c);
448 
449 	oprintf(fp, "  OEM Data: 0x%x\n", c.smbc_oemdata);
450 	oprintf(fp, "  SKU number: %s\n",
451 	    c.smbc_sku[0] == '\0' ? "<unknown>" : c.smbc_sku);
452 	oprintf(fp, "  Lock Present: %s\n", c.smbc_lock ? "Y" : "N");
453 
454 	desc_printf(smbios_chassis_type_desc(c.smbc_type),
455 	    fp, "  Chassis Type: 0x%x", c.smbc_type);
456 
457 	desc_printf(smbios_chassis_state_desc(c.smbc_bustate),
458 	    fp, "  Boot-Up State: 0x%x", c.smbc_bustate);
459 
460 	desc_printf(smbios_chassis_state_desc(c.smbc_psstate),
461 	    fp, "  Power Supply State: 0x%x", c.smbc_psstate);
462 
463 	desc_printf(smbios_chassis_state_desc(c.smbc_thstate),
464 	    fp, "  Thermal State: 0x%x", c.smbc_thstate);
465 
466 	oprintf(fp, "  Chassis Height: %uu\n", c.smbc_uheight);
467 	oprintf(fp, "  Power Cords: %u\n", c.smbc_cords);
468 
469 	elem_cnt = c.smbc_elems;
470 	oprintf(fp, "  Element Records: %u\n", elem_cnt);
471 
472 	if (elem_cnt > 0) {
473 		id_t *elems;
474 		uint8_t type;
475 		int i, n, cnt;
476 
477 		elems = alloca(c.smbc_elems * sizeof (id_t));
478 		cnt = smbios_info_contains(shp, id, elem_cnt, elems);
479 		if (cnt > SMB_CONT_MAX)
480 			return;
481 		n = MIN(elem_cnt, cnt);
482 
483 		oprintf(fp, "\n");
484 		for (i = 0; i < n; i++) {
485 			type = (uint8_t)elems[i];
486 			if (type & 0x80) {
487 				/* SMBIOS structrure Type */
488 				desc_printf(smbios_type_name(type & 0x7f), fp,
489 				    "  Contained SMBIOS structure Type: %u",
490 				    type & 0x80);
491 			} else {
492 				/* SMBIOS Base Board Type */
493 				desc_printf(smbios_bboard_type_desc(type), fp,
494 				    "  Contained SMBIOS Base Board Type: 0x%x",
495 				    type);
496 			}
497 		}
498 	}
499 }
500 
501 static void
502 print_processor(smbios_hdl_t *shp, id_t id, FILE *fp)
503 {
504 	smbios_processor_t p;
505 	uint_t status;
506 
507 	(void) smbios_info_processor(shp, id, &p);
508 	status = SMB_PRSTATUS_STATUS(p.smbp_status);
509 
510 	desc_printf(smbios_processor_family_desc(p.smbp_family),
511 	    fp, "  Family: %u", p.smbp_family);
512 
513 	oprintf(fp, "  CPUID: 0x%llx\n", (u_longlong_t)p.smbp_cpuid);
514 
515 	desc_printf(smbios_processor_type_desc(p.smbp_type),
516 	    fp, "  Type: %u", p.smbp_type);
517 
518 	desc_printf(smbios_processor_upgrade_desc(p.smbp_upgrade),
519 	    fp, "  Socket Upgrade: %u", p.smbp_upgrade);
520 
521 	oprintf(fp, "  Socket Status: %s\n",
522 	    SMB_PRSTATUS_PRESENT(p.smbp_status) ?
523 	    "Populated" : "Not Populated");
524 
525 	desc_printf(smbios_processor_status_desc(status),
526 	    fp, "  Processor Status: %u", status);
527 
528 	if (SMB_PRV_LEGACY(p.smbp_voltage)) {
529 		oprintf(fp, "  Supported Voltages:");
530 		switch (p.smbp_voltage) {
531 		case SMB_PRV_5V:
532 			oprintf(fp, " 5.0V");
533 			break;
534 		case SMB_PRV_33V:
535 			oprintf(fp, " 3.3V");
536 			break;
537 		case SMB_PRV_29V:
538 			oprintf(fp, " 2.9V");
539 			break;
540 		}
541 		oprintf(fp, "\n");
542 	} else {
543 		oprintf(fp, "  Supported Voltages: %.1fV\n",
544 		    (float)SMB_PRV_VOLTAGE(p.smbp_voltage) / 10);
545 	}
546 
547 	if (p.smbp_corecount != 0) {
548 		oprintf(fp, "  Core Count: %u\n", p.smbp_corecount);
549 	} else {
550 		oprintf(fp, "  Core Count: Unknown\n");
551 	}
552 
553 	if (p.smbp_coresenabled != 0) {
554 		oprintf(fp, "  Cores Enabled: %u\n", p.smbp_coresenabled);
555 	} else {
556 		oprintf(fp, "  Cores Enabled: Unknown\n");
557 	}
558 
559 	if (p.smbp_threadcount != 0) {
560 		oprintf(fp, "  Thread Count: %u\n", p.smbp_threadcount);
561 	} else {
562 		oprintf(fp, "  Thread Count: Unknown\n");
563 	}
564 
565 	if (p.smbp_cflags) {
566 		flag_printf(fp, "Processor Characteristics",
567 		    p.smbp_cflags, sizeof (p.smbp_cflags) * NBBY,
568 		    smbios_processor_core_flag_name,
569 		    smbios_processor_core_flag_desc);
570 	}
571 
572 	if (p.smbp_clkspeed != 0)
573 		oprintf(fp, "  External Clock Speed: %uMHz\n", p.smbp_clkspeed);
574 	else
575 		oprintf(fp, "  External Clock Speed: Unknown\n");
576 
577 	if (p.smbp_maxspeed != 0)
578 		oprintf(fp, "  Maximum Speed: %uMHz\n", p.smbp_maxspeed);
579 	else
580 		oprintf(fp, "  Maximum Speed: Unknown\n");
581 
582 	if (p.smbp_curspeed != 0)
583 		oprintf(fp, "  Current Speed: %uMHz\n", p.smbp_curspeed);
584 	else
585 		oprintf(fp, "  Current Speed: Unknown\n");
586 
587 	id_printf(fp, "  L1 Cache Handle: ", p.smbp_l1cache);
588 	id_printf(fp, "  L2 Cache Handle: ", p.smbp_l2cache);
589 	id_printf(fp, "  L3 Cache Handle: ", p.smbp_l3cache);
590 }
591 
592 static void
593 print_cache(smbios_hdl_t *shp, id_t id, FILE *fp)
594 {
595 	smbios_cache_t c;
596 
597 	(void) smbios_info_cache(shp, id, &c);
598 
599 	oprintf(fp, "  Level: %u\n", c.smba_level);
600 	oprintf(fp, "  Maximum Installed Size: %" PRIu64 " bytes\n",
601 	    c.smba_maxsize2);
602 
603 	if (c.smba_size2 != 0) {
604 		oprintf(fp, "  Installed Size: %" PRIu64 " bytes\n",
605 		    c.smba_size2);
606 	} else {
607 		oprintf(fp, "  Installed Size: Not Installed\n");
608 	}
609 
610 	if (c.smba_speed != 0)
611 		oprintf(fp, "  Speed: %uns\n", c.smba_speed);
612 	else
613 		oprintf(fp, "  Speed: Unknown\n");
614 
615 	flag_printf(fp, "Supported SRAM Types",
616 	    c.smba_stype, sizeof (c.smba_stype) * NBBY,
617 	    smbios_cache_ctype_name, smbios_cache_ctype_desc);
618 
619 	desc_printf(smbios_cache_ctype_desc(c.smba_ctype),
620 	    fp, "  Current SRAM Type: 0x%x", c.smba_ctype);
621 
622 	desc_printf(smbios_cache_ecc_desc(c.smba_etype),
623 	    fp, "  Error Correction Type: %u", c.smba_etype);
624 
625 	desc_printf(smbios_cache_logical_desc(c.smba_ltype),
626 	    fp, "  Logical Cache Type: %u", c.smba_ltype);
627 
628 	desc_printf(smbios_cache_assoc_desc(c.smba_assoc),
629 	    fp, "  Associativity: %u", c.smba_assoc);
630 
631 	desc_printf(smbios_cache_mode_desc(c.smba_mode),
632 	    fp, "  Mode: %u", c.smba_mode);
633 
634 	desc_printf(smbios_cache_loc_desc(c.smba_location),
635 	    fp, "  Location: %u", c.smba_location);
636 
637 	flag_printf(fp, "Flags", c.smba_flags, sizeof (c.smba_flags) * NBBY,
638 	    smbios_cache_flag_name, smbios_cache_flag_desc);
639 }
640 
641 static void
642 print_port(smbios_hdl_t *shp, id_t id, FILE *fp)
643 {
644 	smbios_port_t p;
645 
646 	(void) smbios_info_port(shp, id, &p);
647 
648 	oprintf(fp, "  Internal Reference Designator: %s\n", p.smbo_iref);
649 	oprintf(fp, "  External Reference Designator: %s\n", p.smbo_eref);
650 
651 	desc_printf(smbios_port_conn_desc(p.smbo_itype),
652 	    fp, "  Internal Connector Type: %u", p.smbo_itype);
653 
654 	desc_printf(smbios_port_conn_desc(p.smbo_etype),
655 	    fp, "  External Connector Type: %u", p.smbo_etype);
656 
657 	desc_printf(smbios_port_type_desc(p.smbo_ptype),
658 	    fp, "  Port Type: %u", p.smbo_ptype);
659 }
660 
661 static void
662 print_slot(smbios_hdl_t *shp, id_t id, FILE *fp)
663 {
664 	smbios_slot_t s;
665 	smbios_version_t v;
666 
667 	(void) smbios_info_slot(shp, id, &s);
668 	smbios_info_smbios_version(shp, &v);
669 
670 	oprintf(fp, "  Reference Designator: %s\n", s.smbl_name);
671 	oprintf(fp, "  Slot ID: 0x%x\n", s.smbl_id);
672 
673 	desc_printf(smbios_slot_type_desc(s.smbl_type),
674 	    fp, "  Type: 0x%x", s.smbl_type);
675 
676 	desc_printf(smbios_slot_width_desc(s.smbl_width),
677 	    fp, "  Width: 0x%x", s.smbl_width);
678 
679 	desc_printf(smbios_slot_usage_desc(s.smbl_usage),
680 	    fp, "  Usage: 0x%x", s.smbl_usage);
681 
682 	desc_printf(smbios_slot_length_desc(s.smbl_length),
683 	    fp, "  Length: 0x%x", s.smbl_length);
684 
685 	flag_printf(fp, "Slot Characteristics 1",
686 	    s.smbl_ch1, sizeof (s.smbl_ch1) * NBBY,
687 	    smbios_slot_ch1_name, smbios_slot_ch1_desc);
688 
689 	flag_printf(fp, "Slot Characteristics 2",
690 	    s.smbl_ch2, sizeof (s.smbl_ch2) * NBBY,
691 	    smbios_slot_ch2_name, smbios_slot_ch2_desc);
692 
693 	if (check_oem(shp) != 0 && !smbios_vergteq(&v, 2, 6))
694 		return;
695 
696 	oprintf(fp, "  Segment Group: %u\n", s.smbl_sg);
697 	oprintf(fp, "  Bus Number: %u\n", s.smbl_bus);
698 	oprintf(fp, "  Device/Function Number: %u/%u\n", s.smbl_df >> 3,
699 	    s.smbl_df & 0x7);
700 
701 	if (s.smbl_dbw != 0) {
702 		oprintf(fp, "  Data Bus Width: %d\n", s.smbl_dbw);
703 	}
704 
705 	if (s.smbl_npeers > 0) {
706 		smbios_slot_peer_t *peer;
707 		uint_t i, npeers;
708 
709 		if (smbios_info_slot_peers(shp, id, &npeers, &peer) != 0) {
710 			smbios_warn(shp, "failed to read slot peer "
711 			    "information");
712 			return;
713 		}
714 
715 		for (i = 0; i < npeers; i++) {
716 			oprintf(fp, "  Slot Peer %u:\n", i);
717 			oprintf(fp, "    Segment group: %u\n",
718 			    peer[i].smblp_group);
719 			oprintf(fp, "    Bus/Device/Function: %u/%u/%u",
720 			    peer[i].smblp_bus, peer[i].smblp_device,
721 			    peer[i].smblp_function);
722 			oprintf(fp, "    Electrical width: %u\n",
723 			    peer[i].smblp_data_width);
724 		}
725 
726 		smbios_info_slot_peers_free(shp, npeers, peer);
727 	}
728 }
729 
730 static void
731 print_obdevs_ext(smbios_hdl_t *shp, id_t id, FILE *fp)
732 {
733 	boolean_t enabled;
734 	smbios_obdev_ext_t oe;
735 	const char *type;
736 
737 	(void) smbios_info_obdevs_ext(shp, id, &oe);
738 
739 	/*
740 	 * Bit 7 is always whether or not the device is enabled while bits 0:6
741 	 * are the actual device type.
742 	 */
743 	enabled = oe.smboe_dtype >> 7;
744 	type = smbios_onboard_type_desc(oe.smboe_dtype & 0x7f);
745 
746 	oprintf(fp, "  Reference Designator: %s\n", oe.smboe_name);
747 	oprintf(fp, "  Device Enabled: %s\n", enabled == B_TRUE ? "true" :
748 	    "false");
749 	oprintf(fp, "  Device Type: %s\n", type);
750 	oprintf(fp, "  Device Type Instance: %u\n", oe.smboe_dti);
751 	oprintf(fp, "  Segment Group Number: %u\n", oe.smboe_sg);
752 	oprintf(fp, "  Bus Number: %u\n", oe.smboe_bus);
753 	oprintf(fp, "  Device/Function Number: %u\n", oe.smboe_df);
754 }
755 
756 static void
757 print_obdevs(smbios_hdl_t *shp, id_t id, FILE *fp)
758 {
759 	smbios_obdev_t *argv;
760 	int i, argc;
761 
762 	if ((argc = smbios_info_obdevs(shp, id, 0, NULL)) > 0) {
763 		argv = alloca(sizeof (smbios_obdev_t) * argc);
764 		(void) smbios_info_obdevs(shp, id, argc, argv);
765 		for (i = 0; i < argc; i++)
766 			oprintf(fp, "  %s\n", argv[i].smbd_name);
767 	}
768 }
769 
770 static void
771 print_strtab(smbios_hdl_t *shp, id_t id, FILE *fp)
772 {
773 	const char **argv;
774 	int i, argc;
775 
776 	if ((argc = smbios_info_strtab(shp, id, 0, NULL)) > 0) {
777 		argv = alloca(sizeof (char *) * argc);
778 		(void) smbios_info_strtab(shp, id, argc, argv);
779 		for (i = 0; i < argc; i++)
780 			oprintf(fp, "  %s\n", argv[i]);
781 	}
782 }
783 
784 static void
785 print_lang(smbios_hdl_t *shp, id_t id, FILE *fp)
786 {
787 	smbios_lang_t l;
788 
789 	(void) smbios_info_lang(shp, &l);
790 
791 	oprintf(fp, "  Current Language: %s\n", l.smbla_cur);
792 	oprintf(fp, "  Language String Format: %u\n", l.smbla_fmt);
793 	oprintf(fp, "  Number of Installed Languages: %u\n", l.smbla_num);
794 	oprintf(fp, "  Installed Languages:\n");
795 
796 	print_strtab(shp, id, fp);
797 }
798 
799 /*ARGSUSED*/
800 static void
801 print_evlog(smbios_hdl_t *shp, id_t id, FILE *fp)
802 {
803 	smbios_evlog_t ev;
804 	uint32_t i;
805 
806 	(void) smbios_info_eventlog(shp, &ev);
807 
808 	oprintf(fp, "  Log Area Size: %lu bytes\n", (ulong_t)ev.smbev_size);
809 	oprintf(fp, "  Header Offset: %lu\n", (ulong_t)ev.smbev_hdr);
810 	oprintf(fp, "  Data Offset: %lu\n", (ulong_t)ev.smbev_data);
811 
812 	desc_printf(smbios_evlog_method_desc(ev.smbev_method),
813 	    fp, "  Data Access Method: %u", ev.smbev_method);
814 
815 	flag_printf(fp, "Log Flags",
816 	    ev.smbev_flags, sizeof (ev.smbev_flags) * NBBY,
817 	    smbios_evlog_flag_name, smbios_evlog_flag_desc);
818 
819 	desc_printf(smbios_evlog_format_desc(ev.smbev_format),
820 	    fp, "  Log Header Format: %u", ev.smbev_format);
821 
822 	oprintf(fp, "  Update Token: 0x%x\n", ev.smbev_token);
823 	oprintf(fp, "  Data Access Address: ");
824 
825 	switch (ev.smbev_method) {
826 	case SMB_EVM_1x1i_1x1d:
827 	case SMB_EVM_2x1i_1x1d:
828 	case SMB_EVM_1x2i_1x1d:
829 		oprintf(fp, "Index Address 0x%x, Data Address 0x%x\n",
830 		    ev.smbev_addr.eva_io.evi_iaddr,
831 		    ev.smbev_addr.eva_io.evi_daddr);
832 		break;
833 	case SMB_EVM_GPNV:
834 		oprintf(fp, "0x%x\n", ev.smbev_addr.eva_gpnv);
835 		break;
836 	default:
837 		oprintf(fp, "0x%x\n", ev.smbev_addr.eva_addr);
838 	}
839 
840 	oprintf(fp, "  Type Descriptors:\n");
841 
842 	for (i = 0; i < ev.smbev_typec; i++) {
843 		oprintf(fp, "  %u: Log Type 0x%x, Data Type 0x%x\n", i,
844 		    ev.smbev_typev[i].smbevt_ltype,
845 		    ev.smbev_typev[i].smbevt_dtype);
846 	}
847 }
848 
849 static void
850 print_bytes(const uint8_t *data, size_t size, FILE *fp)
851 {
852 	size_t row, rows = P2ROUNDUP(size, 16) / 16;
853 	size_t col, cols;
854 
855 	char buf[17];
856 	uint8_t x;
857 
858 	oprintf(fp, "\n  offset:   0 1 2 3  4 5 6 7  8 9 a b  c d e f  "
859 	    "0123456789abcdef\n");
860 
861 	for (row = 0; row < rows; row++) {
862 		oprintf(fp, "  %#6lx: ", (ulong_t)row * 16);
863 		cols = MIN(size - row * 16, 16);
864 
865 		for (col = 0; col < cols; col++) {
866 			if (col % 4 == 0)
867 				oprintf(fp, " ");
868 			x = *data++;
869 			oprintf(fp, "%02x", x);
870 			buf[col] = x <= ' ' || x > '~' ? '.' : x;
871 		}
872 
873 		for (; col < 16; col++) {
874 			if (col % 4 == 0)
875 				oprintf(fp, " ");
876 			oprintf(fp, "  ");
877 			buf[col] = ' ';
878 		}
879 
880 		buf[col] = '\0';
881 		oprintf(fp, "  %s\n", buf);
882 	}
883 
884 	oprintf(fp, "\n");
885 }
886 
887 static void
888 print_memarray(smbios_hdl_t *shp, id_t id, FILE *fp)
889 {
890 	smbios_memarray_t ma;
891 
892 	(void) smbios_info_memarray(shp, id, &ma);
893 
894 	desc_printf(smbios_memarray_loc_desc(ma.smbma_location),
895 	    fp, "  Location: %u", ma.smbma_location);
896 
897 	desc_printf(smbios_memarray_use_desc(ma.smbma_use),
898 	    fp, "  Use: %u", ma.smbma_use);
899 
900 	desc_printf(smbios_memarray_ecc_desc(ma.smbma_ecc),
901 	    fp, "  ECC: %u", ma.smbma_ecc);
902 
903 	oprintf(fp, "  Number of Slots/Sockets: %u\n", ma.smbma_ndevs);
904 	id_printf(fp, "  Memory Error Data: ", ma.smbma_err);
905 	oprintf(fp, "  Max Capacity: %llu bytes\n",
906 	    (u_longlong_t)ma.smbma_size);
907 }
908 
909 static void
910 print_memdevice(smbios_hdl_t *shp, id_t id, FILE *fp)
911 {
912 	smbios_memdevice_t md;
913 
914 	(void) smbios_info_memdevice(shp, id, &md);
915 
916 	id_printf(fp, "  Physical Memory Array: ", md.smbmd_array);
917 	id_printf(fp, "  Memory Error Data: ", md.smbmd_error);
918 
919 	if (md.smbmd_twidth != -1u)
920 		oprintf(fp, "  Total Width: %u bits\n", md.smbmd_twidth);
921 	else
922 		oprintf(fp, "  Total Width: Unknown\n");
923 
924 	if (md.smbmd_dwidth != -1u)
925 		oprintf(fp, "  Data Width: %u bits\n", md.smbmd_dwidth);
926 	else
927 		oprintf(fp, "  Data Width: Unknown\n");
928 
929 	switch (md.smbmd_size) {
930 	case -1ull:
931 		oprintf(fp, "  Size: Unknown\n");
932 		break;
933 	case 0:
934 		oprintf(fp, "  Size: Not Populated\n");
935 		break;
936 	default:
937 		oprintf(fp, "  Size: %llu bytes\n",
938 		    (u_longlong_t)md.smbmd_size);
939 	}
940 
941 	desc_printf(smbios_memdevice_form_desc(md.smbmd_form),
942 	    fp, "  Form Factor: %u", md.smbmd_form);
943 
944 	if (md.smbmd_set == 0)
945 		oprintf(fp, "  Set: None\n");
946 	else if (md.smbmd_set == (uint8_t)-1u)
947 		oprintf(fp, "  Set: Unknown\n");
948 	else
949 		oprintf(fp, "  Set: %u\n", md.smbmd_set);
950 
951 	if (md.smbmd_rank != 0) {
952 		desc_printf(smbios_memdevice_rank_desc(md.smbmd_rank),
953 		    fp, "  Rank: %u", md.smbmd_rank);
954 	} else {
955 		oprintf(fp, "  Rank: Unknown\n");
956 	}
957 
958 	desc_printf(smbios_memdevice_type_desc(md.smbmd_type),
959 	    fp, "  Memory Type: %u", md.smbmd_type);
960 
961 	flag_printf(fp, "Flags", md.smbmd_flags, sizeof (md.smbmd_flags) * NBBY,
962 	    smbios_memdevice_flag_name, smbios_memdevice_flag_desc);
963 
964 	if (md.smbmd_extspeed != 0) {
965 		oprintf(fp, "  Speed: %" PRIu64 " MT/s\n", md.smbmd_extspeed);
966 	} else {
967 		oprintf(fp, "  Speed: Unknown\n");
968 	}
969 
970 	if (md.smbmd_extclkspeed != 0) {
971 		oprintf(fp, "  Configured Speed: %" PRIu64 " MT/s\n",
972 		    md.smbmd_extclkspeed);
973 	} else {
974 		oprintf(fp, "  Configured Speed: Unknown\n");
975 	}
976 
977 	oprintf(fp, "  Device Locator: %s\n", md.smbmd_dloc);
978 	oprintf(fp, "  Bank Locator: %s\n", md.smbmd_bloc);
979 
980 	if (md.smbmd_minvolt != 0) {
981 		oprintf(fp, "  Minimum Voltage: %.2fV\n",
982 		    md.smbmd_minvolt / 1000.0);
983 	} else {
984 		oprintf(fp, "  Minimum Voltage: Unknown\n");
985 	}
986 
987 	if (md.smbmd_maxvolt != 0) {
988 		oprintf(fp, "  Maximum Voltage: %.2fV\n",
989 		    md.smbmd_maxvolt / 1000.0);
990 	} else {
991 		oprintf(fp, "  Maximum Voltage: Unknown\n");
992 	}
993 
994 	if (md.smbmd_confvolt != 0) {
995 		oprintf(fp, "  Configured Voltage: %.2fV\n",
996 		    md.smbmd_confvolt / 1000.0);
997 	} else {
998 		oprintf(fp, "  Configured Voltage: Unknown\n");
999 	}
1000 
1001 	if (md.smbmd_memtech != 0) {
1002 		desc_printf(smbios_memdevice_memtech_desc(md.smbmd_memtech),
1003 		    fp, "  Memory Technology: %u", md.smbmd_memtech);
1004 	}
1005 
1006 	if (md.smbmd_opcap_flags != 0) {
1007 		flag_printf(fp, "Operating Mode Capabilities",
1008 		    md.smbmd_opcap_flags, sizeof (md.smbmd_opcap_flags) * NBBY,
1009 		    smbios_memdevice_op_capab_name,
1010 		    smbios_memdevice_op_capab_desc);
1011 	}
1012 
1013 	if (md.smbmd_firmware_rev[0] != '\0') {
1014 		oprintf(fp, "  Firmware Revision: %s\n", md.smbmd_firmware_rev);
1015 	}
1016 
1017 	if (md.smbmd_modmfg_id != 0) {
1018 		jedec_print(fp, "Module Manufacturer ID", md.smbmd_modmfg_id);
1019 	}
1020 
1021 	if (md.smbmd_modprod_id  != 0) {
1022 		jedec_print(fp, "Module Product ID", md.smbmd_modprod_id);
1023 	}
1024 
1025 	if (md.smbmd_cntrlmfg_id != 0) {
1026 		jedec_print(fp, "Memory Subsystem Controller Manufacturer ID",
1027 		    md.smbmd_cntrlmfg_id);
1028 	}
1029 
1030 	if (md.smbmd_cntrlprod_id != 0) {
1031 		jedec_print(fp, "Memory Subsystem Controller Product ID",
1032 		    md.smbmd_cntrlprod_id);
1033 	}
1034 
1035 	if (md.smbmd_nvsize == UINT64_MAX) {
1036 		oprintf(fp, "  Non-volatile Size: Unknown\n");
1037 	} else if (md.smbmd_nvsize != 0) {
1038 		oprintf(fp, "  Non-volatile Size: %llu bytes\n",
1039 		    (u_longlong_t)md.smbmd_nvsize);
1040 	}
1041 
1042 	if (md.smbmd_volatile_size == UINT64_MAX) {
1043 		oprintf(fp, "  Volatile Size: Unknown\n");
1044 	} else if (md.smbmd_volatile_size != 0) {
1045 		oprintf(fp, "  Volatile Size: %llu bytes\n",
1046 		    (u_longlong_t)md.smbmd_volatile_size);
1047 	}
1048 
1049 	if (md.smbmd_cache_size == UINT64_MAX) {
1050 		oprintf(fp, "  Cache Size: Unknown\n");
1051 	} else if (md.smbmd_cache_size != 0) {
1052 		oprintf(fp, "  Cache Size: %llu bytes\n",
1053 		    (u_longlong_t)md.smbmd_cache_size);
1054 	}
1055 
1056 	if (md.smbmd_logical_size == UINT64_MAX) {
1057 		oprintf(fp, "  Logical Size: Unknown\n");
1058 	} else if (md.smbmd_logical_size != 0) {
1059 		oprintf(fp, "  Logical Size: %llu bytes\n",
1060 		    (u_longlong_t)md.smbmd_logical_size);
1061 	}
1062 }
1063 
1064 static void
1065 print_memarrmap(smbios_hdl_t *shp, id_t id, FILE *fp)
1066 {
1067 	smbios_memarrmap_t ma;
1068 
1069 	(void) smbios_info_memarrmap(shp, id, &ma);
1070 
1071 	id_printf(fp, "  Physical Memory Array: ", ma.smbmam_array);
1072 	oprintf(fp, "  Devices per Row: %u\n", ma.smbmam_width);
1073 
1074 	oprintf(fp, "  Physical Address: 0x%llx\n  Size: %llu bytes\n",
1075 	    (u_longlong_t)ma.smbmam_addr, (u_longlong_t)ma.smbmam_size);
1076 }
1077 
1078 static void
1079 print_memdevmap(smbios_hdl_t *shp, id_t id, FILE *fp)
1080 {
1081 	smbios_memdevmap_t md;
1082 
1083 	(void) smbios_info_memdevmap(shp, id, &md);
1084 
1085 	id_printf(fp, "  Memory Device: ", md.smbmdm_device);
1086 	id_printf(fp, "  Memory Array Mapped Address: ", md.smbmdm_arrmap);
1087 
1088 	oprintf(fp, "  Physical Address: 0x%llx\n  Size: %llu bytes\n",
1089 	    (u_longlong_t)md.smbmdm_addr, (u_longlong_t)md.smbmdm_size);
1090 
1091 	oprintf(fp, "  Partition Row Position: %u\n", md.smbmdm_rpos);
1092 	oprintf(fp, "  Interleave Position: %u\n", md.smbmdm_ipos);
1093 	oprintf(fp, "  Interleave Data Depth: %u\n", md.smbmdm_idepth);
1094 }
1095 
1096 static void
1097 print_hwsec(smbios_hdl_t *shp, FILE *fp)
1098 {
1099 	smbios_hwsec_t h;
1100 
1101 	(void) smbios_info_hwsec(shp, &h);
1102 
1103 	desc_printf(smbios_hwsec_desc(h.smbh_pwr_ps),
1104 	    fp, "  Power-On Password Status: %u", h.smbh_pwr_ps);
1105 	desc_printf(smbios_hwsec_desc(h.smbh_kbd_ps),
1106 	    fp, "  Keyboard Password Status: %u", h.smbh_kbd_ps);
1107 	desc_printf(smbios_hwsec_desc(h.smbh_adm_ps),
1108 	    fp, "  Administrator Password Status: %u", h.smbh_adm_ps);
1109 	desc_printf(smbios_hwsec_desc(h.smbh_pan_ps),
1110 	    fp, "  Front Panel Reset Status: %u", h.smbh_pan_ps);
1111 }
1112 
1113 static void
1114 print_vprobe(smbios_hdl_t *shp, id_t id, FILE *fp)
1115 {
1116 	smbios_vprobe_t vp;
1117 
1118 	if (smbios_info_vprobe(shp, id, &vp) != 0) {
1119 		smbios_warn(shp, "failed to read voltage probe information");
1120 		return;
1121 	}
1122 
1123 	oprintf(fp, "  Description: %s\n", vp.smbvp_description != NULL ?
1124 	    vp.smbvp_description : "unknown");
1125 	desc_printf(smbios_vprobe_loc_desc(vp.smbvp_location),
1126 	    fp, "  Location: %u", vp.smbvp_location);
1127 	desc_printf(smbios_vprobe_status_desc(vp.smbvp_status),
1128 	    fp, "  Status: %u", vp.smbvp_status);
1129 
1130 	if (vp.smbvp_maxval != SMB_PROBE_UNKNOWN_VALUE) {
1131 		oprintf(fp, "  Maximum Possible Voltage: %u mV\n",
1132 		    vp.smbvp_maxval);
1133 	} else {
1134 		oprintf(fp, "  Maximum Possible Voltage: unknown\n");
1135 	}
1136 
1137 	if (vp.smbvp_minval != SMB_PROBE_UNKNOWN_VALUE) {
1138 		oprintf(fp, "  Minimum Possible Voltage: %u mV\n",
1139 		    vp.smbvp_minval);
1140 	} else {
1141 		oprintf(fp, "  Minimum Possible Voltage: unknown\n");
1142 	}
1143 
1144 	if (vp.smbvp_resolution != SMB_PROBE_UNKNOWN_VALUE) {
1145 		oprintf(fp, "  Probe Resolution: %u.%u mV\n",
1146 		    vp.smbvp_resolution / 10,
1147 		    vp.smbvp_resolution % 10);
1148 	} else {
1149 		oprintf(fp, "  Probe Resolution: unknown\n");
1150 	}
1151 
1152 	if (vp.smbvp_tolerance != SMB_PROBE_UNKNOWN_VALUE) {
1153 		oprintf(fp, "  Probe Tolerance: +/-%u mV\n",
1154 		    vp.smbvp_tolerance);
1155 	} else {
1156 		oprintf(fp, "  Probe Tolerance: unknown\n");
1157 	}
1158 
1159 	if (vp.smbvp_accuracy != SMB_PROBE_UNKNOWN_VALUE) {
1160 		oprintf(fp, "  Probe Accuracy: +/-%u.%02u%%\n",
1161 		    vp.smbvp_accuracy / 100,
1162 		    vp.smbvp_accuracy % 100);
1163 	} else {
1164 		oprintf(fp, "  Probe Accuracy: unknown\n");
1165 	}
1166 
1167 	oprintf(fp, "  OEM- or BIOS- defined value: 0x%x\n", vp.smbvp_oem);
1168 
1169 	if (vp.smbvp_nominal != SMB_PROBE_UNKNOWN_VALUE) {
1170 		oprintf(fp, "  Probe Nominal Value: %u mV\n", vp.smbvp_nominal);
1171 	} else {
1172 		oprintf(fp, "  Probe Nominal Value: unknown\n");
1173 	}
1174 }
1175 
1176 static void
1177 print_cooldev(smbios_hdl_t *shp, id_t id, FILE *fp)
1178 {
1179 	smbios_cooldev_t cd;
1180 
1181 	if (smbios_info_cooldev(shp, id, &cd) != 0) {
1182 		smbios_warn(shp, "failed to read cooling device "
1183 		    "information");
1184 		return;
1185 	}
1186 
1187 	id_printf(fp, "  Temperature Probe Handle: ", cd.smbcd_tprobe);
1188 	desc_printf(smbios_cooldev_type_desc(cd.smbcd_type),
1189 	    fp, "  Device Type: %u", cd.smbcd_type);
1190 	desc_printf(smbios_cooldev_status_desc(cd.smbcd_status),
1191 	    fp, "  Status: %u", cd.smbcd_status);
1192 	oprintf(fp, "  Cooling Unit Group: %u\n", cd.smbcd_group);
1193 	oprintf(fp, "  OEM- or BIOS- defined data: 0x%x\n", cd.smbcd_oem);
1194 	if (cd.smbcd_nominal != SMB_PROBE_UNKNOWN_VALUE) {
1195 		oprintf(fp, "  Nominal Speed: %u RPM\n", cd.smbcd_nominal);
1196 	} else {
1197 		oprintf(fp, "  Nominal Speed: unknown\n");
1198 	}
1199 
1200 	if (cd.smbcd_descr != NULL && cd.smbcd_descr[0] != '\0') {
1201 		oprintf(fp, "  Description: %s\n", cd.smbcd_descr);
1202 	}
1203 }
1204 
1205 static void
1206 print_tprobe(smbios_hdl_t *shp, id_t id, FILE *fp)
1207 {
1208 	smbios_tprobe_t tp;
1209 
1210 	if (smbios_info_tprobe(shp, id, &tp) != 0) {
1211 		smbios_warn(shp, "failed to read temperature probe "
1212 		    "information");
1213 		return;
1214 	}
1215 
1216 	oprintf(fp, "  Description: %s\n", tp.smbtp_description != NULL ?
1217 	    tp.smbtp_description : "unknown");
1218 	desc_printf(smbios_tprobe_loc_desc(tp.smbtp_location),
1219 	    fp, "  Location: %u", tp.smbtp_location);
1220 	desc_printf(smbios_tprobe_status_desc(tp.smbtp_status),
1221 	    fp, "  Status: %u", tp.smbtp_status);
1222 
1223 	if (tp.smbtp_maxval != SMB_PROBE_UNKNOWN_VALUE) {
1224 		oprintf(fp, "  Maximum Possible Temperature: %u.%u C\n",
1225 		    tp.smbtp_maxval / 10, tp.smbtp_maxval % 10);
1226 	} else {
1227 		oprintf(fp, "  Maximum Possible Temperature: unknown\n");
1228 	}
1229 
1230 	if (tp.smbtp_minval != SMB_PROBE_UNKNOWN_VALUE) {
1231 		oprintf(fp, "  Minimum Possible Temperature: %u.%u C\n",
1232 		    tp.smbtp_minval / 10, tp.smbtp_minval % 10);
1233 	} else {
1234 		oprintf(fp, "  Minimum Possible Temperature: unknown\n");
1235 	}
1236 
1237 	if (tp.smbtp_resolution != SMB_PROBE_UNKNOWN_VALUE) {
1238 		oprintf(fp, "  Probe Resolution: %u.%03u C\n",
1239 		    tp.smbtp_resolution / 1000,
1240 		    tp.smbtp_resolution % 1000);
1241 	} else {
1242 		oprintf(fp, "  Probe Resolution: unknown\n");
1243 	}
1244 
1245 	if (tp.smbtp_tolerance != SMB_PROBE_UNKNOWN_VALUE) {
1246 		oprintf(fp, "  Probe Tolerance: +/-%u.%u C\n",
1247 		    tp.smbtp_tolerance / 10, tp.smbtp_tolerance % 10);
1248 	} else {
1249 		oprintf(fp, "  Probe Tolerance: unknown\n");
1250 	}
1251 
1252 	if (tp.smbtp_accuracy != SMB_PROBE_UNKNOWN_VALUE) {
1253 		oprintf(fp, "  Probe Accuracy: +/-%u.%02u%%\n",
1254 		    tp.smbtp_accuracy / 100,
1255 		    tp.smbtp_accuracy % 100);
1256 	} else {
1257 		oprintf(fp, "  Probe Accuracy: unknown\n");
1258 	}
1259 
1260 	oprintf(fp, "  OEM- or BIOS- defined value: 0x%x\n", tp.smbtp_oem);
1261 
1262 	if (tp.smbtp_nominal != SMB_PROBE_UNKNOWN_VALUE) {
1263 		oprintf(fp, "  Probe Nominal Value: %u.%u C\n",
1264 		    tp.smbtp_nominal / 10, tp.smbtp_nominal % 10);
1265 	} else {
1266 		oprintf(fp, "  Probe Nominal Value: unknown\n");
1267 	}
1268 }
1269 
1270 static void
1271 print_iprobe(smbios_hdl_t *shp, id_t id, FILE *fp)
1272 {
1273 	smbios_iprobe_t ip;
1274 
1275 	if (smbios_info_iprobe(shp, id, &ip) != 0) {
1276 		smbios_warn(shp, "failed to read current probe information");
1277 		return;
1278 	}
1279 
1280 	oprintf(fp, "  Description: %s\n", ip.smbip_description != NULL ?
1281 	    ip.smbip_description : "unknown");
1282 	desc_printf(smbios_iprobe_loc_desc(ip.smbip_location),
1283 	    fp, "  Location: %u", ip.smbip_location);
1284 	desc_printf(smbios_iprobe_status_desc(ip.smbip_status),
1285 	    fp, "  Status: %u", ip.smbip_status);
1286 
1287 	if (ip.smbip_maxval != SMB_PROBE_UNKNOWN_VALUE) {
1288 		oprintf(fp, "  Maximum Possible Current: %u mA\n",
1289 		    ip.smbip_maxval);
1290 	} else {
1291 		oprintf(fp, "  Maximum Possible Current: unknown\n");
1292 	}
1293 
1294 	if (ip.smbip_minval != SMB_PROBE_UNKNOWN_VALUE) {
1295 		oprintf(fp, "  Minimum Possible Current: %u mA\n",
1296 		    ip.smbip_minval);
1297 	} else {
1298 		oprintf(fp, "  Minimum Possible Current: unknown\n");
1299 	}
1300 
1301 	if (ip.smbip_resolution != SMB_PROBE_UNKNOWN_VALUE) {
1302 		oprintf(fp, "  Probe Resolution: %u.%u mA\n",
1303 		    ip.smbip_resolution / 10,
1304 		    ip.smbip_resolution % 10);
1305 	} else {
1306 		oprintf(fp, "  Probe Resolution: unknown\n");
1307 	}
1308 
1309 	if (ip.smbip_tolerance != SMB_PROBE_UNKNOWN_VALUE) {
1310 		oprintf(fp, "  Probe Tolerance: +/-%u mA\n",
1311 		    ip.smbip_tolerance);
1312 	} else {
1313 		oprintf(fp, "  Probe Tolerance: unknown\n");
1314 	}
1315 
1316 	if (ip.smbip_accuracy != SMB_PROBE_UNKNOWN_VALUE) {
1317 		oprintf(fp, "  Probe Accuracy: +/-%u.%02u%%\n",
1318 		    ip.smbip_accuracy / 100,
1319 		    ip.smbip_accuracy % 100);
1320 	} else {
1321 		oprintf(fp, "  Probe Accuracy: unknown\n");
1322 	}
1323 
1324 	oprintf(fp, "  OEM- or BIOS- defined value: 0x%x\n", ip.smbip_oem);
1325 
1326 	if (ip.smbip_nominal != SMB_PROBE_UNKNOWN_VALUE) {
1327 		oprintf(fp, "  Probe Nominal Value: %u mA\n", ip.smbip_nominal);
1328 	} else {
1329 		oprintf(fp, "  Probe Nominal Value: unknown\n");
1330 	}
1331 }
1332 
1333 
1334 static void
1335 print_boot(smbios_hdl_t *shp, FILE *fp)
1336 {
1337 	smbios_boot_t b;
1338 
1339 	(void) smbios_info_boot(shp, &b);
1340 
1341 	desc_printf(smbios_boot_desc(b.smbt_status),
1342 	    fp, "  Boot Status Code: 0x%x", b.smbt_status);
1343 
1344 	if (b.smbt_size != 0) {
1345 		oprintf(fp, "  Boot Data (%lu bytes):\n", (ulong_t)b.smbt_size);
1346 		print_bytes(b.smbt_data, b.smbt_size, fp);
1347 	}
1348 }
1349 
1350 static void
1351 print_ipmi(smbios_hdl_t *shp, FILE *fp)
1352 {
1353 	smbios_ipmi_t i;
1354 
1355 	(void) smbios_info_ipmi(shp, &i);
1356 
1357 	desc_printf(smbios_ipmi_type_desc(i.smbip_type),
1358 	    fp, "  Type: %u", i.smbip_type);
1359 
1360 	oprintf(fp, "  BMC IPMI Version: %u.%u\n",
1361 	    i.smbip_vers.smbv_major, i.smbip_vers.smbv_minor);
1362 
1363 	oprintf(fp, "  i2c Bus Slave Address: 0x%x\n", i.smbip_i2c);
1364 	oprintf(fp, "  NV Storage Device Bus ID: 0x%x\n", i.smbip_bus);
1365 	oprintf(fp, "  BMC Base Address: 0x%llx\n", (u_longlong_t)i.smbip_addr);
1366 	oprintf(fp, "  Interrupt Number: %u\n", i.smbip_intr);
1367 	oprintf(fp, "  Register Spacing: %u\n", i.smbip_regspacing);
1368 
1369 	flag_printf(fp, "Flags", i.smbip_flags, sizeof (i.smbip_flags) * NBBY,
1370 	    smbios_ipmi_flag_name, smbios_ipmi_flag_desc);
1371 }
1372 
1373 static void
1374 print_powersup(smbios_hdl_t *shp, id_t id, FILE *fp)
1375 {
1376 	smbios_powersup_t p;
1377 
1378 	if (smbios_info_powersup(shp, id, &p) != 0) {
1379 		smbios_warn(shp, "failed to read power supply information");
1380 		return;
1381 	}
1382 
1383 	oprintf(fp, "  Power Supply Group: %u\n", p.smbps_group);
1384 	if (p.smbps_maxout != 0x8000) {
1385 		oprintf(fp, "  Maximum Output: %llu mW\n", p.smbps_maxout);
1386 	} else {
1387 		oprintf(fp, "  Maximum Output: unknown\n");
1388 	}
1389 
1390 	flag_printf(fp, "Characteristics", p.smbps_flags,
1391 	    sizeof (p.smbps_flags) * NBBY, smbios_powersup_flag_name,
1392 	    smbios_powersup_flag_desc);
1393 
1394 	desc_printf(smbios_powersup_input_desc(p.smbps_ivrs),
1395 	    fp, "  Input Voltage Range Switching: %u", p.smbps_ivrs);
1396 	desc_printf(smbios_powersup_status_desc(p.smbps_status),
1397 	    fp, "  Status: %u", p.smbps_status);
1398 	desc_printf(smbios_powersup_type_desc(p.smbps_pstype),
1399 	    fp, "  Type: %u", p.smbps_pstype);
1400 
1401 	if (p.smbps_vprobe != 0xffff) {
1402 		oprintf(fp, "  Voltage Probe Handle: %lu\n", p.smbps_vprobe);
1403 	}
1404 
1405 	if (p.smbps_cooldev != 0xffff) {
1406 		oprintf(fp, "  Cooling Device Handle: %lu\n", p.smbps_cooldev);
1407 	}
1408 
1409 	if (p.smbps_iprobe != 0xffff) {
1410 		oprintf(fp, "  Current Probe Handle: %lu\n", p.smbps_iprobe);
1411 	}
1412 }
1413 
1414 static void
1415 print_processor_info_riscv(smbios_hdl_t *shp, id_t id, FILE *fp)
1416 {
1417 	smbios_processor_info_riscv_t rv;
1418 
1419 	if (smbios_info_processor_riscv(shp, id, &rv) != 0) {
1420 		smbios_warn(shp, "failed to read RISC-V specific processor "
1421 		    "information");
1422 		return;
1423 	}
1424 
1425 	if (rv.smbpirv_boothart != 0) {
1426 		oprintf(fp, "    Boot Hart\n");
1427 	}
1428 	u128_print(fp, "    Hart ID", rv.smbpirv_hartid);
1429 	u128_print(fp, "    Vendor ID", rv.smbpirv_vendid);
1430 	u128_print(fp, "    Architecture ID", rv.smbpirv_archid);
1431 	u128_print(fp, "    Implementation ID", rv.smbpirv_machid);
1432 	flag64_printf(fp, "  ISA", rv.smbpirv_isa,
1433 	    sizeof (rv.smbpirv_isa) * NBBY, smbios_riscv_isa_name,
1434 	    smbios_riscv_isa_desc);
1435 	flag_printf(fp, "  Privilege Levels", rv.smbpirv_privlvl,
1436 	    sizeof (rv.smbpirv_privlvl) * NBBY, smbios_riscv_priv_name,
1437 	    smbios_riscv_priv_desc);
1438 	u128_print(fp, "    Machine Exception Trap Delegation",
1439 	    rv.smbpirv_metdi);
1440 	u128_print(fp, "    Machine Interrupt Trap Delegation",
1441 	    rv.smbpirv_mitdi);
1442 	desc_printf(smbios_riscv_width_desc(rv.smbpirv_xlen),
1443 	    fp, "    Register Width: 0x%x", rv.smbpirv_xlen);
1444 	desc_printf(smbios_riscv_width_desc(rv.smbpirv_mxlen),
1445 	    fp, "    M-Mode Register Width: 0x%x", rv.smbpirv_mxlen);
1446 	desc_printf(smbios_riscv_width_desc(rv.smbpirv_sxlen),
1447 	    fp, "    S-Mode Register Width: 0x%x", rv.smbpirv_sxlen);
1448 	desc_printf(smbios_riscv_width_desc(rv.smbpirv_uxlen),
1449 	    fp, "    U-Mode Register Width: 0x%x", rv.smbpirv_uxlen);
1450 }
1451 
1452 static void
1453 print_processor_info(smbios_hdl_t *shp, id_t id, FILE *fp)
1454 {
1455 	smbios_processor_info_t p;
1456 
1457 	if (smbios_info_processor_info(shp, id, &p) != 0) {
1458 		smbios_warn(shp, "failed to read processor additional "
1459 		    "information");
1460 		return;
1461 	}
1462 
1463 	id_printf(fp, "  Processor Handle: ", p.smbpi_processor);
1464 	desc_printf(smbios_processor_info_type_desc(p.smbpi_ptype),
1465 	    fp, "  Processor Type: %u", p.smbpi_ptype);
1466 
1467 	switch (p.smbpi_ptype) {
1468 	case SMB_PROCINFO_T_RV32:
1469 	case SMB_PROCINFO_T_RV64:
1470 	case SMB_PROCINFO_T_RV128:
1471 		oprintf(fp, "  RISC-V Additional Processor Information:\n");
1472 		print_processor_info_riscv(shp, id, fp);
1473 		break;
1474 	default:
1475 		break;
1476 	}
1477 }
1478 
1479 static void
1480 print_battery(smbios_hdl_t *shp, id_t id, FILE *fp)
1481 {
1482 	smbios_battery_t bat;
1483 
1484 	if (smbios_info_battery(shp, id, &bat) != 0) {
1485 		smbios_warn(shp, "failed to read battery information");
1486 		return;
1487 	}
1488 
1489 	if (bat.smbb_date != NULL) {
1490 		oprintf(fp, "  Manufacture Date: %s\n", bat.smbb_date);
1491 	}
1492 
1493 	if (bat.smbb_serial != NULL) {
1494 		oprintf(fp, "  Serial Number: %s\n", bat.smbb_serial);
1495 	}
1496 
1497 	if (bat.smbb_chem != SMB_BDC_UNKNOWN) {
1498 		desc_printf(smbios_battery_chem_desc(bat.smbb_chem),
1499 		    fp, "  Battery Chemistry: 0x%x", bat.smbb_chem);
1500 	}
1501 
1502 	if (bat.smbb_cap != 0) {
1503 		oprintf(fp, "  Design Capacity: %u mWh\n", bat.smbb_cap);
1504 	} else {
1505 		oprintf(fp, "  Design Capacity: unknown\n");
1506 	}
1507 
1508 	if (bat.smbb_volt != 0) {
1509 		oprintf(fp, "  Design Voltage: %u mV\n", bat.smbb_volt);
1510 	} else {
1511 		oprintf(fp, "  Design Voltage: unknown\n");
1512 	}
1513 
1514 	oprintf(fp, "  SBDS Version Number: %s\n", bat.smbb_version);
1515 	if (bat.smbb_err != UINT8_MAX) {
1516 		oprintf(fp, "  Maximum Error: %u\n", bat.smbb_err);
1517 	} else {
1518 		oprintf(fp, "  Maximum Error: unknown\n", bat.smbb_err);
1519 	}
1520 	oprintf(fp, "  SBDS Serial Number: %04x\n", bat.smbb_ssn);
1521 	oprintf(fp, "  SBDS Manufacture Date: %u-%02u-%02u\n", bat.smbb_syear,
1522 	    bat.smbb_smonth, bat.smbb_sday);
1523 	oprintf(fp, "  SBDS Device Chemistry: %s\n", bat.smbb_schem);
1524 	oprintf(fp, "  OEM-specific Information: 0x%08x\n", bat.smbb_oemdata);
1525 }
1526 
1527 static void
1528 print_pointdev(smbios_hdl_t *shp, id_t id, FILE *fp)
1529 {
1530 	smbios_pointdev_t pd;
1531 
1532 	if (smbios_info_pointdev(shp, id, &pd) != 0) {
1533 		smbios_warn(shp, "failed to read pointer device information");
1534 		return;
1535 	}
1536 
1537 	desc_printf(smbios_pointdev_type_desc(pd.smbpd_type),
1538 	    fp, "  Type: %u", pd.smbpd_type);
1539 	desc_printf(smbios_pointdev_iface_desc(pd.smbpd_iface),
1540 	    fp, "  Interface: %u", pd.smbpd_iface);
1541 	oprintf(fp, "  Buttons: %u\n", pd.smbpd_nbuttons);
1542 }
1543 
1544 static void
1545 print_extprocessor(smbios_hdl_t *shp, id_t id, FILE *fp)
1546 {
1547 	int i;
1548 	smbios_processor_ext_t ep;
1549 
1550 	if (check_oem(shp) != 0)
1551 		return;
1552 
1553 	(void) smbios_info_extprocessor(shp, id, &ep);
1554 
1555 	oprintf(fp, "  Processor: %u\n", ep.smbpe_processor);
1556 	oprintf(fp, "  FRU: %u\n", ep.smbpe_fru);
1557 	oprintf(fp, "  Initial APIC ID count: %u\n\n", ep.smbpe_n);
1558 
1559 	for (i = 0; i < ep.smbpe_n; i++) {
1560 		oprintf(fp, "  Logical Strand %u: Initial APIC ID: %u\n", i,
1561 		    ep.smbpe_apicid[i]);
1562 	}
1563 }
1564 
1565 static void
1566 print_extport(smbios_hdl_t *shp, id_t id, FILE *fp)
1567 {
1568 	smbios_port_ext_t epo;
1569 
1570 	if (check_oem(shp) != 0)
1571 		return;
1572 
1573 	(void) smbios_info_extport(shp, id, &epo);
1574 
1575 	oprintf(fp, "  Chassis Handle: %u\n", epo.smbporte_chassis);
1576 	oprintf(fp, "  Port Connector Handle: %u\n", epo.smbporte_port);
1577 	oprintf(fp, "  Device Type: %u\n", epo.smbporte_dtype);
1578 	oprintf(fp, "  Device Handle: %u\n", epo.smbporte_devhdl);
1579 	oprintf(fp, "  PHY: %u\n", epo.smbporte_phy);
1580 }
1581 
1582 static void
1583 print_pciexrc(smbios_hdl_t *shp, id_t id, FILE *fp)
1584 {
1585 	smbios_pciexrc_t pcie;
1586 
1587 	if (check_oem(shp) != 0)
1588 		return;
1589 
1590 	(void) smbios_info_pciexrc(shp, id, &pcie);
1591 
1592 	oprintf(fp, "  Component ID: %u\n", pcie.smbpcie_bb);
1593 	oprintf(fp, "  BDF: 0x%x\n", pcie.smbpcie_bdf);
1594 }
1595 
1596 static void
1597 print_extmemarray(smbios_hdl_t *shp, id_t id, FILE *fp)
1598 {
1599 	smbios_memarray_ext_t em;
1600 
1601 	if (check_oem(shp) != 0)
1602 		return;
1603 
1604 	(void) smbios_info_extmemarray(shp, id, &em);
1605 
1606 	oprintf(fp, "  Physical Memory Array Handle: %u\n", em.smbmae_ma);
1607 	oprintf(fp, "  Component Parent Handle: %u\n", em.smbmae_comp);
1608 	oprintf(fp, "  BDF: 0x%x\n", em.smbmae_bdf);
1609 }
1610 
1611 static void
1612 print_extmemdevice(smbios_hdl_t *shp, id_t id, FILE *fp)
1613 {
1614 	int i;
1615 	smbios_memdevice_ext_t emd;
1616 
1617 	if (check_oem(shp) != 0)
1618 		return;
1619 
1620 	(void) smbios_info_extmemdevice(shp, id, &emd);
1621 
1622 	oprintf(fp, "  Memory Device Handle: %u\n", emd.smbmdeve_md);
1623 	oprintf(fp, "  DRAM Channel: %u\n", emd.smbmdeve_drch);
1624 	oprintf(fp, "  Number of Chip Selects: %u\n", emd.smbmdeve_ncs);
1625 
1626 	for (i = 0; i < emd.smbmdeve_ncs; i++) {
1627 		oprintf(fp, "  Chip Select: %u\n", emd.smbmdeve_cs[i]);
1628 	}
1629 }
1630 
1631 static int
1632 print_struct(smbios_hdl_t *shp, const smbios_struct_t *sp, void *fp)
1633 {
1634 	smbios_info_t info;
1635 	int hex = opt_x;
1636 	const char *s;
1637 
1638 	if (opt_t != -1 && opt_t != sp->smbstr_type)
1639 		return (0); /* skip struct if type doesn't match -t */
1640 
1641 	if (!opt_O && (sp->smbstr_type == SMB_TYPE_MEMCTL ||
1642 	    sp->smbstr_type == SMB_TYPE_MEMMOD))
1643 		return (0); /* skip struct if type is obsolete */
1644 
1645 	if (g_hdr++ == 0 || !opt_s)
1646 		oprintf(fp, "%-5s %-4s %s\n", "ID", "SIZE", "TYPE");
1647 
1648 	oprintf(fp, "%-5u %-4lu",
1649 	    (uint_t)sp->smbstr_id, (ulong_t)sp->smbstr_size);
1650 
1651 	if ((s = smbios_type_name(sp->smbstr_type)) != NULL)
1652 		oprintf(fp, " %s (type %u)", s, sp->smbstr_type);
1653 	else if (sp->smbstr_type > SMB_TYPE_OEM_LO &&
1654 	    sp->smbstr_type < SMB_TYPE_OEM_HI)
1655 		oprintf(fp, " %s+%u (type %u)", "SMB_TYPE_OEM_LO",
1656 		    sp->smbstr_type - SMB_TYPE_OEM_LO, sp->smbstr_type);
1657 	else
1658 		oprintf(fp, " %u", sp->smbstr_type);
1659 
1660 	if ((s = smbios_type_desc(sp->smbstr_type)) != NULL)
1661 		oprintf(fp, " (%s)\n", s);
1662 	else
1663 		oprintf(fp, "\n");
1664 
1665 	if (opt_s)
1666 		return (0); /* only print header line if -s specified */
1667 
1668 	if (smbios_info_common(shp, sp->smbstr_id, &info) == 0) {
1669 		oprintf(fp, "\n");
1670 		print_common(&info, fp);
1671 	}
1672 
1673 	switch (sp->smbstr_type) {
1674 	case SMB_TYPE_BIOS:
1675 		oprintf(fp, "\n");
1676 		print_bios(shp, fp);
1677 		break;
1678 	case SMB_TYPE_SYSTEM:
1679 		oprintf(fp, "\n");
1680 		print_system(shp, fp);
1681 		break;
1682 	case SMB_TYPE_BASEBOARD:
1683 		oprintf(fp, "\n");
1684 		print_bboard(shp, sp->smbstr_id, fp);
1685 		break;
1686 	case SMB_TYPE_CHASSIS:
1687 		oprintf(fp, "\n");
1688 		print_chassis(shp, sp->smbstr_id, fp);
1689 		break;
1690 	case SMB_TYPE_PROCESSOR:
1691 		oprintf(fp, "\n");
1692 		print_processor(shp, sp->smbstr_id, fp);
1693 		break;
1694 	case SMB_TYPE_CACHE:
1695 		oprintf(fp, "\n");
1696 		print_cache(shp, sp->smbstr_id, fp);
1697 		break;
1698 	case SMB_TYPE_PORT:
1699 		oprintf(fp, "\n");
1700 		print_port(shp, sp->smbstr_id, fp);
1701 		break;
1702 	case SMB_TYPE_SLOT:
1703 		oprintf(fp, "\n");
1704 		print_slot(shp, sp->smbstr_id, fp);
1705 		break;
1706 	case SMB_TYPE_OBDEVS:
1707 		oprintf(fp, "\n");
1708 		print_obdevs(shp, sp->smbstr_id, fp);
1709 		break;
1710 	case SMB_TYPE_OEMSTR:
1711 	case SMB_TYPE_SYSCONFSTR:
1712 		oprintf(fp, "\n");
1713 		print_strtab(shp, sp->smbstr_id, fp);
1714 		break;
1715 	case SMB_TYPE_LANG:
1716 		oprintf(fp, "\n");
1717 		print_lang(shp, sp->smbstr_id, fp);
1718 		break;
1719 	case SMB_TYPE_EVENTLOG:
1720 		oprintf(fp, "\n");
1721 		print_evlog(shp, sp->smbstr_id, fp);
1722 		break;
1723 	case SMB_TYPE_MEMARRAY:
1724 		oprintf(fp, "\n");
1725 		print_memarray(shp, sp->smbstr_id, fp);
1726 		break;
1727 	case SMB_TYPE_MEMDEVICE:
1728 		oprintf(fp, "\n");
1729 		print_memdevice(shp, sp->smbstr_id, fp);
1730 		break;
1731 	case SMB_TYPE_MEMARRAYMAP:
1732 		oprintf(fp, "\n");
1733 		print_memarrmap(shp, sp->smbstr_id, fp);
1734 		break;
1735 	case SMB_TYPE_MEMDEVICEMAP:
1736 		oprintf(fp, "\n");
1737 		print_memdevmap(shp, sp->smbstr_id, fp);
1738 		break;
1739 	case SMB_TYPE_BATTERY:
1740 		oprintf(fp, "\n");
1741 		print_battery(shp, sp->smbstr_id, fp);
1742 		break;
1743 	case SMB_TYPE_POINTDEV:
1744 		oprintf(fp, "\n");
1745 		print_pointdev(shp, sp->smbstr_id, fp);
1746 		break;
1747 	case SMB_TYPE_SECURITY:
1748 		oprintf(fp, "\n");
1749 		print_hwsec(shp, fp);
1750 		break;
1751 	case SMB_TYPE_VPROBE:
1752 		oprintf(fp, "\n");
1753 		print_vprobe(shp, sp->smbstr_id, fp);
1754 		break;
1755 	case SMB_TYPE_COOLDEV:
1756 		oprintf(fp, "\n");
1757 		print_cooldev(shp, sp->smbstr_id, fp);
1758 		break;
1759 	case SMB_TYPE_TPROBE:
1760 		oprintf(fp, "\n");
1761 		print_tprobe(shp, sp->smbstr_id, fp);
1762 		break;
1763 	case SMB_TYPE_IPROBE:
1764 		oprintf(fp, "\n");
1765 		print_iprobe(shp, sp->smbstr_id, fp);
1766 		break;
1767 	case SMB_TYPE_BOOT:
1768 		oprintf(fp, "\n");
1769 		print_boot(shp, fp);
1770 		break;
1771 	case SMB_TYPE_IPMIDEV:
1772 		oprintf(fp, "\n");
1773 		print_ipmi(shp, fp);
1774 		break;
1775 	case SMB_TYPE_POWERSUP:
1776 		oprintf(fp, "\n");
1777 		print_powersup(shp, sp->smbstr_id, fp);
1778 		break;
1779 	case SMB_TYPE_OBDEVEXT:
1780 		oprintf(fp, "\n");
1781 		print_obdevs_ext(shp, sp->smbstr_id, fp);
1782 		break;
1783 	case SMB_TYPE_PROCESSOR_INFO:
1784 		oprintf(fp, "\n");
1785 		print_processor_info(shp, sp->smbstr_id, fp);
1786 		break;
1787 	case SUN_OEM_EXT_PROCESSOR:
1788 		oprintf(fp, "\n");
1789 		print_extprocessor(shp, sp->smbstr_id, fp);
1790 		break;
1791 	case SUN_OEM_EXT_PORT:
1792 		oprintf(fp, "\n");
1793 		print_extport(shp, sp->smbstr_id, fp);
1794 		break;
1795 	case SUN_OEM_PCIEXRC:
1796 		oprintf(fp, "\n");
1797 		print_pciexrc(shp, sp->smbstr_id, fp);
1798 		break;
1799 	case SUN_OEM_EXT_MEMARRAY:
1800 		oprintf(fp, "\n");
1801 		print_extmemarray(shp, sp->smbstr_id, fp);
1802 		break;
1803 	case SUN_OEM_EXT_MEMDEVICE:
1804 		oprintf(fp, "\n");
1805 		print_extmemdevice(shp, sp->smbstr_id, fp);
1806 		break;
1807 	default:
1808 		hex++;
1809 	}
1810 
1811 	if (hex)
1812 		print_bytes(sp->smbstr_data, sp->smbstr_size, fp);
1813 	else
1814 		oprintf(fp, "\n");
1815 
1816 	return (0);
1817 }
1818 
1819 static uint16_t
1820 getu16(const char *name, const char *s)
1821 {
1822 	u_longlong_t val;
1823 	char *p;
1824 
1825 	errno = 0;
1826 	val = strtoull(s, &p, 0);
1827 
1828 	if (errno != 0 || p == s || *p != '\0' || val > UINT16_MAX) {
1829 		(void) fprintf(stderr, "%s: invalid %s argument -- %s\n",
1830 		    g_pname, name, s);
1831 		exit(SMBIOS_USAGE);
1832 	}
1833 
1834 	return ((uint16_t)val);
1835 }
1836 
1837 static uint16_t
1838 getstype(const char *name, const char *s)
1839 {
1840 	const char *ts;
1841 	uint16_t t;
1842 
1843 	for (t = 0; t < SMB_TYPE_OEM_LO; t++) {
1844 		if ((ts = smbios_type_name(t)) != NULL && strcmp(s, ts) == 0)
1845 			return (t);
1846 	}
1847 
1848 	(void) fprintf(stderr, "%s: invalid %s argument -- %s\n",
1849 	    g_pname, name, s);
1850 
1851 	exit(SMBIOS_USAGE);
1852 	/*NOTREACHED*/
1853 }
1854 
1855 static int
1856 usage(FILE *fp)
1857 {
1858 	(void) fprintf(fp, "Usage: %s "
1859 	    "[-BeOsx] [-i id] [-t type] [-w file] [file]\n\n", g_pname);
1860 
1861 	(void) fprintf(fp,
1862 	    "\t-B disable header validation for broken BIOSes\n"
1863 	    "\t-e display SMBIOS entry point information\n"
1864 	    "\t-i display only the specified structure\n"
1865 	    "\t-O display obsolete structure types\n"
1866 	    "\t-s display only a summary of structure identifiers and types\n"
1867 	    "\t-t display only the specified structure type\n"
1868 	    "\t-w write the raw data to the specified file\n"
1869 	    "\t-x display raw data for structures\n");
1870 
1871 	return (SMBIOS_USAGE);
1872 }
1873 
1874 int
1875 main(int argc, char *argv[])
1876 {
1877 	const char *ifile = NULL;
1878 	const char *ofile = NULL;
1879 	int oflags = 0;
1880 
1881 	smbios_hdl_t *shp;
1882 	smbios_struct_t s;
1883 	int err, fd, c;
1884 	char *p;
1885 
1886 	if ((p = strrchr(argv[0], '/')) == NULL)
1887 		g_pname = argv[0];
1888 	else
1889 		g_pname = p + 1;
1890 
1891 	while (optind < argc) {
1892 		while ((c = getopt(argc, argv, "Bei:Ost:w:xZ")) != EOF) {
1893 			switch (c) {
1894 			case 'B':
1895 				oflags |= SMB_O_NOCKSUM | SMB_O_NOVERS;
1896 				break;
1897 			case 'e':
1898 				opt_e++;
1899 				break;
1900 			case 'i':
1901 				opt_i = getu16("struct ID", optarg);
1902 				break;
1903 			case 'O':
1904 				opt_O++;
1905 				break;
1906 			case 's':
1907 				opt_s++;
1908 				break;
1909 			case 't':
1910 				if (isdigit(optarg[0]))
1911 					opt_t = getu16("struct type", optarg);
1912 				else
1913 					opt_t = getstype("struct type", optarg);
1914 				break;
1915 			case 'w':
1916 				ofile = optarg;
1917 				break;
1918 			case 'x':
1919 				opt_x++;
1920 				break;
1921 			case 'Z':
1922 				oflags |= SMB_O_ZIDS; /* undocumented */
1923 				break;
1924 			default:
1925 				return (usage(stderr));
1926 			}
1927 		}
1928 
1929 		if (optind < argc) {
1930 			if (ifile != NULL) {
1931 				(void) fprintf(stderr, "%s: illegal "
1932 				    "argument -- %s\n", g_pname, argv[optind]);
1933 				return (SMBIOS_USAGE);
1934 			}
1935 			ifile = argv[optind++];
1936 		}
1937 	}
1938 
1939 	if ((shp = smbios_open(ifile, SMB_VERSION, oflags, &err)) == NULL) {
1940 		(void) fprintf(stderr, "%s: failed to load SMBIOS: %s\n",
1941 		    g_pname, smbios_errmsg(err));
1942 		return (SMBIOS_ERROR);
1943 	}
1944 
1945 	if (opt_i == -1 && opt_t == -1 && opt_e == 0 &&
1946 	    smbios_truncated(shp))
1947 		(void) fprintf(stderr, "%s: SMBIOS table is truncated\n",
1948 		    g_pname);
1949 
1950 	if (ofile != NULL) {
1951 		if ((fd = open(ofile, O_WRONLY|O_CREAT|O_TRUNC, 0666)) == -1) {
1952 			(void) fprintf(stderr, "%s: failed to open %s: %s\n",
1953 			    g_pname, ofile, strerror(errno));
1954 			err = SMBIOS_ERROR;
1955 		} else if (smbios_write(shp, fd) != 0) {
1956 			(void) fprintf(stderr, "%s: failed to write %s: %s\n",
1957 			    g_pname, ofile, smbios_errmsg(smbios_errno(shp)));
1958 			err = SMBIOS_ERROR;
1959 		}
1960 		smbios_close(shp);
1961 		return (err);
1962 	}
1963 
1964 	if (opt_e) {
1965 		print_smbios(shp, stdout);
1966 		smbios_close(shp);
1967 		return (SMBIOS_SUCCESS);
1968 	}
1969 
1970 	if (opt_O && (opt_i != -1 || opt_t != -1))
1971 		opt_O++; /* -i or -t imply displaying obsolete records */
1972 
1973 	if (opt_i != -1)
1974 		err = smbios_lookup_id(shp, opt_i, &s);
1975 	else
1976 		err = smbios_iter(shp, print_struct, stdout);
1977 
1978 	if (err != 0) {
1979 		(void) fprintf(stderr, "%s: failed to access SMBIOS: %s\n",
1980 		    g_pname, smbios_errmsg(smbios_errno(shp)));
1981 		smbios_close(shp);
1982 		return (SMBIOS_ERROR);
1983 	}
1984 
1985 	if (opt_i != -1)
1986 		(void) print_struct(shp, &s, stdout);
1987 
1988 	smbios_close(shp);
1989 	return (SMBIOS_SUCCESS);
1990 }
1991