mca.c revision 100411
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 100411 2002-07-20 19:31:11Z peter $"); 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 <stdio.h> 48#include <stdlib.h> 49#include <string.h> 50#include <unistd.h> 51 52#define BCD(x) ((x >> 4) * 10 + (x & 15)) 53 54static char hw_mca_count[] = "hw.mca.count"; 55static char hw_mca_first[] = "hw.mca.first"; 56static char hw_mca_last[] = "hw.mca.last"; 57static char hw_mca_recid[] = "hw.mca.%d"; 58 59static char default_dumpfile[] = "/var/log/mca.log"; 60 61int fl_dump; 62char *file; 63 64static const char * 65severity(int error) 66{ 67 68 switch (error) { 69 case MCA_RH_ERROR_RECOVERABLE: 70 return ("recoverable"); 71 case MCA_RH_ERROR_FATAL: 72 return ("fatal"); 73 case MCA_RH_ERROR_CORRECTED: 74 return ("corrected"); 75 } 76 77 return ("unknown"); 78} 79 80static const char * 81uuid(struct uuid *id) 82{ 83 static char buffer[64]; 84 85 sprintf(buffer, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", 86 id->time_low, id->time_mid, id->time_hi_and_version, 87 id->clock_seq_hi_and_reserved, id->clock_seq_low, id->node[0], 88 id->node[1], id->node[2], id->node[3], id->node[4], id->node[5]); 89 return (buffer); 90} 91 92static size_t 93show_header(struct mca_record_header *rh) 94{ 95 96 printf(" <header>\n"); 97 printf(" seqnr=%lld\n", (long long)rh->rh_seqnr); 98 printf(" revision=%d.%d\n", BCD(rh->rh_major), BCD(rh->rh_minor)); 99 printf(" severity=%s\n", severity(rh->rh_error)); 100 printf(" length=%lld\n", (long long)rh->rh_length); 101 printf(" date=%d%02d/%02d/%02d\n", 102 BCD(rh->rh_time[MCA_RH_TIME_CENT]), 103 BCD(rh->rh_time[MCA_RH_TIME_YEAR]), 104 BCD(rh->rh_time[MCA_RH_TIME_MON]), 105 BCD(rh->rh_time[MCA_RH_TIME_MDAY])); 106 printf(" time=%02d:%02d:%02d\n", 107 BCD(rh->rh_time[MCA_RH_TIME_HOUR]), 108 BCD(rh->rh_time[MCA_RH_TIME_MIN]), 109 BCD(rh->rh_time[MCA_RH_TIME_SEC])); 110 if (rh->rh_flags & MCA_RH_FLAGS_PLATFORM_ID) 111 printf(" platform=%s\n", uuid(&rh->rh_platform)); 112 printf(" </header>\n"); 113 return (rh->rh_length); 114} 115 116static void 117show_cpu_mod(const char *what, int idx, struct mca_cpu_mod *cpu_mod) 118{ 119 printf(" <%s-%d>\n", what, idx); 120 if (cpu_mod->cpu_mod_flags & MCA_CPU_MOD_FLAGS_INFO) 121 printf(" info=0x%016llx\n", 122 (long long)cpu_mod->cpu_mod_info); 123 if (cpu_mod->cpu_mod_flags & MCA_CPU_MOD_FLAGS_REQID) 124 printf(" requester=0x%016llx\n", 125 (long long)cpu_mod->cpu_mod_reqid); 126 if (cpu_mod->cpu_mod_flags & MCA_CPU_MOD_FLAGS_RSPID) 127 printf(" responder=0x%016llx\n", 128 (long long)cpu_mod->cpu_mod_rspid); 129 if (cpu_mod->cpu_mod_flags & MCA_CPU_MOD_FLAGS_TGTID) 130 printf(" target=0x%016llx\n", 131 (long long)cpu_mod->cpu_mod_tgtid); 132 if (cpu_mod->cpu_mod_flags & MCA_CPU_MOD_FLAGS_IP) 133 printf(" ip=0x%016llx\n", 134 (long long)cpu_mod->cpu_mod_ip); 135 printf(" </%s-%d>\n", what, idx); 136} 137 138static void 139show_cpu(struct mca_cpu_record *cpu) 140{ 141 struct mca_cpu_mod *mod; 142 struct mca_cpu_cpuid *cpuid; 143 struct mca_cpu_psi *psi; 144 int i, n; 145 146 printf(" <cpu>\n"); 147 148 if (cpu->cpu_flags & MCA_CPU_FLAGS_ERRMAP) 149 printf(" errmap=0x%016llx\n", (long long)cpu->cpu_errmap); 150 if (cpu->cpu_flags & MCA_CPU_FLAGS_STATE) 151 printf(" state=0x%016llx\n", (long long)cpu->cpu_state); 152 if (cpu->cpu_flags & MCA_CPU_FLAGS_CR_LID) 153 printf(" cr_lid=0x%016llx\n", (long long)cpu->cpu_cr_lid); 154 155 mod = (struct mca_cpu_mod*)(cpu + 1); 156 n = MCA_CPU_FLAGS_CACHE(cpu->cpu_flags); 157 for (i = 0; i < n; i++) 158 show_cpu_mod("cache", i, mod++); 159 n = MCA_CPU_FLAGS_TLB(cpu->cpu_flags); 160 for (i = 0; i < n; i++) 161 show_cpu_mod("tlb", i, mod++); 162 n = MCA_CPU_FLAGS_BUS(cpu->cpu_flags); 163 for (i = 0; i < n; i++) 164 show_cpu_mod("bus", i, mod++); 165 n = MCA_CPU_FLAGS_REG(cpu->cpu_flags); 166 for (i = 0; i < n; i++) 167 show_cpu_mod("reg", i, mod++); 168 n = MCA_CPU_FLAGS_MS(cpu->cpu_flags); 169 for (i = 0; i < n; i++) 170 show_cpu_mod("ms", i, mod++); 171 172 cpuid = (struct mca_cpu_cpuid*)mod; 173 for (i = 0; i < 6; i++) 174 printf(" cpuid%d=0x%016llx\n", i, 175 (long long)cpuid->cpuid[i]); 176 177 psi = (struct mca_cpu_psi*)(cpuid + 1); 178 /* TODO: Dump PSI */ 179 180 printf(" </cpu>\n"); 181} 182 183static void 184show_memory(struct mca_mem_record *mem) 185{ 186 printf(" <memory>\n"); 187 188 if (mem->mem_flags & MCA_MEM_FLAGS_STATUS) 189 printf(" status=0x%016llx\n", (long long)mem->mem_status); 190 if (mem->mem_flags & MCA_MEM_FLAGS_ADDR) 191 printf(" address=0x%016llx\n", (long long)mem->mem_addr); 192 if (mem->mem_flags & MCA_MEM_FLAGS_ADDRMASK) 193 printf(" mask=0x%016llx\n", (long long)mem->mem_addrmask); 194 if (mem->mem_flags & MCA_MEM_FLAGS_NODE) 195 printf(" node=0x%04x\n", mem->mem_node); 196 if (mem->mem_flags & MCA_MEM_FLAGS_CARD) 197 printf(" card=0x%04x\n", mem->mem_card); 198 if (mem->mem_flags & MCA_MEM_FLAGS_MODULE) 199 printf(" module=0x%04x\n", mem->mem_module); 200 if (mem->mem_flags & MCA_MEM_FLAGS_BANK) 201 printf(" bank=0x%04x\n", mem->mem_bank); 202 if (mem->mem_flags & MCA_MEM_FLAGS_DEVICE) 203 printf(" device=0x%04x\n", mem->mem_device); 204 if (mem->mem_flags & MCA_MEM_FLAGS_ROW) 205 printf(" row=0x%04x\n", mem->mem_row); 206 if (mem->mem_flags & MCA_MEM_FLAGS_COLUMN) 207 printf(" column=0x%04x\n", mem->mem_column); 208 if (mem->mem_flags & MCA_MEM_FLAGS_BITPOS) 209 printf(" bit=0x%04x\n", mem->mem_bitpos); 210 if (mem->mem_flags & MCA_MEM_FLAGS_REQID) 211 printf(" requester=0x%016llx\n", 212 (long long)mem->mem_reqid); 213 if (mem->mem_flags & MCA_MEM_FLAGS_RSPID) 214 printf(" responder=0x%016llx\n", 215 (long long)mem->mem_rspid); 216 if (mem->mem_flags & MCA_MEM_FLAGS_TGTID) 217 printf(" target=0x%016llx\n", 218 (long long)mem->mem_tgtid); 219 if (mem->mem_flags & MCA_MEM_FLAGS_BUSDATA) 220 printf(" status=0x%016llx\n", 221 (long long)mem->mem_busdata); 222 if (mem->mem_flags & MCA_MEM_FLAGS_OEM_ID) 223 printf(" oem=%s\n", uuid(&mem->mem_oem_id)); 224 /* TODO: Dump OEM data */ 225 226 printf(" </memory>\n"); 227} 228 229static void 230show_sel(void) 231{ 232 printf(" # SEL\n"); 233} 234 235static void 236show_pci_bus(struct mca_pcibus_record *pcibus) 237{ 238 printf(" <pci-bus>\n"); 239 240 if (pcibus->pcibus_flags & MCA_PCIBUS_FLAGS_STATUS) 241 printf(" status=0x%016llx\n", 242 (long long)pcibus->pcibus_status); 243 if (pcibus->pcibus_flags & MCA_PCIBUS_FLAGS_ERROR) 244 printf(" error=0x%04x\n", pcibus->pcibus_error); 245 if (pcibus->pcibus_flags & MCA_PCIBUS_FLAGS_BUS) 246 printf(" bus=0x%04x\n", pcibus->pcibus_bus); 247 if (pcibus->pcibus_flags & MCA_PCIBUS_FLAGS_ADDR) 248 printf(" address=0x%016llx\n", 249 (long long)pcibus->pcibus_addr); 250 if (pcibus->pcibus_flags & MCA_PCIBUS_FLAGS_DATA) 251 printf(" data=0x%016llx\n", 252 (long long)pcibus->pcibus_data); 253 if (pcibus->pcibus_flags & MCA_PCIBUS_FLAGS_CMD) 254 printf(" cmd=0x%016llx\n", 255 (long long)pcibus->pcibus_cmd); 256 if (pcibus->pcibus_flags & MCA_PCIBUS_FLAGS_REQID) 257 printf(" requester=0x%016llx\n", 258 (long long)pcibus->pcibus_reqid); 259 if (pcibus->pcibus_flags & MCA_PCIBUS_FLAGS_RSPID) 260 printf(" responder=0x%016llx\n", 261 (long long)pcibus->pcibus_rspid); 262 if (pcibus->pcibus_flags & MCA_PCIBUS_FLAGS_TGTID) 263 printf(" target=0x%016llx\n", 264 (long long)pcibus->pcibus_tgtid); 265 if (pcibus->pcibus_flags & MCA_PCIBUS_FLAGS_OEM_ID) 266 printf(" oem=%s\n", uuid(&pcibus->pcibus_oem_id)); 267 /* TODO: Dump OEM data */ 268 269 printf(" </pci-bus>\n"); 270} 271 272static void 273show_smbios(void) 274{ 275 printf(" # SMBIOS\n"); 276} 277 278static void 279show_pci_dev(struct mca_pcidev_record *pcidev) 280{ 281 printf(" <pci-dev>\n"); 282 283 if (pcidev->pcidev_flags & MCA_PCIDEV_FLAGS_STATUS) 284 printf(" status=0x%016llx\n", 285 (long long)pcidev->pcidev_status); 286 if (pcidev->pcidev_flags & MCA_PCIDEV_FLAGS_INFO) { 287 printf(" vendor=0x%04x\n", 288 pcidev->pcidev_info.info_vendor); 289 printf(" device=0x%04x\n", 290 pcidev->pcidev_info.info_device); 291 printf(" class=0x%06x\n", 292 MCA_PCIDEV_INFO_CLASS(pcidev->pcidev_info.info_ccfn)); 293 printf(" function=0x%02x\n", 294 MCA_PCIDEV_INFO_FUNCTION(pcidev->pcidev_info.info_ccfn)); 295 printf(" slot=0x%02x\n", 296 pcidev->pcidev_info.info_slot); 297 printf(" bus=0x%04x\n", 298 pcidev->pcidev_info.info_bus); 299 printf(" segment=0x%04x\n", 300 pcidev->pcidev_info.info_segment); 301 } 302 /* TODO: dump registers */ 303 /* TODO: Dump OEM data */ 304 305 printf(" </pci-dev>\n"); 306} 307 308static void 309show_generic(void) 310{ 311 printf(" # GENERIC\n"); 312} 313 314static size_t 315show_section(struct mca_section_header *sh) 316{ 317 static struct uuid uuid_cpu = MCA_UUID_CPU; 318 static struct uuid uuid_memory = MCA_UUID_MEMORY; 319 static struct uuid uuid_sel = MCA_UUID_SEL; 320 static struct uuid uuid_pci_bus = MCA_UUID_PCI_BUS; 321 static struct uuid uuid_smbios = MCA_UUID_SMBIOS; 322 static struct uuid uuid_pci_dev = MCA_UUID_PCI_DEV; 323 static struct uuid uuid_generic = MCA_UUID_GENERIC; 324 325 printf(" <section>\n"); 326 printf(" uuid=%s\n", uuid(&sh->sh_uuid)); 327 printf(" revision=%d.%d\n", BCD(sh->sh_major), BCD(sh->sh_minor)); 328 329 if (!memcmp(&sh->sh_uuid, &uuid_cpu, sizeof(uuid_cpu))) 330 show_cpu((void*)(sh + 1)); 331 else if (!memcmp(&sh->sh_uuid, &uuid_memory, sizeof(uuid_memory))) 332 show_memory((void*)(sh + 1)); 333 else if (!memcmp(&sh->sh_uuid, &uuid_sel, sizeof(uuid_sel))) 334 show_sel(); 335 else if (!memcmp(&sh->sh_uuid, &uuid_pci_bus, sizeof(uuid_pci_bus))) 336 show_pci_bus((void*)(sh + 1)); 337 else if (!memcmp(&sh->sh_uuid, &uuid_smbios, sizeof(uuid_smbios))) 338 show_smbios(); 339 else if (!memcmp(&sh->sh_uuid, &uuid_pci_dev, sizeof(uuid_pci_dev))) 340 show_pci_dev((void*)(sh + 1)); 341 else if (!memcmp(&sh->sh_uuid, &uuid_generic, sizeof(uuid_generic))) 342 show_generic(); 343 344 printf(" </section>\n"); 345 return (sh->sh_length); 346} 347 348static void 349show(char *data) 350{ 351 size_t reclen, seclen; 352 353 printf("<record>\n"); 354 reclen = show_header((void*)data) - sizeof(struct mca_record_header); 355 data += sizeof(struct mca_record_header); 356 while (reclen > sizeof(struct mca_section_header)) { 357 seclen = show_section((void*)data); 358 reclen -= seclen; 359 data += seclen; 360 } 361 printf("</record>\n"); 362} 363 364static void 365showall(char *buf, size_t buflen) 366{ 367 struct mca_record_header *rh; 368 size_t reclen; 369 370 do { 371 if (buflen < sizeof(struct mca_record_header)) 372 return; 373 374 rh = (void*)buf; 375 reclen = rh->rh_length; 376 if (buflen < reclen) 377 return; 378 379 show(buf); 380 381 buf += reclen; 382 buflen -= reclen; 383 } 384 while (1); 385} 386 387static void 388dump(char *data) 389{ 390 struct mca_record_header *rh; 391 const char *fn; 392 int fd; 393 394 rh = (void*)data; 395 fn = (file) ? file : default_dumpfile; 396 fd = open(fn, O_WRONLY|O_CREAT|O_APPEND, 0660); 397 if (fd == -1) 398 err(2, "open(%s)", fn); 399 if (write(fd, (void*)rh, rh->rh_length) == -1) 400 err(2, "write(%s)", fn); 401 close(fd); 402} 403 404static void 405usage(void) 406{ 407 408 fprintf(stderr, "usage: mca [-df]\n"); 409 exit (1); 410} 411 412int 413main(int argc, char **argv) 414{ 415 char mib[32]; 416 char *buf; 417 size_t len; 418 int ch, error, fd; 419 int count, first, last; 420 421 while ((ch = getopt(argc, argv, "df:")) != -1) { 422 switch(ch) { 423 case 'd': /* dump */ 424 fl_dump = 1; 425 break; 426 case 'f': 427 if (file) 428 free(file); /* XXX complain! */ 429 file = strdup(optarg); 430 break; 431 default: 432 usage(); 433 } 434 } 435 436 argc -= optind; 437 argv += optind; 438 439 if (file == NULL || fl_dump) { 440 len = sizeof(count); 441 error = sysctlbyname(hw_mca_count, &count, &len, NULL, 0); 442 if (error) 443 err(1, hw_mca_count); 444 445 if (count == 0) 446 errx(0, "no error records found"); 447 448 len = sizeof(first); 449 error = sysctlbyname(hw_mca_first, &first, &len, NULL, 0); 450 if (error) 451 err(1, hw_mca_first); 452 453 len = sizeof(last); 454 error = sysctlbyname(hw_mca_last, &last, &len, NULL, 0); 455 if (error) 456 err(1, hw_mca_last); 457 458 while (count && first <= last) { 459 sprintf(mib, hw_mca_recid, first); 460 len = 0; 461 error = sysctlbyname(mib, NULL, &len, NULL, 0); 462 if (error == ENOENT) { 463 first++; 464 continue; 465 } 466 if (error) 467 err(1, "%s(1)", mib); 468 469 buf = malloc(len); 470 if (buf == NULL) 471 err(1, "buffer"); 472 473 error = sysctlbyname(mib, buf, &len, NULL, 0); 474 if (error) 475 err(1, "%s(2)", mib); 476 477 if (fl_dump) 478 dump(buf); 479 else 480 show(buf); 481 482 free(buf); 483 first++; 484 count--; 485 } 486 } else { 487 fd = open(file, O_RDONLY); 488 if (fd == -1) 489 err(1, "open(%s)", file); 490 491 len = lseek(fd, 0LL, SEEK_END); 492 buf = mmap(NULL, len, PROT_READ, 0U, fd, 0LL); 493 if (buf == MAP_FAILED) 494 err(1, "mmap(%s)", file); 495 496 showall(buf, len); 497 498 munmap(buf, len); 499 close(fd); 500 } 501 502 return (0); 503} 504