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