257 lines
5.7 KiB
C
257 lines
5.7 KiB
C
/*
|
|
* fru_decode.c-
|
|
*
|
|
* This file decodes the various structures returned by the FRU analysis
|
|
* code and prints the results.
|
|
*
|
|
*/
|
|
|
|
#include "evfru.h"
|
|
|
|
/*
|
|
*Structure for a FRU entry. FRU is really a misnomer here. What we're
|
|
* saying is that these are things that can fail whether field replaceable
|
|
* or not.
|
|
*/
|
|
typedef struct fru_table_entry_s {
|
|
short fru_id;
|
|
char *fru_name;
|
|
} fru_table_entry_t;
|
|
|
|
/*
|
|
* Here's the "FRU" table. Each "FRU" identifier is made up of a class
|
|
* (e.g. board, bus ASIC, IO adapter) and an instance. Check out evfru.h
|
|
* for more details.
|
|
*/
|
|
static fru_table_entry_t fru_table[37] = {
|
|
{FRU_NONE, "None"},
|
|
|
|
{FRU_SOFTWARE, "Software"},
|
|
|
|
{FRU_IPBOARD, "PROCESSOR BOARD"},
|
|
{FRU_A, "A CHIP"},
|
|
{FRU_D, "D CHIP"},
|
|
{FRU_CPU, "CPU"},
|
|
{FRU_CACHE, "CACHE"},
|
|
{FRU_CC, "CC CHIP"},
|
|
{FRU_BBCC, "BBCC CHIP"},
|
|
{FRU_TAGRAM, "TAG RAM"},
|
|
{FRU_GCACHE, "GCACHE"},
|
|
{FRU_DB, "DB CHIP"},
|
|
{FRU_BUSTAG, "BUS TAG"},
|
|
{FRU_FPU, "FPU"},
|
|
|
|
{FRU_MCBOARD, "MEMORY BOARD"},
|
|
{FRU_MA, "MA CHIP"},
|
|
{FRU_MD, "MD CHIP"},
|
|
{FRU_BANK, "MEMORY BANK"},
|
|
{FRU_MD, "MEMORY SIMM"},
|
|
|
|
{FRU_IOBOARD, "IO4 BOARD"},
|
|
{FRU_IA, "IA CHIP"},
|
|
{FRU_ID, "ID CHIP"},
|
|
{FRU_MAPRAM, "IO4 MAP RAM"},
|
|
{FRU_EPC, "EPC CHIP"},
|
|
{FRU_S1, "S1 CHIP"},
|
|
{FRU_SCIP, "SCIP CHIP"},
|
|
{FRU_F, "F CHIP"},
|
|
{FRU_VMECC, "VMECC on VCAM"},
|
|
{FRU_FCG, "FCG CHIP"},
|
|
{FRU_DANG, "DANG CHIP"},
|
|
{FRU_HIPPI, "HIPPI ADAPTER"},
|
|
|
|
{FRU_ANIOA, "IO ADAPTERS"},
|
|
|
|
{FRU_VMEDEV, "VME DEVICE or DRIVER SOFTWARE"},
|
|
|
|
{FRU_SCACHE, "SECONDARY CACHE SIMMS"},
|
|
{FRU_PCACHE, "PRIMARY CACHE"},
|
|
{FRU_SYSAD, "SysAd Bus or Other CPUs"},
|
|
|
|
{-1, (char *)0}
|
|
};
|
|
|
|
|
|
/*
|
|
* These are the confidence levels we use to call out errors.
|
|
* The percentages are somewhat arbitrary. We use them only to
|
|
* present something field engineers will be familiar with.
|
|
*/
|
|
char *confidence_strings[NUM_CONFIDENCE_LEVELS] = {
|
|
"Not involved",
|
|
"10%", /* Witnessed error */
|
|
"30%", /* Possible */
|
|
"40%", /* Possible */
|
|
"70%", /* Probable */
|
|
"90%", /* Definite */
|
|
"95%" /* Exact pattern match */
|
|
};
|
|
|
|
|
|
/* Print out a particular diagnosed element. */
|
|
/* ARGSUSED */
|
|
static void print_fru(fru_element_t *element, fru_table_entry_t *entry,
|
|
evcfginfo_t *ec)
|
|
/* ec will be used to determine what's actually a FRU */
|
|
{
|
|
int class;
|
|
|
|
class = element->unit_type & FRU_CLASSMASK;
|
|
|
|
if (element->unit_type & FRUF_SOFTWARE)
|
|
if (!fru_ignore_sw)
|
|
class = FRUC_SOFTWARE;
|
|
else
|
|
FRU_PRINTF("Likely SOFTWARE: ");
|
|
|
|
/* Use class to determine print format. */
|
|
switch (class) {
|
|
|
|
case FRUC_NONE:
|
|
FRU_PRINTF("No error found");
|
|
break;
|
|
|
|
case FRUC_SOFTWARE:
|
|
FRU_PRINTF("Error caused by SOFTWARE");
|
|
break;
|
|
|
|
case FRUC_BOARD:
|
|
FRU_PRINTF("%s", entry->fru_name);
|
|
break;
|
|
|
|
case FRUC_EBUS_ASIC:
|
|
FRU_PRINTF("Integral component (%s)",
|
|
entry->fru_name);
|
|
break;
|
|
|
|
case FRUC_MEM_BANK:
|
|
if (element->unit_num != NO_UNIT) {
|
|
int leaf = element->unit_num >> 2;
|
|
int bank = element->unit_num & 3;
|
|
FRU_PRINTF("%s: leaf %d bank %d (%c)",
|
|
entry->fru_name,
|
|
leaf, bank,
|
|
bank_letter(leaf, bank));
|
|
} else {
|
|
FRU_PRINTF("%s: Can't identify bank",
|
|
entry->fru_name);
|
|
}
|
|
break;
|
|
|
|
case FRUC_IOA:
|
|
FRU_PRINTF("%s (IO adapter %d)", entry->fru_name,
|
|
element->unit_num);
|
|
break;
|
|
|
|
case FRUC_FCIDEV:
|
|
FRU_PRINTF("%s attached to F chip IO adapter %d",
|
|
entry->fru_name, element->unit_num);
|
|
break;
|
|
|
|
case FRUC_CPUSLICE:
|
|
FRU_PRINTF("CPU slice %d (%s)",
|
|
element->unit_num, entry->fru_name);
|
|
break;
|
|
|
|
case FRUC_ONEOF:
|
|
FRU_PRINTF("ONE OF THE %s", entry->fru_name);
|
|
break;
|
|
|
|
case FRUC_VMEDEV:
|
|
FRU_PRINTF("%s, VME bus adapter %d, address 0x%llx",
|
|
entry->fru_name, element->unit_num,
|
|
element->unit_address);
|
|
break;
|
|
|
|
default:
|
|
FRU_PRINTF("Unknown FRU class (0x%x) %s", class,
|
|
entry->fru_name);
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
/* Decode a FRU identifier and get its hum,an readable name. */
|
|
void decode_fru(fru_element_t *element, evcfginfo_t *ec)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; fru_table[i].fru_name; i++) {
|
|
if (fru_table[i].fru_id == (FRU_MASK & element->unit_type)) {
|
|
print_fru(element, &(fru_table[i]), ec);
|
|
return;
|
|
}
|
|
}
|
|
|
|
FRU_PRINTF("Can't decode FRU (0x%x)", element->unit_type);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/* Convert a board type to a string. */
|
|
char *type_to_string(int board)
|
|
{
|
|
switch(board) {
|
|
case EVTYPE_IP19:
|
|
return "IP19";
|
|
case EVTYPE_IP21:
|
|
return "IP21";
|
|
case EVTYPE_MC3:
|
|
return "MC3";
|
|
case EVTYPE_IO4:
|
|
return "IO4";
|
|
}
|
|
return "Unknown";
|
|
}
|
|
|
|
|
|
/* Print which board a display applies to. */
|
|
/* ARGSUSED */
|
|
void decode_board(whatswrong_t *ww, evcfginfo_t *ec)
|
|
/* ec will be used to determine what's actually a FRU */
|
|
{
|
|
/* Don't print the board if we think it's a software error. */
|
|
if ((FRU_CLASS(ww->src.unit_type) == FRUC_SOFTWARE) ||
|
|
(!fru_ignore_sw && (ww->src.unit_type & FRUF_SOFTWARE))) {
|
|
FRU_PRINTF(FRU_INDENT "++ ");
|
|
return;
|
|
}
|
|
if (FRU_CLASS(ww->src.unit_type) == FRUC_BOARD)
|
|
FRU_PRINTF(FRU_INDENT "++ ");
|
|
else
|
|
FRU_PRINTF(FRU_INDENT "++ on the ");
|
|
FRU_PRINTF("%s board in slot %d: ",
|
|
type_to_string(ww->board_type),
|
|
ww->slot_num);
|
|
}
|
|
|
|
|
|
/*
|
|
* Display the information stored in a whatswrong_t - That is, all information
|
|
* about devices connected to a particular Ebus slot.
|
|
*/
|
|
void display_whatswrong(whatswrong_t *ww, evcfginfo_t *ec)
|
|
{
|
|
FRU_PRINTF(FRU_INDENT "++ ");
|
|
if (ww->src.unit_type && ww->dest.unit_type) {
|
|
decode_fru(&(ww->src), ec);
|
|
FRU_PRINTF("\n" FRU_INDENT "++ and/or ");
|
|
decode_fru(&(ww->dest), ec);
|
|
FRU_PRINTF("\n");
|
|
} else {
|
|
if (ww->src.unit_type)
|
|
decode_fru(&(ww->src), ec);
|
|
else if (ww->dest.unit_type)
|
|
decode_fru(&(ww->dest), ec);
|
|
FRU_PRINTF("\n");
|
|
}
|
|
decode_board(ww, ec);
|
|
|
|
FRU_PRINTF("%s confidence.\n",
|
|
confidence_strings[ww->confidence]);
|
|
return;
|
|
}
|
|
|
|
|