diff options
author | Marcel Moolenaar <marcel@FreeBSD.org> | 2002-04-26 19:30:11 +0000 |
---|---|---|
committer | Marcel Moolenaar <marcel@FreeBSD.org> | 2002-04-26 19:30:11 +0000 |
commit | e477773f011a4596b03cd952f3bbd2d2189ffa5e (patch) | |
tree | 1a816018572e29e9524210ce3bb208faeab86aba /sys/ia64/ia64/mca.c | |
parent | 0f6517b7d8efd1ca7794cca53fe343c8a4678414 (diff) | |
download | src-e477773f011a4596b03cd952f3bbd2d2189ffa5e.tar.gz src-e477773f011a4596b03cd952f3bbd2d2189ffa5e.zip |
Machine Check Architecture (MCA) support code. Error records are
collected at boot and made available through sysctl(8). At the
moment, the following MIB names are created:
hw.mca.count - The number of error records collected.
hw.mca.first - The lowest sequence number present.
hw.mca.last - The highest sequence number present.
hw.mca.<X> - The error record with sequence number <X>.
Using sysctl(8) allows us to easily detect and analyze the records,
which is very helpful during development of MCA but can also be used
in production as a way to collect machine health statistics.
Notes
Notes:
svn path=/head/; revision=95517
Diffstat (limited to 'sys/ia64/ia64/mca.c')
-rw-r--r-- | sys/ia64/ia64/mca.c | 178 |
1 files changed, 178 insertions, 0 deletions
diff --git a/sys/ia64/ia64/mca.c b/sys/ia64/ia64/mca.c new file mode 100644 index 000000000000..c11ebb53c2ef --- /dev/null +++ b/sys/ia64/ia64/mca.c @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2002 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/sysctl.h> +#include <vm/vm.h> +#include <vm/vm_kern.h> +#include <machine/mca.h> +#include <machine/sal.h> +#include <machine/smp.h> + +MALLOC_DEFINE(M_MCA, "MCA", "Machine Check Architecture"); + +int64_t mca_info_size[SAL_INFO_TYPES]; +vm_offset_t mca_info_block; + +SYSCTL_NODE(_hw, OID_AUTO, mca, CTLFLAG_RW, 0, "MCA container"); + +static int mca_count; /* Number of records stored. */ +static int mca_first; /* First (lowest) record ID. */ +static int mca_last; /* Last (highest) record ID. */ + +SYSCTL_INT(_hw_mca, OID_AUTO, count, CTLFLAG_RD, &mca_count, 0, + "Record count"); +SYSCTL_INT(_hw_mca, OID_AUTO, first, CTLFLAG_RD, &mca_first, 0, + "First record id"); +SYSCTL_INT(_hw_mca, OID_AUTO, last, CTLFLAG_RD, &mca_last, 0, + "Last record id"); + +static int +mca_sysctl_handler(SYSCTL_HANDLER_ARGS) +{ + int error = 0; + + if (!arg1) + return (EINVAL); + error = SYSCTL_OUT(req, arg1, arg2); + + if (error || !req->newptr) + return (error); + + error = SYSCTL_IN(req, arg1, arg2); + return (error); +} + +void +ia64_mca_save_state(int type) +{ + struct ia64_sal_result result; + struct mca_record_header *hdr; + struct sysctl_oid *oidp; + char *name, *state; + size_t recsz, totsz; + + /* + * Don't try to get the state if we couldn't get the size of + * the state information previously. + */ + if (mca_info_size[type] == -1) + return; + + while (1) { + result = ia64_sal_entry(SAL_GET_STATE_INFO, type, 0, + mca_info_block, 0, 0, 0, 0); + if (result.sal_status < 0) /* any error records? */ + return; + + hdr = (struct mca_record_header *)mca_info_block; + recsz = hdr->rh_length; + totsz = sizeof(struct sysctl_oid) + recsz + 16; + + oidp = malloc(totsz, M_MCA, M_WAITOK|M_ZERO); + state = (char*)(oidp + 1); + name = state + recsz; + + sprintf(name, "%d", hdr->rh_seqnr); + bcopy((char*)mca_info_block, state, recsz); + + oidp->oid_parent = &sysctl__hw_mca_children; + oidp->oid_number = OID_AUTO; + oidp->oid_kind = CTLTYPE_OPAQUE|CTLFLAG_RD|CTLFLAG_DYN; + oidp->oid_arg1 = state; + oidp->oid_arg2 = recsz; + oidp->oid_name = name; + oidp->oid_handler = mca_sysctl_handler; + oidp->oid_fmt = "S,MCA"; + oidp->descr = "Error record"; + sysctl_register_oid(oidp); + + if (mca_count > 0) { + if (hdr->rh_seqnr < mca_first) + mca_first = hdr->rh_seqnr; + else if (hdr->rh_seqnr > mca_last) + mca_last = hdr->rh_seqnr; + } else + mca_first = mca_last = hdr->rh_seqnr; + + mca_count++; + + /* Clear the record */ + result = ia64_sal_entry(SAL_CLEAR_STATE_INFO, type, 0, 0, 0, + 0, 0, 0); + } +} + +void +ia64_mca_init(void) +{ + struct ia64_sal_result result; + uint64_t max_size; + char *p; + int i; + + /* + * Get the sizes of the state information we can get from SAL and + * allocate a common block (forgive me my Fortran :-) for use by + * support functions. We create a region 7 address to make it + * easy on the OS_MCA or OS_INIT handlers to get the state info + * under unreliable conditions. + */ + max_size = 0; + for (i = 0; i <= SAL_INFO_TYPES; i++) { + result = ia64_sal_entry(SAL_GET_STATE_INFO_SIZE, i, 0, 0, 0, + 0, 0, 0); + if (result.sal_status == 0) { + mca_info_size[i] = result.sal_result[0]; + if (mca_info_size[i] > max_size) + max_size = mca_info_size[i]; + } else + mca_info_size[i] = -1; + } + max_size = round_page(max_size); + + p = contigmalloc(max_size, M_TEMP, M_WAITOK, 0ul, 256*1024*1024 - 1, + PAGE_SIZE, 256*1024*1024); + + mca_info_block = IA64_PHYS_TO_RR7(ia64_tpa((u_int64_t)p)); + + if (bootverbose) + printf("MCA: allocated %d bytes for state information\n", + max_size); + + /* + * Get and save any processor and platfom error records. Note that in + * a SMP configuration the processor records are for the BSP only. We + * let the APs get and save their own records when we wake them up. + */ + for (i = 0; i < SAL_INFO_TYPES; i++) + ia64_mca_save_state(i); +} |