]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sbin/mca/mca.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.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 const char hw_mca_count[] = "hw.mca.count";
59 static const char hw_mca_first[] = "hw.mca.first";
60 static const char hw_mca_last[] = "hw.mca.last";
61 static const char hw_mca_recid[] = "hw.mca.%d.%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 #ifdef notyet
166         struct mca_cpu_psi *psi;
167 #endif
168         int i, n;
169
170         printf("    <cpu>\n");
171
172         if (cpu->cpu_flags & MCA_CPU_FLAGS_ERRMAP)
173                 show_value(6, "errmap", "0x%016llx",
174                     (long long)cpu->cpu_errmap);
175         if (cpu->cpu_flags & MCA_CPU_FLAGS_STATE)
176                 show_value(6, "state", "0x%016llx",
177                     (long long)cpu->cpu_state);
178         if (cpu->cpu_flags & MCA_CPU_FLAGS_CR_LID)
179                 show_value(6, "cr_lid", "0x%016llx",
180                     (long long)cpu->cpu_cr_lid);
181
182         mod = (struct mca_cpu_mod*)(cpu + 1);
183         n = MCA_CPU_FLAGS_CACHE(cpu->cpu_flags);
184         for (i = 0; i < n; i++)
185                 show_cpu_mod("cache", i, mod++);
186         n = MCA_CPU_FLAGS_TLB(cpu->cpu_flags);
187         for (i = 0; i < n; i++)
188                 show_cpu_mod("tlb", i, mod++);
189         n = MCA_CPU_FLAGS_BUS(cpu->cpu_flags);
190         for (i = 0; i < n; i++)
191                 show_cpu_mod("bus", i, mod++);
192         n = MCA_CPU_FLAGS_REG(cpu->cpu_flags);
193         for (i = 0; i < n; i++)
194                 show_cpu_mod("reg", i, mod++);
195         n = MCA_CPU_FLAGS_MS(cpu->cpu_flags);
196         for (i = 0; i < n; i++)
197                 show_cpu_mod("ms", i, mod++);
198
199         cpuid = (struct mca_cpu_cpuid*)mod;
200         for (i = 0; i < 6; i++) {
201                 sprintf(var, "cpuid-%d", i);
202                 show_value(6, var, "0x%016llx", (long long)cpuid->cpuid[i]);
203         }
204
205 #ifdef notyet
206          psi = (struct mca_cpu_psi*)(cpuid + 1);
207 #endif
208          /* TODO: Dump PSI */
209
210         printf("    </cpu>\n");
211 }
212
213 static void
214 show_memory(struct mca_mem_record *mem)
215 {
216         printf("    <memory>\n");
217
218         if (mem->mem_flags & MCA_MEM_FLAGS_STATUS)
219                 show_value(6, "status", "0x%016llx",
220                     (long long)mem->mem_status);
221         if (mem->mem_flags & MCA_MEM_FLAGS_ADDR)
222                 show_value(6, "address", "0x%016llx",
223                     (long long)mem->mem_addr);
224         if (mem->mem_flags & MCA_MEM_FLAGS_ADDRMASK)
225                 show_value(6, "mask", "0x%016llx",
226                     (long long)mem->mem_addrmask);
227         if (mem->mem_flags & MCA_MEM_FLAGS_NODE)
228                 show_value(6, "node", "0x%04x", mem->mem_node);
229         if (mem->mem_flags & MCA_MEM_FLAGS_CARD)
230                 show_value(6, "card", "0x%04x", mem->mem_card);
231         if (mem->mem_flags & MCA_MEM_FLAGS_MODULE)
232                 show_value(6, "module", "0x%04x", mem->mem_module);
233         if (mem->mem_flags & MCA_MEM_FLAGS_BANK)
234                 show_value(6, "bank", "0x%04x", mem->mem_bank);
235         if (mem->mem_flags & MCA_MEM_FLAGS_DEVICE)
236                 show_value(6, "device", "0x%04x", mem->mem_device);
237         if (mem->mem_flags & MCA_MEM_FLAGS_ROW)
238                 show_value(6, "row", "0x%04x", mem->mem_row);
239         if (mem->mem_flags & MCA_MEM_FLAGS_COLUMN)
240                 show_value(6, "column", "0x%04x", mem->mem_column);
241         if (mem->mem_flags & MCA_MEM_FLAGS_BITPOS)
242                 show_value(6, "bit", "0x%04x", mem->mem_bitpos);
243         if (mem->mem_flags & MCA_MEM_FLAGS_REQID)
244                 show_value(6, "requester", "0x%016llx",
245                     (long long)mem->mem_reqid);
246         if (mem->mem_flags & MCA_MEM_FLAGS_RSPID)
247                 show_value(6, "responder", "0x%016llx",
248                     (long long)mem->mem_rspid);
249         if (mem->mem_flags & MCA_MEM_FLAGS_TGTID)
250                 show_value(6, "target", "0x%016llx",
251                     (long long)mem->mem_tgtid);
252         if (mem->mem_flags & MCA_MEM_FLAGS_BUSDATA)
253                 show_value(6, "status", "0x%016llx",
254                     (long long)mem->mem_busdata);
255         if (mem->mem_flags & MCA_MEM_FLAGS_OEM_ID)
256                 show_value(6, "oem", "%s", uuid(&mem->mem_oem_id));
257         /* TODO: Dump OEM data */
258
259         printf("    </memory>\n");
260 }
261
262 static void
263 show_sel(void)
264 {
265         printf("    # SEL\n");
266 }
267
268 static void
269 show_pci_bus(struct mca_pcibus_record *pcibus)
270 {
271         printf("    <pci-bus>\n");
272
273         if (pcibus->pcibus_flags & MCA_PCIBUS_FLAGS_STATUS)
274                 show_value(6, "status", "0x%016llx",
275                     (long long)pcibus->pcibus_status);
276         if (pcibus->pcibus_flags & MCA_PCIBUS_FLAGS_ERROR)
277                 show_value(6, "error", "0x%04x", pcibus->pcibus_error);
278         if (pcibus->pcibus_flags & MCA_PCIBUS_FLAGS_BUS)
279                 show_value(6, "bus", "0x%04x", pcibus->pcibus_bus);
280         if (pcibus->pcibus_flags & MCA_PCIBUS_FLAGS_ADDR)
281                 show_value(6, "address", "0x%016llx",
282                     (long long)pcibus->pcibus_addr);
283         if (pcibus->pcibus_flags & MCA_PCIBUS_FLAGS_DATA)
284                 show_value(6, "data", "0x%016llx",
285                     (long long)pcibus->pcibus_data);
286         if (pcibus->pcibus_flags & MCA_PCIBUS_FLAGS_CMD)
287                 show_value(6, "cmd", "0x%016llx",
288                     (long long)pcibus->pcibus_cmd);
289         if (pcibus->pcibus_flags & MCA_PCIBUS_FLAGS_REQID)
290                 show_value(6, "requester", "0x%016llx",
291                     (long long)pcibus->pcibus_reqid);
292         if (pcibus->pcibus_flags & MCA_PCIBUS_FLAGS_RSPID)
293                 show_value(6, "responder", "0x%016llx",
294                     (long long)pcibus->pcibus_rspid);
295         if (pcibus->pcibus_flags & MCA_PCIBUS_FLAGS_TGTID)
296                 show_value(6, "target", "0x%016llx",
297                     (long long)pcibus->pcibus_tgtid);
298         if (pcibus->pcibus_flags & MCA_PCIBUS_FLAGS_OEM_ID)
299                 show_value(6, "oem", "%s", uuid(&pcibus->pcibus_oem_id));
300         /* TODO: Dump OEM data */
301
302         printf("    </pci-bus>\n");
303 }
304
305 static void
306 show_smbios(void)
307 {
308         printf("    # SMBIOS\n");
309 }
310
311 static void
312 show_pci_dev(struct mca_pcidev_record *pcidev)
313 {
314         printf("    <pci-dev>\n");
315
316         if (pcidev->pcidev_flags & MCA_PCIDEV_FLAGS_STATUS)
317                 show_value(6, "status", "0x%016llx",
318                     (long long)pcidev->pcidev_status);
319         if (pcidev->pcidev_flags & MCA_PCIDEV_FLAGS_INFO) {
320                 show_value(6, "vendor", "0x%04x",
321                     pcidev->pcidev_info.info_vendor);
322                 show_value(6, "device", "0x%04x",
323                     pcidev->pcidev_info.info_device);
324                 show_value(6, "class", "0x%06x",
325                     MCA_PCIDEV_INFO_CLASS(pcidev->pcidev_info.info_ccfn));
326                 show_value(6, "function", "0x%02x",
327                     MCA_PCIDEV_INFO_FUNCTION(pcidev->pcidev_info.info_ccfn));
328                 show_value(6, "slot", "0x%02x", pcidev->pcidev_info.info_slot);
329                 show_value(6, "bus", "0x%04x", pcidev->pcidev_info.info_bus);
330                 show_value(6, "segment", "0x%04x",
331                     pcidev->pcidev_info.info_segment);
332         }
333         /* TODO: dump registers */
334         /* TODO: Dump OEM data */
335
336         printf("    </pci-dev>\n");
337 }
338
339 static void
340 show_generic(void)
341 {
342         printf("    # GENERIC\n");
343 }
344
345 static size_t
346 show_section(struct mca_section_header *sh)
347 {
348         static uuid_t uuid_cpu = MCA_UUID_CPU;
349         static uuid_t uuid_memory = MCA_UUID_MEMORY;
350         static uuid_t uuid_sel = MCA_UUID_SEL;
351         static uuid_t uuid_pci_bus = MCA_UUID_PCI_BUS;
352         static uuid_t uuid_smbios = MCA_UUID_SMBIOS;
353         static uuid_t uuid_pci_dev = MCA_UUID_PCI_DEV;
354         static uuid_t uuid_generic = MCA_UUID_GENERIC;
355
356         printf("  <section>\n");
357         show_value(4, "uuid", "%s", uuid(&sh->sh_uuid));
358         show_value(4, "revision", "%d.%d", BCD(sh->sh_major),
359             BCD(sh->sh_minor));
360
361         if (uuid_equal(&sh->sh_uuid, &uuid_cpu, NULL))
362                 show_cpu((void*)(sh + 1));
363         else if (uuid_equal(&sh->sh_uuid, &uuid_memory, NULL))
364                 show_memory((void*)(sh + 1));
365         else if (uuid_equal(&sh->sh_uuid, &uuid_sel, NULL))
366                 show_sel();
367         else if (uuid_equal(&sh->sh_uuid, &uuid_pci_bus, NULL))
368                 show_pci_bus((void*)(sh + 1));
369         else if (uuid_equal(&sh->sh_uuid, &uuid_smbios, NULL))
370                 show_smbios();
371         else if (uuid_equal(&sh->sh_uuid, &uuid_pci_dev, NULL))
372                 show_pci_dev((void*)(sh + 1));
373         else if (uuid_equal(&sh->sh_uuid, &uuid_generic, NULL))
374                 show_generic();
375
376         printf("  </section>\n");
377         return (sh->sh_length);
378 }
379
380 static void
381 show(char *data, const char *mib)
382 {
383         size_t reclen, seclen;
384
385         if (mib != NULL)
386                 printf("<!-- MIB: %s -->\n", mib);
387
388         printf("<record>\n");
389         reclen = show_header((void*)data) - sizeof(struct mca_record_header);
390         data += sizeof(struct mca_record_header);
391         while (reclen > sizeof(struct mca_section_header)) {
392                 seclen = show_section((void*)data);
393                 reclen -= seclen;
394                 data += seclen;
395         }
396         printf("</record>\n");
397 }
398
399 static void
400 showall(char *buf, size_t buflen)
401 {
402         struct mca_record_header *rh;
403         size_t reclen;
404
405         do {
406                 if (buflen < sizeof(struct mca_record_header))
407                         return;
408
409                 rh = (void*)buf;
410                 reclen = rh->rh_length;
411                 if (buflen < reclen)
412                         return;
413
414                 show(buf, NULL);
415
416                 buf += reclen;
417                 buflen -= reclen;
418         }
419         while (1);
420 }
421
422 static void
423 dump(char *data)
424 {
425         struct mca_record_header *rh;
426         const char *fn;
427         int fd;
428
429         rh = (void*)data;
430         fn = (file) ? file : default_dumpfile;
431         fd = open(fn, O_WRONLY|O_CREAT|O_APPEND, 0660);
432         if (fd == -1)
433                 err(2, "open(%s)", fn);
434         if (write(fd, (void*)rh, rh->rh_length) == -1)
435                 err(2, "write(%s)", fn);
436         close(fd);
437 }
438
439 static void
440 usage(void)
441 {
442
443         fprintf(stderr, "usage: mca [-df]\n");
444         exit (1);
445 }
446
447 int
448 main(int argc, char **argv)
449 {
450         char mib[32];
451         char *buf;
452         size_t len;
453         int ch, error, fd;
454         int count, first, last, cpuid;
455
456         while ((ch = getopt(argc, argv, "df:")) != -1) {
457                 switch(ch) {
458                 case 'd':       /* dump */
459                         fl_dump = 1;
460                         break;
461                 case 'f':
462                         if (file)
463                                 free(file);             /* XXX complain! */
464                         file = strdup(optarg);
465                         break;
466                 default:
467                         usage();
468                 }
469         }
470
471         argc -= optind;
472         argv += optind;
473
474         if (file == NULL || fl_dump) {
475                 len = sizeof(count);
476                 if (sysctlbyname(hw_mca_count, &count, &len, NULL, 0) == -1)
477                         err(1, hw_mca_count);
478
479                 if (count == 0)
480                         errx(0, "no error records found");
481
482                 len = sizeof(first);
483                 if (sysctlbyname(hw_mca_first, &first, &len, NULL, 0) == -1)
484                         err(1, hw_mca_first);
485
486                 len = sizeof(last);
487                 if (sysctlbyname(hw_mca_last, &last, &len, NULL, 0) == -1)
488                         err(1, hw_mca_last);
489
490                 cpuid = 0;
491                 error = 0;
492                 while (count && first <= last) {
493                         do {
494                                 sprintf(mib, hw_mca_recid, first, cpuid);
495                                 len = 0;
496                                 ch = sysctlbyname(mib, NULL, &len, NULL, 0);
497                                 error = (ch == -1) ? errno : 0;
498                                 if (error != ENOENT)
499                                         break;
500                                 cpuid++;
501                         } while (cpuid <= HW_MCA_MAX_CPUID);
502                         if (error == ENOENT && cpuid > HW_MCA_MAX_CPUID) {
503                                 first++;
504                                 cpuid = 0;
505                                 continue;
506                         }
507                         if (error)
508                                 errc(1, error, "%s(1)", mib);
509
510                         buf = malloc(len);
511                         if (buf == NULL)
512                                 err(1, "buffer");
513
514                         if (sysctlbyname(mib, buf, &len, NULL, 0) == -1)
515                                 err(1, "%s(2)", mib);
516
517                         if (fl_dump)
518                                 dump(buf);
519                         else
520                                 show(buf, mib);
521
522                         free(buf);
523                         count--;
524                         if (cpuid == HW_MCA_MAX_CPUID) {
525                                 first++;
526                                 cpuid = 0;
527                         } else
528                                 cpuid++;
529                 }
530         } else {
531                 fd = open(file, O_RDONLY);
532                 if (fd == -1)
533                         err(1, "open(%s)", file);
534
535                 len = lseek(fd, 0LL, SEEK_END);
536                 buf = mmap(NULL, len, PROT_READ, 0U, fd, 0LL);
537                 if (buf == MAP_FAILED)
538                         err(1, "mmap(%s)", file);
539
540                 showall(buf, len);
541
542                 munmap(buf, len);
543                 close(fd);
544         }
545
546         return (0);
547 }