cmd_memerr_arch.c revision 50e6accba1026e52ccc1b0d86109daeb4d7cc039
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Ereport-handling routines for memory errors
*/
#include <cmd_mem.h>
#include <cmd_dimm.h>
#include <cmd_bank.h>
#include <cmd_page.h>
#include <cmd_cpu.h>
#include <cmd_branch.h>
#include <cmd_state.h>
#include <cmd.h>
#include <assert.h>
#include <strings.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/errclassify.h>
#include <sys/niagararegs.h>
#include <ctype.h>
#define VF_TS3_FCR 0x000000000000FFFFULL
#define VF_L2ESYR_C2C 0x8000000000000000ULL
#define UTS2_CPUS_PER_CHIP 64
#define FBR_ERROR ".fbr"
extern ldom_hdl_t *cpumem_diagnosis_lhp;
static void *
{
}
static void
{
}
/*ARGSUSED*/
{
/*
* Niagara writebacks from L2 containing UEs are placed in memory
* with the poison syndrome NI_DRAM_POISON_SYND_FROM_LDWU.
* Memory UE ereports showing this syndrome are dropped because they
* indicate an L2 problem, which should be diagnosed from the
* corresponding L2 cache ereport.
*/
case CPU_ULTRASPARC_T1:
if (synd == NI_DRAM_POISON_SYND_FROM_LDWU) {
"discarding UE due to magic syndrome %x\n",
synd);
return (CMD_EVD_UNUSED);
}
break;
case CPU_ULTRASPARC_T2:
case CPU_ULTRASPARC_T2plus:
if (synd == N2_DRAM_POISON_SYND_FROM_LDWU) {
"discarding UE due to magic syndrome %x\n",
synd);
return (CMD_EVD_UNUSED);
}
break;
default:
break;
}
return (CMD_EVD_OK);
}
static int
{
uint32_t i;
return (-1);
}
*cpuid = i;
return (0);
}
}
}
return (-1);
}
/*ARGSUSED*/
{
int rc;
/*
* If the c2c bit is set, the sending cache of the
* cpu must be faulted instead of the memory.
* If the detector is chip0, the cache of the chip1
* is faulted and vice versa.
*/
if (cpuid < UTS2_CPUS_PER_CHIP)
else
cpuid = 0;
if (rc != -1) {
if (nvlist_add_uint32(det,
FM_FMRI_CPU_ID, cpuid) == 0) {
}
}
}
return (CMD_EVD_BAD);
}
/*
* sun4v's xe_common routine has an extra argument, clcode, compared
* to routine of same name in sun4u.
*/
static cmd_evdisp_t
{
char *typenm;
int minorvers = 1;
if (nvlist_lookup_uint64(nvl,
FM_EREPORT_PAYLOAD_NAME_L2_AFSR, &l2_afsr) != 0 &&
FM_EREPORT_PAYLOAD_NAME_L2_ESR, &l2_afsr) != 0)
return (CMD_EVD_BAD);
if (nvlist_lookup_uint64(nvl,
FM_EREPORT_PAYLOAD_NAME_DRAM_AFSR, &dram_afsr) != 0 &&
return (CMD_EVD_BAD);
if (nvlist_lookup_uint64(nvl,
FM_EREPORT_PAYLOAD_NAME_L2_AFAR, &l2_afar) != 0 &&
FM_EREPORT_PAYLOAD_NAME_L2_EAR, &l2_afar) != 0)
return (CMD_EVD_BAD);
if (nvlist_lookup_uint64(nvl,
FM_EREPORT_PAYLOAD_NAME_DRAM_AFAR, &dram_afar) != 0 &&
return (CMD_EVD_BAD);
if (nvlist_lookup_pairs(nvl, 0,
NULL) != 0)
return (CMD_EVD_BAD);
/*
* Niagara afar and synd validity.
* For a given set of error registers, the payload value is valid if
* no higher priority error status bit is set. See UltraSPARC-T1.h for
* error status bit values and priority settings. Note that for DAC
* and DAU, afar value is taken from l2 error registers, syndrome
* from dram error * registers; for DSC and DSU, both afar and
* syndrome are taken from dram * error registers. DSU afar and
* syndrome are always valid because no
* higher priority error will override.
*/
switch (clcode) {
case CMD_ERRCL_DAC:
break;
case CMD_ERRCL_DSC:
break;
case CMD_ERRCL_DAU:
&l2_esyr) == 0) {
if (l2_esyr & VF_L2ESYR_C2C) {
}
}
break;
case CMD_ERRCL_DSU:
break;
default:
clcode);
return (CMD_EVD_UNUSED);
}
}
/*ARGSUSED*/
{
}
/*ARGSUSED*/
{
}
/*ARGSUSED*/
{
return (CMD_EVD_UNUSED);
}
/*ARGSUSED*/
{
const char *uuid;
return (NULL);
}
return (NULL);
}
return (NULL);
}
return (CMD_EVD_UNUSED);
}
return (CMD_EVD_REDUND);
}
}
"Processing fbr with lane failover\n");
"fault.memory.link-f", det);
} else {
}
if (fmd_serd_record(hdl,
return (CMD_EVD_OK); /* engine hasn't fired */
"fault.memory.link-c", det);
}
} else {
det);
}
}
return (CMD_EVD_OK);
}
void
{
}
/*ARGSUSED*/
{
/*
* Compute and return the total physical memory in pages from the
* Cache its value.
*/
if (npage > 0) {
return (npage);
}
if (cpumem_hdl == NULL) {
cpumem_hdl = hdl;
}
return (0);
}
return (0);
}
for (i = 0; i < nmblocks; i++) {
physmem = 0;
break;
}
}
return (npage);
}
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 0 */
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, /* 1 */
{ 0, 2, 4, 6, 8, 10, 12, 14, 3, 1, 7, 5, 11, 9, 15, 13}, /* 2 */
{ 0, 3, 6, 5, 12, 15, 10, 9, 11, 8, 13, 14, 7, 4, 1, 2}, /* 3 */
{ 0, 4, 8, 12, 3, 7, 11, 15, 6, 2, 14, 10, 5, 1, 13, 9}, /* 4 */
{ 0, 5, 10, 15, 7, 2, 13, 8, 14, 11, 4, 1, 9, 12, 3, 6}, /* 5 */
{ 0, 6, 12, 10, 11, 13, 7, 1, 5, 3, 9, 15, 14, 8, 2, 4}, /* 6 */
{ 0, 7, 14, 9, 15, 8, 1, 6, 13, 10, 3, 4, 2, 5, 12, 11}, /* 7 */
{ 0, 8, 3, 11, 6, 14, 5, 13, 12, 4, 15, 7, 10, 2, 9, 1}, /* 8 */
{ 0, 9, 1, 8, 2, 11, 3, 10, 4, 13, 5, 12, 6, 15, 7, 14}, /* 9 */
{ 0, 10, 7, 13, 14, 4, 9, 3, 15, 5, 8, 2, 1, 11, 6, 12}, /* A */
{ 0, 11, 5, 14, 10, 1, 15, 4, 7, 12, 2, 9, 13, 6, 8, 3}, /* B */
{ 0, 12, 11, 7, 5, 9, 14, 2, 10, 6, 1, 13, 15, 3, 4, 8}, /* C */
{ 0, 13, 9, 4, 1, 12, 8, 5, 2, 15, 11, 6, 3, 14, 10, 7}, /* D */
{ 0, 14, 15, 1, 13, 3, 2, 12, 9, 7, 6, 8, 4, 10, 11, 5}, /* E */
{ 0, 15, 13, 2, 9, 6, 4, 11, 1, 14, 12, 3, 8, 7, 5, 10} /* F */
};
static int
int i;
for (i = 0; i < 16; i++) {
return (i);
}
return (-1);
}
/*
* Data nibbles N0-N31 => 0-31
* check nibbles C0-3 => 32-35
*/
int
if (syndrome == 0)
return (-1); /* clean syndrome, not a CE */
if (s3 == 0) {
return (32); /* 0 0 0 e => C0 */
return (33); /* 0 0 e 0 => C1 */
return (34); /* 0 e 0 0 => C2 */
return (31); /* 0 d d d => N31 */
return (-1); /* multibit error */
} else if (s2 == 0) {
return (35); /* e 0 0 0 => C4 */
return (-1); /* not a 0 b c */
return (-1); /* check nibble not valid */
} else if (s1 == 0) {
return (-1); /* not a b 0 c */
return (-1); /* check nibble not valid */
} else if (s0 == 0) {
return (30); /* d d d 0 => N30 */
return (-1);
} else return (-1);
}
int
/*
* function will become more complicated.
*/
return ((int)upos);
}
typedef struct tr_ent {
const char *nac_component;
const char *hc_component;
} tr_ent_t;
{ "MB", "motherboard" },
{ "CMP", "chip" },
{ "BR", "branch" },
{ "CH", "dram-channel" },
{ "R", "rank" },
{ "D", "dimm" }
};
static int
map_name(const char *p) {
int i;
for (i = 0; i < tr_tbl_n; i++) {
return (i);
}
return (-1);
}
static int
{
int num = 0;
cptr++;
}
return (num);
}
/*
* This version of breakup_components assumes that all component names which
* it sees are of the form: <nonnumeric piece><numeric piece>
* i.e. no embedded numerals in component name which have to be spelled out.
*/
static int
{
i = 0;
continue; /* skip names that don't map */
if (instlen == 0) {
} else {
}
tr_tbl[j].hc_component) != 0 ||
return (-1);
i++;
}
return (1);
}
nvlist_t *
int i, n;
unsigned int usi;
} else {
}
for (i = 0; i < n; i++) {
(void) nvlist_alloc(&hc_list[i],
}
for (i = 0; i < n; i++) {
nvlist_free(hc_list[i]);
}
return (NULL);
}
FM_HC_VERS0) != 0) ||
for (i = 0; i < n; i++) {
nvlist_free(hc_list[i]);
}
return (NULL);
}
for (i = 0; i < n; i++) {
nvlist_free(hc_list[i]);
}
return (NULL);
}
}
return (NULL);
}
}
return (fp);
}