xref: /titanic_51/usr/src/cmd/prtdiag/i386/smbios.c (revision caf590b518921f14033a11d17fafa827bb2caa4b)
1ae115bc7Smrj /*
2ae115bc7Smrj  * CDDL HEADER START
3ae115bc7Smrj  *
4ae115bc7Smrj  * The contents of this file are subject to the terms of the
542a58d9dSsethg  * Common Development and Distribution License (the "License").
642a58d9dSsethg  * 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 /*
2342a58d9dSsethg  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24ae115bc7Smrj  * Use is subject to license terms.
25ae115bc7Smrj  */
26*caf590b5SRobert Mustacchi /*
27*caf590b5SRobert Mustacchi  * Copyright 2015 Joyent, Inc.
28*caf590b5SRobert Mustacchi  */
29ae115bc7Smrj 
30ae115bc7Smrj /*
31ae115bc7Smrj  * x86 System Management BIOS prtdiag
32ae115bc7Smrj  *
33ae115bc7Smrj  * Most modern x86 systems support a System Management BIOS, which is a memory
34ae115bc7Smrj  * buffer filled in by the BIOS at boot time that describes the hardware.  This
35ae115bc7Smrj  * data format is described by DMTF specification DSP0134 (see http://dmtf.org)
36ae115bc7Smrj  * This file implements a rudimentary prtdiag(1M) display using the SMBIOS.
37ae115bc7Smrj  * Access to the data is provided by libsmbios: see <sys/smbios.h> for info.
38ae115bc7Smrj  *
39ae115bc7Smrj  * NOTE: It is important to understand that x86 hardware varies extremely
40ae115bc7Smrj  * widely and that the DMTF SMBIOS specification leaves way too much latitude
41ae115bc7Smrj  * for implementors, and provides no standardized validation mechanism.  As
42ae115bc7Smrj  * such, it is not uncommon to find out-of-spec SMBIOSes or fields that
43ae115bc7Smrj  * contain strange and possibly even incorrect information.  As such, this
44ae115bc7Smrj  * file should not be extended to report every SMBIOS tidbit or structure in
45ae115bc7Smrj  * the spec unless we have good reason to believe it tends to be reliable.
46ae115bc7Smrj  *
47ae115bc7Smrj  * Similarly, the prtdiag(1M) utility itself should not be used to spit out
48ae115bc7Smrj  * every possible bit of x86 configuration data from every possible source;
49ae115bc7Smrj  * otherwise this code will become an unmaintainable and untestable disaster.
50ae115bc7Smrj  * Extensions to prtdiag should prefer to use more stable kernel mechanisms
51ae115bc7Smrj  * that actually discover the true hardware when such subsystems are available,
52ae115bc7Smrj  * and should generally limit themselves to commonly needed h/w data.  As such,
53ae115bc7Smrj  * extensions to x86 prtdiag should focus on integration with the device tree.
54ae115bc7Smrj  *
55ae115bc7Smrj  * The prtdiag(1M) utility is for service personnel and system administrators:
56ae115bc7Smrj  * it is not your personal ACPI disassembler or CPUID decoder ring.  The
57ae115bc7Smrj  * complete SMBIOS data is available from smbdump(1), and other specialized
58ae115bc7Smrj  * tools can be created to display the state of other x86 features, especially
59ae115bc7Smrj  * when that information is more for kernel developers than box administrators.
60ae115bc7Smrj  */
61ae115bc7Smrj 
62ae115bc7Smrj #include <smbios.h>
63ae115bc7Smrj #include <alloca.h>
64ae115bc7Smrj #include <locale.h>
65ae115bc7Smrj #include <strings.h>
66ae115bc7Smrj #include <stdlib.h>
67ae115bc7Smrj #include <stdio.h>
68ae115bc7Smrj #include <ctype.h>
69*caf590b5SRobert Mustacchi #include <pcidb.h>
70*caf590b5SRobert Mustacchi #include <fm/libtopo.h>
71*caf590b5SRobert Mustacchi #include <fm/topo_hc.h>
72*caf590b5SRobert Mustacchi #include <sys/fm/protocol.h>
73*caf590b5SRobert Mustacchi 
74*caf590b5SRobert Mustacchi static pcidb_hdl_t *prt_php;
75ae115bc7Smrj 
76ae115bc7Smrj /*ARGSUSED*/
77ae115bc7Smrj static int
78ae115bc7Smrj do_procs(smbios_hdl_t *shp, const smbios_struct_t *sp, void *arg)
79ae115bc7Smrj {
80ae115bc7Smrj 	smbios_processor_t p;
81ae115bc7Smrj 	smbios_info_t info;
82ae115bc7Smrj 	const char *v;
83ae115bc7Smrj 	char *s;
84ae115bc7Smrj 	size_t n;
85ae115bc7Smrj 
86ae115bc7Smrj 	if (sp->smbstr_type == SMB_TYPE_PROCESSOR &&
87ae115bc7Smrj 	    smbios_info_processor(shp, sp->smbstr_id, &p) != SMB_ERR &&
88ae115bc7Smrj 	    smbios_info_common(shp, sp->smbstr_id, &info) != SMB_ERR &&
89ae115bc7Smrj 	    SMB_PRSTATUS_PRESENT(p.smbp_status)) {
90ae115bc7Smrj 
91ae115bc7Smrj 		/*
92ae115bc7Smrj 		 * Obtaining a decent string for the type of processor is
93ae115bc7Smrj 		 * messy: the BIOS has hopefully filled in the SMBIOS record.
94ae115bc7Smrj 		 * If so, strip trailing spaces and \r (seen in some BIOSes).
95ae115bc7Smrj 		 * If not, fall back to the family name for p.smbp_family.
96ae115bc7Smrj 		 */
97ae115bc7Smrj 		if (info.smbi_version != NULL && *info.smbi_version != '\0') {
98ae115bc7Smrj 			n = strlen(info.smbi_version);
99ae115bc7Smrj 			v = s = alloca(n + 1);
100ae115bc7Smrj 			(void) strcpy(s, info.smbi_version);
101ae115bc7Smrj 
102ae115bc7Smrj 			if (s[n - 1] == '\r')
103ae115bc7Smrj 				s[--n] = '\0';
104ae115bc7Smrj 
105ae115bc7Smrj 			while (n != 0 && isspace(s[n - 1]))
106ae115bc7Smrj 				s[--n] = '\0';
107ae115bc7Smrj 
108ae115bc7Smrj 		} else if ((v = smbios_processor_family_desc(
109ae115bc7Smrj 		    p.smbp_family)) == NULL) {
110ae115bc7Smrj 			v = gettext("Unknown");
111ae115bc7Smrj 		}
112ae115bc7Smrj 
113ae115bc7Smrj 		(void) printf(gettext("%-32s %s\n"), v, info.smbi_location);
114ae115bc7Smrj 	}
115ae115bc7Smrj 
116ae115bc7Smrj 	return (0);
117ae115bc7Smrj }
118ae115bc7Smrj 
119ae115bc7Smrj /*
120ae115bc7Smrj  * NOTE: It would be very convenient to print the DIMM size in do_memdevs.
121ae115bc7Smrj  * Unfortunately, SMBIOS can only be relied upon to tell us whether a DIMM is
122ae115bc7Smrj  * present or not (smbmd_size == 0).  Some BIOSes do fill in an accurate size
123ae115bc7Smrj  * for DIMMs, whereas others fill in the maximum size, and still others insert
124ae115bc7Smrj  * a wrong value.  Sizes will need to wait for x86 memory controller interfaces
125ae115bc7Smrj  * or integration with IPMI, which can actually read the true DIMM SPD data.
126ae115bc7Smrj  */
127ae115bc7Smrj /*ARGSUSED*/
128ae115bc7Smrj static int
129ae115bc7Smrj do_memdevs(smbios_hdl_t *shp, const smbios_struct_t *sp, void *arg)
130ae115bc7Smrj {
131ae115bc7Smrj 	smbios_memdevice_t md;
132ae115bc7Smrj 
133ae115bc7Smrj 	if (sp->smbstr_type == SMB_TYPE_MEMDEVICE &&
134ae115bc7Smrj 	    smbios_info_memdevice(shp, sp->smbstr_id, &md) != SMB_ERR) {
135ae115bc7Smrj 
136ae115bc7Smrj 		const char *t = smbios_memdevice_type_desc(md.smbmd_type);
137ae115bc7Smrj 		char buf[8];
138ae115bc7Smrj 
139ae115bc7Smrj 		if (md.smbmd_set != (uint8_t)-1)
140ae115bc7Smrj 			(void) snprintf(buf, sizeof (buf), "%u", md.smbmd_set);
141ae115bc7Smrj 		else
142ae115bc7Smrj 			(void) strcpy(buf, "-");
143ae115bc7Smrj 
14442a58d9dSsethg 		(void) printf(gettext("%-11s %-6s %-3s %-19s %s\n"),
145ae115bc7Smrj 		    t ? t : gettext("Unknown"),
146ae115bc7Smrj 		    md.smbmd_size ? gettext("in use") : gettext("empty"),
147ae115bc7Smrj 		    buf, md.smbmd_dloc, md.smbmd_bloc);
148ae115bc7Smrj 	}
149ae115bc7Smrj 
150ae115bc7Smrj 	return (0);
151ae115bc7Smrj }
152ae115bc7Smrj 
153ae115bc7Smrj /*ARGSUSED*/
154ae115bc7Smrj static int
155ae115bc7Smrj do_obdevs(smbios_hdl_t *shp, const smbios_struct_t *sp, void *arg)
156ae115bc7Smrj {
157ae115bc7Smrj 	smbios_obdev_t *argv;
158ae115bc7Smrj 	int i, argc;
159ae115bc7Smrj 
160ae115bc7Smrj 	if (sp->smbstr_type == SMB_TYPE_OBDEVS &&
161ae115bc7Smrj 	    (argc = smbios_info_obdevs(shp, sp->smbstr_id, 0, NULL)) > 0) {
162ae115bc7Smrj 		argv = alloca(sizeof (smbios_obdev_t) * argc);
163ae115bc7Smrj 		(void) smbios_info_obdevs(shp, sp->smbstr_id, argc, argv);
164ae115bc7Smrj 		for (i = 0; i < argc; i++)
165ae115bc7Smrj 			(void) printf(gettext("%s\n"), argv[i].smbd_name);
166ae115bc7Smrj 	}
167ae115bc7Smrj 
168ae115bc7Smrj 	return (0);
169ae115bc7Smrj }
170ae115bc7Smrj 
171ae115bc7Smrj /*ARGSUSED*/
172ae115bc7Smrj static int
173*caf590b5SRobert Mustacchi do_slot_mapping_cb(topo_hdl_t *thp, tnode_t *node, void *arg)
174*caf590b5SRobert Mustacchi {
175*caf590b5SRobert Mustacchi 	int err, ret;
176*caf590b5SRobert Mustacchi 	nvlist_t *rsrc = NULL;
177*caf590b5SRobert Mustacchi 	const char *match = arg;
178*caf590b5SRobert Mustacchi 	char *s, *fmri = NULL;
179*caf590b5SRobert Mustacchi 	char *didstr = NULL, *driver = NULL, *vidstr = NULL;
180*caf590b5SRobert Mustacchi 	boolean_t printed = B_FALSE;
181*caf590b5SRobert Mustacchi 
182*caf590b5SRobert Mustacchi 	ret = TOPO_WALK_NEXT;
183*caf590b5SRobert Mustacchi 	if (topo_node_resource(node, &rsrc, &err) < 0)
184*caf590b5SRobert Mustacchi 		goto next;
185*caf590b5SRobert Mustacchi 	if (topo_fmri_nvl2str(thp, rsrc, &fmri, &err) < 0)
186*caf590b5SRobert Mustacchi 		goto next;
187*caf590b5SRobert Mustacchi 
188*caf590b5SRobert Mustacchi 	if ((s = strstr(fmri, match)) == NULL)
189*caf590b5SRobert Mustacchi 		goto next;
190*caf590b5SRobert Mustacchi 	if (s[strlen(match)] != '\0')
191*caf590b5SRobert Mustacchi 		goto next;
192*caf590b5SRobert Mustacchi 
193*caf590b5SRobert Mustacchi 	/* At this point we think we've found a match */
194*caf590b5SRobert Mustacchi 	ret = TOPO_WALK_TERMINATE;
195*caf590b5SRobert Mustacchi 	if (topo_prop_get_string(node, TOPO_PGROUP_IO, TOPO_IO_DRIVER, &driver,
196*caf590b5SRobert Mustacchi 	    &err) != 0)
197*caf590b5SRobert Mustacchi 		driver = NULL;
198*caf590b5SRobert Mustacchi 
199*caf590b5SRobert Mustacchi 	if (topo_prop_get_string(node, TOPO_PGROUP_PCI, TOPO_PCI_VENDID,
200*caf590b5SRobert Mustacchi 	    &vidstr, &err) != 0)
201*caf590b5SRobert Mustacchi 		goto next;
202*caf590b5SRobert Mustacchi 
203*caf590b5SRobert Mustacchi 	if (topo_prop_get_string(node, TOPO_PGROUP_PCI, TOPO_PCI_DEVID,
204*caf590b5SRobert Mustacchi 	    &didstr, &err) != 0)
205*caf590b5SRobert Mustacchi 		goto next;
206*caf590b5SRobert Mustacchi 
207*caf590b5SRobert Mustacchi 	if (prt_php != NULL) {
208*caf590b5SRobert Mustacchi 		long vid, did;
209*caf590b5SRobert Mustacchi 
210*caf590b5SRobert Mustacchi 		vid = strtol(vidstr, NULL, 16);
211*caf590b5SRobert Mustacchi 		did = strtol(didstr, NULL, 16);
212*caf590b5SRobert Mustacchi 		if (vid >= 0 && vid <= UINT16_MAX &&
213*caf590b5SRobert Mustacchi 		    did >= 0 && did <= UINT16_MAX) {
214*caf590b5SRobert Mustacchi 			pcidb_device_t *pdev;
215*caf590b5SRobert Mustacchi 
216*caf590b5SRobert Mustacchi 			pdev = pcidb_lookup_device(prt_php, vid, did);
217*caf590b5SRobert Mustacchi 			if (pdev != NULL) {
218*caf590b5SRobert Mustacchi 				pcidb_vendor_t *pvend;
219*caf590b5SRobert Mustacchi 				pvend = pcidb_device_vendor(pdev);
220*caf590b5SRobert Mustacchi 				(void) printf(gettext(", %s %s (%s)"),
221*caf590b5SRobert Mustacchi 				    pcidb_vendor_name(pvend),
222*caf590b5SRobert Mustacchi 				    pcidb_device_name(pdev),
223*caf590b5SRobert Mustacchi 				    driver != NULL ? driver : "<unknown>");
224*caf590b5SRobert Mustacchi 				printed = B_TRUE;
225*caf590b5SRobert Mustacchi 			}
226*caf590b5SRobert Mustacchi 		}
227*caf590b5SRobert Mustacchi 	}
228*caf590b5SRobert Mustacchi 
229*caf590b5SRobert Mustacchi 	if (printed == B_FALSE) {
230*caf590b5SRobert Mustacchi 		(void) printf(gettext(", pci%s,%s (%s)"), vidstr, didstr,
231*caf590b5SRobert Mustacchi 		    driver != NULL ? driver : "<unknown>");
232*caf590b5SRobert Mustacchi 	}
233*caf590b5SRobert Mustacchi next:
234*caf590b5SRobert Mustacchi 	topo_hdl_strfree(thp, didstr);
235*caf590b5SRobert Mustacchi 	topo_hdl_strfree(thp, driver);
236*caf590b5SRobert Mustacchi 	topo_hdl_strfree(thp, vidstr);
237*caf590b5SRobert Mustacchi 	topo_hdl_strfree(thp, fmri);
238*caf590b5SRobert Mustacchi 	nvlist_free(rsrc);
239*caf590b5SRobert Mustacchi 	return (ret);
240*caf590b5SRobert Mustacchi }
241*caf590b5SRobert Mustacchi 
242*caf590b5SRobert Mustacchi static void
243*caf590b5SRobert Mustacchi do_slot_mapping(smbios_slot_t *s, topo_hdl_t *thp)
244*caf590b5SRobert Mustacchi {
245*caf590b5SRobert Mustacchi 	int err;
246*caf590b5SRobert Mustacchi 	uint_t dev, func;
247*caf590b5SRobert Mustacchi 	topo_walk_t *twp;
248*caf590b5SRobert Mustacchi 	char pciex[256];
249*caf590b5SRobert Mustacchi 
250*caf590b5SRobert Mustacchi 	/*
251*caf590b5SRobert Mustacchi 	 * Bits 7:3 are the device number and bits 2:0 are the function.
252*caf590b5SRobert Mustacchi 	 */
253*caf590b5SRobert Mustacchi 	dev = s->smbl_df >> 3;
254*caf590b5SRobert Mustacchi 	func = s->smbl_df & 0x7;
255*caf590b5SRobert Mustacchi 
256*caf590b5SRobert Mustacchi 	(void) snprintf(pciex, sizeof (pciex), "%s=%u/%s=%u/%s=%d",
257*caf590b5SRobert Mustacchi 	    PCIEX_BUS, s->smbl_bus, PCIEX_DEVICE, dev, PCIEX_FUNCTION, func);
258*caf590b5SRobert Mustacchi 
259*caf590b5SRobert Mustacchi 	twp = topo_walk_init(thp, FM_FMRI_SCHEME_HC, do_slot_mapping_cb, pciex,
260*caf590b5SRobert Mustacchi 	    &err);
261*caf590b5SRobert Mustacchi 	if (twp == NULL)
262*caf590b5SRobert Mustacchi 		return;
263*caf590b5SRobert Mustacchi 
264*caf590b5SRobert Mustacchi 	(void) topo_walk_step(twp, TOPO_WALK_CHILD);
265*caf590b5SRobert Mustacchi 	topo_walk_fini(twp);
266*caf590b5SRobert Mustacchi }
267*caf590b5SRobert Mustacchi 
268*caf590b5SRobert Mustacchi /*ARGSUSED*/
269*caf590b5SRobert Mustacchi static int
270ae115bc7Smrj do_slots(smbios_hdl_t *shp, const smbios_struct_t *sp, void *arg)
271ae115bc7Smrj {
272ae115bc7Smrj 	smbios_slot_t s;
273ae115bc7Smrj 
274ae115bc7Smrj 	if (sp->smbstr_type == SMB_TYPE_SLOT &&
275ae115bc7Smrj 	    smbios_info_slot(shp, sp->smbstr_id, &s) != SMB_ERR) {
276ae115bc7Smrj 
277ae115bc7Smrj 		const char *t = smbios_slot_type_desc(s.smbl_type);
278ae115bc7Smrj 		const char *u = smbios_slot_usage_desc(s.smbl_usage);
279ae115bc7Smrj 
280*caf590b5SRobert Mustacchi 		(void) printf(gettext("%-3u %-9s %-16s %s"),
281ae115bc7Smrj 		    s.smbl_id, u ? u : gettext("Unknown"),
282ae115bc7Smrj 		    t ? t : gettext("Unknown"), s.smbl_name);
283*caf590b5SRobert Mustacchi 
284*caf590b5SRobert Mustacchi 		/*
285*caf590b5SRobert Mustacchi 		 * If the slot isn't of a type where this makes sense, then
286*caf590b5SRobert Mustacchi 		 * SMBIOS will populate any of these members with the value
287*caf590b5SRobert Mustacchi 		 * 0xff. Therefore if we find any of them set there, we just
288*caf590b5SRobert Mustacchi 		 * ignore it for now.
289*caf590b5SRobert Mustacchi 		 */
290*caf590b5SRobert Mustacchi 		if (s.smbl_sg != 0xff && s.smbl_bus != 0xff &&
291*caf590b5SRobert Mustacchi 		    s.smbl_df != 0xff && arg != NULL)
292*caf590b5SRobert Mustacchi 			do_slot_mapping(&s, arg);
293*caf590b5SRobert Mustacchi 
294*caf590b5SRobert Mustacchi 		(void) printf(gettext("\n"));
295ae115bc7Smrj 	}
296ae115bc7Smrj 
297ae115bc7Smrj 	return (0);
298ae115bc7Smrj }
299ae115bc7Smrj 
300ae115bc7Smrj /*ARGSUSED*/
301ae115bc7Smrj int
302ae115bc7Smrj do_prominfo(int opt_v, char *progname, int opt_l, int opt_p)
303ae115bc7Smrj {
304ae115bc7Smrj 	smbios_hdl_t *shp;
305ae115bc7Smrj 	smbios_system_t sys;
306ae115bc7Smrj 	smbios_bios_t bios;
307ae115bc7Smrj 	smbios_ipmi_t ipmi;
308ae115bc7Smrj 	smbios_info_t info;
309*caf590b5SRobert Mustacchi 	topo_hdl_t *thp;
310*caf590b5SRobert Mustacchi 	char *uuid;
311ae115bc7Smrj 
312ae115bc7Smrj 	const char *s;
313ae115bc7Smrj 	id_t id;
314ae115bc7Smrj 	int err;
315ae115bc7Smrj 
316ae115bc7Smrj 	if ((shp = smbios_open(NULL, SMB_VERSION, 0, &err)) == NULL) {
317ae115bc7Smrj 		(void) fprintf(stderr,
318ae115bc7Smrj 		    gettext("%s: failed to open SMBIOS: %s\n"),
319ae115bc7Smrj 		    progname, smbios_errmsg(err));
320ae115bc7Smrj 		return (1);
321ae115bc7Smrj 	}
322ae115bc7Smrj 
323ae115bc7Smrj 	if ((id = smbios_info_system(shp, &sys)) != SMB_ERR &&
324ae115bc7Smrj 	    smbios_info_common(shp, id, &info) != SMB_ERR) {
325ae115bc7Smrj 		(void) printf(gettext("System Configuration: %s %s\n"),
326ae115bc7Smrj 		    info.smbi_manufacturer, info.smbi_product);
327ae115bc7Smrj 	} else {
328ae115bc7Smrj 		(void) fprintf(stderr,
329ae115bc7Smrj 		    gettext("%s: failed to get system info: %s\n"),
330ae115bc7Smrj 		    progname, smbios_errmsg(smbios_errno(shp)));
331ae115bc7Smrj 	}
332ae115bc7Smrj 
333ae115bc7Smrj 	if (smbios_info_bios(shp, &bios) != SMB_ERR) {
334ae115bc7Smrj 		(void) printf(gettext("BIOS Configuration: %s %s %s\n"),
335ae115bc7Smrj 		    bios.smbb_vendor, bios.smbb_version, bios.smbb_reldate);
336ae115bc7Smrj 	} else {
337ae115bc7Smrj 		(void) fprintf(stderr,
338ae115bc7Smrj 		    gettext("%s: failed to get bios info: %s\n"),
339ae115bc7Smrj 		    progname, smbios_errmsg(smbios_errno(shp)));
340ae115bc7Smrj 	}
341ae115bc7Smrj 
342ae115bc7Smrj 	if (smbios_info_ipmi(shp, &ipmi) != SMB_ERR) {
343ae115bc7Smrj 		if ((s = smbios_ipmi_type_desc(ipmi.smbip_type)) == NULL)
344ae115bc7Smrj 			s = gettext("Unknown");
345ae115bc7Smrj 
346ae115bc7Smrj 		(void) printf(gettext("BMC Configuration: IPMI %u.%u (%s)\n"),
347ae115bc7Smrj 		    ipmi.smbip_vers.smbv_major, ipmi.smbip_vers.smbv_minor, s);
348ae115bc7Smrj 	}
349ae115bc7Smrj 
350*caf590b5SRobert Mustacchi 	/*
351*caf590b5SRobert Mustacchi 	 * Silently swallow all libtopo and libpcidb related errors.
352*caf590b5SRobert Mustacchi 	 */
353*caf590b5SRobert Mustacchi 	uuid = NULL;
354*caf590b5SRobert Mustacchi 	if ((thp = topo_open(TOPO_VERSION, NULL, &err)) != NULL) {
355*caf590b5SRobert Mustacchi 		if ((uuid = topo_snap_hold(thp, NULL, &err)) == NULL) {
356*caf590b5SRobert Mustacchi 			topo_close(thp);
357*caf590b5SRobert Mustacchi 			thp = NULL;
358*caf590b5SRobert Mustacchi 		}
359*caf590b5SRobert Mustacchi 	}
360*caf590b5SRobert Mustacchi 
361*caf590b5SRobert Mustacchi 	prt_php = pcidb_open(PCIDB_VERSION);
362*caf590b5SRobert Mustacchi 
363ae115bc7Smrj 	(void) printf(gettext(
364ae115bc7Smrj 	    "\n==== Processor Sockets ====================================\n"));
365ae115bc7Smrj 
366ae115bc7Smrj 	(void) printf(gettext("\n%-32s %s"), "Version", "Location Tag");
367ae115bc7Smrj 
368ae115bc7Smrj 	(void) printf(gettext(
369ae115bc7Smrj 	    "\n-------------------------------- --------------------------\n"));
370ae115bc7Smrj 	(void) smbios_iter(shp, do_procs, NULL);
371ae115bc7Smrj 
372ae115bc7Smrj 	(void) printf(gettext(
373ae115bc7Smrj 	    "\n==== Memory Device Sockets ================================\n"));
374ae115bc7Smrj 
37542a58d9dSsethg 	(void) printf(gettext("\n%-11s %-6s %-3s %-19s %s"),
376ae115bc7Smrj 	    "Type", "Status", "Set", "Device Locator", "Bank Locator");
377ae115bc7Smrj 
378ae115bc7Smrj 	(void) printf(gettext(
379ae115bc7Smrj 	    "\n----------- ------ --- ------------------- ----------------\n"));
380ae115bc7Smrj 	(void) smbios_iter(shp, do_memdevs, NULL);
381ae115bc7Smrj 
382ae115bc7Smrj 	(void) printf(gettext(
383ae115bc7Smrj 	    "\n==== On-Board Devices =====================================\n"));
384ae115bc7Smrj 	(void) smbios_iter(shp, do_obdevs, NULL);
385ae115bc7Smrj 
386ae115bc7Smrj 	(void) printf(gettext(
387ae115bc7Smrj 	    "\n==== Upgradeable Slots ====================================\n"));
388ae115bc7Smrj 
389ae115bc7Smrj 	(void) printf(gettext("\n%-3s %-9s %-16s %s"),
390ae115bc7Smrj 	    "ID", "Status", "Type", "Description");
391ae115bc7Smrj 
392ae115bc7Smrj 	(void) printf(gettext(
393ae115bc7Smrj 	    "\n--- --------- ---------------- ----------------------------\n"));
394*caf590b5SRobert Mustacchi 	(void) smbios_iter(shp, do_slots, thp);
395ae115bc7Smrj 
396ae115bc7Smrj 	smbios_close(shp);
397*caf590b5SRobert Mustacchi 
398*caf590b5SRobert Mustacchi 	topo_hdl_strfree(thp, uuid);
399*caf590b5SRobert Mustacchi 	if (thp != NULL) {
400*caf590b5SRobert Mustacchi 		topo_snap_release(thp);
401*caf590b5SRobert Mustacchi 		topo_close(thp);
402*caf590b5SRobert Mustacchi 	}
403*caf590b5SRobert Mustacchi 	pcidb_close(prt_php);
404*caf590b5SRobert Mustacchi 
405ae115bc7Smrj 	return (0);
406ae115bc7Smrj }
407