1
0
Files
irix-657m-src/stand/arcs/lib/libkl/fru/sn0_fru_analysis.c
2022-09-29 17:59:04 +03:00

1806 lines
45 KiB
C

/**************************************************************************
* *
* Copyright (C) 1992-1996, Silicon Graphics, Inc. *
* *
* These coded instructions, statements, and computer programs contain *
* unpublished proprietary information of Silicon Graphics, Inc., and *
* are protected by Federal copyright law. They may not be disclosed *
* to third parties or copied or duplicated in any form, in whole or *
* in part, without the prior written consent of Silicon Graphics, Inc. *
* *
**************************************************************************/
#include <sys/types.h>
#include <libkl.h>
#include <sys/SN/klconfig.h>
#include <sys/SN/error.h>
#include <sys/SN/slotnum.h>
#if !defined(FRUTEST) && !defined(_STANDALONE)
#include "../sn0_private.h"
#include <sys/debug.h>
#endif /* FRUTEST */
#include "sn0_fru_analysis.h"
#include <sys/SN/SN0/ip27config.h>
#ifdef FRUTEST
extern kl_config_hdr_t g_node[];
extern confidence_t g_io_conf;
extern confidence_t g_sn0net_conf;
extern confidence_t g_xbow_conf;
#endif /* #ifdef FRUTEST */
#if defined(_STANDALONE)
#include <sys/SN/promcfg.h>
extern nasid_t get_nasid(void);
#else
extern int numnodes;
#endif /* _STANDALONE */
/*
* some global table declarations which are needed by the fru analyzer
*/
extern kf_rule_t kf_rule_tab[]; /* table of rule encodings */
extern kf_cond_t kf_cond_tab[]; /* table of condition encodings */
extern kf_action_set_t kf_action_set_tab[]; /* table of action set encodings */
confidence_t *kf_conf_tab[MAX_COMPS]; /* table of component confidence
* level pointers
*/
hubreg_t kf_reg_tab[MAX_ERR_REGS]; /* table of error register
* pointers
*/
kf_analysis_t kf_analysis[MAX_GUESSES]; /* final analysis array */
int (*kf_printf)(const char *,...); /* printf function */
int sn0_fru_enabled = 1; /* to dynamically allow the fru analysis
* to be turned off in the debugger
*/
confidence_t software_confidence = 0; /* placeholder for fru's software
* confidence
*/
kf_hint_t node_hint[MAXCPUS / 2]; /* hints to the fru on a per-processor
* basis
*/
char *fru_hint_table[] = {
"kernel fault",
"cache error"
};
int fru_hint_table_size = sizeof(fru_hint_table) /
sizeof(fru_hint_table[0]);
int kf_print_where = KF_PRINT_CONSOLE; /* default */
#if defined(_STANDALONE)
int fru_disable_confidence = ABSOLUTE_CONFIDENCE;
/*never disable in prom*/
#else
extern int fru_disable_confidence; /* mtune variable */
#endif
/*
* get the cpu error info for a cpu of a given virtual id
* ARGSUSED
*/
klcpu_err_t *
kf_cpu_err_info_get(lboard_t *board,klinfo_t **prev_cpu_comp,cpuid_t id)
{
klinfo_t *cpu_data;
klcpu_err_t *cpu_err;
/* get the cpu component info for this cpu id */
id = id;
cpu_data = find_component(board,*prev_cpu_comp,KLSTRUCT_CPU);
*prev_cpu_comp = cpu_data;
if (!cpu_data)
return NULL;
/* pull out the error info out of the component info */
cpu_err = CPU_COMP_ERROR(board,cpu_data);
KF_ASSERT(cpu_err);
return cpu_err;
}
/*
* get the error info associated with the hub which lies on the
* given IP27 board
*/
klhub_err_t *
kf_hub_err_info_get(lboard_t *board)
{
klinfo_t *hub_data;
klhub_err_t *hub_err;
/* get the hub component info */
hub_data = find_first_component(board,KLSTRUCT_HUB);
KF_ASSERT(hub_data);
/* pull out the error info out of the component info */
hub_err = HUB_COMP_ERROR(board,hub_data);
KF_ASSERT(hub_err);
return hub_err;
}
/*
* get the router error info of the router component
* on a given router board
*/
klrouter_err_t *
kf_router_err_info_get(lboard_t *board)
{
klinfo_t *router_data;
klrouter_err_t *router_err;
lboard_t *router_board;
/* get the router board info */
router_board = find_lboard(board,KLTYPE_ROUTER2);
if (!router_board)
return NULL; /* might be a 2-cpu 1-hub system */
/* get the router component info
*/
router_data = find_first_component(router_board,KLSTRUCT_ROU);
KF_ASSERT(router_data);
/* pull out the error info out of the component info */
router_err = ROU_COMP_ERROR(router_board, router_data);
KF_ASSERT(router_err);
return router_err;
}
/*
* get the address of the confidence level of the memory & the dimm
* on the node corr. to a given physical address
*/
kf_result_t
kf_mem_conf_get(paddr_t addr,
confidence_t **mem_confidence,
confidence_t **dimm_confidence)
{
int dimm;
nasid_t nasid;
lboard_t *board;
klinfo_t *hub_info;
klhub_err_t *hub_err;
nasid = NASID_GET(addr);
dimm = (addr & MEM_DIMM_MASK) >> MEM_DIMM_SHFT;
#ifndef FRUTEST
{
/* get the pointer to the start of the list of boards */
board = (lboard_t *)KL_CONFIG_INFO(nasid);
}
#else
board = (lboard_t *)(g_node[nasid].ch_board_info);
#endif /* #ifdef FRUTEST */
if (!board) {
*mem_confidence = NULL;
*dimm_confidence = NULL;
return KF_FAILURE;
}
/* get the IP27 board structure on this node */
board = find_lboard(board,KLTYPE_IP27);
if (!board) {
*mem_confidence = NULL;
*dimm_confidence = NULL;
return KF_FAILURE;
}
/* get the hub component of this IP27 board */
hub_info = KLCF_COMP(board,IP27_HUB_INDEX);
KF_ASSERT(hub_info);
/* get the hub error structure */
hub_err = HUB_COMP_ERROR(board,hub_info);
KF_ASSERT(hub_err);
/* finally get the reqd. mem confidence level address */
*mem_confidence = &(KF_MEM_CONF(hub_err));
*dimm_confidence = &(KF_DIMM_CONF(hub_err,dimm));
return KF_SUCCESS;
}
/*
* build the node part of the register address table and confidence level address table
* by traversing the klconfig structure
* SASHA will be building the io side of these tables
*/
kf_result_t
kf_node_tables_build(nasid_t nasid)
{
lboard_t *board;
klcpu_err_t *cpu_err; /* cpu error info */
klhub_err_t *hub_err; /* hub error info */
klrouter_err_t *router_err; /* router error info */
int i;
klinfo_t *cpu_comp;
#ifdef FRUTEST
board = (lboard_t *)g_node[nasid].ch_board_info;
#else
board = (lboard_t *)KL_CONFIG_INFO(nasid);
#endif /* #ifdef FRUTEST */
board = find_lboard(board,KLTYPE_IP27);
cpu_comp = NULL;
/* get the cpuA error info for this ip27 board */
cpu_err = kf_cpu_err_info_get(board,&cpu_comp,0);
if (cpu_err) {
/* store the pointer to the cpuA cache error register
* in the error register address table
*/
kf_reg_tab[KF_CACHE_ERR0_INDEX] = cpu_err->ce_cache_err_dmp.ce_cache_err;
/* store the pointer to the confidence level of cpuA */
kf_conf_tab[KF_CPU0_CONF_INDEX] = &KF_CPU_CONF(cpu_err);
kf_conf_tab[KF_IC0_CONF_INDEX] = &KF_ICACHE_CONF(cpu_err);
kf_conf_tab[KF_DC0_CONF_INDEX] = &KF_DCACHE_CONF(cpu_err);
kf_conf_tab[KF_SC0_CONF_INDEX] = &KF_SCACHE_CONF(cpu_err);
}
/* get the cpuB error info for this ip27 board */
cpu_err = kf_cpu_err_info_get(board,&cpu_comp,1);
if (cpu_err) {
/* store the pointer to the cpuB cache error register
* in the error register address table
*/
kf_reg_tab[KF_CACHE_ERR1_INDEX] = cpu_err->ce_cache_err_dmp.ce_cache_err;
/* store the pointer to the confidence level of cpuB */
kf_conf_tab[KF_CPU1_CONF_INDEX] = &KF_CPU_CONF(cpu_err);
kf_conf_tab[KF_IC1_CONF_INDEX] = &KF_ICACHE_CONF(cpu_err);
kf_conf_tab[KF_DC1_CONF_INDEX] = &KF_DCACHE_CONF(cpu_err);
kf_conf_tab[KF_SC1_CONF_INDEX] = &KF_SCACHE_CONF(cpu_err);
}
/* get the hub error info for the hub in this ip27 board */
hub_err = kf_hub_err_info_get(board);
KF_ASSERT(hub_err);
/*
* store the addresses of the hub error registers in the register address
* table
*/
kf_reg_tab[KF_PI_ERR_INT_PEND_INDEX] = KF_PI_ERR_INT_PEND(hub_err);
kf_reg_tab[KF_PI_ERR_STS0_A_INDEX] = KF_PI_ERR_STS0_A(hub_err);
kf_reg_tab[KF_PI_ERR_STS0_B_INDEX] = KF_PI_ERR_STS0_B(hub_err);
kf_reg_tab[KF_PI_ERR_STS1_A_INDEX] = KF_PI_ERR_STS1_A(hub_err);
kf_reg_tab[KF_PI_ERR_STS1_B_INDEX] = KF_PI_ERR_STS1_B(hub_err);
kf_reg_tab[KF_MD_DIR_ERR_INDEX] = KF_MD_DIR_ERR(hub_err);
kf_reg_tab[KF_MD_MEM_ERR_INDEX] = KF_MD_MEM_ERR(hub_err);
kf_reg_tab[KF_MD_PROTO_ERR_INDEX] = KF_MD_PROTO_ERR(hub_err);
kf_reg_tab[KF_MD_MISC_ERR_INDEX] = KF_MD_MISC_ERR(hub_err);
kf_reg_tab[KF_II_WIDGET_STATUS_INDEX] = KF_II_WIDGET_STATUS(hub_err);
for(i = 0 ; i < IIO_NUM_CRBS;i++)
kf_reg_tab[KF_II_CRB_ENT0_A_INDEX + i] = KF_II_CRB_ENTA(hub_err,i);
kf_reg_tab[KF_II_BTE0_STS_INDEX] = KF_II_BTE0_STS(hub_err);
kf_reg_tab[KF_II_BTE1_STS_INDEX] = KF_II_BTE1_STS(hub_err);
kf_reg_tab[KF_II_BTE0_SRC_INDEX] = KF_II_BTE0_SRC(hub_err);
kf_reg_tab[KF_II_BTE1_SRC_INDEX] = KF_II_BTE1_SRC(hub_err);
kf_reg_tab[KF_II_BTE0_DST_INDEX] = KF_II_BTE0_DST(hub_err);
kf_reg_tab[KF_II_BTE1_DST_INDEX] = KF_II_BTE1_DST(hub_err);
kf_reg_tab[KF_NI_VECT_STS_INDEX] = KF_NI_VECT_STS(hub_err);
kf_reg_tab[KF_NI_PORT_ERR_INDEX] = KF_NI_PORT_ERR(hub_err);
/* hub error info structure contains the confidence levels of
* hub , sysbus (connection to the processors), mem banks ,
* directory & memory buses. get them
*/
kf_conf_tab[KF_SYSBUS_CONF_INDEX] = &KF_SYSBUS_CONF(hub_err);
kf_conf_tab[KF_HUB_CONF_INDEX] = &KF_HUB_CONF(hub_err);
kf_conf_tab[KF_HUB_LINK_CONF_INDEX] = &KF_HUB_LINK_CONF(hub_err);
kf_conf_tab[KF_PI_CONF_INDEX] = &KF_PI_CONF(hub_err);
kf_conf_tab[KF_MD_CONF_INDEX] = &KF_MD_CONF(hub_err);
kf_conf_tab[KF_II_CONF_INDEX] = &KF_II_CONF(hub_err);
kf_conf_tab[KF_NI_CONF_INDEX] = &KF_NI_CONF(hub_err);
kf_conf_tab[KF_MEM_CONF_INDEX] = &KF_MEM_CONF(hub_err);
for (i = 0; i < MAX_DIMMS; i++)
kf_conf_tab[KF_DIMM0_CONF_INDEX + i] = &KF_DIMM_CONF(hub_err,i);
/* get the router error info of the router connected to the
* hub on this ip27 board.
* pretty sure that router is a separate board as opposed to
* being a component on the ip27 board.
* should change this properly.
*/
router_err = kf_router_err_info_get(board);
if (router_err) {
kf_conf_tab[KF_ROUTER_CONF_INDEX] = &KF_ROUTER_CONF(router_err);
for (i = 0; i < MAX_ROUTER_PORTS; i++) {
kf_conf_tab[KF_ROUTER_LINK0_CONF_INDEX + i] = &KF_ROUTER_LINK_CONF(router_err,i);
kf_reg_tab[KF_ROUTER_STS_ERR0_INDEX + i] = KF_ROUTER_STS_ERR(router_err,i);
}
}
#ifdef FRUTEST
/* right now io confidence is a separate variable.
* should incorporate this along with other confidence levels
* in the klconfig or change the relevant rules
*/
kf_conf_tab[KF_SOFTWARE_CONF_INDEX] = &(g_node[nasid].ch_sw_belief);
kf_conf_tab[KF_XBOW_CONF_INDEX] = &g_xbow_conf;
#else
kf_conf_tab[KF_SOFTWARE_CONF_INDEX] = &(software_confidence);
#endif /* #ifdef FRUTEST */
return KF_SUCCESS;
}
/*
* compute whether the condition of a rule is true or false
*/
hubreg_t
kf_condition_compute(kf_cond_t *cond) {
hubreg_t eval_stack[MAX_COND_ELEMENTS];
/* temporary place to hold the partially
* evaluated condition
*/
kf_cond_t *curr_pos = cond; /* start at the beginning of the condition */
int top = -1; /* the index into the buffer where the next
* literal will be inserted
* -1 indicates the buffer is empty
*/
/* keep on going until the end of condition is reached */
while(curr_pos->kc_type != KF_LIST_SENTINEL) {
if (curr_pos->kc_type == KC_OPERAND) {
/* currently we are looking at an operand in the condition
* perform the operation associated with the operand
*/
switch(KF_OPERAND(curr_pos)) {
case KF_AND:
{
if (top < 1)
return KF_FALSE;
eval_stack[top-1] = eval_stack[top - 1] && eval_stack[top];
/* do a boolean-and of the top 2
* bits in the eval_stack
*/
top--;
break;
}
case KF_OR:
{
if (top < 1)
return KF_FALSE;
eval_stack[top-1] = eval_stack[top - 1] || eval_stack[top];
/* do a boolean-or of the top 2
* bits in the eval_stack
*/
top--;
break;
}
case KF_NOT:
{
if (top < 0)
return KF_FALSE;
eval_stack[top] = !eval_stack[top];
/* do a boolean-not of the top
* bit in the eval_stack
*/
break;
}
}
} else {
/* currently we are looking at a literal in the condition
* evaluate it and put it on the eval stack
*/
top++;
eval_stack[top] = KF_LITERAL_EVAL(curr_pos);
}
curr_pos++;
}
return eval_stack[0];
}
/*
* perform the set of actions associated with a rule
*/
kf_result_t
kf_action_set_perform(kf_action_set_t *act_set)
{
kf_action_set_t *p = act_set;
while(p->kas_type != KF_LIST_SENTINEL) {
if (p->kas_type == KAS_ACTION) {
if (kf_conf_tab[p->kas_conf_index]) {
KF_CONF_UPDATE(*kf_conf_tab[p->kas_conf_index],
p->kas_conf_val);
}
#ifdef FRU_DEBUG_RULES
else {
kf_print("Warning: conf tab index %d is NULL\n",
p->kas_conf_index);
}
#endif
}
p++;
}
return KF_SUCCESS;
}
/*
* trigger a rule
* should do proper validation
*/
kf_result_t
kf_rule_trigger(kf_rule_t *rule)
{
if (kf_condition_compute(&kf_cond_tab[rule->kr_cond_tab_index])) {
if (kf_action_set_perform(&kf_action_set_tab[rule->kr_action_set_tab_index]) != KF_SUCCESS)
return KF_FAILURE;
KF_DEBUG_RULES("*\t\t\t\t\t\trule (%d , %d) triggered\n",
rule->kr_cond_tab_index,
rule->kr_action_set_tab_index);
}
return KF_SUCCESS;
}
extern nasid_t current_nasid; /* nasid of the node whose
* error state is being analyzed
*/
/*
* analyze the list of local boards on a node
* for now we do ip27 analysis followed by router analysis
* some work needs to be done on this function
*/
kf_result_t
kf_node_analyze(nasid_t nasid,kf_analysis_t *curr_analysis)
{
lboard_t *board;
kf_result_t rv = KF_SUCCESS;
#ifdef _STANDALONE
int i;
#endif
KF_DEBUG("kf_node_analyze:doing node %d analysis......\n",nasid);
current_nasid = nasid;
#ifndef FRUTEST
/* Make sure that klconfig is setup properly */
if (!(KL_CONFIG_CHECK_MAGIC(nasid))) {
printf("FRU:Local klconfig not setup properly\n");
return KF_FAILURE;
}
#endif
if (kf_node_tables_build(nasid) == KF_FAILURE)
return KF_FAILURE; /* build the kf_conf_tab & kf_reg_tab */
#ifdef FRUTEST
board = find_lboard((lboard_t *)g_node[nasid].ch_board_info,KLTYPE_IP27);
#else
board = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid),KLTYPE_IP27);
#endif /* #ifdef FRUTEST */
if (curr_analysis) {
/* Remember the nasid of the node for which this analysis
* is being collected
*/
curr_analysis->kfa_nasid = nasid;
curr_analysis->kfa_io_board = 0;
curr_analysis->kfa_serial_number[0] = 0;
if (kf_conf_tab[KF_SOFTWARE_CONF_INDEX] &&
*kf_conf_tab[KF_SOFTWARE_CONF_INDEX]) {
curr_analysis->kfa_info[KF_SOFTWARE_LEVEL].kfi_type = KFTYPE_SOFTWARE;
curr_analysis->kfa_info[KF_SOFTWARE_LEVEL].kfi_inst = 0;
curr_analysis->kfa_conf = *kf_conf_tab[KF_SOFTWARE_CONF_INDEX];
kf_guess_put(curr_analysis);
}
curr_analysis->kfa_info[KF_MODULE_LEVEL].kfi_type = KFTYPE_MODULE;
curr_analysis->kfa_info[KF_MODULE_LEVEL].kfi_inst = KLCF_MODULE_ID(board);
curr_analysis->kfa_conf = 0;
} else {
#ifdef _STANDALONE
/* Initiliaze all the confidences (except io frus)to zeroes */
for(i = 0 ; i <= KF_SOFTWARE_CONF_INDEX; i++)
if (kf_conf_tab[i])
*kf_conf_tab[i] = 0;
#endif
/* If there is a kernel fault hint suspect the software */
KF_CONDITIONAL_UPDATE(kf_conf_tab[KF_SOFTWARE_CONF_INDEX],
(node_hint[nasid].kh_hint_type == KF_HINT_KERNEL_FAULT),
90);
}
/* do the io analysis first so that xbow conf pointers etc.
* get set up
*/
kf_io_analyze(nasid,curr_analysis);
/* analyze the ip27 board first and then analyze the router board */
while (board) {
rv = kf_board_analyze(board,curr_analysis); /* analyze the current board */
if (rv != KF_SUCCESS)
return rv;
board = KLCF_NEXT(board); /* go to the next board on this
* node
*/
}
KF_DEBUG("kf_node_analyze:finished node %d analysis\n",nasid);
return rv;
}
kf_result_t
kf_rule_tab_analyze(int start_index)
{
int i = start_index;
KF_DEBUG("\t\t\t\t\tdoing rule table driven analysis.......\n");
while (kf_rule_tab[i].kr_cond_tab_index != KF_LIST_SENTINEL) {
if (kf_rule_trigger(&kf_rule_tab[i]) != KF_SUCCESS)
return KF_FAILURE;
i++;
}
KF_DEBUG("\t\t\t\t\tfinished rule table driven analysis\n");
return KF_SUCCESS;
}
#ifndef FRUTEST
/* entry point into the fru analyzer */
int
sn0_fru_entry(int (*print)(const char *,...))
{
int cnode;
kf_analysis_t curr_analysis;
#if defined(_STANDALONE)
/* Traversed nodes is used to keep track off the way
* we traverse the nodes. It can be done either
* through the GDA or Prom config.
*/
int traversed_nodes = 0;
gda_t *gdap = GDA;
pcfg_hub_t *hub_cf;
#else
static int nestedcall = 0;
/* to eliminate recursive calls to fru code */
if (nestedcall)
return KF_FAILURE;
else
nestedcall = 1;
#endif
kf_printf = print;
/* Print the starting fru analysis message */
kf_fru_begin_msg_print();
/* analyze the various nodes in the system */
#if !defined(_STANDALONE)
for(cnode = 0; cnode < numnodes; cnode++) {
nasid_t nasid;
nasid = COMPACT_TO_NASID_NODEID(cnode);
if (kf_node_analyze(nasid,NULL) == KF_FAILURE)
kf_print("FRU : node (cnodeid = %d , nasid = %d)analysis failed\n",
cnode,nasid);
}
#else
/* initiliaze the node hint table */
for(cnode = 0 ; cnode < MAXCPUS / 2 ; cnode++)
node_hint[cnode].kh_hint_type = -1;
if ((gdap) && (gdap->g_magic == GDA_MAGIC) &&
(gdap->g_nasidtable[1] != INVALID_NASID)) {
nasid_t nasid;
traversed_nodes = 1;
for (cnode = 0; cnode < MAX_COMPACT_NODES; cnode++) {
if ((nasid = gdap->g_nasidtable[cnode]) ==
INVALID_NASID)
continue;
if (kf_node_analyze(nasid,NULL) == KF_FAILURE)
kf_print("FRU : node (cnodeid = %d ,"
"nasid = %d) analysis failed\n",
cnode,nasid);
}
}
if (traversed_nodes == 0) {
/* Do the analysis for the node which started
* fru analysis first.
*/
if (kf_node_analyze(get_nasid(),NULL)
== KF_FAILURE)
kf_print("FRU : node (cnodeid = %d ,"
"nasid = %d) analysis failed\n",
cnode,get_nasid());
for(cnode = 0; cnode < PCFG(get_nasid())->count;cnode++) {
nasid_t nasid;
hub_cf = &PCFG_PTR(get_nasid(),cnode)->hub;
if (hub_cf->type != PCFG_TYPE_HUB)
continue;
if (((nasid = hub_cf->nasid) != INVALID_NASID) &&
(nasid != get_nasid())) {
if (kf_node_analyze(nasid,NULL) == KF_FAILURE)
kf_print("FRU : node (cnodeid = %d ,"
"nasid = %d) analysis failed\n",
cnode,nasid);
}
}
}
else
traversed_nodes = 0;
#endif /* !_STANDALONE */
/* do this initialization once so that all the
* node analyses' guesses are preserved
*/
kf_analysis_tab_init();
/* analyze the various nodes in the system */
#if !defined(_STANDALONE)
for(cnode = 0; cnode < numnodes; cnode++) {
nasid_t nasid;
nasid = COMPACT_TO_NASID_NODEID(cnode);
kf_analysis_init(&curr_analysis);
if (kf_node_analyze(nasid,&curr_analysis) == KF_FAILURE)
kf_print("FRU : node (cnodeid = %d , nasid = %d)analysis failed\n",
cnode,nasid);
}
#else
if ((gdap) && (gdap->g_magic == GDA_MAGIC) &&
(gdap->g_nasidtable[1] != INVALID_NASID)) {
nasid_t nasid;
traversed_nodes = 1;
for (cnode = 0; cnode < MAX_COMPACT_NODES; cnode++) {
if ((nasid = gdap->g_nasidtable[cnode]) ==
INVALID_NASID)
continue;
kf_analysis_init(&curr_analysis);
if (kf_node_analyze(nasid,&curr_analysis) == KF_FAILURE)
kf_print("FRU : node (cnodeid = %d ,"
"nasid = %d) analysis failed\n",
cnode,nasid);
}
}
if (traversed_nodes == 0) {
kf_analysis_init(&curr_analysis);
/* Do the analysis for the node which started
* fru analysis first.
*/
if (kf_node_analyze(get_nasid(),&curr_analysis)
== KF_FAILURE)
kf_print("FRU : node (cnodeid = %d ,"
"nasid = %d) analysis failed\n",
cnode,get_nasid());
for(cnode = 0; cnode < PCFG(get_nasid())->count;cnode++) {
nasid_t nasid;
hub_cf = &PCFG_PTR(get_nasid(),cnode)->hub;
if (hub_cf->type != PCFG_TYPE_HUB)
continue;
if (((nasid = hub_cf->nasid) != INVALID_NASID) &&
(nasid != get_nasid())) {
kf_analysis_init(&curr_analysis);
if (kf_node_analyze(nasid,&curr_analysis)
== KF_FAILURE)
kf_print("FRU : node (cnodeid = %d ,"
"nasid = %d) analysis failed\n",
cnode,nasid);
}
}
} else
traversed_nodes = 0;
#endif /* !_STANDALONE */
#ifdef DEBUG
kf_fru_summary_print(MAX_GUESSES);
#else
kf_fru_summary_print(1);
#endif
return 1;
}
#endif
/* check if two analysis structure are equal in terms
* of the heirarchical path they correspond to
* if they are equal then if analysis a2's confidence is more
* than that of a1's then return 2 otherwise return 1
* this function is used when trying to find an analysis guess
* with the least confidence level in the global array of guesses.
* basically we try to see if there is already an analysis guess
* which is identical to the current analysis guess that we are
* trying to store. if there is one store the one with the higher
* confidence level.
*/
int
kf_analysis_eq(kf_analysis_t *a1,kf_analysis_t *a2)
{
int level;
for (level = 0 ; level < MAX_LEVELS; level++) {
if ((a1->kfa_info[level].kfi_type != a2->kfa_info[level].kfi_type) ||
(a1->kfa_info[level].kfi_inst != a2->kfa_info[level].kfi_inst))
return 0;
}
return ((a1->kfa_conf > a2->kfa_conf) ? 1 : 2 );
}
/* removes the analysis guess with the lower confidence
* level if two identical analysis guesses were found
*/
int
kf_analysis_dup_remove(kf_analysis_t *a)
{
int guess;
for (guess = 0; guess < MAX_GUESSES; guess++) {
if (kf_analysis_eq(&kf_analysis[guess],a) == 2) {
kf_analysis[guess] = *a;
return 1;
}
}
return 0;
}
/* find the analysis guess among the list of stored analysis
* guesses which corresponds to the lowest confidence level
*/
kf_analysis_t *
kf_analysis_info_find_least(kf_analysis_t *curr_analysis)
{
int i;
kf_analysis_t *min_analysis;
if (kf_analysis_dup_remove(curr_analysis))
return NULL;
min_analysis = &(kf_analysis[0]);
for(i = 0 ; i < MAX_GUESSES; i++) {
if (min_analysis->kfa_conf > kf_analysis[i].kfa_conf)
min_analysis = &(kf_analysis[i]);
}
return min_analysis;
}
/* put the current analysis guess in the table of guesses
* if there is a guess with a lower confidence level
*/
kf_result_t
kf_guess_put(kf_analysis_t *curr_analysis)
{
kf_analysis_t save_curr_analysis;
kf_analysis_t *least_conf_anal_info;
save_curr_analysis = *curr_analysis;
if ((least_conf_anal_info = kf_analysis_info_find_least(curr_analysis)) == NULL) {
*curr_analysis = save_curr_analysis;
return KF_SUCCESS;
}
if (least_conf_anal_info->kfa_conf < curr_analysis->kfa_conf) {
*least_conf_anal_info = *curr_analysis;
}
*curr_analysis = save_curr_analysis;
return KF_SUCCESS;
}
/* initialize an analysis guess */
void
kf_analysis_init(kf_analysis_t *analysis)
{
int level;
for(level = 0 ; level < MAX_LEVELS; level++) {
analysis->kfa_info[level].kfi_type = KF_UNKNOWN;
analysis->kfa_info[level].kfi_inst = KF_UNKNOWN;
}
}
/* initialize the list of analysis guesses */
void
kf_analysis_tab_init(void)
{
int guess;
for (guess = 0 ; guess < MAX_GUESSES; guess++) {
kf_analysis[guess].kfa_conf = 0;
kf_analysis_init(&kf_analysis[guess]);
}
}
typedef struct fru_name_s {
int type;
char type_name[30];
} fru_name_t;
#if defined(DEBUG) && !defined(_STANDALONE)
char error_msg[25];
#endif
char *
type_name_get(int type,fru_name_t *name,int len)
{
int i;
for (i = 0 ; i < len ; i++)
if (type == name[i].type)
return name[i].type_name;
return "unknown";
}
/* print out an analysis guess */
#define KF_TYPE_NAME_LEN sizeof(type_name)/ sizeof(fru_name_t)
void
kf_bridge_analysis_print(kf_analysis_t *anal, int level,
fru_name_t type_name[], int name_len)
{
int type = anal->kfa_info[++level].kfi_type;
/* if there is something below the bridge? */
switch (type) {
case KFTYPE_BRIDGE_PCI_DEV:
kf_print("/%s/%d\t\t: %d%%\n",
type_name_get(type,type_name,name_len),
anal->kfa_info[level].kfi_inst,
anal->kfa_conf);
#if !defined(FRUTEST) && !defined(_STANDALONE)
if (anal->kfa_conf >= fru_disable_confidence) {
kf_pci_component_disable(
anal->kfa_io_board,
anal->kfa_info[KF_MODULE_LEVEL].kfi_inst,
anal->kfa_info[KF_WIDGET_LEVEL].kfi_inst,
anal->kfa_info[KF_BRIDGE_PCI_DEV_LEVEL].kfi_inst);
}
#endif /* !FRUTEST && !_STANDALONE */
break;
case KFTYPE_BRIDGE_SSRAM:
kf_print("/bridge/%s\t: %d%%\n",
type_name_get(type,type_name,name_len),
anal->kfa_conf);
break;
case KFTYPE_BRIDGE_LINK:
kf_print("/%s\t\t: %d%%\n",
type_name_get(type,type_name,name_len),
anal->kfa_conf);
break;
/* nope,the bridge is the suspected component */
case KF_UNKNOWN:
type = anal->kfa_info[--level].kfi_type;
kf_print("/bridge\t\t: %d%%\n",
anal->kfa_conf);
break;
default:
#ifdef DEBUG
kf_print("\nError: Unknown KF_TYPE %d line: %d file:%s\n",
type, __LINE__, __FILE__);
#else
kf_print("<undefined>\n");
#endif
break;
}
}
void
kf_cpu_analysis_print(kf_analysis_t *anal, int level, fru_name_t type_name[],
int name_len)
{
int type = anal->kfa_info[++level].kfi_type;
int slice = anal->kfa_info[level - 1].kfi_inst ;
#if !defined(FRUTEST) && !defined(_STANDALONE)
/* If the confidence is more than the tunable "fru_disable_confidence"
* then disable the cpu
*/
if (anal->kfa_conf >= fru_disable_confidence)
kf_cpu_disable(slice,anal->kfa_nasid);
#endif /* !FRUTEST && !_STANDALONE */
kf_print("/cpu/%c", (slice ? 'b' : 'a'));
if (type == KF_UNKNOWN) {
type = anal->kfa_info[--level].kfi_type;
kf_print("\t\t\t: %d%%\n", anal->kfa_conf);
}
else {
kf_print("/%s\t\t: %d%%\n",
type_name_get(type,type_name,name_len),
anal->kfa_conf);
}
}
void
kf_memory_analysis_print(kf_analysis_t *anal, int level,
fru_name_t type_name[], int name_len)
{
int type = anal->kfa_info[++level].kfi_type;
int bank_dimm = anal->kfa_info[level].kfi_inst;
if (type == KFTYPE_DIMM0) {
#if !defined(FRUTEST) && !defined(_STANDALONE)
/* Disable the bank if the confidence is above the
* tunable "fru_disable_confidence"
*/
if (anal->kfa_conf >= fru_disable_confidence)
kf_memory_bank_disable(bank_dimm,anal->kfa_nasid);
#endif /* !FRUTEST && !_STANDALONE */
#ifdef FRUTEST
if (0) {
#else
if (SN00) {
#endif
/* Speedo dimm callout
* bank 0 --> slots 1 & 2
* bank 1 --> slots 3 & 4
* bank 2 --> slots 5 & 6
* bank 3 --> slots 7 & 8
*/
if (bank_dimm < MAX_DIMM_BANKS_SN00)
kf_print("/%s/%d\n++\t\t\t\t"
"[Physical Bank Labels %d or %d]\t\t: %d%%\n",
type_name_get(type,type_name,name_len),
anal->kfa_info[level].kfi_inst,
bank_dimm * 2 + 1,
bank_dimm * 2 + 2,
anal->kfa_conf);
else
kf_print("/%s/%d\n++\t\t\t\t: %d%%\n",
type_name_get(type,type_name,name_len),
anal->kfa_info[level].kfi_inst,
anal->kfa_conf);
} else {
/* Lego dimm callout */
kf_print("/%s/%d\n++\t\t",
type_name_get(type,type_name,name_len),
anal->kfa_info[level].kfi_inst);
kf_print("[MM%cH%d OR MM%cL%d OR DIR%c%d",
bank_dimm < 4 ? 'X' : 'Y',
bank_dimm,
bank_dimm < 4 ? 'X' : 'Y',
bank_dimm,
bank_dimm < 4 ? 'X' : 'Y',
bank_dimm);
kf_print("(premium mode only)]\t: %d%%\n",
anal->kfa_conf);
}
}
else if (type == KF_UNKNOWN) {
type = anal->kfa_info[--level].kfi_type;
kf_print("/%s\t\t: %d%%\n",
type_name_get(type,type_name,name_len),
anal->kfa_conf);
}
else {
#ifdef DEBUG
kf_print("\nError: Unknown KF_TYPE %d line: %d file:%s\n",
type, __LINE__, __FILE__);
#else
kf_print("<undefined>\n");
#endif
}
}
void
kf_hub_analysis_print(kf_analysis_t *anal, int level, fru_name_t type_name[],
int name_len)
{
int type = anal->kfa_info[++level].kfi_type;
switch(type) {
case KFTYPE_HUB_LINK:
kf_print("\n");
kf_print("++\t\t[suspect faulty midplane connection]\t: %d%%\n",
anal->kfa_conf);
break;
case KFTYPE_MD:
type = anal->kfa_info[++level].kfi_type;
if (type == KFTYPE_MEM) {
kf_memory_analysis_print(anal,level,type_name,
name_len);
}
else if (type == KF_UNKNOWN) {
type = anal->kfa_info[--level].kfi_type;
kf_print("/hub/%s\t\t: %d%%\n",
type_name_get(type,type_name,
name_len),
anal->kfa_conf);
}
else {
#ifdef DEBUG
kf_print("\nError: Unknown KF_TYPE %d line: %d file:%s\n",
type, __LINE__, __FILE__);
#else
kf_print("<undefined>\n");
#endif
}
break;
case KFTYPE_II:
case KFTYPE_PI:
case KFTYPE_NI:
kf_print("/hub/%s\t\t: %d%%\n",
type_name_get(type,type_name,name_len),
anal->kfa_conf);
break;
case KFTYPE_T5_WB_SURPRISE:
kf_print("\n");
kf_print("++\tFailed with the incident (T5 WB) error "
"signature,\n++\tplease contact your service "
"representaive.\t: %d%%\n",
anal->kfa_conf);
break;
case KFTYPE_BTE_PUSH :
kf_print("\n");
kf_print("++\tFailed with the incident (BTE PUSH) error "
"signature,\n++\tplease contact your service "
"representaive.\t: %d%%\n",
anal->kfa_conf);
break;
case KF_UNKNOWN:
type = anal->kfa_info[--level].kfi_type;
kf_print("/%s\t\t\t: %d%%\n",
type_name_get(type,type_name,name_len),
anal->kfa_conf);
break;
default:
#ifdef DEBUG
kf_print("\nError: Unknown KF_TYPE %d line: %d file:%s\n",
type, __LINE__, __FILE__);
#else
kf_print("<undefined>\n");
#endif
break;
}
}
void
kf_analysis_print(kf_analysis_t *anal)
{
int level;
int type;
char slot_name[SLOTNUM_MAXLENGTH];
static fru_name_t type_name[] =
{
{KFTYPE_WEIRDCPU, "unknown_cpu"},
{KFTYPE_IP27, "node"},
{KFTYPE_WEIRDIO, "unknown"},
{KFTYPE_BASEIO, "baseio"},
{KFTYPE_4CHSCSI, "mscsi"},
{KFTYPE_ETHERNET, "menet"},
{KFTYPE_FDDI, "fddi"},
{KFTYPE_GFX, "graphics"},
{KFTYPE_HAROLD, "pci_xio"},
{KFTYPE_PCI, "pci"},
{KFTYPE_VME, "vme_remote"},
{KFTYPE_MIO, "mio"},
{KFTYPE_FC, "fibre_channel"},
{KFTYPE_LINC, "linc"},
{KFTYPE_WEIRDROUTER, "unknown_router"},
{KFTYPE_NULL_ROUTER, "null_router"},
{KFTYPE_META_ROUTER, "meta_router"},
{KFTYPE_WEIRDMIDPLANE, "unknown_midplane"},
{KFTYPE_MIDPLANE, "midplane"},
{KFTYPE_CPU0, "cpu"},
{KFTYPE_IC0, "icache"},
{KFTYPE_DC0, "dcache"},
{KFTYPE_SC0, "scache"},
{KFTYPE_SYSBUS, "himm"},
{KFTYPE_HUB, "hub"},
{KFTYPE_PI, "pi"},
{KFTYPE_MD, "md"},
{KFTYPE_II, "ii"},
{KFTYPE_NI, "ni"},
{KFTYPE_MEM, "memory"},
{KFTYPE_DIMM0, "memory/dimm_bank"},
{KFTYPE_ROUTER, "router"},
{KFTYPE_ROUTER_LINK0, "link"},
{KFTYPE_SOFTWARE, "Software"},
{KFTYPE_XBOW, "xbow"},
{KFTYPE_BRIDGE_LINK, "link"},
{KFTYPE_BRIDGE, "bridge"},
{KFTYPE_BRIDGE_PCI_DEV, "pci"},
{KFTYPE_BRIDGE_SSRAM, "ssram"},
{KFTYPE_MODULE, "module"},
{KFTYPE_TPU, "tpu"},
{KFTYPE_GSN_A, "primary gsn"},
{KFTYPE_GSN_B, "auxiliary gsn"}
};
level = KF_MODULE_LEVEL;
type = anal->kfa_info[level].kfi_type;
switch (type) {
case KFTYPE_SOFTWARE:
kf_print("++\t%s\t\t\t\t\t: %d%%\n",
type_name_get(type,type_name,KF_TYPE_NAME_LEN),
anal->kfa_conf);
return;
case KFTYPE_MODULE:
if (anal->kfa_serial_number[0])
kf_print("++\t[board serial number %s]\n",anal->kfa_serial_number);
kf_print("++\t/hw/%s/%d/",
type_name_get(type,type_name,KF_TYPE_NAME_LEN),
anal->kfa_info[level].kfi_inst);
break;
case KF_UNKNOWN:
/* no confideces were assigned so just return */
return;
default:
#ifdef DEBUG
kf_print("\nError: Unknown KF_TYPE %d line: %d file:%s\n",
type, __LINE__, __FILE__);
#else
kf_print("<undefined>\n");
#endif
break;
}
type = anal->kfa_info[++level].kfi_type;
switch (type) {
case KFTYPE_ROUTER2:
case KFTYPE_ROUTER:
#ifdef FRUTEST
kf_print("slot/r%d/%s",
anal->kfa_info[level].kfi_inst,
type_name_get(type,type_name,KF_TYPE_NAME_LEN));
#else
/* convert encoded slot number to slot name string */
get_slotname(anal->kfa_info[level].kfi_inst,
slot_name);
kf_print("slot/%s/%s",slot_name,
type_name_get(type,type_name,KF_TYPE_NAME_LEN));
#endif
type = anal->kfa_info[++level].kfi_type;
if (type == KFTYPE_ROUTER_LINK0) {
kf_print("/%s/%d\t\t\t: %d%%\n",
type_name_get(type,type_name,KF_TYPE_NAME_LEN),
anal->kfa_info[level].kfi_inst,
anal->kfa_conf);
}
else if (type == KF_UNKNOWN) {
type = anal->kfa_info[--level].kfi_type;
kf_print("\t\t\t\t\t: %d%%\n",
anal->kfa_conf);
}
else {
#ifdef DEBUG
kf_print("\nError: Unknown KF_TYPE %d line: %d file:%s\n",
type, __LINE__, __FILE__);
#else
kf_print("<undefined>\n");
#endif
}
return;
case KFTYPE_IP27:
#ifdef FRUTEST
kf_print("slot/n%d/%s",
anal->kfa_info[level].kfi_inst + 1,
type_name_get(type,type_name, KF_TYPE_NAME_LEN));
#else
/* convert encoded slot number to slot name string */
get_slotname(anal->kfa_info[level].kfi_inst,slot_name);
kf_print("slot/%s/%s",
slot_name,
type_name_get(type,type_name, KF_TYPE_NAME_LEN));
#endif
type = anal->kfa_info[++level].kfi_type;
switch (type) {
case KFTYPE_CPU0:
kf_cpu_analysis_print(anal,level,type_name,
KF_TYPE_NAME_LEN);
break;
case KFTYPE_SYSBUS:
kf_print("/%s\t\t\t: %d%%\n",
type_name_get(type,type_name,
KF_TYPE_NAME_LEN),
anal->kfa_conf);
break;
case KFTYPE_HUB:
kf_hub_analysis_print(anal,level,type_name,
KF_TYPE_NAME_LEN);
break;
case KFTYPE_PCOUNT:
kf_print("\n");
kf_print("++\tFailed with the incident 439797 error "
"signature,\n++\tplease contact your service "
"representative.\t: %d%%\n",
anal->kfa_conf);
break;
case KF_UNKNOWN:
type = anal->kfa_info[level - 1].kfi_type;
kf_print("\t: %d%%\n",
anal->kfa_conf);
break;
default:
#ifdef DEBUG
kf_print("\nError: Unknown KF_TYPE %d line: %d file:%s\n",
type, __LINE__, __FILE__);
#else
kf_print("<undefined>\n");
#endif
break;
}
break;
case KFTYPE_XBOW:
#ifdef FRUTEST
kf_print("slot/io%d/node/xtalk/0/xbow\t\t: %d%%\n",
anal->kfa_info[level].kfi_inst,
anal->kfa_conf);
#else
/* convert encoded slot number to slot name string */
get_slotname(anal->kfa_info[level].kfi_inst,
slot_name);
kf_print("slot/%s/node/xtalk/0/xbow\t\t: %d%%\n",
slot_name,
anal->kfa_conf);
#endif
break;
default:
if (KLCLASS(type) == KLCLASS_IO) {
/* if we have an io board */
#ifdef FRUTEST
kf_print("slot/io%d/%s",
anal->kfa_info[level].kfi_inst,
type_name_get(type,type_name,KF_TYPE_NAME_LEN));
#else
/* convert encoded slot number to slot name string */
get_slotname(anal->kfa_info[level].kfi_inst,
slot_name);
kf_print("slot/%s/%s",slot_name,
type_name_get(type,type_name,KF_TYPE_NAME_LEN));
#endif
type = anal->kfa_info[++level].kfi_type;
if (type == KFTYPE_BRIDGE) {
kf_bridge_analysis_print(anal,level,type_name,
KF_TYPE_NAME_LEN);
}
else if (type == KF_UNKNOWN) {
kf_print("\t\t\t: %d%%\n",
anal->kfa_conf);
}
else {
#ifdef DEBUG
kf_print("\nError: Unknown KF_TYPE %d line: %d"
"file:%s\n",
type, __LINE__, __FILE__);
#else
kf_print("<undefined>\n");
#endif
}
}
else {
#ifdef DEBUG
kf_print("\nError: Unknown KF_TYPE %d line: %d file:%s\n",
type, __LINE__, __FILE__);
#else
kf_print("<undefined>\n");
#endif
}
break;
}
}
/* sort the table of analysis guesses in
* descending order of confidence levels
*/
void
kf_analysis_tab_sort(void)
{
int i,j;
kf_analysis_t temp;
for (j = 0 ; j < MAX_GUESSES - 1; j++) {
for( i = j + 1; i < MAX_GUESSES; i++) {
if (kf_analysis[i].kfa_conf > kf_analysis[j].kfa_conf) {
temp = kf_analysis[i];
kf_analysis[i] = kf_analysis[j];
kf_analysis[j] = temp;
}
}
}
}
/*
* print out the table of analysis guesses
*/
kf_result_t
kf_analysis_tab_print(int num_guesses)
{
int guess;
kf_analysis_tab_sort();
kf_print("++\n");
kf_print("++\n");
kf_print("++\t\t\tFRU Analysis Summary\n");
kf_print("++\n");
if (kf_analysis[0].kfa_info[KF_MODULE_LEVEL].kfi_type == KF_UNKNOWN) {
/* if nothing is set */
kf_print("++\t\t* Inconclusive hardware error state *\n");
kf_print("++\n");
kf_print("++FRU ANALYSIS END\n");
return KF_SUCCESS;
}
#if !defined(FRUTEST) || defined(FRUTEST_DEBUG_OUTPUT)
guess = 1;
while ((guess < MAX_GUESSES) && (kf_analysis[guess].kfa_conf ==
kf_analysis[guess - 1].kfa_conf)) {
if (guess > MAX_EQ_FRU_CONFS) {
kf_print("++\t\t* Inconclusive hardware error state *\n");
kf_print("++\n");
kf_print("++FRU ANALYSIS END\n");
return KF_SUCCESS;
}
guess++;
}
#endif
KF_ASSERT((num_guesses <= MAX_GUESSES));
guess = 0 ;
while ((guess < MAX_GUESSES) &&
(kf_analysis[guess].kfa_info[0].kfi_type != KF_UNKNOWN) &&
((guess <= num_guesses - 1) || (kf_analysis[guess].kfa_conf ==
kf_analysis[guess - 1].kfa_conf))) {
if ((kf_analysis[guess].kfa_conf > MAX_FRU_CONF) &&
(kf_analysis[guess].kfa_conf != FRU_FLAG_CONF)) {
/* this is an invalid confidence value, something is wrong */
#if !defined(_STANDALONE) && !defined(FRUTEST)
if (kdebug) {
kf_print("FRU error: invalid FRU confidence value: %d%%\n",
kf_analysis[guess].kfa_conf);
}
#endif /* !defined(_STANDALONE) */
}
else
kf_analysis_print(&kf_analysis[guess]);
guess++;
}
kf_print("++\n");
kf_print("++FRU ANALYSIS END\n");
return KF_SUCCESS;
}
#if defined(_STANDALONE)
void
sn0_fru_node_entry(nasid_t nasid,int (*print)(const char *,...))
{
int i;
/* initiliaze the node hint table */
for(i = 0 ; i < MAXCPUS / 2 ; i++)
node_hint[i].kh_hint_type = -1;
kf_printf = print;
/* Print the starting fru message */
kf_fru_begin_msg_print();
if (kf_node_analyze(nasid,NULL) == KF_FAILURE)
kf_print("FRU : node ( nasid = %d)analysis failed\n",
nasid);
else {
kf_analysis_t curr_analysis;
kf_analysis_tab_init();
kf_analysis_init(&curr_analysis);
if (kf_node_analyze(nasid,&curr_analysis) == KF_FAILURE)
kf_print("FRU : node (nasid = %d) analysis failed\n",
nasid);
kf_fru_summary_print(MAX_GUESSES);
}
}
#endif
/*
* set the hint for a node . This is later used
* by the fru analyzer during its analysis phase
*/
void
kf_hint_set(nasid_t nasid,char *fru_hint)
{
static int first_call = 1;
int i;
if (first_call) {
first_call = 0;
/* initiliaze the node hint table */
for(i = 0 ; i < MAXCPUS / 2 ; i++)
node_hint[i].kh_hint_type = -1;
}
if (nasid != -1) {
for (i = 0 ; i < fru_hint_table_size; i++) {
if (strcmp(fru_hint,fru_hint_table[i]))
continue;
node_hint[nasid].kh_hint_type = i;
break;
}
}
}
#if !defined(FRUTEST) && !defined(_STANDALONE)
/*================================================================*/
/* Fru support to disable faulty components
* for now sticking to the disabling of
* cpus,
* memory banks,
* pci components
*/
/* Disable cpu [A|B] on node with the given nasid */
kf_result_t
kf_cpu_disable(int slice,nasid_t nasid)
{
char *promlog_var_name[] = { DISABLE_CPU_A , DISABLE_CPU_B };
KF_ASSERT(slice < CPUS_PER_NODE);
/* Set DisableA or DisableB promlog variable on the appropriate
* node so that the during the next reset the cpu is disabled.
*/
ip27log_setenv(nasid,promlog_var_name[slice],KF_REASON_FRU_DISABLE,0);
return(KF_SUCCESS);
}
/* Update the MD_MEMORY_CONFIG register to indicate that the bank has
* been disabled.
*/
void
kf_memory_config_update(nasid_t nasid, int bank)
{
__uint64_t mc = REMOTE_HUB_L(nasid, MD_MEMORY_CONFIG);
int dimm0_sel;
char bank_str[2];
/* If dimm0 sel is non zero, then the size of bank 0
* is the size of the bank that is used as dimm0. Do not
* clobber this value.
*/
if ((bank == 0) && ((mc & MMC_DIMM0_SEL_MASK) >> MMC_DIMM0_SEL_SHFT))
return ;
mc &= ~(MMC_BANK_MASK(bank));
mc |= (MD_SIZE_EMPTY << MMC_BANK_SHFT(bank));
REMOTE_HUB_S(nasid, MD_MEMORY_CONFIG, mc);
dimm0_sel = ((mc & MMC_DIMM0_SEL_MASK) >> MMC_DIMM0_SEL_SHFT) ;
if (dimm0_sel) {
sprintf(bank_str, "%d", dimm0_sel);
ip27log_setenv(nasid, SWAP_BANK, bank_str, 0);
}
}
/* Disable a memory bank on a node */
/* ARGSUSED */
kf_result_t
kf_memory_bank_disable(int bank,nasid_t nasid)
{
char disable_mem_size[MD_MEM_BANKS + 1],
disable_mem_reason[MD_MEM_BANKS + 1],
disable_mem_mask[MD_MEM_BANKS + 1];
hubreg_t memory_config;
char bank_name[2];
int bank1_size = MD_SIZE_EMPTY;
KF_ASSERT(bank < MD_MEM_BANKS);
memory_config = translate_hub_mcreg(REMOTE_HUB_L(nasid,
MD_MEMORY_CONFIG));
/* Get the current values for promlog variables related to the
* disabled memory banks.
*/
if (ip27log_getenv(nasid,DISABLE_MEM_SIZE,disable_mem_size,
DEFAULT_ZERO_STRING,0) < 0)
return(KF_FAILURE);
if (ip27log_getenv(nasid,DISABLE_MEM_REASON,disable_mem_reason,
DEFAULT_ZERO_STRING,
0) < 0)
return(KF_FAILURE);
if (ip27log_getenv(nasid,DISABLE_MEM_MASK,disable_mem_mask,"",0))
return(KF_FAILURE);
/* Make sure that all these strings are terminated by a null char */
disable_mem_size[MD_MEM_BANKS] = 0;
disable_mem_reason[MD_MEM_BANKS] = 0;
disable_mem_mask[MD_MEM_BANKS] = 0;
/* Special case handling for disabling bank 0 .
* Basically bank 0 cannot be disabled unless bank 1 exists
* and has been enabled.
*/
bank1_size = ((memory_config & MMC_BANK_MASK(1)) >> MMC_BANK_SHFT(1));
if ((bank == 0) &&
(strchr(disable_mem_mask,'0' + 1) ||
(bank1_size == MD_SIZE_EMPTY))) {
return(KF_SUCCESS);
}
/* Set the disable mem mask to indicate that this bank is being
* disabled only if it already hasn't been disabled.
*/
sprintf(bank_name,"%d",bank);
if (!strstr(disable_mem_mask,bank_name))
strcat(disable_mem_mask,bank_name);
/* Set the reason for disabling this bank as due to fru analysis */
if (disable_mem_reason[bank] == '0')
disable_mem_reason[bank] = '0' + MEM_DISABLE_FRU;
/* Set the disable bank configured size */
disable_mem_size[bank] =
'0' +
(memory_config & MMC_BANK_MASK(bank) >> MMC_BANK_SHFT(bank));
/* Store the new values for promlog variables related to the
* disable memory banks.
*/
ip27log_setenv(nasid,DISABLE_MEM_SIZE,disable_mem_size,0);
ip27log_setenv(nasid,DISABLE_MEM_REASON,disable_mem_reason,0);
ip27log_setenv(nasid,DISABLE_MEM_MASK,disable_mem_mask,0);
/* Tell the hardware that the bank has been disabled */
kf_memory_config_update(nasid,bank);
/* Set the SWAP_BANK promlog variable if we are disabling bank 0 */
if (bank == 0)
ip27log_setenv(nasid,SWAP_BANK,"2",0);
return(KF_SUCCESS);
}
#include <sys/SN/nvram.h>
int
kf_component_index_get(int npci, lboard_t *lb)
{
int i ;
klinfo_t *k ;
for (i=0; i<lb->brd_numcompts; i++) {
k = (klinfo_t *)(NODE_OFFSET_TO_K1(
lb->brd_nasid,
lb->brd_compts[i])) ;
if (k->struct_type == KLSTRUCT_BRI)
continue ;
if (k->physid == npci)
return(i);
}
return(-1);
}
/* Disable a component in the given pci slot of the a given io board in
* the given slot of the given module.
*/
kf_result_t
kf_pci_component_disable(lboard_t *io_board,char module,char slot,char comp)
{
dict_entry_t dict;
unchar index;
int comp_index;
/* Create disable io component entry structure */
dict.module = module;
dict.slot = slot;
if (!io_board ||
(comp_index = kf_component_index_get(comp,io_board)) == -1)
return(KF_FAILURE);
dict.comp = (unchar)comp_index;
/* Get the first free slot in the nvram table */
index = nvram_dict_first_free_index_get();
/* Put the entry correspoding to this io component
* in the table's slot.
*/
nvram_dict_index_set(&dict,index);
return(KF_SUCCESS);
}
#endif /* !FRUTEST && !_STANDALONE */
/* FRU print wrapper routine */
int
kf_print(const char *fmt,...)
{
va_list ap;
char buf[128];
va_start(ap,fmt);
vsprintf(buf,(char *)fmt,ap);
va_end(ap);
/* Depending on the print target print the fru
* message either to the promlog or the console
*/
if (kf_print_where == KF_PRINT_PROMLOG) {
if (buf[0] == '+')
ip27log_printf(IP27LOG_INFO,"%s",buf);
else
ip27log_printf(IP27LOG_INFO,"++\t%s",buf);
} else if (kf_print_where == KF_PRINT_CONSOLE)
kf_printf("%s",buf);
return(0);
}
/* Print the fru summary */
kf_result_t
kf_fru_summary_print(int max_guesses)
{
kf_result_t rv;
/* Print the fru summary in the promlog */
kf_print_where = KF_PRINT_PROMLOG;
rv = kf_analysis_tab_print(max_guesses);
if (rv != KF_SUCCESS)
return(rv);
/* Print the fru summary in the promlog */
kf_print_where = KF_PRINT_CONSOLE;
rv = kf_analysis_tab_print(max_guesses);
return(rv);
}
/* Print the starting fru message */
void
kf_fru_begin_msg_print(void)
{
/* Print the starting fru message in the prom log */
kf_print_where = KF_PRINT_PROMLOG;
kf_print("\n");
kf_print("\n");
kf_print("++FRU ANALYSIS BEGIN\n");
/* Print the starting fru message on the console */
kf_print_where = KF_PRINT_CONSOLE;
kf_print("\n");
kf_print("\n");
kf_print("++FRU ANALYSIS BEGIN\n");
}