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

2958 lines
76 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. *
* *
**************************************************************************/
/***********************************************************************\
* File: SN0.c *
* *
* This file contains the the definitions of the cpu-dependent *
* functions for SN0-based systems. For the most part, *
* this file should work for IP27 based machines. *
* *
\***********************************************************************/
#define PROM /* XXX - We can change this when the address defines for
* the PROM move out of sn0addrs.h
*/
#include <sys/i8251uart.h>
#include <sys/types.h>
#include <sys/sbd.h>
#include <sys/immu.h>
#include <sys/time.h>
#include <sys/ktime.h>
#include <sys/cpu.h>
#include <sys/loaddrs.h>
#include <sys/iotlb.h>
#include <sys/i8254clock.h>
#include <sys/z8530.h>
#include <sys/ns16550.h>
#include <arcs/io.h>
#include <sys/nic.h>
#include <standcfg.h>
#include <stringlist.h>
#include <libsc.h>
#include <libsk.h>
#include <libkl.h>
#include <menu.h>
#include <stdarg.h>
#include <io6fprom.h>
#include <arcs/folder.h>
#include <arcs/errno.h>
#include <arcs/hinv.h>
#include <arcs/cfgtree.h>
#include <arcs/types.h>
#include <arcs/time.h>
#include <sys/SN/addrs.h>
#include <sys/SN/klconfig.h>
#include <sys/SN/kldiag.h>
#include <sys/SN/promcfg.h>
#include <sys/SN/SN0/ip27config.h>
#include <sys/SN/SN0/ip27log.h>
#include <sys/SN/gda.h>
#include <sys/SN/SN0/klhwinit.h>
#include <sys/SN/nvram.h>
#include <sys/PCI/bridge.h>
#include <promgraph.h>
#include <pgdrv.h>
#include <sys/iograph.h>
#include <klclock.h>
#include <sys/PCI/PCI_defs.h>
#include <gfxgui.h>
#include <libsc_internal.h>
#include <sn0hinv.h>
#define DECLARE_HWGHDL graph_hdl_t ghdl ; \
vertex_hdl_t rvhdl ;
#ifdef SN_PDI
extern graph_hdl_t pg_hdl ;
extern vertex_hdl_t snpdi_rvhdl ;
#define CHOOSE_GHDL (ghdl = pg_hdl) ;
#define CHOOSE_RVHDL (rvhdl = snpdi_rvhdl) ;
#else
extern graph_hdl_t prom_graph_hdl ;
extern vertex_hdl_t hw_vertex_hdl ;
#define CHOOSE_GHDL ghdl = prom_graph_hdl ;
#define CHOOSE_RVHDL rvhdl = hw_vertex_hdl ;
#endif
extern int month_days[12]; /* in libsc.a */
extern int sk_sable;
extern int _symmon;
moduleid_t master_baseio_modid ;
slotid_t master_baseio_slotid ;
char master_console_path[64] ;
extern int cpu_set_nvram_offset(int, int, char *);
char *copy_nic_field(char *, char *) ;
void sn0_dev2eng(COMPONENT *, char *) ;
char *make_serial(int) ;
/*nasid_t get_dis_node_brd_nasid(moduleid_t, slotid_t) ;*/
/*
* cpu_makecfgroot()
* Creates the Root node of the SN0 ARCS configuration tree.
*/
static int
log2(int x)
{
int n, v;
for (n = 0, v = 1; v < x; v <<= 1, n++) ;
return n;
}
#define SYSBOARDIDLEN 9
static COMPONENT root_template = {
SystemClass,
ARC,
(IDENTIFIERFLAG)0,
SGI_ARCS_VERS,
SGI_ARCS_REV,
0,
0,
0,
SYSBOARDIDLEN,
0
};
cfgnode_t *
cpu_makecfgroot(void)
{
COMPONENT *root = &root_template;
printf("cpu_makecfgroot called. \n") ;
root->Identifier = "SGI-IP27";
root = AddChild(NULL, &root_template, (void*)NULL);
if (root == (COMPONENT*)NULL)
cpu_acpanic("root");
return ((cfgnode_t*)root);
}
/*
* cpu_install()
* Adds nodes in the ARCS configuration tree for
* all of the cpus and their subcomponents (FPUS and
* caches). This routine deals with IP27 based
* boards (and hopefully their descendents, if
* any ever show up).
*/
static COMPONENT cputmpl = {
ProcessorClass, /* Class */
CPU, /* Type */
(IDENTIFIERFLAG)0, /* Flags */
SGI_ARCS_VERS, /* Version */
SGI_ARCS_REV, /* Revision */
0, /* Key */
0x01, /* Affinity */
0, /* ConfigurationDataSize */
0, /* IdentifierLength */
NULL /* Identifier */
};
static COMPONENT fputmpl = {
ProcessorClass, /* Class */
FPU, /* Type */
(IDENTIFIERFLAG)0, /* Flags */
SGI_ARCS_VERS, /* Version */
SGI_ARCS_REV, /* Revision */
0, /* Key */
0x01, /* Affinity */
0, /* ConfigurationDataSize */
0, /* IdentifierLength */
NULL /* Identifier */
};
static COMPONENT cachetmpl = {
CacheClass, /* Class */
PrimaryICache, /* Type */
(IDENTIFIERFLAG)0, /* Flags */
SGI_ARCS_VERS, /* Version */
SGI_ARCS_REV, /* Revision */
0, /* Key */
0x01, /* Affinity */
0, /* ConfigurationDataSize */
0, /* IdentifierLength */
NULL /* Identifier */
};
static COMPONENT memtmpl = {
MemoryClass, /* Class */
Memory, /* Type */
(IDENTIFIERFLAG)0, /* Flags */
SGI_ARCS_VERS, /* Version */
SGI_ARCS_REV, /* Revision */
0, /* Key */
0x01, /* Affinity */
0, /* ConfigurationDataSize */
0, /* Identifier Length */
NULL /* Identifier */
};
void
cpu_install(COMPONENT *root)
{
panic("cpu_install should not be called\n") ;
}
/*
* cpu_reset
* Perform any board-specific start up initialization.
*/
void
cpu_reset(void)
{
initsplocks(); /* initialize spin lock subsystem */
}
/*
* cpu_hardreset
* Performs a hard reset by slamming the Kamikaze reset
* vector.
*/
void
cpu_hardreset(void)
{
printf("Resetting the system...\n");
*LOCAL_HUB(NI_PORT_RESET) = NPR_PORTRESET | NPR_LOCALRESET;
for (;;) /* Loop Forever */ ;
/* NOTREACHED */
}
/*
* cpu_show_fault()
*/
/*ARGSUSED*/
void
cpu_show_fault(unsigned long saved_cause)
{
printf("fixme: cpu_show_fault\n") ;
}
/*
* cpu_soft_powerdown()
*/
void
cpu_soft_powerdown(void)
{
printf("fixme: cpu_soft_powerdown\n") ;
}
int
cpu_get_max_nodes(void)
{
int cnode ;
gda_t *gdap ;
gdap = GDA ;
if (gdap) {
for (cnode = 0; cnode < MAX_COMPACT_NODES; cnode ++) {
if (gdap->g_nasidtable[cnode] == INVALID_NASID)
return cnode ;
}
}
/* NOTREACHED */
}
/*
* Visits every board struct in klconfig.
* Calls the function pointer fp with the argument pointer ap for
* respective lboard struct and a result pointer rp.
* fp(lboard_t *, void *, void *)
*/
int
visit_lboard(int (*fp)(), void *ap, void *rp)
{
int rv = 0 ;
cnodeid_t cnode ;
nasid_t nasid ;
lboard_t *lbptr ;
gda_t *gdap;
gdap = (gda_t *)GDA_ADDR(get_nasid());
if (gdap->g_magic != GDA_MAGIC) {
printf("visit_lboard: Invalid GDA MAGIC\n") ;
return 0 ;
}
for (cnode = 0; cnode < MAX_COMPACT_NODES; cnode ++) {
nasid = gdap->g_nasidtable[cnode];
if (nasid == INVALID_NASID)
continue;
lbptr = (lboard_t *)KL_CONFIG_INFO(nasid) ;
while (lbptr) {
if (!(lbptr->brd_flags & DUPLICATE_BOARD))
if (!((*fp)(lbptr, ap, rp)))
return 1 ;
lbptr = KLCF_NEXT(lbptr);
}
}
return 1 ;
}
int
mem_size(lboard_t *l, void *ap, void *rp)
{
klmembnk_t *mem_ptr ;
if (l->brd_type == KLTYPE_IP27) {
mem_ptr = NULL ;
mem_ptr = (klmembnk_t *)find_component(l,
(klinfo_t *)mem_ptr, KLSTRUCT_MEMBNK) ;
/* 4k pages */
*(int *)rp = *(int *)rp + (mem_ptr->membnk_memsz * 256) ;
}
return 1 ;
}
/*
* cpu_get_memsize()
*/
unsigned int
cpu_get_memsize(void)
{
int total_mem = 0 ;
visit_lboard(mem_size, NULL, &total_mem) ;
return total_mem ;
}
/* Memory disable routines */
unsigned int
dismem_size(nasid_t nasid, char *dmbnk)
{
int disable, mem_dis = 0, bank ;
char mem_disable[MD_MEM_BANKS + 1];
char disable_sz[MD_MEM_BANKS + 1];
disable = (ip27log_getenv(nasid, "DisableMemMask",
mem_disable, 0, 0) >= 0);
if (disable) {
if (ip27log_getenv(nasid, "DisableMemSz", disable_sz,
0, 0) >= 0)
for (bank = 0; bank < MD_MEM_BANKS; bank++)
if (strchr(mem_disable, '0' + bank))
mem_dis += MD_SIZE_MBYTES(
disable_sz[bank] - '0');
if (dmbnk) {
*dmbnk = 0 ;
strcpy(dmbnk, disable_sz) ;
}
}
return mem_dis ;
}
dismem_size_l(lboard_t *l, void *ap, void *rp)
{
if (l->brd_type == KLTYPE_IP27)
*(int *)rp = *(int *)rp + dismem_size(l->brd_nasid, NULL) ;
return 1 ;
}
dismem_size_k(klinfo_t *k, char *dmbnk)
{
return dismem_size(k->nasid, dmbnk) ;
}
cpu_get_dismem(void)
{
int dismem = 0 ;
visit_lboard(dismem_size_l, NULL, &dismem) ;
return dismem ;
}
/* these decode routines need to be kept in sync with the routines in
irix/kern/ml/SN0/module_info.c */
#define SN00_SERIAL_FUDGE 0x3b1af409d513c2
#define SN0_SERIAL_FUDGE 0x6e
void
decode_int_serial(unsigned long long src, unsigned long long *dest) {
unsigned long long val;
int i;
for (i = 0; i < sizeof(long long); i++) {
((char*)&val)[sizeof(long long)/2 +
((i%2) ? ((i/2 * -1) - 1) : (i/2))] =
((char*)&src)[i];
}
*dest = val - SN00_SERIAL_FUDGE;
}
void
decode_str_serial(const char *src, char *dest) {
int i;
for (i = 0; i < MAX_SERIAL_NUM_SIZE; i++) {
dest[MAX_SERIAL_NUM_SIZE/2 +
((i%2) ? ((i/2 * -1) - 1) : (i/2))] = src[i] -
SN0_SERIAL_FUDGE;
}
}
int
prmod_snum(lboard_t *l, void *ap, void *rp)
{
int i, cnt ;
klmod_serial_num_t *snump ;
if (l->brd_type == KLTYPE_MIDPLANE) {
/* Print serial numbers only for xbow 0 */
if (!SN00) {
if (CONFIG_12P4I) {
/* Print the serial number only once .
* Without this check in the worst case
* we might see 5 duplicate error messages
*/
if (l->brd_nasid)
return 1;
}
if (get_node_crossbow(l->brd_nasid) & 1)
return 1 ;
}
snump = GET_SNUM_COMP(l) ;
if (snump->snum_info.struct_type == KLSTRUCT_MOD_SERIAL_NUM) {
char snum_str[MAX_SERIAL_NUM_SIZE + 1];
unsigned long long snum_val = 0;
if (SN00)
decode_int_serial(snump->snum.snum_int,
&snum_val);
else {
decode_str_serial(snump->snum.snum_str,
snum_str);
/* make sure it is null terminated */
snum_str[MAX_SERIAL_NUM_SIZE] = '\0';
}
if (snum_val) {
/* if we have a valid SN00 serial number,
we are only printing out the lower 4 bytes to
be consistent with the kernel. The uppper 2 bytes
of the MAC address will always be 0x0800 */
printf("Module %d: Serial: %x\n",
l->brd_module,snum_val & 0xffffffffll);
}
else if (snum_str[0] == 'K') {
/* if we have a valid SN0 serial number */
printf("Module %d: Serial: %s\n",
l->brd_module,snum_str);
}
else {
printf("Invalid serial number for module %d\n",
l->brd_module);
}
}
}
return 1 ;
}
char *
get_nicstr_from_devinfo(lboard_t *lb)
{
klbri_t *brip ;
char *nicstr = NULL ;
brip = (klbri_t *)find_component(lb, NULL, KLSTRUCT_BRI) ;
if (brip)
nicstr = (char *)NODE_OFFSET_TO_K1(lb->brd_nasid,
brip->bri_mfg_nic) ;
return nicstr ;
}
/*
* find the frequency (in HZ) of the running CPU
*/
int
get_freq(lboard_t *l, void *ap, void *rp)
{
klcpu_t *cpu_ptr ;
if (l->brd_type != KLTYPE_IP27)
return 1 ;
cpu_ptr = NULL ;
do {
cpu_ptr = (klcpu_t *)find_component(l, (klinfo_t *)cpu_ptr,
KLSTRUCT_CPU) ;
if ((cpu_ptr) &&
(KLCONFIG_INFO_ENABLED(&cpu_ptr->cpu_info)) &&
(cpu_ptr->cpu_info.virtid == *(int *)ap)) {
*(int *)rp = (cpu_ptr->cpu_speed * 1000000) ;
return 0 ; /* stop the loop */
}
} while (cpu_ptr) ;
return 1 ;
}
unsigned int
cpu_get_freq(int acpuid)
{
int freq = 0 ;
visit_lboard(get_freq, &acpuid, &freq) ;
if (!freq) /* value not changed */
printf("*** Warning: Cannot find frequency of CPU %d\n", acpuid);
return freq ;
}
int
fill_cpu_list(lboard_t *l, void *ap, void *rp)
{
klinfo_t *kliptr ;
cpu_list_t *cur_rv = (cpu_list_t *)rp ;
int cpu_freq, i, dis_cpus;
if (l->brd_type == KLTYPE_IP27) {
kliptr = NULL ;
while(kliptr = find_component(l, kliptr, KLSTRUCT_CPU)) {
cpu_freq = ((klcpu_t *)kliptr)->cpu_speed;
if(cpu_freq == 0xffff)
{
cpu_freq = (short)((((ip27config_t *)(IP27CONFIG_ADDR_NODE(l->brd_nasid)))->freq_cpu)/1000000);
}
for(i = 0; i < cur_rv->size; i++)
{
if(cur_rv->freq[i] == cpu_freq)
{
cur_rv->count[i] ++;
break;
}
}
if(i >= 16)
return 1;
if(i == cur_rv->size)
{
cur_rv->size ++;
cur_rv->freq[i] = cpu_freq;
cur_rv->count[i] = 1;
}
if (!(KLCONFIG_INFO_ENABLED(kliptr)))
{
dis_cpus = (cur_rv->count[i] >> 16);
dis_cpus ++;
cur_rv->count[i] = (dis_cpus << 16) | (cur_rv->count[i] & 0xffff);
}
}
}
return 1 ;
}
int
count_cpus(lboard_t *l, void *ap, void *rp)
{
klinfo_t *kliptr ;
int cur_rv = *(int *)rp ;
int total_cpus = (cur_rv&0xffff),
dis_cpus = (cur_rv >> 16) ;
if (l->brd_type == KLTYPE_IP27) {
kliptr = NULL ;
while(kliptr = find_component(l, kliptr, KLSTRUCT_CPU)) {
total_cpus++ ;
if (!(KLCONFIG_INFO_ENABLED(kliptr)))
dis_cpus ++ ;
}
cur_rv = (dis_cpus << 16) | (total_cpus) ;
*(int *)rp = cur_rv ;
}
return 1 ;
}
int
kl_get_num_cpus()
{
int num_cpus = 0 ;
visit_lboard(count_cpus, NULL, &num_cpus) ;
return (num_cpus & 0xffff) ;
}
int
hinv_get_num_cpus(cpu_list_t *cpu_list)
{
int i, cpu_cnt;
cpu_list->size = 0;
visit_lboard(fill_cpu_list, NULL, cpu_list) ;
return 0;
}
/*
* match_lb
* visit_lboard callback.
* Get a lboard_t with matching module and slotid.
*/
int
match_lb(lboard_t *lb, void *ap, void *rp)
{
lboard_t *lb1 = (lboard_t *)ap ;
lboard_t *lb2 = (lboard_t *)rp ;
/*
* Two lboards match according to the following criteria:
* 1. They should be in the same module
* 2. If the system is a normal Origin200 then
* the boards should belong to the same class.
* 3. If the system is an Origin2000 or a Origin200
* with an xbox then the lboard's slotids should
* also match. Note that this check encompasses
* the check that the lboards belong to the same
* class since the boards of different classes
* are supposed to have different slotids.
*/
if ((lb->brd_module == lb1->brd_module) &&
((SN00 && !is_xbox_config(get_nasid())) ||
(lb->brd_slot == lb1->brd_slot))) {
/*
* For SN00, since we match only on modid, it
* will match for both CPU and IO boards. So
* we need to match the class also.
*/
if (SN00)
if (KLCLASS(lb->brd_type) != KLCLASS(lb1->brd_type))
return 1 ;
*(lboard_t **)rp = lb ;
return 0 ;
}
return 1 ;
}
lboard_t *
get_match_lb(lboard_t *lb, int flag)
{
lboard_t *rlb = 0 ;
klinfo_t *k;
visit_lboard(match_lb, (void *)lb, (void *)&rlb) ;
/*if ((!rlb) || flag) {
n = get_dis_node_brd_nasid( lb->brd_module,
(lb->brd_slot&KLTYPE_MASK)) ;
if (n != INVALID_NASID) {
lb->brd_nasid = n ;
return lb ;
}
}*/
/* hack to update nasid on disabled boards */
if(rlb && !(rlb->brd_flags & ENABLE_BOARD) && (k = find_component(rlb,NULL,KLSTRUCT_HUB)))
{
rlb->brd_nasid = k->physid;
}
return rlb ;
}
#define MIDPLANE_NAME "MPLN"
int
check_brd_nic(lboard_t *lb, void *ap, void *rp)
{
klhub_t *kh ;
char *sp, *tmp ;
nic_t newnic = 0, inic = *(nic_t *)ap, *onicp = (nic_t *)rp ;
if (lb->brd_type == KLTYPE_IP27) {
if (kh = (klhub_t *)find_component(lb, NULL, KLSTRUCT_HUB))
if (kh->hub_mfg_nic) {
tmp = (char *)NODE_OFFSET_TO_K1(lb->brd_nasid,
kh->hub_mfg_nic) ;
sp = (sp = strstr(tmp, "MODULEID")) ? sp :
strstr(tmp, MIDPLANE_NAME) ;
if (sp)
if (sp = strstr(sp, "Laser:")) {
newnic = strtoull(sp+6, NULL, 16) ;
#ifdef DEBUG
db_printf("sys nic %lx\n", newnic) ;
#endif
if (!inic) {
*onicp = newnic ;
return 0 ;
} else if (inic == newnic) {
*onicp = 1 ;
return 0 ;
} else return 1 ;
}
}
}
return 1 ;
}
/*
* check_sys_nic
* checks if the given nic
* can be found anywhere in the system.
*/
/* ARGSUSED */
nic_t
check_sys_nic(nic_t nic)
{
nic_t rv = 0 ;
/* No problem with SN00. The master NIC is part of the
mother board. */
if (SN00)
return 1 ;
visit_lboard(check_brd_nic, (void *)&nic, (void *)&rv) ;
return rv ;
}
/*
* get_sys_nic
* gets the nic of the midplane in one of the modules in the system
*/
nic_t
get_sys_nic()
{
nic_t rv = 0, nic = 0 ;
if (SN00)
return 1 ;
visit_lboard(check_brd_nic, (void *)&nic, (void *)&rv) ;
return rv ;
}
void check_prev_part_info(void) ;
char *
make_serial(flag)
{
char sname[SLOTNUM_MAXLENGTH] ;
char sav_cons_path[NVLEN_SAV_CONSOLE_PATH] ;
char *mvmsg =
"***WARNING: Console has moved from %s to %s\n"
"Check for LINK errors or setenv ConsolePath to new value.\n" ;
char *hwmod = "/hw/module" ;
extern struct string_list environ_str;
char *cp ;
bzero(sav_cons_path, NVLEN_SAV_CONSOLE_PATH) ;
/* Get the current ConsolePath */
get_slotname(master_baseio_slotid, sname) ;
sprintf(master_console_path, "/hw/module/%d/slot/%s",
master_baseio_modid, sname) ;
/* Get the saved ConsolePath */
cpu_get_nvram_buf(NVOFF_SAV_CONSOLE_PATH,
NVLEN_SAV_CONSOLE_PATH, sav_cons_path) ;
/* Init it if not initted */
if (strncmp(sav_cons_path, hwmod, strlen(hwmod))) {
cpu_set_sav_cons_path(master_console_path) ;
strcpy(sav_cons_path, master_console_path) ;
}
/* Complain if it differs from ConsolePath env var */
if (strcmp(sav_cons_path, master_console_path)) {
printf(mvmsg, sav_cons_path, master_console_path) ;
}
if (flag && master_baseio_modid) {
cpu_set_nvram_offset(NVOFF_CONSOLE_PATH,
NVLEN_CONSOLE_PATH, master_console_path) ;
replace_str("ConsolePath", master_console_path, &environ_str) ;
}
if (!_symmon)
if ((cp = getenv("RestorePartEnv")) && (cp) && (*cp == 'y'))
check_prev_part_info() ;
return NULL ;
}
/*
* The following is a set of routines that return
* the default value of a few important prom variables
* like the normal console, graphics console, keyboard
* and mouse. On EVEREST and other systems, it was called
* tty(0) or video(0) ... using the ARCS convention.
* SN series of systems use the HWGRAPH convention. So,
* these values look like file names. The file names like /dev/...
* are aliases to the full hwgraph path names which also work
* in place of these. The file names like /dev/... still exist
* for backward compatibility. Older NVRAMs contain this path.
*/
#define CONSOLEIN_DEFAULT "/dev/tty/ioc30"
#define CONSOLEIN_DEFAULT_1 "/dev/tty/ioc31"
/*
* cpu_get_serial()
* If console is d2, use tty port 1. rbaud, which is
* associated with this, still does not work on SN0.
*/
char *
cpu_get_serial(void)
{
char *p ;
if ((p = getenv("console")) && (p) &&
(!strcmp(p,"d2")))
return CONSOLEIN_DEFAULT_1 ;
else
return CONSOLEIN_DEFAULT ;
}
/*
* cpu_get_disp_str
*/
char *
cpu_get_disp_str(void)
{
return "/dev/graphics/textport";
}
/*
* cpu_get_kbd_str()
*/
char *
cpu_get_kbd_str(void)
{
if (_symmon)
return cpu_get_serial() ;
return "/dev/input/ioc3pckm0";
}
/*
* cpu_get_mouse()
*/
char *
cpu_get_mouse(void)
{
return "/dev/input/ioc3ms0";
}
/*
* cpu_errputc()
*
* Print a single character to the system's console. The console
* can be switched between the Manufacturing mode console, which
* hangs off the the System Controller, and the System console, which
* hangs off of the serial port. We switch dynamically based on
* an as yet undecided global.
*/
volatile uart_reg_t *cntrl ;
void
cpu_errputc(char c)
{
int timeleft;
if (sk_sable)
timeleft = 1;
else
timeleft = 10000;
#ifndef SABLE
{
if (cntrl == NULL) {
cntrl = (uart_reg_t *)
(KL_CONFIG_CH_CONS_INFO(get_nasid())->uart_base) ;
/* be absolutely sure nasid is OR'ed in */
cntrl = (volatile uart_reg_t *)
TO_NODE(get_nasid(), (__psunsigned_t) cntrl);
}
if (cntrl) {
while (!(RD_REG(cntrl, LINE_STATUS_REG) &
LSR_XMIT_BUF_EMPTY)) {
us_delay(timeleft) ;
}
WR_REG(cntrl, XMIT_BUF_REG, c);
us_delay(timeleft) ;
}
return ;
}
#endif
#if defined(SABLE)
while (timeleft-- && !((*(volatile long *)KL_UART_CMD) & I8251_TXRDY))
/* spin */ ;
*(volatile long *)KL_UART_DATA = c;
#endif /* SABLE */
}
int cpu_errpoll(void)
{
uchar_t status;
cntrl = (uart_reg_t *)(KL_CONFIG_CH_CONS_INFO(get_nasid())->uart_base) ;
cntrl = (volatile uart_reg_t *) TO_NODE(get_nasid(), (__psunsigned_t) cntrl); /* be absolutely sure nasid is OR'ed in */
if (cntrl) {
status = RD_REG(cntrl, LINE_STATUS_REG);
if (status & (LSR_OVERRUN_ERR | LSR_PARITY_ERR |
LSR_FRAMING_ERR))
return 0;
return ((status & LSR_DATA_READY) != 0);
}
return 0;
}
int cpu_errgetc(void)
{
cntrl = (uart_reg_t *)(KL_CONFIG_CH_CONS_INFO(get_nasid())->uart_base) ;
cntrl = (volatile uart_reg_t *) TO_NODE(get_nasid(), (__psunsigned_t) cntrl); /* be absolutely sure nasid is OR'ed in */
if (!cntrl)
return 0;
while (!cpu_errpoll());
return RD_REG(cntrl, RCV_BUF_REG);
}
/*
* cpu_mem_init()
*/
void
cpu_mem_init(void)
{
unsigned int numfreepages;
extern int _ftext[];
extern int _end[];
/* Allocate space for the IO6 PROM. And its various pieces (GFXPROM,
* ENET bufs, etc. We use the _ftext and _end defines so that we
* can move the PROM around in memory without having to recompile.
*/
/* Add 2 pages for Exception and SysParam Block. This has
been split somewhere else.
0 - 0x1000 -> 1 page
0x1000 - 0x2000 -> 1 page
*/
md_add(TO_NODE(get_nasid(), PHYS_RAMBASE), 2, FirmwareTemporary);
/* IO6 PROM Text and Stack.
0x01e01000 - ?? -> 0436 pages
*/
md_add(kvtophys(_ftext),
arcs_btop(kvtophys(_end) - kvtophys(_ftext)),
FirmwareTemporary);
/* 0x1300000 - 0x1400000 -> 256 pages */
md_add(TO_NODE(get_nasid(), K0_TO_PHYS(FLASHBUF_BASE)),
arcs_btop(FLASHPROM_SIZE), FirmwareTemporary);
/* 0x01500000 - 0x1700000 512 pages - 2MB */
md_add(TO_NODE(get_nasid(), K0_TO_PHYS(DIAG_BASE)),
arcs_btop(DIAG_SIZE), FirmwareTemporary);
/* 0x01800000 - 0x1a00000 512 pages - 2MB */
md_add(TO_NODE(get_nasid(), K0_TO_PHYS(ROUTE_BASE)),
arcs_btop(ROUTE_SIZE), FirmwareTemporary);
/* 0x01f80000 - ?? 32 pages - 128 K */
md_add(TO_NODE(get_nasid(), K0_TO_PHYS(ENETBUFS_BASE)),
arcs_btop(ENETBUFS_SIZE), FirmwareTemporary);
/* Free all of the space between the beginning of the NODEBUGUNIX
* address and the base of the flash prom buffer.
* and from top of flashprom buffer to base of 3rd party prom driver space.
*/
md_add(TO_NODE(get_nasid(), K0_TO_PHYS(NODEBUGUNIX_ADDR)),
arcs_btop(MISC_PROM_BASE - NODEBUGUNIX_ADDR), FreeMemory);
md_add(TO_NODE(get_nasid(), K0_TO_PHYS(FLASHBUF_BASE + FLASHPROM_SIZE)),
arcs_btop(MEG), FreeMemory);
#if 0
md_add(K0_TO_PHYS(SLAVESTACK_BASE), arcs_btop(SLAVESTACK_SIZE),
FirmwareTemporary);
#endif
/* Put a permanent memory descriptor in for the IP27 PROM
*/
/* 0x01a00000 - ?? -> 256 pages = 1 MEG */
md_add(TO_NODE(get_nasid(), K0_TO_PHYS(IP27PROM_BASE)),
arcs_btop(IP27PROM_SIZE_MAX), FirmwarePermanent);
/* Put in a memory descriptor for the space occupied by the
* debugging PROM.
*/
md_add(TO_NODE(get_nasid(), K0_TO_PHYS(IO6DPROM_BASE)),
arcs_btop(IO6DPROM_SIZE), FreeMemory);
#if 0
/* ON SN0, since memory is segmented, the value returned by
cpu_get_memsize cannot be used in the way below. It has
to be combined with the mem layout info to either build
the correct mem descs or just assume that each node will
have only 32mb for the prom. This #if 0 does this.
Also, we may have some of the memory banks disabled.
*/
/* Finally, all remaining memory above 32 meg (if any exists) is
* available for use. Because the PROM is limited by the size of
* Kseg0, we never allow more than 100,000 free pages.
*/
numfreepages = (unsigned int)cpu_get_memsize()
- (unsigned int)arcs_btop(K0_TO_PHYS(FREEMEM_BASE));
if (numfreepages > 100000)
numfreepages = 100000;
if (numfreepages > 0)
md_add(TO_NODE(get_nasid(), K0_TO_PHYS(FREEMEM_BASE)),
numfreepages, FreeMemory);
#endif
}
/*
* cpu_acpanic()
*/
void
cpu_acpanic(char *str)
{
printf("Cannot malloc %s component of config tree\n", str);
panic("Incomplete config tree -- cannot continue.\n");
}
/*
* cpu_savecfg()
*/
LONG
cpu_savecfg(void)
{
return ENOSPC;
}
int
sn0_getcpuid(void)
{
return(cpuid()) ;
}
/*
* Clear all appropriate error latches in the system.
* To be used mainly in conjunction with "nofault"
* accesses.
*/
void
cpu_clear_errors(void)
{
/* TBD */
}
/*
* Print all appropriate error state in system.
*/
void
cpu_print_errors(void)
{
/* TBD */ }
/*
* EPC support
*/
static COMPONENT ioc3tmpl = {
AdapterClass, /* Class */
MultiFunctionAdapter, /* Type */
(IDENTIFIERFLAG)0, /* Flags */
SGI_ARCS_VERS, /* Version */
SGI_ARCS_REV, /* Revision */
0, /* Key */
0x01, /* Affinity */
0, /* ConfigurationDataSize */
9, /* IdentifierLength */
"IOC3-1.0" /* Identifier */
};
/* Move to ioc3.c? */
void
ioc3_install(COMPONENT *root)
{
printf("fixme: ioc3_install should not be called\n") ;
root = AddChild(root,&ioc3tmpl,(void *)NULL);
if (root == (COMPONENT *)NULL) cpu_acpanic("IOC3");
return;
}
#define TOD_SGS_M48T35 1
#define TOD_DALLAS_DS1386 2
static __psunsigned_t nvram_base ;
static int tod_chip_type ;
static int
get_tod_chip_type(void)
{
char testval ;
PCI_OUTB(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_DISABLE) ;
PCI_OUTB(RTC_DAL_DAY_ADDR, 0xff) ;
PCI_OUTB(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_ENABLE) ;
testval = PCI_INB(RTC_DAL_DAY_ADDR) ;
if (testval == 0xff)
tod_chip_type = TOD_SGS_M48T35 ;
else
tod_chip_type = TOD_DALLAS_DS1386 ;
return tod_chip_type ;
}
/*
* cpu_get_tod -- get current time-of-day from RTC and prom info, and
* return it in ARCS TIMEINFO format. the libsc routine get_tod will
* convert it to seconds for those who need it in that form.
*/
void
cpu_get_tod(TIMEINFO *t)
{
int month, day, hours, mins, secs, year;
if (nvram_base == NULL) {
nvram_base = kl_ioc3nvram_base(get_nasid());
if (!nvram_base)
return ; /* Actually we should PANIC !!! here */
tod_chip_type = get_tod_chip_type() ;
}
switch (tod_chip_type) {
case TOD_SGS_M48T35:
PCI_OUTB(RTC_SGS_CONTROL_ADDR, RTC_SGS_READ_PROTECT);
secs = BCD_TO_INT(PCI_INB(RTC_SGS_SEC_ADDR));
mins = BCD_TO_INT(PCI_INB(RTC_SGS_MIN_ADDR));
hours = BCD_TO_INT(PCI_INB(RTC_SGS_HOUR_ADDR));
day = BCD_TO_INT(PCI_INB(RTC_SGS_DATE_ADDR));
month = BCD_TO_INT(PCI_INB(RTC_SGS_MONTH_ADDR));
year = BCD_TO_INT(PCI_INB(RTC_SGS_YEAR_ADDR));
PCI_OUTB(RTC_SGS_CONTROL_ADDR, 0);
break ;
case TOD_DALLAS_DS1386:
PCI_OUTB(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_DISABLE);
secs = BCD_TO_INT(PCI_INB(RTC_DAL_SEC_ADDR));
mins = BCD_TO_INT(PCI_INB(RTC_DAL_MIN_ADDR));
hours = BCD_TO_INT(PCI_INB(RTC_DAL_HOUR_ADDR));
day = BCD_TO_INT(PCI_INB(RTC_DAL_DATE_ADDR));
month = BCD_TO_INT(PCI_INB(RTC_DAL_MONTH_ADDR));
year = BCD_TO_INT(PCI_INB(RTC_DAL_YEAR_ADDR));
PCI_OUTB(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_ENABLE);
break ;
default:
break ;
}
#if 0
PCI_OUTB(RTC_CONTROL_ADDR, RTC_READ_PROTECT);
secs = BCD_TO_INT(PCI_INB(RTC_SEC_ADDR));
mins = BCD_TO_INT(PCI_INB(RTC_MIN_ADDR));
hours = BCD_TO_INT(PCI_INB(RTC_HOUR_ADDR));
day = BCD_TO_INT(PCI_INB(RTC_DATE_ADDR));
month = BCD_TO_INT(PCI_INB(RTC_MONTH_ADDR));
year = BCD_TO_INT(PCI_INB(RTC_YEAR_ADDR));
PCI_OUTB(RTC_CONTROL_ADDR, 0);
#endif
year += YRREF ;
#if 0
printf("cpu_get_tod: %d:%d:%d %d/%d/%d\n",
hours,mins,secs, year,month,day);
#endif
t->Month = month;
t->Day = day;
t->Year = year ;
t->Hour = hours;
t->Minutes = mins;
t->Seconds = secs;
t->Milliseconds = 0 ;
return;
}
/*ARGSUSED*/
void
spunlock(lock_t lock, int ospl)
{
/* TBD */
}
/*
* ecc_error_decode()
* Does something, don't know exactly what.
*/
/*ARGSUSED*/
void
ecc_error_decode(u_int ecc_error_reg)
{
#if 0
printf("ecc_error_decode: Not Yet Implemented.\n");
#endif
}
/*
* kl_scsiedtinit()
* Do SN0-specific SCSI probe and initialization code.
*/
void
kl_scsiedtinit(COMPONENT *c)
{
printf("kl_scsiedtinit should not be called for SN0\n");
}
/*
* master_io6()
* Finds the master IO6 board in the system and returns its slot
* number.
*/
static unsigned int
master_io6(void)
{
printf("fixme: master_io6\n"); /* XXX */
return 0;
}
int
flush_iocache(int slot)
{
/* Flush the processor data caches */
flush_cache();
return 0;
}
void
kl_flush_caches(void)
{
flush_iocache(0);
}
void
FlushAllCaches(void)
{
kl_flush_caches();
}
/*
* Make an entry in the TLB to map the IOspace corresponding to IO6 'window '
* and adapter 'anum' into K2 space address
*/
/*
* Function : tlbentry
* Description :
* Make an entry in the TLB for the given window and adapter No,
* and return the virtual address mapped.
* This is a simpleton tlb mapping, and is used mostly to
* map the diagnostic accesses to the Large window address.
*
* Caution : User of tlbentry should make sure to remove this entry
* after its use. Otherwise the table may overflow.
*/
/*
* NOTE :
* Graphics cannot use this routine since it needs a fixed address to
* be remapped a few times to different physical address ..
* Graphics now uses address 0xf0000000 and DONT use that address
*/
#define FIRST_TLB_ENTRY 2
#define MAX_TLBSZ 8
#define VADDR_BASE ( IOMAP_BASE + 0x20000000 )
unsigned tlb_entries[MAX_TLBSZ];
caddr_t
tlbentry(int window, int anum, unsigned offset)
/* offset should be < IOMAP_VPAGESIZE */
{
unsigned vpn2 ,old_pgmask, pfno;
pde_t pfnevn, pfnodd;
int i;
/* Get the address we can use. */
for (i=0; i < MAX_TLBSZ; i++){
if (tlb_entries[i] == 0){
tlb_entries[i] = 1;
break;
}
}
if (i == MAX_TLBSZ)
panic("TLB entries exhausted...\n");
vpn2 = (unsigned) (VADDR_BASE + ( i << (IOMAP_VPAGESHIFT + 1)));
tlb_entries[i] = vpn2;
#if 1
/* printf("fixme: getcachesz\n"); XXX */
pfno = -1;
#else
pfno = LWIN_PFN(window, anum) + (offset >> 12);
#endif
pfnevn.pgi = (pfno << 6 ) | 0x17; /* UNCACHED|MODIFIED|VALID|GLOBAL */
pfno += (IOMAP_VPAGESIZE >> 12);
pfnodd.pgi = (pfno << 6 ) | 0x17;
old_pgmask = get_pgmask();
set_pgmask(IOMAP_TLBPAGEMASK);
tlbwired(i+FIRST_TLB_ENTRY, 0, (caddr_t)(__psunsigned_t)vpn2, pfnevn.pgi, pfnodd.pgi);
set_pgmask(old_pgmask);
return((caddr_t)(__psunsigned_t)vpn2);
}
int
tlbrmentry(caddr_t vaddr)
{
__scunsigned_t i;
i = ((__scunsigned_t)vaddr - VADDR_BASE) >> (IOMAP_VPAGESHIFT + 1) ;
if (tlb_entries[i] == 0)
return(-1);
invaltlb((int)(i+FIRST_TLB_ENTRY));
tlb_entries[i] = 0;
return (0);
}
/*
* just call in an ascending loop till returns != 0
* added for ide - don't want ide to know about internals over here
*/
int
inval_tlbentry(uint slot)
{
if (slot >= MAX_TLBSZ)
return(-1);
invaltlb(slot+(int)FIRST_TLB_ENTRY);
tlb_entries[slot] = 0;
return (0);
}
void
tlbrall(void)
{
int i;
/* zero all tlb entries */
for (i=0; i < MAX_TLBSZ; i++) {
invaltlb(i+(int)FIRST_TLB_ENTRY);
tlb_entries[i] = 0;
}
}
void
cpu_scandevs(void)
{
}
/* check if address is inside a "protected" area */
/*ARGSUSED*/
int
is_protected_adrs(unsigned long low, unsigned long high)
{
return 0; /* none */
}
/*
* Make a PCI DMA Address on SN0.
*/
__psunsigned_t
get_pci64_dma_addr(__psunsigned_t addr, ULONG key)
{
/* XXX Add attribute bits */
nasid_t nasid = GET_HSTNASID_FROM_KEY(key) ;
__psunsigned_t dmaaddr = 0 ;
unsigned char hubwid = GET_HUBWID_FROM_KEY(key) ;
addr = kvtophys((void *) addr) ; /* Phys addr only */
dmaaddr = addr | NODE_OFFSET(nasid) ;
dmaaddr |= ((__psunsigned_t)hubwid << PCI_64_TARGID_SHFT) ;
dmaaddr |= (PCI64_ATTR_PREC|PCI64_ATTR_BAR);
return(dmaaddr) ;
}
#if 0
#include <saio.h>
extern IOBLOCK *net_iob;
/*VARARGS1*/
int
netprintf(const char *fmt, ...)
{
va_list ap;
char scanset = 0;
int rc;
return 1;
#if 0
if (net_iob && (net_iob->Flags & F_SCAN)) {
net_iob->Flags &= ~F_SCAN;
scanset = 1;
}
va_start(ap, fmt);
vprintf(fmt, (char *)ap);
va_end(ap);
if (scanset) {
net_iob->Flags |= F_SCAN;
}
return rc;
#endif
}
#endif
klinfo_t *
kl_find_type(CONFIGTYPE type, void *prev)
{
char tmp_buf[32] ;
graph_error_t graph_err ;
vertex_hdl_t vhdl, vhdl1, *pvhdl ;
char *remain ;
klinfo_t *kliptr ;
graph_edge_place_t eplace = GRAPH_EDGE_PLACE_NONE ;
DECLARE_HWGHDL
CHOOSE_GHDL
CHOOSE_RVHDL
pvhdl = (vertex_hdl_t *)prev ;
strcpy(tmp_buf, "/dev/") ;
switch (type) {
case NetworkController:
strcat(tmp_buf, "ethernet") ;
type = KLSTRUCT_IOC3ENET ;
break ;
case CDROMController:
strcat(tmp_buf, "cdrom") ;
type = KLSTRUCT_CDROM ;
break ;
case TapeController:
strcat(tmp_buf, "tape") ;
type = KLSTRUCT_TAPE ;
break ;
default:
return 0 ;
}
if ((graph_err = hwgraph_path_lookup(rvhdl, tmp_buf,
&vhdl, &remain)) != GRAPH_SUCCESS) {
printf("kl_find_type: Cannot find device of type %s, %d\n",
tmp_buf, graph_err) ;
return 0 ;
}
if ((pvhdl) && (*pvhdl)) { /* search for the previous edge */
do {
graph_err = graph_edge_get_next(ghdl,
vhdl,
tmp_buf,
&vhdl1, &eplace) ;
if (graph_err != GRAPH_SUCCESS) {
return 0 ;
}
}
while (*pvhdl != vhdl1) ;
}
graph_err = graph_edge_get_next(ghdl,
vhdl,
tmp_buf,
&vhdl1, &eplace) ;
if (graph_err != GRAPH_SUCCESS) {
return 0 ;
}
if (pvhdl)
*(vertex_hdl_t *)pvhdl = vhdl1 ;
graph_err = graph_info_get_LBL(ghdl, vhdl1,
INFO_LBL_KLCFG_INFO,NULL,
(arbitrary_info_t *)&kliptr) ;
if (graph_err != GRAPH_SUCCESS) {
printf("kl_find_type: Cannot find info for device %s\n", tmp_buf) ;
return 0 ;
}
if (kliptr->struct_type == type)
return (kliptr) ;
else
return 0 ;
}
int
kl_count_type(CONFIGTYPE type)
{
char tmp_buf[32] ;
graph_error_t graph_err ;
vertex_hdl_t vhdl, vhdl1 ;
char *remain ;
klinfo_t *kliptr ;
graph_edge_place_t eplace = GRAPH_EDGE_PLACE_NONE ;
DECLARE_HWGHDL
CHOOSE_GHDL
CHOOSE_RVHDL
strcpy(tmp_buf, "/dev/") ;
switch (type) {
case NetworkController:
strcat(tmp_buf, "ethernet") ;
type = KLSTRUCT_IOC3ENET ;
break ;
case CDROMController:
strcat(tmp_buf, "cdrom") ;
type = KLSTRUCT_CDROM ;
break ;
case TapeController:
strcat(tmp_buf, "tape") ;
type = KLSTRUCT_TAPE ;
break ;
default:
return 0 ;
}
if ((graph_err = hwgraph_path_lookup(rvhdl, tmp_buf,
&vhdl, &remain)) != GRAPH_SUCCESS) {
printf("kl_find_type: %s not found in HWGRAPH %d\n",
tmp_buf, graph_err) ;
return 0 ;
}
graph_err = graph_edge_get_next(ghdl,
vhdl,
tmp_buf,
&vhdl1, &eplace) ;
if (graph_err != GRAPH_SUCCESS) {
return 0 ;
}
graph_err = graph_info_get_LBL(ghdl, vhdl1,
INFO_LBL_KLCFG_INFO,NULL,
(arbitrary_info_t *)&kliptr) ;
if (graph_err != GRAPH_SUCCESS) {
printf("kl_find_type: Target node has no INFO label\n") ;
return 0 ;
}
if (kliptr->struct_type == type)
return (1) ;
else
return 0 ;
}
#define MAXLIST 26
void
kl_showlist(void *root, CONFIGTYPE type, void *list, int gui)
{
klinfo_t *kliptr ;
cfgnode_t *ac ;
int i ;
COMPONENT **newlist ;
char buf[128] ;
vertex_hdl_t vhdl = NULL ;
newlist = (COMPONENT **)list ;
/* XXX for now, find the first device. later integrate
kl_find_type and this routine.
*/
while (kliptr = kl_find_type(type, (void *)&vhdl)) {
ac = (cfgnode_t *)malloc(sizeof(cfgnode_t)) ;
bzero(ac, sizeof(cfgnode_t)) ;
ac->parent = (cfgnode_t *)malloc(sizeof(cfgnode_t)) ;
bzero(ac->parent, sizeof(cfgnode_t)) ;
bcopy(kliptr->arcs_compt, ac, sizeof(COMPONENT)) ;
ac->comp.Type = type ;
if (type == CDROMController)
ac->comp.Key = (kliptr->arcs_compt->Key) ;
else
if ((type == TapeController) || (type == TapePeripheral))
ac->comp.Key = (kliptr->arcs_compt->Key) ;
else
ac->comp.Key = 0 ;
ac->parent->comp.Type = type ;
if (gui) {
struct _radioButton *b;
sn0_dev2eng(&ac->comp,buf) ;
b = appendRadioList(list,buf,0);
if (b) b->userdata = (void *)&ac->comp ;
}
for (i=0 ; i < MAXLIST; i++)
if (newlist[i] == 0) {
newlist[i] = (COMPONENT *)ac;
break;
}
} /* while */
}
void
sn0_dev2eng(COMPONENT *c, char *buf)
{
klinfo_t *kliptr ;
char *host = getenv("netinsthost");
char *file = getenv("netinstfile");
if (!(kliptr = kl_find_type(c->Type, NULL))) {
*buf = 0;
return ;
}
switch (c->Type) {
case CDROMController:
sprintf(buf,"Local SCSI CD-ROM drive %d, on controller %d",
(kliptr->arcs_compt->Key&0xff),
(kliptr->arcs_compt->Key>>8)) ;
break ;
case NetworkController:
sprintf(buf,"Remote directory %s from server %s.",
file,host);
break ;
case TapeController:
sprintf(buf,"Local Tape drive %d, on controller %d",
(kliptr->arcs_compt->Key&0xff),
(kliptr->arcs_compt->Key>>8)) ;
break ;
default:
*buf = 0;
break ;
}
}
extern int iscdrom ;
char *
kl_fixupname(COMPONENT *tape)
{
static char name[256] ;
name[0] = 0 ;
if (iscdrom = (tape->Type == CDROMController ||
((COMPONENT *)((cfgnode_t *)tape)->parent)->Type
== CDROMController)) {
sprintf(name, "scsi(%d)cdrom(%d)partition(8)\0",
(uchar)(tape->Key >> 8), (uchar)tape->Key) ;
}
if (tape->Type == NetworkController) {
char *cp;
strcat(name,"bootp()");
cp = getenv("netinsthost");
if (cp) {
strcat(name,cp);
cp = getenv("netinstfile");
if (cp) {
strcat(name,":");
strcat(name,cp);
}
}
}
if ((tape->Type == TapeController) ||
(tape->Type == TapePeripheral) ||
(((COMPONENT *)((cfgnode_t *)tape)->parent)->Type
== TapeController) ||
(((COMPONENT *)((cfgnode_t *)tape)->parent)->Type
== TapePeripheral)) {
sprintf(name, "scsi(%d)tape(%d)\0",
(uchar)(tape->Key >> 8), (uchar)tape->Key) ;
}
return(name);
}
char *
kl_inv_find()
{
graph_error_t graph_err ;
char *label_name ;
DECLARE_HWGHDL
CHOOSE_GHDL
CHOOSE_RVHDL
graph_err = graph_info_get_LBL(ghdl, rvhdl,
INFO_LBL_VERTEX_NAME, NULL,
(arbitrary_info_t *)&label_name) ;
if (graph_err == GRAPH_SUCCESS)
return label_name ;
else
return NULL ;
}
char *
copy_nic_field(char *n, char *h)
{
while (*n != ';')
*h++ = *n++ ;
*h = 0 ;
return ++n ;
}
#ifndef SN_PDI
void *
pg_get_lbl(vertex_hdl_t vhdl, char *label)
{
graph_error_t gerr ;
void *k ;
gerr = graph_info_get_LBL(prom_graph_hdl, vhdl,
label, NULL,
(arbitrary_info_t *)&k) ;
if (gerr == GRAPH_SUCCESS)
return k ;
return NULL ;
}
int
pg_add_lbl(vertex_hdl_t vhdl, char *label, void *info)
{
graph_error_t gerr ;
gerr = graph_info_add_LBL(prom_graph_hdl, vhdl,
label, NULL,
(arbitrary_info_t) info) ;
return gerr ;
}
#endif /* SN_PDI */
int
is_ConsoleIn_valid()
{
char *s1, *s2 ;
s1 = getenv("ConsoleIn") ;
s2 = cpu_get_kbd_str() ;
if (!strcmp(s1, s2))
return 1 ;
return 0 ;
}
int
pg_add_nic_info(klinfo_t *k, vertex_hdl_t vhdl)
{
char *mfg_nic ;
klconf_off_t mfg_off ;
graph_error_t gerr ;
switch(k->struct_type) {
case KLSTRUCT_BRI:
mfg_off = ((klbri_t *)k)->bri_mfg_nic ;
break;
case KLSTRUCT_HUB:
mfg_off = ((klhub_t *)k)->hub_mfg_nic ;
break;
case KLSTRUCT_ROU:
mfg_off = ((klrou_t *)k)->rou_mfg_nic ;
break;
case KLSTRUCT_GFX:
mfg_off = ((klgfx_t *)k)->gfx_mfg_nic ;
break;
case KLSTRUCT_TPU:
mfg_off = ((kltpu_t *)k)->tpu_mfg_nic ;
break;
case KLSTRUCT_GSN_A:
case KLSTRUCT_GSN_B:
mfg_off = ((klgsn_t *)k)->gsn_mfg_nic ;
break;
case KLSTRUCT_XTHD:
mfg_off = ((klxthd_t *)k)->xthd_mfg_nic ;
break;
default:
break ;
}
mfg_nic = (char *)NODE_OFFSET_TO_K1(k->nasid, mfg_off) ;
if (gerr = pg_add_lbl(vhdl, INFO_LBL_NIC, (void *)mfg_nic)) {
printf("%d: add LBL NIC error %d\n", k->nasid, gerr);
return 0;
}
return 1 ;
}
#if 0
/* support for completely disabling node boards */
#include <sn_macros.h>
#include <sys/SN/SN0/ip27log.h>
/* struct to remember the nasids of node boards that are
* completely disabled. This means no memory on board too.
* In such a situation, this brd has no klconfig and is
* invisible except to the prom, using promlog variables.
*/
static nasid_t last_nasid, trying_nasid ;
typedef struct dis_nbrd_s {
moduleid_t mod ;
slotid_t slot ;
} dis_nbrd_t ;
dis_nbrd_t dis_node_brd_table[MAX_NASIDS/2] ;
void
do_dis_node_brds(void)
{
char buf[128] ;
int mod, slot = 0 ;
char *tmp = NULL ;
jmp_buf new_buf;
void *old_buf;
if (_symmon)
return ;
last_nasid = 0 ;
if (setfault(new_buf, &old_buf)) {
last_nasid = trying_nasid + 1;
}
for (trying_nasid = last_nasid; trying_nasid < MAX_NASIDS;
trying_nasid++) {
volatile __uint64_t sr0;
sr0 = REMOTE_HUB_L(trying_nasid, NI_SCRATCH_REG0);
REMOTE_HUB_S(trying_nasid, NI_SCRATCH_REG0, sr0);
if (ip27log_getenv( trying_nasid,
DISABLE_NODE_BRD, buf, NULL, 0) < 0)
continue ;
if (strncmp("/hw/module/", buf, 11))
continue ;
mod = strtoull(&buf[11], &tmp, 10) ;
if (!(SN00)) {
if (!tmp)
continue ;
if (strncmp("/slot/n", tmp, 7))
continue ;
slot = strtoull(tmp+7, NULL, 10) ;
}
dis_node_brd_table[trying_nasid].mod = mod ;
dis_node_brd_table[trying_nasid].slot = slot ;
}
restorefault(old_buf);
}
nasid_t
get_dis_node_brd_nasid(moduleid_t mod, slotid_t slot)
{
int i ;
for (i=0;i<MAX_NASIDS/2;i++)
if ((dis_node_brd_table[i].mod == mod) &&
(dis_node_brd_table[i].slot == slot)) {
return i ;
}
return INVALID_NASID ;
}
void
hinv_print_dis_node_brds(void)
{
int i ;
char slot_name[32] ;
for (i=0;i<MAX_NASIDS/2;i++)
if (dis_node_brd_table[i].mod) {
if (SN00)
strcpy(slot_name, "MotherBoard") ;
else
sprintf(slot_name, "n%d",
dis_node_brd_table[i].slot) ;
printf( "IP27 Node Board, Module %d, Slot %s, "
"(nasid %d) ** disabled\n",
dis_node_brd_table[i].mod,
slot_name, i) ;
}
}
#endif
/* Support for reading extra NICs */
#define MAX_EXTRA_NICS 32
#define NIC_STRING_LEN 1024
struct en_s {
lboard_t *lb ;
char *nic ;
} ;
struct {
int cur ;
struct en_s enic[MAX_EXTRA_NICS] ;
} extra_nic ;
#define ENICP(i) (&extra_nic.enic[i])
#define NEW_ENICP (&extra_nic.enic[extra_nic.cur])
#define INCR_ENIC (extra_nic.cur++)
#define ENIC_LIMIT (extra_nic.cur >= MAX_EXTRA_NICS)
#define CHECK_IOC3_NIC(l, p) ((!IS_MIO_IOC3(l, p)) && \
((l->brd_type == KLTYPE_PCI) || \
((l->brd_type == KLTYPE_BASEIO) && \
(SN00) && (p > 3))))
void
init_extra_nic(void)
{
struct en_s *en ;
int i ;
extra_nic.cur = 0 ;
en = NEW_ENICP ;
for(i=0;i<MAX_EXTRA_NICS;i++,en++) {
en->lb = 0 ;
en->nic = 0 ;
}
}
__psunsigned_t
init_ioc3_for_nic(lboard_t *lb, klinfo_t *k)
{
__psunsigned_t base ;
base = NODE_SWIN_BASE(lb->brd_nasid, k->widid) ;
base = base + BRIDGE_DEVIO(k->physid) ;
*(__int32_t *)(base + IOC3_GPCR_S) |= 0x00200000 ;
return(base+IOC3_MCR) ;
}
/* visit_lboard call back */
int
read_extra_nic_lb(lboard_t *lb, void *ap, void *rp)
{
struct en_s *en ;
klinfo_t *k = NULL ;
klhub_t *hubp;
__psunsigned_t base ;
if(!(lb->brd_flags & ENABLE_BOARD) && (k = find_component(lb,k,KLSTRUCT_HUB)))
{
hubp = (klhub_t *)k;
if(hubp->hub_mfg_nic)
{
if (ENIC_LIMIT)
return 1;
en = NEW_ENICP ;
en->nic = malloc(NIC_STRING_LEN) ;
en->lb = lb ;
if (en->nic) {
strcpy(en->nic,(char *)NODE_OFFSET_TO_K1(lb->brd_nasid,hubp->hub_mfg_nic));
INCR_ENIC;
}
}
}
if (!(k = find_component(lb, k, KLSTRUCT_IOC3)))
return 1 ;
do {
if (CHECK_IOC3_NIC(lb, k->physid)) {
if (ENIC_LIMIT)
break ;
en = NEW_ENICP ;
en->nic = malloc(NIC_STRING_LEN) ;
en->lb = lb ;
if (en->nic) {
base = init_ioc3_for_nic(lb, k) ;
klcfg_get_nic_info((nic_data_t)base, en->nic) ;
INCR_ENIC ;
}
}
k = find_component(lb, k, KLSTRUCT_IOC3) ;
} while(k) ;
return 1 ;
}
void
read_extra_nic(void)
{
init_extra_nic() ;
visit_lboard(read_extra_nic_lb, NULL, NULL) ;
}
void
get_hwg_name(lboard_t *lb, char *s)
{
char sname[SLOTNUM_MAXLENGTH];
get_slotname(lb->brd_slot, sname) ;
sprintf(s, "/hw/module/%d/slot/%s",
lb->brd_module, sname) ;
}
void
print_extra_nic(int flags)
{
struct en_s *en ;
int i ;
char lname[64];
en = ENICP(0) ;
for (i=0; i<extra_nic.cur; i++, en++) {
get_hwg_name(en->lb, lname) ;
printf("location: %s\n", lname) ;
if (flags&HINV_MVV)
printf("%s\n", en->nic) ;
else
prnic_fmt(en->nic) ;
printf("\n") ;
}
}
/* End support for reading extra NICs */
#define GOOD_COMP 0x0
#define BAD_NODE 0x1
#define BAD_CPU_A 0x2
#define BAD_CPU_B 0x4
#define BAD_MEM 0x8
#define BAD_ROU 0x10
#define BAD_HUBII 0x20
/*
* Function: dump_scsi_diags -> checks for diagnostic errors on
* specified scsi device
* Args: board pointer, scsi component
* Returns: -1 on failure, 0 on success
*/
int dump_scsi_diags(lboard_t *brd_ptr, klscsi_t *scsi)
{
int numpci, pciid;
unsigned short diag = scsi->scsi_info.diagval;
if (scsi && diag != KLDIAG_PASSED) {
printf("\t\t/hw/module/%d/slot/io%d: SCSI failed diag\n",
brd_ptr->brd_module, SLOTNUM_GETSLOT(brd_ptr->brd_slot));
numpci = (sizeof(diag) * NBBY / NUM_SCSI_FAIL_CODES);
for (pciid=0; pciid<numpci; pciid++) {
if (diag & SCSI_MEM_FAIL_MASK)
printf("\t\t\tReason: pci id %d %s\n",
pciid, get_diag_string(KLDIAG_SCSI_SSRAM_FAIL));
if (diag & SCSI_DMA_FAIL_MASK)
printf("\t\t\tReason: pci id %d %s\n",
pciid, get_diag_string(KLDIAG_SCSI_DMA_FAIL));
if (diag & SCSI_STEST_FAIL_MASK)
printf("\t\t\tReason: pci id %d %s\n",
pciid, get_diag_string(KLDIAG_SCSI_STEST_FAIL));
diag >>= NUM_SCSI_FAIL_CODES;
}
return -1;
}
return 0;
}
/*
* Function: sn0_dump_diag -> dumps complete system cfg and diag
* results
* Args: diag_mode -> DIP switch settings for diag mode
* Returns: Nothing
* Note: Must be called only after gda, etc. are inited
*/
void sn0_dump_diag(int diag_mode)
{
int i, bad, disable, bank, all_disabled;
int ncpu = 0, ncpu_dis = 0, mem = 0, mem_dis = 0;
int node = 0, node_dis = 0, nrou = 0, nrou_dis = 0;
int num_bad_nasid = 0;
char bad_comp[MAX_NASIDS];
lboard_t *brd_ptr;
klcpu_t *cpu;
klhub_t *hub;
klmembnk_t *membank;
klrou_t *rou;
klioc3_t *ioc3;
klscsi_t *scsi;
gda_t *gdap;
char mem_disable[MD_MEM_BANKS + 1], disable_sz[MD_MEM_BANKS + 1];
gdap = (gda_t *)GDA_ADDR(get_nasid());
printf("\n**** System Configuration and Diagnostics Summary ****\n");
for (i = 0; i < MAX_NASIDS; i++)
bad_comp[i] = GOOD_COMP;
for (i = 0; i < MAX_COMPACT_NODES; i++) {
nasid_t d_nasid;
if (gdap->g_nasidtable[i] == INVALID_CNODEID)
continue;
d_nasid = gdap->g_nasidtable[i];
brd_ptr = (lboard_t *) find_lboard((lboard_t *)KL_CONFIG_INFO(d_nasid),
KLTYPE_IP27);
if (!brd_ptr) {
printf("\tWARNING: Could not find brd_ptr for nasid = %d\n",
d_nasid);
continue;
}
if (brd_ptr->brd_flags & DUPLICATE_BOARD)
continue;
if ((!(brd_ptr->brd_flags & ENABLE_BOARD)) ||
(brd_ptr->brd_flags & FAILED_BOARD)) {
bad_comp[d_nasid] |= BAD_NODE;
node_dis++;
}
else
node++;
hub = (klhub_t *) find_first_component(brd_ptr, KLSTRUCT_HUB);
if (hub->hub_info.diagval != KLDIAG_PASSED)
bad_comp[d_nasid] |= BAD_HUBII;
cpu = (klcpu_t *) find_component(brd_ptr, (klinfo_t *) NULL,
KLSTRUCT_CPU);
if (!cpu) {
printf("\tWARNING: Could not find a single CPU on nasid = %d\n",
d_nasid);
continue;
}
if ((!(cpu->cpu_info.flags & KLINFO_ENABLE)) ||
(cpu->cpu_info.flags & KLINFO_FAILED)) {
bad_comp[d_nasid] |= (cpu->cpu_info.physid ?
BAD_CPU_B : BAD_CPU_A);
ncpu_dis++;
}
else
ncpu++;
cpu = (klcpu_t *) find_component(brd_ptr, (klinfo_t *) cpu,
KLSTRUCT_CPU);
if (cpu) {
if ((!(cpu->cpu_info.flags & KLINFO_ENABLE)) ||
(cpu->cpu_info.flags & KLINFO_FAILED)) {
bad_comp[d_nasid] |= (cpu->cpu_info.physid ?
BAD_CPU_B : BAD_CPU_A);
ncpu_dis++;
}
else
ncpu++;
}
membank = (klmembnk_t *) find_component(brd_ptr, (klinfo_t *) NULL,
KLSTRUCT_MEMBNK);
disable = (ip27log_getenv(d_nasid, "DisableMemMask", mem_disable, 0, 0)
>= 0);
if (disable) {
ip27log_getenv(d_nasid, "DisableMemSz", disable_sz, 0, 0);
bad_comp[d_nasid] |= BAD_MEM;
}
if (membank) {
if ((!(membank->membnk_info.flags & KLINFO_ENABLE)) ||
(membank->membnk_info.flags & KLINFO_FAILED)) {
bad_comp[d_nasid] |= BAD_MEM;
mem_dis += membank->membnk_memsz;
}
else
mem += membank->membnk_memsz;
}
else
printf("\tNo Memory found on nasid = %d\n", d_nasid);
if (disable) {
/*if(membank)
membank->membnk_info.flags &= ~KLINFO_ENABLE;*/
for (bank = 0; bank < MD_MEM_BANKS; bank++)
/* If DIP_NODISABLE is active, the bank will not actually
* be disabled, so don't count the memory as disabled. */
if (strchr(mem_disable, '0' + bank) &&
membank->membnk_bnksz[bank] == 0)
{
mem_dis += MD_SIZE_MBYTES(disable_sz[bank] - '0');
/* membank->membnk_info.flags |= 0x1 << (bank + 8);*/
}
}
brd_ptr = KLCF_NEXT(brd_ptr);
while((brd_ptr) && (brd_ptr = find_lboard(brd_ptr,KLTYPE_IP27)))
{
int nasid;
hub = (klhub_t *) find_first_component(brd_ptr, KLSTRUCT_HUB);
if(hub)
nasid = ((klinfo_t *)hub)->physid;
else
continue;
membank = (klmembnk_t *) find_component(brd_ptr, (klinfo_t *) NULL,
KLSTRUCT_MEMBNK);
disable = (ip27log_getenv(nasid, "DisableMemMask", mem_disable, 0, 0)
>= 0);
if (disable) {
ip27log_getenv(nasid, "DisableMemSz", disable_sz, 0, 0);
}
if (membank) {
if ((!(membank->membnk_info.flags & KLINFO_ENABLE)) ||
(membank->membnk_info.flags & KLINFO_FAILED)) {
mem_dis += membank->membnk_memsz;
}
else
mem += membank->membnk_memsz;
}
else
printf("\tNo Memory found on nasid = %d\n", d_nasid);
if (disable) {
/*if(membank)
membank->membnk_info.flags &= ~KLINFO_ENABLE;*/
/* If DIP_NODISABLE is active, the bank will not actually
* be disabled, so don't count the memory as disabled. */
for (bank = 0; bank < MD_MEM_BANKS; bank++)
if (strchr(mem_disable, '0' + bank) &&
membank->membnk_bnksz[bank] == 0)
{
mem_dis += MD_SIZE_MBYTES(disable_sz[bank] - '0');
}
}
brd_ptr = KLCF_NEXT(brd_ptr);
}
brd_ptr = (lboard_t *) find_lboard((lboard_t *) KL_CONFIG_INFO(d_nasid),
KLTYPE_ROUTER);
if (!brd_ptr || (brd_ptr->brd_flags & DUPLICATE_BOARD))
continue;
if ((!(brd_ptr->brd_flags & ENABLE_BOARD)) ||
(brd_ptr->brd_flags & FAILED_BOARD)) {
bad_comp[d_nasid] |= BAD_ROU;
nrou_dis++;
continue;
}
rou = (klrou_t *) find_component(brd_ptr, (klinfo_t *) NULL,
KLSTRUCT_ROU);
if (rou) {
if ((!(rou->rou_info.flags & KLINFO_ENABLE)) ||
(rou->rou_info.flags & KLINFO_FAILED)) {
bad_comp[d_nasid] |= BAD_ROU;
nrou_dis++;
}
else
nrou++;
}
brd_ptr = (lboard_t *) find_lboard((lboard_t *) KL_CONFIG_INFO(d_nasid),
KLTYPE_META_ROUTER);
if (!brd_ptr || (brd_ptr->brd_flags & DUPLICATE_BOARD))
continue;
if ((!(brd_ptr->brd_flags & ENABLE_BOARD)) ||
(brd_ptr->brd_flags & FAILED_BOARD)) {
bad_comp[d_nasid] |= BAD_ROU;
nrou_dis++;
continue;
}
rou = (klrou_t *) find_component(brd_ptr, (klinfo_t *) NULL,
KLSTRUCT_ROU);
if (rou) {
if ((!(rou->rou_info.flags & KLINFO_ENABLE)) ||
(rou->rou_info.flags & KLINFO_FAILED)) {
bad_comp[d_nasid] |= BAD_ROU;
nrou_dis++;
}
else
nrou++;
}
}
printf("CONFIG:\n");
printf("\t\tNo. of NODEs enabled \t= %d\n", node);
printf("\t\tNo. of NODEs disabled \t= %d\n", node_dis);
printf("\t\tNo. of CPUs enabled \t= %d\n", ncpu);
printf("\t\tNo. of CPUs disabled \t= %d\n", ncpu_dis);
printf("\t\tMem enabled \t\t= %d MB\n", mem);
printf("\t\tMem disabled \t\t= %d MB\n", mem_dis);
printf("\t\tNo. of RTRs enabled \t= %d\n", nrou);
printf("\t\tNo. of RTRs disabled \t= %d\n", nrou_dis);
printf("\nDIAG RESULTS:\n");
if (GET_DIAG_MODE(diag_mode) == DIAG_MODE_NONE) {
printf("\t\tNO DIAGS WERE RUN!\n");
goto done;
}
bad = 0;
for (i = 0; i < MAX_NASIDS; i++) {
if (bad_comp[i] == GOOD_COMP)
continue;
brd_ptr = find_lboard((lboard_t *) KL_CONFIG_INFO(i),
KLTYPE_IP27);
if (bad_comp[i] & BAD_NODE) {
bad = 1;
printf("\t\t/hw/module/%d/slot/n%d: NODE BOARD disabled\n",
brd_ptr->brd_module, SLOTNUM_GETSLOT(brd_ptr->brd_slot));
printf("\t\t\tReason: %s\n", get_diag_string(brd_ptr->brd_diagval));
}
if (bad_comp[i] & BAD_HUBII) {
bad = 1;
hub = (klhub_t *) find_first_component(brd_ptr, KLSTRUCT_HUB);
printf("\t\t/hw/module/%d/slot/n%d: HUB IO down\n",
brd_ptr->brd_module, SLOTNUM_GETSLOT(brd_ptr->brd_slot));
printf("\t\t\tReason: %s\n", get_diag_string(hub->hub_info.diagval));
}
if (bad_comp[i] & BAD_CPU_A) {
bad = 1;
cpu = (klcpu_t *) find_component(brd_ptr, (klinfo_t *) NULL,
KLSTRUCT_CPU);
printf("\t\t/hw/module/%d/slot/n%d/node/cpu/%d: CPU A disabled\n",
brd_ptr->brd_module, SLOTNUM_GETSLOT(brd_ptr->brd_slot), cpu->cpu_info.physid);
printf("\t\t\tReason: %s\n", get_diag_string(cpu->cpu_info.diagval));
}
if (bad_comp[i] & BAD_CPU_B) {
bad = 1;
cpu = (klcpu_t *) find_component(brd_ptr, (klinfo_t *) NULL,
KLSTRUCT_CPU);
cpu = (klcpu_t *) find_component(brd_ptr, (klinfo_t *) cpu,
KLSTRUCT_CPU);
printf("\t\t/hw/module/%d/slot/n%d/node/cpu/%d: CPU B disabled\n",
brd_ptr->brd_module, SLOTNUM_GETSLOT(brd_ptr->brd_slot), cpu->cpu_info.physid);
printf("\t\t\tReason: %s\n", get_diag_string(cpu->cpu_info.diagval));
}
if (bad_comp[i] & BAD_MEM) {
char disable_bank[32], disable_reason[32];
int j, found = 0;
bad = 1;
membank = (klmembnk_t *) find_component(brd_ptr, (klinfo_t *)
NULL, KLSTRUCT_MEMBNK);
if (ip27log_getenv(i, "DisableMemMask", disable_bank, 0, 0) < 0)
disable_bank[0] = 0;
else {
char tmp_buf[32];
int n = 0;
/*
* loop through disabled banks. If DIP_NODISABLE is
* turned on, we don't want to record the bank as
* disabled, regardless of what the promlog variable says.
* Check this by checking the size - if DIP_NODISABLE is
* set, mdir_disable_bank() is not called, so the size is
* not set to 0.
*/
for (j = 0; j < strlen(disable_bank); j++) {
if(!membank->membnk_bnksz[disable_bank[j] - '0'])
{
found = 1;
tmp_buf[n++] = disable_bank[j];
tmp_buf[n++] = ' ';
}
}
tmp_buf[n] = 0;
strcpy(disable_bank, tmp_buf);
}
if(found) {
printf("\t\t/hw/module/%d/slot/n%d/node/mem: "
"MEMBANK(S) %s disabled\n", brd_ptr->brd_module,
SLOTNUM_GETSLOT(brd_ptr->brd_slot), disable_bank);
ip27log_getenv(i, "MemDisReason", disable_reason, "00000000",
0);
printf("\t\t\tReason:\n");
for (j = 0; j < MD_MEM_BANKS; j++) {
if (strchr(disable_bank, '0' + j)) {
if (disable_reason[j] == '0')
printf("\t\t\t\tBank %d: Unknown\n", j);
else if (disable_reason[j] == '0' + MEM_DISABLE_USR)
printf("\t\t\t\tBank %d: %s\n", j,
get_diag_string(KLDIAG_MEMORY_DISABLED));
else if (disable_reason[j] == '0' + MEM_DISABLE_AUTO)
printf("\t\t\t\tBank %d: %s\n", j,
get_diag_string(KLDIAG_MEMTEST_FAILED));
else if (disable_reason[j] == '0' + MEM_DISABLE_256MB)
printf("\t\t\t\tBank %d: %s\n", j,
get_diag_string(KLDIAG_IP27_256MB_BANK));
}
}
}
}
if (bad_comp[i] & BAD_ROU) {
brd_ptr = (lboard_t *) find_lboard((lboard_t *) KL_CONFIG_INFO(i),
KLTYPE_ROUTER);
while (brd_ptr) {
if (!(brd_ptr->brd_flags & DUPLICATE_BOARD)) {
rou = (klrou_t *) find_first_component(brd_ptr,
KLSTRUCT_ROU);
if (!(brd_ptr->brd_flags & ENABLE_BOARD) ||
(brd_ptr->brd_flags & FAILED_BOARD) ||
!(rou->rou_info.flags & KLINFO_ENABLE) ||
(rou->rou_info.flags & KLINFO_FAILED)) {
printf("\t\t/hw/module/%d/router/r%d: ROUTER disabled"
"\n", brd_ptr->brd_module,
SLOTNUM_GETSLOT(brd_ptr->brd_slot));
if (!(brd_ptr->brd_flags & ENABLE_BOARD) ||
(brd_ptr->brd_flags & FAILED_BOARD))
printf("\t\t\tReason: %s\n",
get_diag_string(brd_ptr->brd_diagval));
else
printf("\t\t\tReason: %s\n",
get_diag_string(rou->rou_info.diagval));
}
}
brd_ptr = (lboard_t *) find_lboard(brd_ptr, KLTYPE_ROUTER);
}
brd_ptr = (lboard_t *) find_lboard((lboard_t *) KL_CONFIG_INFO(i),
KLTYPE_META_ROUTER);
while (brd_ptr) {
if (!(brd_ptr->brd_flags & DUPLICATE_BOARD)) {
rou = (klrou_t *) find_first_component(brd_ptr,
KLSTRUCT_ROU);
if (!(brd_ptr->brd_flags & ENABLE_BOARD) ||
(brd_ptr->brd_flags & FAILED_BOARD) ||
!(rou->rou_info.flags & KLINFO_ENABLE) ||
(rou->rou_info.flags & KLINFO_FAILED)) {
printf("\t\t/hw/module/%d/router/r%d: ROUTER disabled"
"\n", brd_ptr->brd_module,
SLOTNUM_GETSLOT(brd_ptr->brd_slot));
if (!(brd_ptr->brd_flags & ENABLE_BOARD) ||
(brd_ptr->brd_flags & FAILED_BOARD))
printf("\t\t\tReason: %s\n",
get_diag_string(brd_ptr->brd_diagval));
else
printf("\t\t\tReason: %s\n",
get_diag_string(rou->rou_info.diagval));
}
}
brd_ptr = (lboard_t *) find_lboard(brd_ptr, KLTYPE_META_ROUTER);
}
}
}
/* Do serial_dma, ql & enet summary here */
for (i = 0; i < MAX_COMPACT_NODES; i++) {
nasid_t d_nasid;
d_nasid = gdap->g_nasidtable[i];
if (d_nasid == INVALID_CNODEID)
continue;
brd_ptr = (lboard_t *) find_lboard((lboard_t *) KL_CONFIG_INFO(d_nasid),
KLTYPE_WEIRDIO);
if(brd_ptr)
if ((!(brd_ptr->brd_flags & ENABLE_BOARD)) ||
(brd_ptr->brd_flags & FAILED_BOARD)) {
printf("\t\t/hw/module/%d/slot/io%d: IO link bad\n",
brd_ptr->brd_module, SLOTNUM_GETSLOT(brd_ptr->brd_slot));
bad = 1;
continue;
}
brd_ptr = (lboard_t *) find_lboard((lboard_t *) KL_CONFIG_INFO(d_nasid),
KLTYPE_BASEIO);
if (!brd_ptr || (brd_ptr->brd_flags & DUPLICATE_BOARD))
continue;
if ((!(brd_ptr->brd_flags & ENABLE_BOARD)) ||
(brd_ptr->brd_flags & FAILED_BOARD)) {
printf("\t\t/hw/module/%d/slot/io%d: BASEIO disabled\n",
brd_ptr->brd_module, SLOTNUM_GETSLOT(brd_ptr->brd_slot));
printf("\t\t\tReason: %s\n", get_diag_string(brd_ptr->brd_diagval));
bad = 1;
continue;
}
ioc3 = (klioc3_t *) find_component(brd_ptr, (klinfo_t *) NULL,
KLSTRUCT_IOC3);
if (ioc3 && ioc3->ioc3_info.diagval != KLDIAG_PASSED) {
printf("\t\t/hw/module/%d/slot/io%d: IOC3 failed diag\n",
brd_ptr->brd_module, SLOTNUM_GETSLOT(brd_ptr->brd_slot));
printf("\t\t\tReason: %s\n", get_diag_string(ioc3->ioc3_info.diagval));
bad = 1;
}
if (ioc3 && ioc3->ioc3_enet.diagval != KLDIAG_PASSED) {
printf("\t\t/hw/module/%d/slot/io%d: IOC3 ENET failed diag\n",
brd_ptr->brd_module, SLOTNUM_GETSLOT(brd_ptr->brd_slot));
printf("\t\t\tReason: %s\n", get_diag_string(ioc3->ioc3_enet.diagval));
bad = 1;
}
scsi = (klscsi_t *) find_component(brd_ptr, (klinfo_t *) NULL,
KLSTRUCT_SCSI);
if (dump_scsi_diags(brd_ptr, scsi) < 0)
bad = 1;
scsi = (klscsi_t *) find_component(brd_ptr, (klinfo_t *) scsi,
KLSTRUCT_SCSI);
if (dump_scsi_diags(brd_ptr, scsi) < 0)
bad = 1;
brd_ptr = (lboard_t *) find_lboard((lboard_t *) KL_CONFIG_INFO(d_nasid),
KLTYPE_MSCSI);
if ((!brd_ptr) || (brd_ptr->brd_flags & DUPLICATE_BOARD))
continue;
if ((!(brd_ptr->brd_flags & ENABLE_BOARD)) ||
(brd_ptr->brd_flags & FAILED_BOARD)) {
printf("\t\t/hw/module/%d/slot/io%d: MSCSI disabled\n",
brd_ptr->brd_module, SLOTNUM_GETSLOT(brd_ptr->brd_slot));
printf("\t\t\tReason: %s\n", get_diag_string(brd_ptr->brd_diagval));
bad = 1;
continue;
}
ioc3 = (klioc3_t *) find_component(brd_ptr, (klinfo_t *) NULL,
KLSTRUCT_IOC3);
if (ioc3 && ioc3->ioc3_info.diagval != KLDIAG_PASSED) {
printf("\t\t/hw/module/%d/slot/io%d: IOC3 failed diag\n",
brd_ptr->brd_module, SLOTNUM_GETSLOT(brd_ptr->brd_slot));
printf("\t\t\tReason: %s\n",
get_diag_string(ioc3->ioc3_info.diagval));
bad = 1;
}
if (ioc3 && ioc3->ioc3_enet.diagval != KLDIAG_PASSED) {
printf("\t\t/hw/module/%d/slot/io%d: IOC3 ENET failed diag\n",
brd_ptr->brd_module, SLOTNUM_GETSLOT(brd_ptr->brd_slot));
printf("\t\t\tReason: %s\n",
get_diag_string(ioc3->ioc3_enet.diagval));
bad = 1;
}
scsi = (klscsi_t *) find_component(brd_ptr, (klinfo_t *) NULL,
KLSTRUCT_SCSI);
if (dump_scsi_diags(brd_ptr, scsi) < 0)
bad = 1;
while ((scsi = (klscsi_t *) find_component(brd_ptr, (klinfo_t *) scsi,
KLSTRUCT_SCSI)) != NULL)
if (dump_scsi_diags(brd_ptr, scsi) < 0)
bad = 1;
}
if (!bad)
printf("\t\tALL DIAGS PASSED.\n");
done:
/*
* Check if all CPUs were disabled!
*/
all_disabled = 1;
for (i = 0; i < MAX_COMPACT_NODES; i++) {
nasid_t nasid;
if ((nasid = gdap->g_nasidtable[i]) == INVALID_CNODEID)
continue;
if ((ip27log_getenv(nasid, "DisableA", 0, 0, 0) < 0) ||
(ip27log_getenv(nasid, "DisableB", 0, 0, 0) < 0)) {
all_disabled = 0;
break;
}
}
if (all_disabled)
printf("\t\t\tWARNING: All CPUs disabled. NODISABLE DIP switch (9)\n"
"\t\t\t\toverrode disabling.\n");
printf("**** End System Configuration and Diagnostics Summary ****\n");
}
char* find_board_name(lboard_t *l)
{
#if 0
if(l->brd_type == KLTYPE_IP27)
{
if(strstr(l->brd_name, "IP"))
return l->brd_name;
}
#endif
return ((char *)BOARD_NAME(l->brd_type));
}
/*
* PV 669589. If memory banks 0 and 1 are swapped, the correct
* behavior is for the prom to also swap all other pairs of banks.
* New versions of the proms know how to do this. The IO prom must be
* forwards and backwards compatible with all versions of the CPU
* prom, but we don't know whether the CPU prom which loaded this IO
* prom had the old or new behavior. If the CPU prom had the new
* behavior, it "unswapped" the banks before loading the IO prom,
* thereby re-creating the old behavior. Old CPU proms have the old
* behavior (obviously). Here, we make the behavior correct by
* swapping the config information for banks 2 and up.
*/
void
swap_some_memory_banks()
{
__uint64_t mc0, mc1;
int bank, tmpsz, i;
volatile __uint64_t mc;
lboard_t * lb;
klmembnk_t * mem;
nasid_t nasid;
gda_t * gdap;
cnodeid_t cnode;
unchar junk;
/*
* This nvram variable is treated a bit strangely. In general, any
* new IO prom should set this variable to 'y' because the new IOprom
* has the capability of swapping all banks (the correct behavior).
* However, if for some reason the proms must be flashed downrev, from
* a new version which sets this nvram variable to an older version
* which doesn't set it correctly, the nvram variable will still be
* set to 'y'. This will cause the kernel to assume the IO prom has
* set up the banks in the new formation, and will cause a hang.
*
* To avoid this (admittedly pathological) case, we set the value of
* the nvram variable to 0 here and only change it to 'y' if any set
* of banks is actually swapped.
*/
cpu_set_nvram_offset(NVOFF_SWAP_ALL_BANKS, 1, "");
gdap = (gda_t *)GDA_ADDR(get_nasid());
if (gdap->g_magic != GDA_MAGIC) {
printf("swap_some_memory_banks: Invalid GDA MAGIC\n");
return;
}
/*
* loop through all boards in the system - this routine is only called
* by the global master (called in IO6prom)
*/
for (cnode = 0; cnode < MAX_COMPACT_NODES; cnode ++) {
nasid = gdap->g_nasidtable[cnode];
if (nasid == INVALID_NASID)
continue;
lb = (lboard_t *)find_lboard((lboard_t *)KL_CONFIG_INFO(nasid),
KLTYPE_IP27);
while (lb) {
/* Only swap more banks if banks 0 and 1 are swapped */
mc = REMOTE_HUB_L(nasid, MD_MEMORY_CONFIG);
if ((mc & MMC_DIMM0_SEL_MASK) >> MMC_DIMM0_SEL_SHFT) {
/* tell the kernel that we are swapping all pairs */
cpu_set_nvram_offset(NVOFF_SWAP_ALL_BANKS, 1, "y");
/*
* At this point, banks 0 and 1 are still swapped. Just
* re-swap the rest.
*/
for (bank = 2; bank < MD_MEM_BANKS; bank += 2) {
mc0 = (mc & MMC_BANK_MASK(bank)) >> MMC_BANK_SHFT(bank);
mc1 = (mc & MMC_BANK_MASK(bank+1)) >> MMC_BANK_SHFT(bank+1);
mc &= ~(MMC_BANK_MASK(bank));
mc &= ~(MMC_BANK_MASK(bank+1));
mc |= (mc0 << MMC_BANK_SHFT(bank+1));
mc |= (mc1 << MMC_BANK_SHFT(bank));
}
REMOTE_HUB_S(nasid, MD_MEMORY_CONFIG, mc);
/*
* Also swap the relevant klconfig info. The old
* behavior is for klconfig to hold data exactly in
* sync with the register - i.e. membnk_bnksz[0]
* holds the size of whatever bank is in location 0 of
* the MD_MEMORY_CONFIG register (the size of
* locational bank 0 if dimm0_sel is not set (no swap
* case) or size of locational bank 1 if dimm0_sel is
* set (swap case)). Note that the remaining banks (2
* and up) will automatically be in locational form
* because, in the old case, those were never swapped.
*
* The new behavior must have _all_ bank information in
* "locational" form. In order to create the new
* behavior, banks 0 and 1 must be swapped back into
* "locational" form.
*/
if (mem = (klmembnk_t *)find_component(lb, NULL,
KLSTRUCT_MEMBNK)) {
tmpsz = mem->membnk_bnksz[0];
mem->membnk_bnksz[0] = mem->membnk_bnksz[1];
mem->membnk_bnksz[1] = tmpsz;
}
}
lb = KLCF_NEXT(lb);
if (lb)
lb = find_lboard(lb, KLTYPE_IP27);
}
}
}
#if 0
/*
* Propagates each module's serial number to all
* MIDPLANE boards.
*/
extern int num_modules ;
extern struct mod_tab module_table[] ;
int
propagate_serial_num()
{
int i ;
cnodeid_t cnode ;
nasid_t nasid ;
lboard_t *lbptr ;
gda_t *gdap;
klmod_serial_num_t *snump ;
char snum[MAX_SERIAL_NUM_SIZE] ;
if (SN00)
return 1 ;
gdap = (gda_t *)GDA_ADDR(get_nasid());
if (gdap->g_magic != GDA_MAGIC) {
printf("fix_serial_num: Invalid GDA MAGIC\n") ;
return 0 ;
}
/* For all the modules */
for (i = 1; i <= num_modules; i++) {
/* Not found a serial number yet */
*snum = 0 ;
/* For all the nodes in the system */
for (cnode = 0; cnode < MAX_COMPACT_NODES; cnode ++) {
nasid = gdap->g_nasidtable[cnode];
if (nasid == INVALID_NASID)
continue;
lbptr = (lboard_t *)KL_CONFIG_INFO(nasid) ;
/* Is it our module? */
if (lbptr->brd_module != module_table[i].module_id)
continue ;
if (lbptr = find_lboard(lbptr, KLTYPE_MIDPLANE)) {
if (snump = GET_SNUM_COMP(lbptr)) {
if (snump->snum.snum_str[0]) {
strcpy(snum, snump->snum.snum_str) ;
printf("Found serial number for module %d, %s\n", module_table[i].module_id, snum) ;
break ;
}
}
}
} /* for cnode */
/* No serial num for this module */
if (!(*snum))
continue ;
/* Update the serial number found above to all the XBOWs
in our module */
for (cnode = 0; cnode < MAX_COMPACT_NODES; cnode ++) {
nasid = gdap->g_nasidtable[cnode];
if (nasid == INVALID_NASID)
continue;
lbptr = (lboard_t *)KL_CONFIG_INFO(nasid) ;
if (lbptr->brd_module != module_table[i].module_id)
continue ;
if (lbptr = find_lboard(lbptr, KLTYPE_MIDPLANE)) {
if (snump = GET_SNUM_COMP(lbptr)) {
if (!snump->snum.snum_str[0]) {
if (*snum) {
strcpy(snump->snum.snum_str, snum) ;
printf("Copied serial number %s in module %d\n", snum, module_table[i].module_id) ;
}
}
}
}
} /* for cnode */
} /* for all modules */
return 1 ;
}
#endif