2 * Copyright (c) 2002 Marcel Moolenaar
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/types.h>
32 #include <sys/sysctl.h>
36 * Hack to make this compile on non-ia64 machines.
39 #include <machine/mca.h>
41 #include "../../sys/ia64/include/mca.h"
54 #define BCD(x) ((x >> 4) * 10 + (x & 15))
56 #define HW_MCA_MAX_CPUID 255
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";
63 static char default_dumpfile[] = "/var/log/mca.log";
73 case MCA_RH_ERROR_RECOVERABLE:
74 return ("recoverable");
75 case MCA_RH_ERROR_FATAL:
77 case MCA_RH_ERROR_CORRECTED:
87 static char buffer[64];
90 uuid_to_string(id, &s, NULL);
97 show_value(int indent, const char *var, const char *fmt, ...)
105 len += printf("<%s>", var);
107 len += vprintf(fmt, ap);
108 len += printf("</%s>\n", var);
113 show_header(struct mca_record_header *rh)
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),
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);
138 show_cpu_mod(const char *what, int idx, struct mca_cpu_mod *cpu_mod)
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);
160 show_cpu(struct mca_cpu_record *cpu)
163 struct mca_cpu_mod *mod;
164 struct mca_cpu_cpuid *cpuid;
166 struct mca_cpu_psi *psi;
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);
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++);
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]);
206 psi = (struct mca_cpu_psi*)(cpuid + 1);
214 show_memory(struct mca_mem_record *mem)
216 printf(" <memory>\n");
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 */
259 printf(" </memory>\n");
269 show_pci_bus(struct mca_pcibus_record *pcibus)
271 printf(" <pci-bus>\n");
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 */
302 printf(" </pci-bus>\n");
308 printf(" # SMBIOS\n");
312 show_pci_dev(struct mca_pcidev_record *pcidev)
314 printf(" <pci-dev>\n");
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);
333 /* TODO: dump registers */
334 /* TODO: Dump OEM data */
336 printf(" </pci-dev>\n");
342 printf(" # GENERIC\n");
346 show_section(struct mca_section_header *sh)
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;
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),
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))
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))
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))
376 printf(" </section>\n");
377 return (sh->sh_length);
381 show(char *data, const char *mib)
383 size_t reclen, seclen;
386 printf("<!-- MIB: %s -->\n", mib);
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);
396 printf("</record>\n");
400 showall(char *buf, size_t buflen)
402 struct mca_record_header *rh;
406 if (buflen < sizeof(struct mca_record_header))
410 reclen = rh->rh_length;
425 struct mca_record_header *rh;
430 fn = (file) ? file : default_dumpfile;
431 fd = open(fn, O_WRONLY|O_CREAT|O_APPEND, 0660);
433 err(2, "open(%s)", fn);
434 if (write(fd, (void*)rh, rh->rh_length) == -1)
435 err(2, "write(%s)", fn);
443 fprintf(stderr, "usage: mca [-df]\n");
448 main(int argc, char **argv)
454 int count, first, last, cpuid;
456 while ((ch = getopt(argc, argv, "df:")) != -1) {
463 free(file); /* XXX complain! */
464 file = strdup(optarg);
474 if (file == NULL || fl_dump) {
476 if (sysctlbyname(hw_mca_count, &count, &len, NULL, 0) == -1)
477 err(1, hw_mca_count);
480 errx(0, "no error records found");
483 if (sysctlbyname(hw_mca_first, &first, &len, NULL, 0) == -1)
484 err(1, hw_mca_first);
487 if (sysctlbyname(hw_mca_last, &last, &len, NULL, 0) == -1)
492 while (count && first <= last) {
494 sprintf(mib, hw_mca_recid, first, cpuid);
496 ch = sysctlbyname(mib, NULL, &len, NULL, 0);
497 error = (ch == -1) ? errno : 0;
501 } while (cpuid <= HW_MCA_MAX_CPUID);
502 if (error == ENOENT && cpuid > HW_MCA_MAX_CPUID) {
508 errc(1, error, "%s(1)", mib);
514 if (sysctlbyname(mib, buf, &len, NULL, 0) == -1)
515 err(1, "%s(2)", mib);
524 if (cpuid == HW_MCA_MAX_CPUID) {
531 fd = open(file, O_RDONLY);
533 err(1, "open(%s)", file);
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);