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