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 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 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 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 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 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