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