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