1100411Speter/*
2100411Speter * Copyright (c) 2002 Marcel Moolenaar
3100411Speter * All rights reserved.
4100411Speter *
5100411Speter * Redistribution and use in source and binary forms, with or without
6100411Speter * modification, are permitted provided that the following conditions
7100411Speter * are met:
8100411Speter *
9100411Speter * 1. Redistributions of source code must retain the above copyright
10100411Speter *    notice, this list of conditions and the following disclaimer.
11100411Speter * 2. Redistributions in binary form must reproduce the above copyright
12100411Speter *    notice, this list of conditions and the following disclaimer in the
13100411Speter *    documentation and/or other materials provided with the distribution.
14100411Speter *
15100411Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16100411Speter * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17100411Speter * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18100411Speter * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19100411Speter * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20100411Speter * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21100411Speter * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22100411Speter * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23100411Speter * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24100411Speter * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25100411Speter */
26100411Speter
27100411Speter#include <sys/cdefs.h>
28100411Speter__FBSDID("$FreeBSD$");
29100411Speter
30100411Speter#include <sys/types.h>
31100411Speter#include <sys/mman.h>
32100411Speter#include <sys/sysctl.h>
33100411Speter#include <sys/uuid.h>
34100411Speter
35100411Speter/*
36100411Speter * Hack to make this compile on non-ia64 machines.
37100411Speter */
38100411Speter#ifdef __ia64__
39100411Speter#include <machine/mca.h>
40100411Speter#else
41100411Speter#include "../../sys/ia64/include/mca.h"
42100411Speter#endif
43100411Speter
44100411Speter#include <err.h>
45100411Speter#include <errno.h>
46100411Speter#include <fcntl.h>
47105309Smarcel#include <stdarg.h>
48100411Speter#include <stdio.h>
49100411Speter#include <stdlib.h>
50100411Speter#include <string.h>
51100411Speter#include <unistd.h>
52106284Smarcel#include <uuid.h>
53100411Speter
54100411Speter#define	BCD(x)	((x >> 4) * 10 + (x & 15))
55100411Speter
56206571Smarcel#define	HW_MCA_MAX_CPUID	255
57206571Smarcel
58236355Seadlerstatic const char hw_mca_count[] = "hw.mca.count";
59236355Seadlerstatic const char hw_mca_first[] = "hw.mca.first";
60236355Seadlerstatic const char hw_mca_last[] = "hw.mca.last";
61236355Seadlerstatic const char hw_mca_recid[] = "hw.mca.%d.%u";
62100411Speter
63100411Speterstatic char default_dumpfile[] = "/var/log/mca.log";
64100411Speter
65100411Speterint fl_dump;
66100411Speterchar *file;
67100411Speter
68100411Speterstatic const char *
69100411Speterseverity(int error)
70100411Speter{
71100411Speter
72100411Speter	switch (error) {
73100411Speter	case MCA_RH_ERROR_RECOVERABLE:
74100411Speter		return ("recoverable");
75100411Speter	case MCA_RH_ERROR_FATAL:
76100411Speter		return ("fatal");
77100411Speter	case MCA_RH_ERROR_CORRECTED:
78100411Speter		return ("corrected");
79100411Speter	}
80100411Speter
81100411Speter	return ("unknown");
82100411Speter}
83100411Speter
84100411Speterstatic const char *
85106284Smarceluuid(uuid_t *id)
86100411Speter{
87100411Speter	static char buffer[64];
88106284Smarcel	char *s;
89100411Speter
90106284Smarcel	uuid_to_string(id, &s, NULL);
91106284Smarcel	strcpy(buffer, s);
92106284Smarcel	free(s);
93100411Speter	return (buffer);
94100411Speter}
95100411Speter
96105309Smarcelstatic int
97105309Smarcelshow_value(int indent, const char *var, const char *fmt, ...)
98105309Smarcel{
99105309Smarcel	va_list ap;
100105309Smarcel	int len;
101105309Smarcel
102105309Smarcel	len = indent;
103105309Smarcel	while (indent--)
104105309Smarcel		putchar(' ');
105105309Smarcel	len += printf("<%s>", var);
106105309Smarcel	va_start(ap, fmt);
107105309Smarcel	len += vprintf(fmt, ap);
108105309Smarcel	len += printf("</%s>\n", var);
109105309Smarcel	return (len);
110105309Smarcel}
111105309Smarcel
112100411Speterstatic size_t
113100411Spetershow_header(struct mca_record_header *rh)
114100411Speter{
115100411Speter
116100411Speter	printf("  <header>\n");
117105309Smarcel	show_value(4, "seqnr", "%lld", (long long)rh->rh_seqnr);
118105309Smarcel	show_value(4, "revision", "%d.%d", BCD(rh->rh_major),
119105309Smarcel	    BCD(rh->rh_minor));
120105309Smarcel	show_value(4, "severity", "%s", severity(rh->rh_error));
121105309Smarcel	show_value(4, "length", "%lld", (long long)rh->rh_length);
122105309Smarcel	show_value(4, "date", "%d%02d/%02d/%02d",
123100411Speter	    BCD(rh->rh_time[MCA_RH_TIME_CENT]),
124100411Speter	    BCD(rh->rh_time[MCA_RH_TIME_YEAR]),
125100411Speter	    BCD(rh->rh_time[MCA_RH_TIME_MON]),
126100411Speter	    BCD(rh->rh_time[MCA_RH_TIME_MDAY]));
127105309Smarcel	show_value(4, "time", "%02d:%02d:%02d",
128100411Speter	    BCD(rh->rh_time[MCA_RH_TIME_HOUR]),
129100411Speter	    BCD(rh->rh_time[MCA_RH_TIME_MIN]),
130100411Speter	    BCD(rh->rh_time[MCA_RH_TIME_SEC]));
131100411Speter	if (rh->rh_flags & MCA_RH_FLAGS_PLATFORM_ID)
132105309Smarcel		show_value(4, "platform", "%s", uuid(&rh->rh_platform));
133100411Speter	printf("  </header>\n");
134100411Speter	return (rh->rh_length);
135100411Speter}
136100411Speter
137100411Speterstatic void
138100411Spetershow_cpu_mod(const char *what, int idx, struct mca_cpu_mod *cpu_mod)
139100411Speter{
140100411Speter	printf("      <%s-%d>\n", what, idx);
141100411Speter	if (cpu_mod->cpu_mod_flags & MCA_CPU_MOD_FLAGS_INFO)
142105309Smarcel		show_value(8, "info", "0x%016llx",
143100411Speter		    (long long)cpu_mod->cpu_mod_info);
144100411Speter	if (cpu_mod->cpu_mod_flags & MCA_CPU_MOD_FLAGS_REQID)
145105309Smarcel		show_value(8, "requester", "0x%016llx",
146100411Speter		    (long long)cpu_mod->cpu_mod_reqid);
147100411Speter	if (cpu_mod->cpu_mod_flags & MCA_CPU_MOD_FLAGS_RSPID)
148105309Smarcel		show_value(8, "responder", "0x%016llx",
149100411Speter		    (long long)cpu_mod->cpu_mod_rspid);
150100411Speter	if (cpu_mod->cpu_mod_flags & MCA_CPU_MOD_FLAGS_TGTID)
151105309Smarcel		show_value(8, "target", "0x%016llx",
152100411Speter		    (long long)cpu_mod->cpu_mod_tgtid);
153100411Speter	if (cpu_mod->cpu_mod_flags & MCA_CPU_MOD_FLAGS_IP)
154105309Smarcel		show_value(8, "ip", "0x%016llx",
155100411Speter		    (long long)cpu_mod->cpu_mod_ip);
156100411Speter	printf("      </%s-%d>\n", what, idx);
157100411Speter}
158100411Speter
159100411Speterstatic void
160100411Spetershow_cpu(struct mca_cpu_record *cpu)
161100411Speter{
162105309Smarcel	char var[16];
163100411Speter	struct mca_cpu_mod *mod;
164100411Speter	struct mca_cpu_cpuid *cpuid;
165236355Seadler#ifdef notyet
166100411Speter	struct mca_cpu_psi *psi;
167236355Seadler#endif
168100411Speter	int i, n;
169100411Speter
170100411Speter	printf("    <cpu>\n");
171100411Speter
172100411Speter	if (cpu->cpu_flags & MCA_CPU_FLAGS_ERRMAP)
173105309Smarcel		show_value(6, "errmap", "0x%016llx",
174105309Smarcel		    (long long)cpu->cpu_errmap);
175100411Speter	if (cpu->cpu_flags & MCA_CPU_FLAGS_STATE)
176105309Smarcel		show_value(6, "state", "0x%016llx",
177105309Smarcel		    (long long)cpu->cpu_state);
178100411Speter	if (cpu->cpu_flags & MCA_CPU_FLAGS_CR_LID)
179105309Smarcel		show_value(6, "cr_lid", "0x%016llx",
180105309Smarcel		    (long long)cpu->cpu_cr_lid);
181100411Speter
182100411Speter	mod = (struct mca_cpu_mod*)(cpu + 1);
183100411Speter	n = MCA_CPU_FLAGS_CACHE(cpu->cpu_flags);
184100411Speter	for (i = 0; i < n; i++)
185100411Speter		show_cpu_mod("cache", i, mod++);
186100411Speter	n = MCA_CPU_FLAGS_TLB(cpu->cpu_flags);
187100411Speter	for (i = 0; i < n; i++)
188100411Speter		show_cpu_mod("tlb", i, mod++);
189100411Speter	n = MCA_CPU_FLAGS_BUS(cpu->cpu_flags);
190100411Speter	for (i = 0; i < n; i++)
191100411Speter		show_cpu_mod("bus", i, mod++);
192100411Speter	n = MCA_CPU_FLAGS_REG(cpu->cpu_flags);
193100411Speter	for (i = 0; i < n; i++)
194100411Speter		show_cpu_mod("reg", i, mod++);
195100411Speter	n = MCA_CPU_FLAGS_MS(cpu->cpu_flags);
196100411Speter	for (i = 0; i < n; i++)
197100411Speter		show_cpu_mod("ms", i, mod++);
198100411Speter
199100411Speter	cpuid = (struct mca_cpu_cpuid*)mod;
200105309Smarcel	for (i = 0; i < 6; i++) {
201105309Smarcel		sprintf(var, "cpuid-%d", i);
202105309Smarcel		show_value(6, var, "0x%016llx", (long long)cpuid->cpuid[i]);
203105309Smarcel	}
204100411Speter
205236355Seadler#ifdef notyet
206236355Seadler	 psi = (struct mca_cpu_psi*)(cpuid + 1);
207236355Seadler#endif
208236355Seadler	 /* TODO: Dump PSI */
209100411Speter
210100411Speter	printf("    </cpu>\n");
211100411Speter}
212100411Speter
213100411Speterstatic void
214100411Spetershow_memory(struct mca_mem_record *mem)
215100411Speter{
216100411Speter	printf("    <memory>\n");
217100411Speter
218100411Speter	if (mem->mem_flags & MCA_MEM_FLAGS_STATUS)
219105309Smarcel		show_value(6, "status", "0x%016llx",
220105309Smarcel		    (long long)mem->mem_status);
221100411Speter	if (mem->mem_flags & MCA_MEM_FLAGS_ADDR)
222105309Smarcel		show_value(6, "address", "0x%016llx",
223105309Smarcel		    (long long)mem->mem_addr);
224100411Speter	if (mem->mem_flags & MCA_MEM_FLAGS_ADDRMASK)
225105309Smarcel		show_value(6, "mask", "0x%016llx",
226105309Smarcel		    (long long)mem->mem_addrmask);
227100411Speter	if (mem->mem_flags & MCA_MEM_FLAGS_NODE)
228105309Smarcel		show_value(6, "node", "0x%04x", mem->mem_node);
229100411Speter	if (mem->mem_flags & MCA_MEM_FLAGS_CARD)
230105309Smarcel		show_value(6, "card", "0x%04x", mem->mem_card);
231100411Speter	if (mem->mem_flags & MCA_MEM_FLAGS_MODULE)
232105309Smarcel		show_value(6, "module", "0x%04x", mem->mem_module);
233100411Speter	if (mem->mem_flags & MCA_MEM_FLAGS_BANK)
234105309Smarcel		show_value(6, "bank", "0x%04x", mem->mem_bank);
235100411Speter	if (mem->mem_flags & MCA_MEM_FLAGS_DEVICE)
236105309Smarcel		show_value(6, "device", "0x%04x", mem->mem_device);
237100411Speter	if (mem->mem_flags & MCA_MEM_FLAGS_ROW)
238105309Smarcel		show_value(6, "row", "0x%04x", mem->mem_row);
239100411Speter	if (mem->mem_flags & MCA_MEM_FLAGS_COLUMN)
240105309Smarcel		show_value(6, "column", "0x%04x", mem->mem_column);
241100411Speter	if (mem->mem_flags & MCA_MEM_FLAGS_BITPOS)
242105309Smarcel		show_value(6, "bit", "0x%04x", mem->mem_bitpos);
243100411Speter	if (mem->mem_flags & MCA_MEM_FLAGS_REQID)
244105309Smarcel		show_value(6, "requester", "0x%016llx",
245100411Speter		    (long long)mem->mem_reqid);
246100411Speter	if (mem->mem_flags & MCA_MEM_FLAGS_RSPID)
247105309Smarcel		show_value(6, "responder", "0x%016llx",
248100411Speter		    (long long)mem->mem_rspid);
249100411Speter	if (mem->mem_flags & MCA_MEM_FLAGS_TGTID)
250105309Smarcel		show_value(6, "target", "0x%016llx",
251100411Speter		    (long long)mem->mem_tgtid);
252100411Speter	if (mem->mem_flags & MCA_MEM_FLAGS_BUSDATA)
253105309Smarcel		show_value(6, "status", "0x%016llx",
254100411Speter		    (long long)mem->mem_busdata);
255100411Speter	if (mem->mem_flags & MCA_MEM_FLAGS_OEM_ID)
256105309Smarcel		show_value(6, "oem", "%s", uuid(&mem->mem_oem_id));
257100411Speter	/* TODO: Dump OEM data */
258100411Speter
259100411Speter	printf("    </memory>\n");
260100411Speter}
261100411Speter
262100411Speterstatic void
263100411Spetershow_sel(void)
264100411Speter{
265100411Speter	printf("    # SEL\n");
266100411Speter}
267100411Speter
268100411Speterstatic void
269100411Spetershow_pci_bus(struct mca_pcibus_record *pcibus)
270100411Speter{
271100411Speter	printf("    <pci-bus>\n");
272100411Speter
273100411Speter	if (pcibus->pcibus_flags & MCA_PCIBUS_FLAGS_STATUS)
274105309Smarcel		show_value(6, "status", "0x%016llx",
275100411Speter		    (long long)pcibus->pcibus_status);
276100411Speter	if (pcibus->pcibus_flags & MCA_PCIBUS_FLAGS_ERROR)
277105309Smarcel		show_value(6, "error", "0x%04x", pcibus->pcibus_error);
278100411Speter	if (pcibus->pcibus_flags & MCA_PCIBUS_FLAGS_BUS)
279105309Smarcel		show_value(6, "bus", "0x%04x", pcibus->pcibus_bus);
280100411Speter	if (pcibus->pcibus_flags & MCA_PCIBUS_FLAGS_ADDR)
281105309Smarcel		show_value(6, "address", "0x%016llx",
282100411Speter		    (long long)pcibus->pcibus_addr);
283100411Speter	if (pcibus->pcibus_flags & MCA_PCIBUS_FLAGS_DATA)
284105309Smarcel		show_value(6, "data", "0x%016llx",
285100411Speter		    (long long)pcibus->pcibus_data);
286100411Speter	if (pcibus->pcibus_flags & MCA_PCIBUS_FLAGS_CMD)
287105309Smarcel		show_value(6, "cmd", "0x%016llx",
288100411Speter		    (long long)pcibus->pcibus_cmd);
289100411Speter	if (pcibus->pcibus_flags & MCA_PCIBUS_FLAGS_REQID)
290105309Smarcel		show_value(6, "requester", "0x%016llx",
291100411Speter		    (long long)pcibus->pcibus_reqid);
292100411Speter	if (pcibus->pcibus_flags & MCA_PCIBUS_FLAGS_RSPID)
293105309Smarcel		show_value(6, "responder", "0x%016llx",
294100411Speter		    (long long)pcibus->pcibus_rspid);
295100411Speter	if (pcibus->pcibus_flags & MCA_PCIBUS_FLAGS_TGTID)
296105309Smarcel		show_value(6, "target", "0x%016llx",
297100411Speter		    (long long)pcibus->pcibus_tgtid);
298100411Speter	if (pcibus->pcibus_flags & MCA_PCIBUS_FLAGS_OEM_ID)
299105309Smarcel		show_value(6, "oem", "%s", uuid(&pcibus->pcibus_oem_id));
300100411Speter	/* TODO: Dump OEM data */
301100411Speter
302100411Speter	printf("    </pci-bus>\n");
303100411Speter}
304100411Speter
305100411Speterstatic void
306100411Spetershow_smbios(void)
307100411Speter{
308100411Speter	printf("    # SMBIOS\n");
309100411Speter}
310100411Speter
311100411Speterstatic void
312100411Spetershow_pci_dev(struct mca_pcidev_record *pcidev)
313100411Speter{
314100411Speter	printf("    <pci-dev>\n");
315100411Speter
316100411Speter	if (pcidev->pcidev_flags & MCA_PCIDEV_FLAGS_STATUS)
317105309Smarcel		show_value(6, "status", "0x%016llx",
318100411Speter		    (long long)pcidev->pcidev_status);
319100411Speter	if (pcidev->pcidev_flags & MCA_PCIDEV_FLAGS_INFO) {
320105309Smarcel		show_value(6, "vendor", "0x%04x",
321100411Speter		    pcidev->pcidev_info.info_vendor);
322105309Smarcel		show_value(6, "device", "0x%04x",
323100411Speter		    pcidev->pcidev_info.info_device);
324105309Smarcel		show_value(6, "class", "0x%06x",
325100411Speter		    MCA_PCIDEV_INFO_CLASS(pcidev->pcidev_info.info_ccfn));
326105309Smarcel		show_value(6, "function", "0x%02x",
327100411Speter		    MCA_PCIDEV_INFO_FUNCTION(pcidev->pcidev_info.info_ccfn));
328105309Smarcel		show_value(6, "slot", "0x%02x", pcidev->pcidev_info.info_slot);
329105309Smarcel		show_value(6, "bus", "0x%04x", pcidev->pcidev_info.info_bus);
330105309Smarcel		show_value(6, "segment", "0x%04x",
331100411Speter		    pcidev->pcidev_info.info_segment);
332100411Speter	}
333100411Speter	/* TODO: dump registers */
334100411Speter	/* TODO: Dump OEM data */
335100411Speter
336100411Speter	printf("    </pci-dev>\n");
337100411Speter}
338100411Speter
339100411Speterstatic void
340100411Spetershow_generic(void)
341100411Speter{
342100411Speter	printf("    # GENERIC\n");
343100411Speter}
344100411Speter
345100411Speterstatic size_t
346100411Spetershow_section(struct mca_section_header *sh)
347100411Speter{
348106284Smarcel	static uuid_t uuid_cpu = MCA_UUID_CPU;
349106284Smarcel	static uuid_t uuid_memory = MCA_UUID_MEMORY;
350106284Smarcel	static uuid_t uuid_sel = MCA_UUID_SEL;
351106284Smarcel	static uuid_t uuid_pci_bus = MCA_UUID_PCI_BUS;
352106284Smarcel	static uuid_t uuid_smbios = MCA_UUID_SMBIOS;
353106284Smarcel	static uuid_t uuid_pci_dev = MCA_UUID_PCI_DEV;
354106284Smarcel	static uuid_t uuid_generic = MCA_UUID_GENERIC;
355100411Speter
356100411Speter	printf("  <section>\n");
357105309Smarcel	show_value(4, "uuid", "%s", uuid(&sh->sh_uuid));
358105309Smarcel	show_value(4, "revision", "%d.%d", BCD(sh->sh_major),
359105309Smarcel	    BCD(sh->sh_minor));
360100411Speter
361106284Smarcel	if (uuid_equal(&sh->sh_uuid, &uuid_cpu, NULL))
362100411Speter		show_cpu((void*)(sh + 1));
363106284Smarcel	else if (uuid_equal(&sh->sh_uuid, &uuid_memory, NULL))
364100411Speter		show_memory((void*)(sh + 1));
365106284Smarcel	else if (uuid_equal(&sh->sh_uuid, &uuid_sel, NULL))
366100411Speter		show_sel();
367106284Smarcel	else if (uuid_equal(&sh->sh_uuid, &uuid_pci_bus, NULL))
368100411Speter		show_pci_bus((void*)(sh + 1));
369106284Smarcel	else if (uuid_equal(&sh->sh_uuid, &uuid_smbios, NULL))
370100411Speter		show_smbios();
371106284Smarcel	else if (uuid_equal(&sh->sh_uuid, &uuid_pci_dev, NULL))
372100411Speter		show_pci_dev((void*)(sh + 1));
373106284Smarcel	else if (uuid_equal(&sh->sh_uuid, &uuid_generic, NULL))
374100411Speter		show_generic();
375100411Speter
376100411Speter	printf("  </section>\n");
377100411Speter	return (sh->sh_length);
378100411Speter}
379100411Speter
380100411Speterstatic void
381206571Smarcelshow(char *data, const char *mib)
382100411Speter{
383100411Speter	size_t reclen, seclen;
384100411Speter
385206571Smarcel	if (mib != NULL)
386206571Smarcel		printf("<!-- MIB: %s -->\n", mib);
387206571Smarcel
388100411Speter	printf("<record>\n");
389100411Speter	reclen = show_header((void*)data) - sizeof(struct mca_record_header);
390100411Speter	data += sizeof(struct mca_record_header);
391100411Speter	while (reclen > sizeof(struct mca_section_header)) {
392100411Speter		seclen = show_section((void*)data);
393100411Speter		reclen -= seclen;
394100411Speter		data += seclen;
395100411Speter	}
396100411Speter	printf("</record>\n");
397100411Speter}
398100411Speter
399100411Speterstatic void
400100411Spetershowall(char *buf, size_t buflen)
401100411Speter{
402100411Speter	struct mca_record_header *rh;
403100411Speter	size_t reclen;
404100411Speter
405100411Speter	do {
406100411Speter		if (buflen < sizeof(struct mca_record_header))
407100411Speter			return;
408100411Speter
409100411Speter		rh = (void*)buf;
410100411Speter		reclen = rh->rh_length;
411100411Speter		if (buflen < reclen)
412100411Speter			return;
413100411Speter
414206571Smarcel		show(buf, NULL);
415100411Speter
416100411Speter		buf += reclen;
417100411Speter		buflen -= reclen;
418100411Speter	}
419100411Speter	while (1);
420100411Speter}
421100411Speter
422100411Speterstatic void
423100411Speterdump(char *data)
424100411Speter{
425100411Speter	struct mca_record_header *rh;
426100411Speter	const char *fn;
427100411Speter	int fd;
428100411Speter
429100411Speter	rh = (void*)data;
430100411Speter	fn = (file) ? file : default_dumpfile;
431100411Speter	fd = open(fn, O_WRONLY|O_CREAT|O_APPEND, 0660);
432100411Speter	if (fd == -1)
433100411Speter		err(2, "open(%s)", fn);
434100411Speter	if (write(fd, (void*)rh, rh->rh_length) == -1)
435100411Speter		err(2, "write(%s)", fn);
436100411Speter	close(fd);
437100411Speter}
438100411Speter
439100411Speterstatic void
440100411Speterusage(void)
441100411Speter{
442100411Speter
443100411Speter	fprintf(stderr, "usage: mca [-df]\n");
444100411Speter	exit (1);
445100411Speter}
446100411Speter
447100411Speterint
448100411Spetermain(int argc, char **argv)
449100411Speter{
450100411Speter	char mib[32];
451100411Speter	char *buf;
452100411Speter	size_t len;
453100411Speter	int ch, error, fd;
454206571Smarcel	int count, first, last, cpuid;
455100411Speter
456100411Speter	while ((ch = getopt(argc, argv, "df:")) != -1) {
457100411Speter		switch(ch) {
458100411Speter		case 'd':	/* dump */
459100411Speter			fl_dump = 1;
460100411Speter			break;
461100411Speter		case 'f':
462100411Speter			if (file)
463100411Speter				free(file);		/* XXX complain! */
464100411Speter			file = strdup(optarg);
465100411Speter			break;
466100411Speter		default:
467100411Speter			usage();
468100411Speter		}
469100411Speter	}
470100411Speter
471100411Speter	argc -= optind;
472100411Speter	argv += optind;
473100411Speter
474100411Speter	if (file == NULL || fl_dump) {
475100411Speter		len = sizeof(count);
476209677Smarcel		if (sysctlbyname(hw_mca_count, &count, &len, NULL, 0) == -1)
477100411Speter			err(1, hw_mca_count);
478100411Speter
479100411Speter		if (count == 0)
480100411Speter			errx(0, "no error records found");
481100411Speter
482100411Speter		len = sizeof(first);
483209677Smarcel		if (sysctlbyname(hw_mca_first, &first, &len, NULL, 0) == -1)
484100411Speter			err(1, hw_mca_first);
485100411Speter
486100411Speter		len = sizeof(last);
487209677Smarcel		if (sysctlbyname(hw_mca_last, &last, &len, NULL, 0) == -1)
488100411Speter			err(1, hw_mca_last);
489100411Speter
490206571Smarcel		cpuid = 0;
491209677Smarcel		error = 0;
492100411Speter		while (count && first <= last) {
493206571Smarcel			do {
494206571Smarcel				sprintf(mib, hw_mca_recid, first, cpuid);
495206571Smarcel				len = 0;
496209677Smarcel				ch = sysctlbyname(mib, NULL, &len, NULL, 0);
497209677Smarcel				error = (ch == -1) ? errno : 0;
498206571Smarcel				if (error != ENOENT)
499206571Smarcel					break;
500206571Smarcel				cpuid++;
501206571Smarcel			} while (cpuid <= HW_MCA_MAX_CPUID);
502206571Smarcel			if (error == ENOENT && cpuid > HW_MCA_MAX_CPUID) {
503100411Speter				first++;
504206571Smarcel				cpuid = 0;
505100411Speter				continue;
506100411Speter			}
507100411Speter			if (error)
508209677Smarcel				errc(1, error, "%s(1)", mib);
509100411Speter
510100411Speter			buf = malloc(len);
511100411Speter			if (buf == NULL)
512100411Speter				err(1, "buffer");
513100411Speter
514209677Smarcel			if (sysctlbyname(mib, buf, &len, NULL, 0) == -1)
515100411Speter				err(1, "%s(2)", mib);
516100411Speter
517100411Speter			if (fl_dump)
518100411Speter				dump(buf);
519100411Speter			else
520206571Smarcel				show(buf, mib);
521100411Speter
522100411Speter			free(buf);
523100411Speter			count--;
524206571Smarcel			if (cpuid == HW_MCA_MAX_CPUID) {
525206571Smarcel				first++;
526206571Smarcel				cpuid = 0;
527206571Smarcel			} else
528206571Smarcel				cpuid++;
529100411Speter		}
530100411Speter	} else {
531100411Speter		fd = open(file, O_RDONLY);
532100411Speter		if (fd == -1)
533100411Speter			err(1, "open(%s)", file);
534100411Speter
535100411Speter		len = lseek(fd, 0LL, SEEK_END);
536100411Speter		buf = mmap(NULL, len, PROT_READ, 0U, fd, 0LL);
537100411Speter		if (buf == MAP_FAILED)
538100411Speter			err(1, "mmap(%s)", file);
539100411Speter
540100411Speter		showall(buf, len);
541100411Speter
542100411Speter		munmap(buf, len);
543100411Speter		close(fd);
544100411Speter	}
545100411Speter
546100411Speter	return (0);
547100411Speter}
548