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