xref: /titanic_53/usr/src/cmd/prtdiag/i386/smbios.c (revision ae115bc77f6fcde83175c75b4206dc2e50747966)
1*ae115bc7Smrj /*
2*ae115bc7Smrj  * CDDL HEADER START
3*ae115bc7Smrj  *
4*ae115bc7Smrj  * The contents of this file are subject to the terms of the
5*ae115bc7Smrj  * Common Development and Distribution License, Version 1.0 only
6*ae115bc7Smrj  * (the "License").  You may not use this file except in compliance
7*ae115bc7Smrj  * with the License.
8*ae115bc7Smrj  *
9*ae115bc7Smrj  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*ae115bc7Smrj  * or http://www.opensolaris.org/os/licensing.
11*ae115bc7Smrj  * See the License for the specific language governing permissions
12*ae115bc7Smrj  * and limitations under the License.
13*ae115bc7Smrj  *
14*ae115bc7Smrj  * When distributing Covered Code, include this CDDL HEADER in each
15*ae115bc7Smrj  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*ae115bc7Smrj  * If applicable, add the following below this CDDL HEADER, with the
17*ae115bc7Smrj  * fields enclosed by brackets "[]" replaced with your own identifying
18*ae115bc7Smrj  * information: Portions Copyright [yyyy] [name of copyright owner]
19*ae115bc7Smrj  *
20*ae115bc7Smrj  * CDDL HEADER END
21*ae115bc7Smrj  */
22*ae115bc7Smrj 
23*ae115bc7Smrj /*
24*ae115bc7Smrj  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
25*ae115bc7Smrj  * Use is subject to license terms.
26*ae115bc7Smrj  */
27*ae115bc7Smrj 
28*ae115bc7Smrj #pragma ident	"%Z%%M%	%I%	%E% SMI"
29*ae115bc7Smrj 
30*ae115bc7Smrj /*
31*ae115bc7Smrj  * x86 System Management BIOS prtdiag
32*ae115bc7Smrj  *
33*ae115bc7Smrj  * Most modern x86 systems support a System Management BIOS, which is a memory
34*ae115bc7Smrj  * buffer filled in by the BIOS at boot time that describes the hardware.  This
35*ae115bc7Smrj  * data format is described by DMTF specification DSP0134 (see http://dmtf.org)
36*ae115bc7Smrj  * This file implements a rudimentary prtdiag(1M) display using the SMBIOS.
37*ae115bc7Smrj  * Access to the data is provided by libsmbios: see <sys/smbios.h> for info.
38*ae115bc7Smrj  *
39*ae115bc7Smrj  * NOTE: It is important to understand that x86 hardware varies extremely
40*ae115bc7Smrj  * widely and that the DMTF SMBIOS specification leaves way too much latitude
41*ae115bc7Smrj  * for implementors, and provides no standardized validation mechanism.  As
42*ae115bc7Smrj  * such, it is not uncommon to find out-of-spec SMBIOSes or fields that
43*ae115bc7Smrj  * contain strange and possibly even incorrect information.  As such, this
44*ae115bc7Smrj  * file should not be extended to report every SMBIOS tidbit or structure in
45*ae115bc7Smrj  * the spec unless we have good reason to believe it tends to be reliable.
46*ae115bc7Smrj  *
47*ae115bc7Smrj  * Similarly, the prtdiag(1M) utility itself should not be used to spit out
48*ae115bc7Smrj  * every possible bit of x86 configuration data from every possible source;
49*ae115bc7Smrj  * otherwise this code will become an unmaintainable and untestable disaster.
50*ae115bc7Smrj  * Extensions to prtdiag should prefer to use more stable kernel mechanisms
51*ae115bc7Smrj  * that actually discover the true hardware when such subsystems are available,
52*ae115bc7Smrj  * and should generally limit themselves to commonly needed h/w data.  As such,
53*ae115bc7Smrj  * extensions to x86 prtdiag should focus on integration with the device tree.
54*ae115bc7Smrj  *
55*ae115bc7Smrj  * The prtdiag(1M) utility is for service personnel and system administrators:
56*ae115bc7Smrj  * it is not your personal ACPI disassembler or CPUID decoder ring.  The
57*ae115bc7Smrj  * complete SMBIOS data is available from smbdump(1), and other specialized
58*ae115bc7Smrj  * tools can be created to display the state of other x86 features, especially
59*ae115bc7Smrj  * when that information is more for kernel developers than box administrators.
60*ae115bc7Smrj  */
61*ae115bc7Smrj 
62*ae115bc7Smrj #include <smbios.h>
63*ae115bc7Smrj #include <alloca.h>
64*ae115bc7Smrj #include <locale.h>
65*ae115bc7Smrj #include <strings.h>
66*ae115bc7Smrj #include <stdlib.h>
67*ae115bc7Smrj #include <stdio.h>
68*ae115bc7Smrj #include <ctype.h>
69*ae115bc7Smrj 
70*ae115bc7Smrj /*ARGSUSED*/
71*ae115bc7Smrj static int
72*ae115bc7Smrj do_procs(smbios_hdl_t *shp, const smbios_struct_t *sp, void *arg)
73*ae115bc7Smrj {
74*ae115bc7Smrj 	smbios_processor_t p;
75*ae115bc7Smrj 	smbios_info_t info;
76*ae115bc7Smrj 	const char *v;
77*ae115bc7Smrj 	char *s;
78*ae115bc7Smrj 	size_t n;
79*ae115bc7Smrj 
80*ae115bc7Smrj 	if (sp->smbstr_type == SMB_TYPE_PROCESSOR &&
81*ae115bc7Smrj 	    smbios_info_processor(shp, sp->smbstr_id, &p) != SMB_ERR &&
82*ae115bc7Smrj 	    smbios_info_common(shp, sp->smbstr_id, &info) != SMB_ERR &&
83*ae115bc7Smrj 	    SMB_PRSTATUS_PRESENT(p.smbp_status)) {
84*ae115bc7Smrj 
85*ae115bc7Smrj 		/*
86*ae115bc7Smrj 		 * Obtaining a decent string for the type of processor is
87*ae115bc7Smrj 		 * messy: the BIOS has hopefully filled in the SMBIOS record.
88*ae115bc7Smrj 		 * If so, strip trailing spaces and \r (seen in some BIOSes).
89*ae115bc7Smrj 		 * If not, fall back to the family name for p.smbp_family.
90*ae115bc7Smrj 		 */
91*ae115bc7Smrj 		if (info.smbi_version != NULL && *info.smbi_version != '\0') {
92*ae115bc7Smrj 			n = strlen(info.smbi_version);
93*ae115bc7Smrj 			v = s = alloca(n + 1);
94*ae115bc7Smrj 			(void) strcpy(s, info.smbi_version);
95*ae115bc7Smrj 
96*ae115bc7Smrj 			if (s[n - 1] == '\r')
97*ae115bc7Smrj 				s[--n] = '\0';
98*ae115bc7Smrj 
99*ae115bc7Smrj 			while (n != 0 && isspace(s[n - 1]))
100*ae115bc7Smrj 				s[--n] = '\0';
101*ae115bc7Smrj 
102*ae115bc7Smrj 		} else if ((v = smbios_processor_family_desc(
103*ae115bc7Smrj 		    p.smbp_family)) == NULL) {
104*ae115bc7Smrj 			v = gettext("Unknown");
105*ae115bc7Smrj 		}
106*ae115bc7Smrj 
107*ae115bc7Smrj 		(void) printf(gettext("%-32s %s\n"), v, info.smbi_location);
108*ae115bc7Smrj 	}
109*ae115bc7Smrj 
110*ae115bc7Smrj 	return (0);
111*ae115bc7Smrj }
112*ae115bc7Smrj 
113*ae115bc7Smrj /*
114*ae115bc7Smrj  * NOTE: It would be very convenient to print the DIMM size in do_memdevs.
115*ae115bc7Smrj  * Unfortunately, SMBIOS can only be relied upon to tell us whether a DIMM is
116*ae115bc7Smrj  * present or not (smbmd_size == 0).  Some BIOSes do fill in an accurate size
117*ae115bc7Smrj  * for DIMMs, whereas others fill in the maximum size, and still others insert
118*ae115bc7Smrj  * a wrong value.  Sizes will need to wait for x86 memory controller interfaces
119*ae115bc7Smrj  * or integration with IPMI, which can actually read the true DIMM SPD data.
120*ae115bc7Smrj  */
121*ae115bc7Smrj /*ARGSUSED*/
122*ae115bc7Smrj static int
123*ae115bc7Smrj do_memdevs(smbios_hdl_t *shp, const smbios_struct_t *sp, void *arg)
124*ae115bc7Smrj {
125*ae115bc7Smrj 	smbios_memdevice_t md;
126*ae115bc7Smrj 
127*ae115bc7Smrj 	if (sp->smbstr_type == SMB_TYPE_MEMDEVICE &&
128*ae115bc7Smrj 	    smbios_info_memdevice(shp, sp->smbstr_id, &md) != SMB_ERR) {
129*ae115bc7Smrj 
130*ae115bc7Smrj 		const char *t = smbios_memdevice_type_desc(md.smbmd_type);
131*ae115bc7Smrj 		char buf[8];
132*ae115bc7Smrj 
133*ae115bc7Smrj 		if (md.smbmd_set != (uint8_t)-1)
134*ae115bc7Smrj 			(void) snprintf(buf, sizeof (buf), "%u", md.smbmd_set);
135*ae115bc7Smrj 		else
136*ae115bc7Smrj 			(void) strcpy(buf, "-");
137*ae115bc7Smrj 
138*ae115bc7Smrj 		(void) printf(gettext("%-7s %-6s %-3s %-19s %s\n"),
139*ae115bc7Smrj 		    t ? t : gettext("Unknown"),
140*ae115bc7Smrj 		    md.smbmd_size ? gettext("in use") : gettext("empty"),
141*ae115bc7Smrj 		    buf, md.smbmd_dloc, md.smbmd_bloc);
142*ae115bc7Smrj 	}
143*ae115bc7Smrj 
144*ae115bc7Smrj 	return (0);
145*ae115bc7Smrj }
146*ae115bc7Smrj 
147*ae115bc7Smrj /*ARGSUSED*/
148*ae115bc7Smrj static int
149*ae115bc7Smrj do_obdevs(smbios_hdl_t *shp, const smbios_struct_t *sp, void *arg)
150*ae115bc7Smrj {
151*ae115bc7Smrj 	smbios_obdev_t *argv;
152*ae115bc7Smrj 	int i, argc;
153*ae115bc7Smrj 
154*ae115bc7Smrj 	if (sp->smbstr_type == SMB_TYPE_OBDEVS &&
155*ae115bc7Smrj 	    (argc = smbios_info_obdevs(shp, sp->smbstr_id, 0, NULL)) > 0) {
156*ae115bc7Smrj 		argv = alloca(sizeof (smbios_obdev_t) * argc);
157*ae115bc7Smrj 		(void) smbios_info_obdevs(shp, sp->smbstr_id, argc, argv);
158*ae115bc7Smrj 		for (i = 0; i < argc; i++)
159*ae115bc7Smrj 			(void) printf(gettext("%s\n"), argv[i].smbd_name);
160*ae115bc7Smrj 	}
161*ae115bc7Smrj 
162*ae115bc7Smrj 	return (0);
163*ae115bc7Smrj }
164*ae115bc7Smrj 
165*ae115bc7Smrj /*ARGSUSED*/
166*ae115bc7Smrj static int
167*ae115bc7Smrj do_slots(smbios_hdl_t *shp, const smbios_struct_t *sp, void *arg)
168*ae115bc7Smrj {
169*ae115bc7Smrj 	smbios_slot_t s;
170*ae115bc7Smrj 
171*ae115bc7Smrj 	if (sp->smbstr_type == SMB_TYPE_SLOT &&
172*ae115bc7Smrj 	    smbios_info_slot(shp, sp->smbstr_id, &s) != SMB_ERR) {
173*ae115bc7Smrj 
174*ae115bc7Smrj 		const char *t = smbios_slot_type_desc(s.smbl_type);
175*ae115bc7Smrj 		const char *u = smbios_slot_usage_desc(s.smbl_usage);
176*ae115bc7Smrj 
177*ae115bc7Smrj 		(void) printf(gettext("%-3u %-9s %-16s %s\n"),
178*ae115bc7Smrj 		    s.smbl_id, u ? u : gettext("Unknown"),
179*ae115bc7Smrj 		    t ? t : gettext("Unknown"), s.smbl_name);
180*ae115bc7Smrj 	}
181*ae115bc7Smrj 
182*ae115bc7Smrj 	return (0);
183*ae115bc7Smrj }
184*ae115bc7Smrj 
185*ae115bc7Smrj /*ARGSUSED*/
186*ae115bc7Smrj int
187*ae115bc7Smrj do_prominfo(int opt_v, char *progname, int opt_l, int opt_p)
188*ae115bc7Smrj {
189*ae115bc7Smrj 	smbios_hdl_t *shp;
190*ae115bc7Smrj 	smbios_system_t sys;
191*ae115bc7Smrj 	smbios_bios_t bios;
192*ae115bc7Smrj 	smbios_ipmi_t ipmi;
193*ae115bc7Smrj 	smbios_info_t info;
194*ae115bc7Smrj 
195*ae115bc7Smrj 	const char *s;
196*ae115bc7Smrj 	id_t id;
197*ae115bc7Smrj 	int err;
198*ae115bc7Smrj 
199*ae115bc7Smrj 	if ((shp = smbios_open(NULL, SMB_VERSION, 0, &err)) == NULL) {
200*ae115bc7Smrj 		(void) fprintf(stderr,
201*ae115bc7Smrj 		    gettext("%s: failed to open SMBIOS: %s\n"),
202*ae115bc7Smrj 		    progname, smbios_errmsg(err));
203*ae115bc7Smrj 		return (1);
204*ae115bc7Smrj 	}
205*ae115bc7Smrj 
206*ae115bc7Smrj 	if ((id = smbios_info_system(shp, &sys)) != SMB_ERR &&
207*ae115bc7Smrj 	    smbios_info_common(shp, id, &info) != SMB_ERR) {
208*ae115bc7Smrj 		(void) printf(gettext("System Configuration: %s %s\n"),
209*ae115bc7Smrj 		    info.smbi_manufacturer, info.smbi_product);
210*ae115bc7Smrj 	} else {
211*ae115bc7Smrj 		(void) fprintf(stderr,
212*ae115bc7Smrj 		    gettext("%s: failed to get system info: %s\n"),
213*ae115bc7Smrj 		    progname, smbios_errmsg(smbios_errno(shp)));
214*ae115bc7Smrj 	}
215*ae115bc7Smrj 
216*ae115bc7Smrj 	if (smbios_info_bios(shp, &bios) != SMB_ERR) {
217*ae115bc7Smrj 		(void) printf(gettext("BIOS Configuration: %s %s %s\n"),
218*ae115bc7Smrj 		    bios.smbb_vendor, bios.smbb_version, bios.smbb_reldate);
219*ae115bc7Smrj 	} else {
220*ae115bc7Smrj 		(void) fprintf(stderr,
221*ae115bc7Smrj 		    gettext("%s: failed to get bios info: %s\n"),
222*ae115bc7Smrj 		    progname, smbios_errmsg(smbios_errno(shp)));
223*ae115bc7Smrj 	}
224*ae115bc7Smrj 
225*ae115bc7Smrj 	if (smbios_info_ipmi(shp, &ipmi) != SMB_ERR) {
226*ae115bc7Smrj 		if ((s = smbios_ipmi_type_desc(ipmi.smbip_type)) == NULL)
227*ae115bc7Smrj 			s = gettext("Unknown");
228*ae115bc7Smrj 
229*ae115bc7Smrj 		(void) printf(gettext("BMC Configuration: IPMI %u.%u (%s)\n"),
230*ae115bc7Smrj 		    ipmi.smbip_vers.smbv_major, ipmi.smbip_vers.smbv_minor, s);
231*ae115bc7Smrj 	}
232*ae115bc7Smrj 
233*ae115bc7Smrj 	(void) printf(gettext(
234*ae115bc7Smrj 	    "\n==== Processor Sockets ====================================\n"));
235*ae115bc7Smrj 
236*ae115bc7Smrj 	(void) printf(gettext("\n%-32s %s"), "Version", "Location Tag");
237*ae115bc7Smrj 
238*ae115bc7Smrj 	(void) printf(gettext(
239*ae115bc7Smrj 	    "\n-------------------------------- --------------------------\n"));
240*ae115bc7Smrj 	(void) smbios_iter(shp, do_procs, NULL);
241*ae115bc7Smrj 
242*ae115bc7Smrj 	(void) printf(gettext(
243*ae115bc7Smrj 	    "\n==== Memory Device Sockets ================================\n"));
244*ae115bc7Smrj 
245*ae115bc7Smrj 	(void) printf(gettext("\n%-7s %-6s %-3s %-19s %s"),
246*ae115bc7Smrj 	    "Type", "Status", "Set", "Device Locator", "Bank Locator");
247*ae115bc7Smrj 
248*ae115bc7Smrj 	(void) printf(gettext(
249*ae115bc7Smrj 	    "\n------- ------ --- ------------------- --------------------\n"));
250*ae115bc7Smrj 	(void) smbios_iter(shp, do_memdevs, NULL);
251*ae115bc7Smrj 
252*ae115bc7Smrj 	(void) printf(gettext(
253*ae115bc7Smrj 	    "\n==== On-Board Devices =====================================\n"));
254*ae115bc7Smrj 	(void) smbios_iter(shp, do_obdevs, NULL);
255*ae115bc7Smrj 
256*ae115bc7Smrj 	(void) printf(gettext(
257*ae115bc7Smrj 	    "\n==== Upgradeable Slots ====================================\n"));
258*ae115bc7Smrj 
259*ae115bc7Smrj 	(void) printf(gettext("\n%-3s %-9s %-16s %s"),
260*ae115bc7Smrj 	    "ID", "Status", "Type", "Description");
261*ae115bc7Smrj 
262*ae115bc7Smrj 	(void) printf(gettext(
263*ae115bc7Smrj 	    "\n--- --------- ---------------- ----------------------------\n"));
264*ae115bc7Smrj 	(void) smbios_iter(shp, do_slots, NULL);
265*ae115bc7Smrj 
266*ae115bc7Smrj 	smbios_close(shp);
267*ae115bc7Smrj 	return (0);
268*ae115bc7Smrj }
269