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