mca.c revision 105309
1/* 2 * Copyright (c) 2002 Marcel Moolenaar 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: head/sbin/mca/mca.c 105309 2002-10-17 05:41:10Z marcel $"); 29 30#include <sys/types.h> 31#include <sys/mman.h> 32#include <sys/sysctl.h> 33#include <sys/uuid.h> 34 35/* 36 * Hack to make this compile on non-ia64 machines. 37 */ 38#ifdef __ia64__ 39#include <machine/mca.h> 40#else 41#include "../../sys/ia64/include/mca.h" 42#endif 43 44#include <err.h> 45#include <errno.h> 46#include <fcntl.h> 47#include <stdarg.h> 48#include <stdio.h> 49#include <stdlib.h> 50#include <string.h> 51#include <unistd.h> 52 53#define BCD(x) ((x >> 4) * 10 + (x & 15)) 54 55static char hw_mca_count[] = "hw.mca.count"; 56static char hw_mca_first[] = "hw.mca.first"; 57static char hw_mca_last[] = "hw.mca.last"; 58static char hw_mca_recid[] = "hw.mca.%d"; 59 60static char default_dumpfile[] = "/var/log/mca.log"; 61 62int fl_dump; 63char *file; 64 65static const char * 66severity(int error) 67{ 68 69 switch (error) { 70 case MCA_RH_ERROR_RECOVERABLE: 71 return ("recoverable"); 72 case MCA_RH_ERROR_FATAL: 73 return ("fatal"); 74 case MCA_RH_ERROR_CORRECTED: 75 return ("corrected"); 76 } 77 78 return ("unknown"); 79} 80 81static const char * 82uuid(struct uuid *id) 83{ 84 static char buffer[64]; 85 86 sprintf(buffer, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", 87 id->time_low, id->time_mid, id->time_hi_and_version, 88 id->clock_seq_hi_and_reserved, id->clock_seq_low, id->node[0], 89 id->node[1], id->node[2], id->node[3], id->node[4], id->node[5]); 90 return (buffer); 91} 92 93static int 94show_value(int indent, const char *var, const char *fmt, ...) 95{ 96 va_list ap; 97 int len; 98 99 len = indent; 100 while (indent--) 101 putchar(' '); 102 len += printf("<%s>", var); 103 va_start(ap, fmt); 104 len += vprintf(fmt, ap); 105 len += printf("</%s>\n", var); 106 return (len); 107} 108 109static size_t 110show_header(struct mca_record_header *rh) 111{ 112 113 printf(" <header>\n"); 114 show_value(4, "seqnr", "%lld", (long long)rh->rh_seqnr); 115 show_value(4, "revision", "%d.%d", BCD(rh->rh_major), 116 BCD(rh->rh_minor)); 117 show_value(4, "severity", "%s", severity(rh->rh_error)); 118 show_value(4, "length", "%lld", (long long)rh->rh_length); 119 show_value(4, "date", "%d%02d/%02d/%02d", 120 BCD(rh->rh_time[MCA_RH_TIME_CENT]), 121 BCD(rh->rh_time[MCA_RH_TIME_YEAR]), 122 BCD(rh->rh_time[MCA_RH_TIME_MON]), 123 BCD(rh->rh_time[MCA_RH_TIME_MDAY])); 124 show_value(4, "time", "%02d:%02d:%02d", 125 BCD(rh->rh_time[MCA_RH_TIME_HOUR]), 126 BCD(rh->rh_time[MCA_RH_TIME_MIN]), 127 BCD(rh->rh_time[MCA_RH_TIME_SEC])); 128 if (rh->rh_flags & MCA_RH_FLAGS_PLATFORM_ID) 129 show_value(4, "platform", "%s", uuid(&rh->rh_platform)); 130 printf(" </header>\n"); 131 return (rh->rh_length); 132} 133 134static void 135show_cpu_mod(const char *what, int idx, struct mca_cpu_mod *cpu_mod) 136{ 137 printf(" <%s-%d>\n", what, idx); 138 if (cpu_mod->cpu_mod_flags & MCA_CPU_MOD_FLAGS_INFO) 139 show_value(8, "info", "0x%016llx", 140 (long long)cpu_mod->cpu_mod_info); 141 if (cpu_mod->cpu_mod_flags & MCA_CPU_MOD_FLAGS_REQID) 142 show_value(8, "requester", "0x%016llx", 143 (long long)cpu_mod->cpu_mod_reqid); 144 if (cpu_mod->cpu_mod_flags & MCA_CPU_MOD_FLAGS_RSPID) 145 show_value(8, "responder", "0x%016llx", 146 (long long)cpu_mod->cpu_mod_rspid); 147 if (cpu_mod->cpu_mod_flags & MCA_CPU_MOD_FLAGS_TGTID) 148 show_value(8, "target", "0x%016llx", 149 (long long)cpu_mod->cpu_mod_tgtid); 150 if (cpu_mod->cpu_mod_flags & MCA_CPU_MOD_FLAGS_IP) 151 show_value(8, "ip", "0x%016llx", 152 (long long)cpu_mod->cpu_mod_ip); 153 printf(" </%s-%d>\n", what, idx); 154} 155 156static void 157show_cpu(struct mca_cpu_record *cpu) 158{ 159 char var[16]; 160 struct mca_cpu_mod *mod; 161 struct mca_cpu_cpuid *cpuid; 162 struct mca_cpu_psi *psi; 163 int i, n; 164 165 printf(" <cpu>\n"); 166 167 if (cpu->cpu_flags & MCA_CPU_FLAGS_ERRMAP) 168 show_value(6, "errmap", "0x%016llx", 169 (long long)cpu->cpu_errmap); 170 if (cpu->cpu_flags & MCA_CPU_FLAGS_STATE) 171 show_value(6, "state", "0x%016llx", 172 (long long)cpu->cpu_state); 173 if (cpu->cpu_flags & MCA_CPU_FLAGS_CR_LID) 174 show_value(6, "cr_lid", "0x%016llx", 175 (long long)cpu->cpu_cr_lid); 176 177 mod = (struct mca_cpu_mod*)(cpu + 1); 178 n = MCA_CPU_FLAGS_CACHE(cpu->cpu_flags); 179 for (i = 0; i < n; i++) 180 show_cpu_mod("cache", i, mod++); 181 n = MCA_CPU_FLAGS_TLB(cpu->cpu_flags); 182 for (i = 0; i < n; i++) 183 show_cpu_mod("tlb", i, mod++); 184 n = MCA_CPU_FLAGS_BUS(cpu->cpu_flags); 185 for (i = 0; i < n; i++) 186 show_cpu_mod("bus", i, mod++); 187 n = MCA_CPU_FLAGS_REG(cpu->cpu_flags); 188 for (i = 0; i < n; i++) 189 show_cpu_mod("reg", i, mod++); 190 n = MCA_CPU_FLAGS_MS(cpu->cpu_flags); 191 for (i = 0; i < n; i++) 192 show_cpu_mod("ms", i, mod++); 193 194 cpuid = (struct mca_cpu_cpuid*)mod; 195 for (i = 0; i < 6; i++) { 196 sprintf(var, "cpuid-%d", i); 197 show_value(6, var, "0x%016llx", (long long)cpuid->cpuid[i]); 198 } 199 200 psi = (struct mca_cpu_psi*)(cpuid + 1); 201 /* TODO: Dump PSI */ 202 203 printf(" </cpu>\n"); 204} 205 206static void 207show_memory(struct mca_mem_record *mem) 208{ 209 printf(" <memory>\n"); 210 211 if (mem->mem_flags & MCA_MEM_FLAGS_STATUS) 212 show_value(6, "status", "0x%016llx", 213 (long long)mem->mem_status); 214 if (mem->mem_flags & MCA_MEM_FLAGS_ADDR) 215 show_value(6, "address", "0x%016llx", 216 (long long)mem->mem_addr); 217 if (mem->mem_flags & MCA_MEM_FLAGS_ADDRMASK) 218 show_value(6, "mask", "0x%016llx", 219 (long long)mem->mem_addrmask); 220 if (mem->mem_flags & MCA_MEM_FLAGS_NODE) 221 show_value(6, "node", "0x%04x", mem->mem_node); 222 if (mem->mem_flags & MCA_MEM_FLAGS_CARD) 223 show_value(6, "card", "0x%04x", mem->mem_card); 224 if (mem->mem_flags & MCA_MEM_FLAGS_MODULE) 225 show_value(6, "module", "0x%04x", mem->mem_module); 226 if (mem->mem_flags & MCA_MEM_FLAGS_BANK) 227 show_value(6, "bank", "0x%04x", mem->mem_bank); 228 if (mem->mem_flags & MCA_MEM_FLAGS_DEVICE) 229 show_value(6, "device", "0x%04x", mem->mem_device); 230 if (mem->mem_flags & MCA_MEM_FLAGS_ROW) 231 show_value(6, "row", "0x%04x", mem->mem_row); 232 if (mem->mem_flags & MCA_MEM_FLAGS_COLUMN) 233 show_value(6, "column", "0x%04x", mem->mem_column); 234 if (mem->mem_flags & MCA_MEM_FLAGS_BITPOS) 235 show_value(6, "bit", "0x%04x", mem->mem_bitpos); 236 if (mem->mem_flags & MCA_MEM_FLAGS_REQID) 237 show_value(6, "requester", "0x%016llx", 238 (long long)mem->mem_reqid); 239 if (mem->mem_flags & MCA_MEM_FLAGS_RSPID) 240 show_value(6, "responder", "0x%016llx", 241 (long long)mem->mem_rspid); 242 if (mem->mem_flags & MCA_MEM_FLAGS_TGTID) 243 show_value(6, "target", "0x%016llx", 244 (long long)mem->mem_tgtid); 245 if (mem->mem_flags & MCA_MEM_FLAGS_BUSDATA) 246 show_value(6, "status", "0x%016llx", 247 (long long)mem->mem_busdata); 248 if (mem->mem_flags & MCA_MEM_FLAGS_OEM_ID) 249 show_value(6, "oem", "%s", uuid(&mem->mem_oem_id)); 250 /* TODO: Dump OEM data */ 251 252 printf(" </memory>\n"); 253} 254 255static void 256show_sel(void) 257{ 258 printf(" # SEL\n"); 259} 260 261static void 262show_pci_bus(struct mca_pcibus_record *pcibus) 263{ 264 printf(" <pci-bus>\n"); 265 266 if (pcibus->pcibus_flags & MCA_PCIBUS_FLAGS_STATUS) 267 show_value(6, "status", "0x%016llx", 268 (long long)pcibus->pcibus_status); 269 if (pcibus->pcibus_flags & MCA_PCIBUS_FLAGS_ERROR) 270 show_value(6, "error", "0x%04x", pcibus->pcibus_error); 271 if (pcibus->pcibus_flags & MCA_PCIBUS_FLAGS_BUS) 272 show_value(6, "bus", "0x%04x", pcibus->pcibus_bus); 273 if (pcibus->pcibus_flags & MCA_PCIBUS_FLAGS_ADDR) 274 show_value(6, "address", "0x%016llx", 275 (long long)pcibus->pcibus_addr); 276 if (pcibus->pcibus_flags & MCA_PCIBUS_FLAGS_DATA) 277 show_value(6, "data", "0x%016llx", 278 (long long)pcibus->pcibus_data); 279 if (pcibus->pcibus_flags & MCA_PCIBUS_FLAGS_CMD) 280 show_value(6, "cmd", "0x%016llx", 281 (long long)pcibus->pcibus_cmd); 282 if (pcibus->pcibus_flags & MCA_PCIBUS_FLAGS_REQID) 283 show_value(6, "requester", "0x%016llx", 284 (long long)pcibus->pcibus_reqid); 285 if (pcibus->pcibus_flags & MCA_PCIBUS_FLAGS_RSPID) 286 show_value(6, "responder", "0x%016llx", 287 (long long)pcibus->pcibus_rspid); 288 if (pcibus->pcibus_flags & MCA_PCIBUS_FLAGS_TGTID) 289 show_value(6, "target", "0x%016llx", 290 (long long)pcibus->pcibus_tgtid); 291 if (pcibus->pcibus_flags & MCA_PCIBUS_FLAGS_OEM_ID) 292 show_value(6, "oem", "%s", uuid(&pcibus->pcibus_oem_id)); 293 /* TODO: Dump OEM data */ 294 295 printf(" </pci-bus>\n"); 296} 297 298static void 299show_smbios(void) 300{ 301 printf(" # SMBIOS\n"); 302} 303 304static void 305show_pci_dev(struct mca_pcidev_record *pcidev) 306{ 307 printf(" <pci-dev>\n"); 308 309 if (pcidev->pcidev_flags & MCA_PCIDEV_FLAGS_STATUS) 310 show_value(6, "status", "0x%016llx", 311 (long long)pcidev->pcidev_status); 312 if (pcidev->pcidev_flags & MCA_PCIDEV_FLAGS_INFO) { 313 show_value(6, "vendor", "0x%04x", 314 pcidev->pcidev_info.info_vendor); 315 show_value(6, "device", "0x%04x", 316 pcidev->pcidev_info.info_device); 317 show_value(6, "class", "0x%06x", 318 MCA_PCIDEV_INFO_CLASS(pcidev->pcidev_info.info_ccfn)); 319 show_value(6, "function", "0x%02x", 320 MCA_PCIDEV_INFO_FUNCTION(pcidev->pcidev_info.info_ccfn)); 321 show_value(6, "slot", "0x%02x", pcidev->pcidev_info.info_slot); 322 show_value(6, "bus", "0x%04x", pcidev->pcidev_info.info_bus); 323 show_value(6, "segment", "0x%04x", 324 pcidev->pcidev_info.info_segment); 325 } 326 /* TODO: dump registers */ 327 /* TODO: Dump OEM data */ 328 329 printf(" </pci-dev>\n"); 330} 331 332static void 333show_generic(void) 334{ 335 printf(" # GENERIC\n"); 336} 337 338static size_t 339show_section(struct mca_section_header *sh) 340{ 341 static struct uuid uuid_cpu = MCA_UUID_CPU; 342 static struct uuid uuid_memory = MCA_UUID_MEMORY; 343 static struct uuid uuid_sel = MCA_UUID_SEL; 344 static struct uuid uuid_pci_bus = MCA_UUID_PCI_BUS; 345 static struct uuid uuid_smbios = MCA_UUID_SMBIOS; 346 static struct uuid uuid_pci_dev = MCA_UUID_PCI_DEV; 347 static struct uuid uuid_generic = MCA_UUID_GENERIC; 348 349 printf(" <section>\n"); 350 show_value(4, "uuid", "%s", uuid(&sh->sh_uuid)); 351 show_value(4, "revision", "%d.%d", BCD(sh->sh_major), 352 BCD(sh->sh_minor)); 353 354 if (!memcmp(&sh->sh_uuid, &uuid_cpu, sizeof(uuid_cpu))) 355 show_cpu((void*)(sh + 1)); 356 else if (!memcmp(&sh->sh_uuid, &uuid_memory, sizeof(uuid_memory))) 357 show_memory((void*)(sh + 1)); 358 else if (!memcmp(&sh->sh_uuid, &uuid_sel, sizeof(uuid_sel))) 359 show_sel(); 360 else if (!memcmp(&sh->sh_uuid, &uuid_pci_bus, sizeof(uuid_pci_bus))) 361 show_pci_bus((void*)(sh + 1)); 362 else if (!memcmp(&sh->sh_uuid, &uuid_smbios, sizeof(uuid_smbios))) 363 show_smbios(); 364 else if (!memcmp(&sh->sh_uuid, &uuid_pci_dev, sizeof(uuid_pci_dev))) 365 show_pci_dev((void*)(sh + 1)); 366 else if (!memcmp(&sh->sh_uuid, &uuid_generic, sizeof(uuid_generic))) 367 show_generic(); 368 369 printf(" </section>\n"); 370 return (sh->sh_length); 371} 372 373static void 374show(char *data) 375{ 376 size_t reclen, seclen; 377 378 printf("<record>\n"); 379 reclen = show_header((void*)data) - sizeof(struct mca_record_header); 380 data += sizeof(struct mca_record_header); 381 while (reclen > sizeof(struct mca_section_header)) { 382 seclen = show_section((void*)data); 383 reclen -= seclen; 384 data += seclen; 385 } 386 printf("</record>\n"); 387} 388 389static void 390showall(char *buf, size_t buflen) 391{ 392 struct mca_record_header *rh; 393 size_t reclen; 394 395 do { 396 if (buflen < sizeof(struct mca_record_header)) 397 return; 398 399 rh = (void*)buf; 400 reclen = rh->rh_length; 401 if (buflen < reclen) 402 return; 403 404 show(buf); 405 406 buf += reclen; 407 buflen -= reclen; 408 } 409 while (1); 410} 411 412static void 413dump(char *data) 414{ 415 struct mca_record_header *rh; 416 const char *fn; 417 int fd; 418 419 rh = (void*)data; 420 fn = (file) ? file : default_dumpfile; 421 fd = open(fn, O_WRONLY|O_CREAT|O_APPEND, 0660); 422 if (fd == -1) 423 err(2, "open(%s)", fn); 424 if (write(fd, (void*)rh, rh->rh_length) == -1) 425 err(2, "write(%s)", fn); 426 close(fd); 427} 428 429static void 430usage(void) 431{ 432 433 fprintf(stderr, "usage: mca [-df]\n"); 434 exit (1); 435} 436 437int 438main(int argc, char **argv) 439{ 440 char mib[32]; 441 char *buf; 442 size_t len; 443 int ch, error, fd; 444 int count, first, last; 445 446 while ((ch = getopt(argc, argv, "df:")) != -1) { 447 switch(ch) { 448 case 'd': /* dump */ 449 fl_dump = 1; 450 break; 451 case 'f': 452 if (file) 453 free(file); /* XXX complain! */ 454 file = strdup(optarg); 455 break; 456 default: 457 usage(); 458 } 459 } 460 461 argc -= optind; 462 argv += optind; 463 464 if (file == NULL || fl_dump) { 465 len = sizeof(count); 466 error = sysctlbyname(hw_mca_count, &count, &len, NULL, 0); 467 if (error) 468 err(1, hw_mca_count); 469 470 if (count == 0) 471 errx(0, "no error records found"); 472 473 len = sizeof(first); 474 error = sysctlbyname(hw_mca_first, &first, &len, NULL, 0); 475 if (error) 476 err(1, hw_mca_first); 477 478 len = sizeof(last); 479 error = sysctlbyname(hw_mca_last, &last, &len, NULL, 0); 480 if (error) 481 err(1, hw_mca_last); 482 483 while (count && first <= last) { 484 sprintf(mib, hw_mca_recid, first); 485 len = 0; 486 error = sysctlbyname(mib, NULL, &len, NULL, 0); 487 if (error == ENOENT) { 488 first++; 489 continue; 490 } 491 if (error) 492 err(1, "%s(1)", mib); 493 494 buf = malloc(len); 495 if (buf == NULL) 496 err(1, "buffer"); 497 498 error = sysctlbyname(mib, buf, &len, NULL, 0); 499 if (error) 500 err(1, "%s(2)", mib); 501 502 if (fl_dump) 503 dump(buf); 504 else 505 show(buf); 506 507 free(buf); 508 first++; 509 count--; 510 } 511 } else { 512 fd = open(file, O_RDONLY); 513 if (fd == -1) 514 err(1, "open(%s)", file); 515 516 len = lseek(fd, 0LL, SEEK_END); 517 buf = mmap(NULL, len, PROT_READ, 0U, fd, 0LL); 518 if (buf == MAP_FAILED) 519 err(1, "mmap(%s)", file); 520 521 showall(buf, len); 522 523 munmap(buf, len); 524 close(fd); 525 } 526 527 return (0); 528} 529