1
0
Files
2022-09-29 17:59:04 +03:00

445 lines
10 KiB
C

/*
* fru_io4.c-
*
* This file contains all of the functions needed to analyze an
* IO4 board and the ASICs connected to it.
*
*/
#include "evfru.h" /* FRU analyzer definitions */
#include <sys/EVEREST/io4.h> /* IA chip */
#include <sys/EVEREST/dang.h> /* DANG chip */
#include <sys/EVEREST/fchip.h> /* F chip */
#include <sys/EVEREST/s1chip.h> /* S1 chip */
#include <sys/EVEREST/vmecc.h> /* VMECC chip */
#include "fru_pattern.h"
/* Forward declarations */
short ioa_to_frutype(unsigned char);
void check_epc(evbrdinfo_t *, everror_t *, whatswrong_t *, int);
void check_dang(evbrdinfo_t *, everror_t *, whatswrong_t *, int);
void check_fchip(evbrdinfo_t *, everror_t *, whatswrong_t *, int);
void check_s1(evbrdinfo_t *, everror_t *, whatswrong_t *, int);
void check_scip(evbrdinfo_t *, everror_t *, whatswrong_t *, int);
void check_vmecc(evbrdinfo_t *, everror_t *, whatswrong_t *, int, int);
void check_fcg(evbrdinfo_t *, everror_t *, whatswrong_t *, int, int);
void check_hippi(evbrdinfo_t *, everror_t *, whatswrong_t *, int, int);
/* ARGSUSED */
void check_io4(evbrdinfo_t *eb, everror_t *ee, everror_ext_t *eex,
whatswrong_t *ww, evcfginfo_t *ec)
/* ec is here to let us tell what's _really_ a FRU */
{
int islot;
int i_error, e_error;
int vid;
fru_element_t e_side, sw;
#ifdef DEBUG
if (fru_debug)
FRU_PRINTF("Check IO4\n");
#endif
e_side.unit_type = FRU_IOBOARD;
e_side.unit_num = NO_UNIT;
vid = eb->eb_io.eb_winnum;
e_error = ee->io4[vid].ebus_error;
#define IO4_E_WITNESS IO4_EBUSERROR_DATA_ERR | \
IO4_EBUSERROR_ADDR_ERR
#define IO4_E_PROBABLE IO4_EBUSERROR_MY_DATA_ERR | \
IO4_EBUSERROR_MY_ADDR_ERR
#define IO4_E_POSSIBLE IO4_EBUSERROR_INVDIRTYCACHE | \
IO4_EBUSERROR_TRANTIMEOUT
#define IO4_E_SOFTWARE IO4_EBUSERROR_BADIOA | \
IO4_EBUSERROR_PIO
#define IO4_E_KNOWNERR 0
/* Read resource timeouts are a nasty case. They _usually_ involve the
* I/O board, but we don't really have a way of knowing which board
* it was.
*/
if (e_error & IO4_EBUSERROR_TIMEOUT) {
fru_element_t bad_ioa;
bad_ioa.unit_type = FRU_ANIOA;
update_confidence(ww, POSSIBLE, &bad_ioa, NO_ELEM);
}
conditional_update(ww, WITNESS, e_error, IO4_E_WITNESS, &e_side, NO_ELEM);
conditional_update(ww, POSSIBLE, e_error, IO4_E_POSSIBLE, &e_side, NO_ELEM);
if (e_error & (IO4_E_SOFTWARE)) {
sw.unit_type = FRU_IOBOARD | FRUF_SOFTWARE;
sw.unit_num = NO_UNIT;
update_confidence(ww, POSSIBLE, &sw, NO_ELEM);
}
conditional_update(ww, PROBABLE, e_error, IO4_E_PROBABLE, &e_side, NO_ELEM);
#ifdef DEBUG
if (fru_debug)
FRU_PRINTF(" e_error = 0x%x\n", e_error);
#endif
i_error = ee->io4[vid].ibus_error;
#define IO4_I_WITNESS
#define IO4_I_PROSSIBLE IO4_IBUSERROR_DMAWDATA | \
IO4_IBUSERROR_PIORESPDATA | \
IO4_IBUSERROR_PIOWDATA | \
IO4_IBUSERROR_IARESP
#define IO4_I_PROBABLE IO4_IBUSERROR_1LVLMAPRESP | \
IO4_IBUSERROR_1LVLMAPDATA | \
IO4_IBUSERROR_2LVLMAPRESP | \
IO4_IBUSERROR_2LVL1MAP
#define IO4_I_KNOWNERR IO4_IBUSERROR_COMMAND | \
IO4_IBUSERROR_PIORESPCMND | \
IO4_IBUSERROR_DMAWCMND | \
IO4_IBUSERROR_PIOWCMND | \
IO4_IBUSERROR_PIORCMND | \
IO4_IBUSERROR_GFXWCMND | \
IO4_IBUSERROR_DMARESPCMND
islot = IO4_IBUSERROR_IOA(i_error);
#ifdef DEBUG
if (fru_debug)
FRU_PRINTF(" i_error = 0x%x\n", i_error);
#endif
for (islot = 1; islot < IO4_MAX_PADAPS; islot++) {
switch(eb->eb_ioarr[islot].ioa_type) {
case IO4_ADAP_SCSI:
break;
case IO4_ADAP_EPC:
check_epc(eb, ee, ww, islot);
break;
case IO4_ADAP_FCHIP:
case IO4_ADAP_VMECC:
case IO4_ADAP_HIPPI:
case IO4_ADAP_FCG:
check_fchip(eb, ee, ww, islot);
break;
case IO4_ADAP_DANG:
check_dang(eb, ee, ww, islot);
break;
case IO4_ADAP_SCIP:
check_scip(eb, ee, ww, islot);
break;
} /* switch */
} /* for islot */
return;
}
/* This guy needs some work. */
/* ARGSUSED */
void check_epc(evbrdinfo_t *eb, everror_t *ee, whatswrong_t *ww, int islot)
{
int ibus_error, ia_np_error1, ia_np_error2, error;
/*
evioacfg_t *ioa;
*/
int vid;
fru_element_t epc_side, e_side;
vid = eb->eb_ioarr[islot].ioa_virtid;
ibus_error = ee->epc[vid].ibus_error;
ia_np_error1 = ee->epc[vid].ia_np_error1;
ia_np_error2 = ee->epc[vid].ia_np_error2;
error = EPC_IERR_IA(ibus_error);
/* Analyze errors from IA to IOA. */
e_side.unit_type = FRU_IA;
e_side.unit_num = NO_UNIT;
epc_side.unit_type = FRU_EPC;
epc_side.unit_num = islot;
error = EPC_IERR_EPC(ibus_error);
#define EPC_IA_KNOWNERR EPC_IERR_EPC_PIOR_CMND | \
EPC_IERR_EPC_DMAR_CMND | \
EPC_IERR_EPC_DMAW_CMND | \
EPC_IERR_EPC_INTR_CMND | \
EPC_IERR_EPC_PIOR_CMNDX | \
EPC_IERR_EPC_DMAR_CMNDX | \
EPC_IERR_EPC_DMAW_CMNDX
conditional_update(ww, DEFINITE, error, EPC_IA_KNOWNERR,
&e_side, &epc_side);
#define EPC_ID_KNOWNERR EPC_IERR_EPC_PIOR_DATA | \
EPC_IERR_EPC_DMAW_DATA | \
EPC_IERR_EPC_PIOR_DATAX | \
EPC_IERR_EPC_DMAW_DATAX
e_side.unit_type = FRU_ID;
conditional_update(ww, DEFINITE, error, EPC_ID_KNOWNERR,
&e_side, &epc_side);
/* Analyze errors on EPC side. */
}
/* ARGSUSED */
void check_s1(evbrdinfo_t *eb, everror_t *ee, whatswrong_t *ww, int islot)
{
#if S1_LATER
int ibus_error, csr, ierr_loglo, ierr_loghi;
evioacfg_t *ioa;
int vid;
#endif
}
void check_fchip(evbrdinfo_t *eb, everror_t *ee, whatswrong_t *ww,
int islot)
{
int error;
evioacfg_t *ioa;
int vid;
fru_element_t ibus_side, f_side, fci_side;
fchiperror_t *fe;
#ifdef DEBUG
if (fru_debug)
FRU_PRINTF("Checking F chip...\n");
#endif
ioa = &(eb->eb_ioarr[islot]);
vid = ioa->ioa_virtid;
switch (ioa->ioa_type) {
case IO4_ADAP_VMECC:
fe = &(ee->fvmecc[vid]);
break;
case IO4_ADAP_HIPPI:
fe = &(ee->fio4hip[vid]);
break;
case IO4_ADAP_FCG:
fe = &(ee->ffcg[vid]);
break;
case IO4_ADAP_FCHIP:
/*
* XXX - Is this a bug? Shall we just assume it's OK? Do we even save info
* in this case?
*/
return;
default:
FRU_PRINTF("evfru: Unknown FCI adapter ioa_type (0x%x)\n",
ioa->ioa_type);
return;
}
error = fe->error;
f_side.unit_type = FRU_F;
f_side.unit_num = islot;
ibus_side.unit_type = FRU_ID;
ibus_side.unit_num = NO_UNIT;
#define F_ID_PROBABLE \
FCHIP_ERROR_TO_IBUS_PIOR_DATA | \
FCHIP_ERROR_FR_IBUS_DMAR_DATA | \
FCHIP_ERROR_FR_IBUS_PIOW_DATA | \
FCHIP_ERROR_TO_IBUS_DMAW_DATA
conditional_update(ww, PROBABLE, error, F_ID_PROBABLE,
&f_side, &ibus_side);
ibus_side.unit_type = FRU_IA;
#define F_IA_PROBABLE \
FCHIP_ERROR_TO_IBUS_CMND | \
FCHIP_ERROR_TO_IBUS_DMAR_TO | \
FCHIP_ERROR_FR_IBUS_CMND | \
FCHIP_ERROR_TO_IBUS_DMAW_CMND | \
FCHIP_ERROR_TO_IBUS_AMAP_CMND | \
FCHIP_ERROR_FR_IBUS_AMAP_DATA | \
FCHIP_ERROR_TO_IBUS_AMAP_TO
/*
* FCHIP_ERROR_FR_IBUS_AMAP_DATA is in here because a failure on the IO
* side will be a single-level map which is stored in the IA chip map RAM.
*/
conditional_update(ww, PROBABLE, error, F_IA_PROBABLE,
&f_side, &ibus_side);
#define F_IA_DEFINITE \
FCHIP_ERROR_FR_IBUS_PIOW_INTRNL | \
FCHIP_ERROR_FR_IBUS_SUPRISE
conditional_update(ww, DEFINITE, error, F_IA_DEFINITE,
&f_side, &ibus_side);
#define F_DEFINITE \
FCHIP_ERROR_DROP_PIOW_MODE | \
FCHIP_ERROR_DROP_DMAW_MODE | \
FCHIP_ERROR_TO_IBUS_INTR_CMND | \
FCHIP_ERROR_FAKE_DMAR_MODE
conditional_update(ww, DEFINITE, error, F_DEFINITE,
&f_side, NO_ELEM);
fci_side.unit_type = ioa_to_frutype(ioa->ioa_type);
fci_side.unit_num = islot;
#define FCI_PROBABLE \
FCHIP_ERROR_FR_FCI_DMAW_DATA | \
FCHIP_ERROR_FR_FCI_PIOR_DATA | \
FCHIP_ERROR_FR_FCI_LOAD_ADDRR
conditional_update(ww, PROBABLE, error, FCI_PROBABLE,
&f_side, &fci_side);
switch (ioa->ioa_type) {
case IO4_ADAP_VMECC:
check_vmecc(eb, ee, ww, islot, vid);
break;
case IO4_ADAP_HIPPI:
check_hippi(eb, ee, ww, islot, vid);
break;
case IO4_ADAP_FCG:
check_fcg(eb, ee, ww, islot, vid);
break;
}
}
/* ARGSUSED */
void check_vmecc(evbrdinfo_t *eb, everror_t *ee, whatswrong_t *ww, int islot,
int vid)
/* We'll need eb to figure out what's really a FRU */
{
int error;
fru_element_t fci_side, vme_side, vmecc_side;
error = ee->vmecc[vid].error;
fci_side.unit_type = FRU_F;
fci_side.unit_num = islot;
vme_side.unit_type = FRU_VMEDEV;
vme_side.unit_num = vid;
vme_side.unit_address = (long long)ee->vmecc[vid].addrvme;
vmecc_side.unit_type = FRU_VMECC;
vmecc_side.unit_num = islot;
#define VMECC_FCI_PROBABLE \
VMECC_ERROR_FCIDB_TO | VMECC_ERROR_FCI_PIOPAR | VMECC_ERROR_VMEBUS_SLVP
conditional_update(ww, PROBABLE, error, VMECC_FCI_PROBABLE,
&fci_side, &vmecc_side);
#define VME_DEFINITE \
VMECC_ERROR_VMEBUS_PIOW | VMECC_ERROR_VMEBUS_PIOR | \
VMECC_ERROR_VMEBUS_TO
conditional_update(ww, DEFINITE, error, VME_DEFINITE,
&vmecc_side, &vme_side);
return;
}
/* ARGSUSED */
void check_fcg(evbrdinfo_t *eb, everror_t *ee, whatswrong_t *ww, int islot,
int vid)
{
return;
}
/* ARGSUSED */
void check_hippi(evbrdinfo_t *eb, everror_t *ee, whatswrong_t *ww, int islot,
int vid)
{
return;
}
/* ARGSUSED */
void check_dang(evbrdinfo_t *eb, everror_t *ee, whatswrong_t *ww,
int islot)
{
}
/* ARGSUSED */
void check_scip(evbrdinfo_t *eb, everror_t *ee, whatswrong_t *ww,
int islot)
{
}
struct ioa_fru_translation {
unsigned char ioa_type;
short fru_type;
} ioa_fru_table[] = {
{ IO4_ADAP_SCSI, FRU_S1 },
{ IO4_ADAP_EPC, FRU_EPC },
{ IO4_ADAP_FCHIP, FRU_F },
{ IO4_ADAP_SCIP, FRU_SCIP },
{ IO4_ADAP_VMECC, FRU_VMECC },
{ IO4_ADAP_HIPPI, FRU_HIPPI },
{ IO4_ADAP_FCG, FRU_FCG },
{ IO4_ADAP_DANG, FRU_DANG },
{ IO4_ADAP_NULL, FRU_NONE }
};
short ioa_to_frutype(unsigned char ioa)
{
int i;
for (i = 0; ioa_fru_table[i].ioa_type; i++) {
if (ioa_fru_table[i].ioa_type == ioa)
return ioa_fru_table[i].fru_type;
}
return FRU_UNKNOWN;
}
#ifdef FRU_PATTERN_MATCHER
int match_io4board(fru_entry_t **token, everror_t *errbuf, evcfginfo_t *ecbuf,
whatswrong_t *ww, fru_case_t *case_ptr)
{
*token = find_board_end(*token);
return 1;
}
#endif /* FRU_PATTERN_MATCHER */