📄 kn02ba.c
字号:
#ifndef lintstatic char *sccsid = "@(#)kn02ba.c 4.8 (ULTRIX) 3/7/91";#endif lint/************************************************************************ * * * Copyright (c) 1989 by * * Digital Equipment Corporation, Maynard, MA * * All rights reserved. * * * * This software is furnished under a license and may be used and * * copied only in accordance with the terms of such license and * * with the inclusion of the above copyright notice. This * * software or any other copies thereof may not be provided or * * otherwise made available to any other person. No title to and * * ownership of the software is hereby transferred. * * * * The information in this software is subject to change without * * notice and should not be construed as a commitment by Digital * * Equipment Corporation. * * * * Digital assumes no responsibility for the use or reliability * * of its software on equipment which is not supplied by Digital. * * * ************************************************************************//* * Modification History: * * 7-Mar-91 Randall Brown * Fixed a bug in isolatepar(). Print out more information about * which CPU card is in the system. * * 7-Mar-91 Jaw * 3min spl optimization. * * 21-Jan-91 Randall Brown * Modified kn02ba_isolate_memerr() to use tc_memerr_status struct. * Modified kn02ba_isolate_par() to take the blocksize as * a parameter. * * 06-Dec-90 Randall Brown * Added isolate_memerr() routine for logging of memory errors * that occur during I/O. * * 15-Oct-90 Randall Brown * Added error handling code. * * 06-Sep-90 Randall Brown * Changed slot_order to config_order. * * 23-Feb-90 Randall Brown * Created file for support of 3MIN (DS5000_100). * */#include "../h/param.h"#include "../h/systm.h"#include "../h/types.h"#include "../h/cpudata.h"#include "../machine/cpu.h"#include "../h/user.h"#include "../h/proc.h"#include "../h/vm.h"#include "../h/errlog.h"#include "../h/cmap.h"#include "../machine/pte.h"#include "../../machine/common/cpuconf.h"#include "../io/tc/tc.h"#include "../machine/reg.h"#include "../machine/kn02ba.h"#include "../machine/mc146818clock.h"extern softclock(), softnet(), hardclock(), fpuintr();int kn02ba_stray(), kn02ba_sysintr(), kn02ba_halt();int kn02ba_enable_option(), kn02ba_disable_option();int kn02ba_clear_errors(), kn02ba_isolate_memerr();extern u_int printstate; /* how to print to the console */extern char *rt_clock_addr; /* addr of the mc146818clock chip */extern struct timeval time; /* the system time */extern int hz;extern int tick;extern int tickadj;extern int fixtick; /* set to the number of microsec's that the clock looses per second *//* The SR reg masks for splxxx usage */int kn02ba_splm[SPLMSIZE] = { KN02BA_SR_IMASK0, /* 0 SPLNONE */ KN02BA_SR_IMASK1, /* 1 SPLSOFTC */ KN02BA_SR_IMASK2, /* 2 SPLNET */ 0, /* 3 NOT_USED */ 0, /* 4 NOT_USED */ KN02BA_SR_IMASK5, /* 5 SPLBIO, SPLIMP, SPLTTY */ KN02BA_SR_IMASK6, /* 6 SPLCLOCK */ KN02BA_SR_IMASK7, /* 7 SPLMEM */ KN02BA_SR_IMASK8, /* 8 SPLFPU */};/* The mask values for the system interrup mask */int kn02ba_sim[SPLMSIZE] = { SPL0_MASK, /* 0 SPLNONE */ SPL1_MASK, /* 1 SPLSOFTC */ SPL2_MASK, /* 2 SPLNET */ 0, /* 3 NOT_USED */ 0, /* 4 NOT_USED */ SPLIO_MASK, /* 5 SPLBIO, SPLIMP, SPLTTY */ SPLCLOCK_MASK, /* 6 SPLCLOCK */ SPLMEM_MASK, /* 7 SPLMEM */ SPLFPU_MASK, /* 8 SPLFPU */};u_int kn02ba_slotaddr[TC_IOSLOTS] = {KN02BA_SL_0_ADDR, KN02BA_SL_1_ADDR, KN02BA_SL_2_ADDR, KN02BA_SL_3_ADDR, KN02BA_SL_4_ADDR, KN02BA_SL_5_ADDR, KN02BA_SL_6_ADDR, KN02BA_SL_7_ADDR};/* * Program the order in which to probe the IO slots on the system. * This determines the order in which we assign unit numbers to like devices. * It also determines how many slots (and what slot numbers) there are to probe. * Terminate the list with a -1. * Note: this agrees with the console's idea of unit numbers */int kn02ba_config_order [] = { 3, 4, 5, 0, 1, 2, -1 };/* ipllevel describes the current interrupt level the processor is *//* running at. The values that ipllevel can be are SPLNONE -> SPLEXTREME. *//* These values are defined in cpu.h */int ipllevel = SPLEXTREME;int clk_counter;int kn02ba_transintvl = KN02BA_TRANSINTVL;/* global var so we can change it */int kn02ba_translog = 1; /* is trans logging currently enabled */struct trans_errcnt kn02ba_trans_errcnt = { 0, 0 };int kn02ba_tcount[MAXSIMM]; /* # of transient parity errs per simm*/int kn02ba_scount[MAXSIMM]; /* # of soft errs on each simm */int kn02ba_hcount[MAXSIMM]; /* # of hard errs on each simm */int kn02ba_pswarn; /* set true if we had a ps-warning */int kn02ba_model_number;/* Initial value is worst case, real value is determined in kn02ba_init() */int kn02ba_delay_mult = 25; int kn02ba_psintvl = (60 * 1); /* time delta to check pswarn bit */ /* global var so we can change it */unsigned kn02ba_isolatepar();int kn02ba_transenable();int kn02ba_pscheck();caddr_t vatophys();kn02ba_init(){ int i; extern int c0vec_tblsize; extern int (*c0vec_tbl[])(); extern int splm[]; extern struct cpusw *cpup; extern u_int sr_usermask; /* * Initialize the interrupt dispatch table c0vec_tbl. * Initialize the spl table for the system we are running on. * Initialize the interrupt masks for the system we are running on. * This must be done very early on at boot time and must * be done before any interrupt is allowed. */ bcopy(kn02ba_splm, splm, (SPLMSIZE) * sizeof(int)); /* Initialize the spl dispatch table and the intr dispatch routine */ spl_init(); /* disable all DMA's, but don't reset the chips */ *(u_int *)(PHYS_TO_K1(KN02BA_SSR_ADDR)) = 0xf00;/* rpbfix: do we want to enable halt interrupt at this point */ splextreme(); /* * Set up the system specific value for "hz", the number of clock * interrupts per second; and corresponding tick and tickadj values. */ hz = cpup->HZ; tick = 1000000 / hz; tickadj = 240000 / (60 * hz); fixtick = 1000000 - (tick * hz); /* * Assign the rt_clock_addr for this processor */ rt_clock_addr = (char *)PHYS_TO_K1(KN02BA_CLOCK_ADDR); clk_counter = kn02ba_conf_clk_speed(); if (clk_counter < 8775) { kn02ba_model_number = 120; kn02ba_delay_mult = 11; } else if (clk_counter < 11311) { kn02ba_model_number = 125; kn02ba_delay_mult = 13; } else if (clk_counter < 14000) { kn02ba_model_number = 133; kn02ba_delay_mult = 19; } else { kn02ba_model_number = 0; kn02ba_delay_mult = 25; } /* * */ sr_usermask = (KN02BA_SR_IMASK0 | SR_IEP | SR_KUP ); sr_usermask &= ~(SR_IEC); /* Initialize the TURBOchannel */ tc_init(); /* Fill in the TURBOchannel slot addresses */ for (i = 0; i < TC_IOSLOTS; i++) tc_slotaddr[i] = kn02ba_slotaddr[i]; /* Fill in the TURBOchannel switch table */ tc_sw.isolate_memerr = kn02ba_isolate_memerr; tc_sw.enable_option = kn02ba_enable_option; tc_sw.disable_option = kn02ba_disable_option; tc_sw.clear_errors = kn02ba_clear_errors; tc_sw.config_order = kn02ba_config_order; /* * Fixed 3min IO devices */ strcpy(tc_slot[KN02BA_SCSI_INDEX].devname,"asc"); strcpy(tc_slot[KN02BA_SCSI_INDEX].modulename, "PMAZ-BA "); tc_slot[KN02BA_SCSI_INDEX].slot = 3; tc_slot[KN02BA_SCSI_INDEX].module_width = 1; tc_slot[KN02BA_SCSI_INDEX].physaddr = KN02BA_SCSI_ADDR; tc_slot[KN02BA_SCSI_INDEX].intr_b4_probe = 0; tc_slot[KN02BA_SCSI_INDEX].intr_aft_attach = 1; tc_slot[KN02BA_SCSI_INDEX].adpt_config = 0; strcpy(tc_slot[KN02BA_LN_INDEX].devname,"ln"); strcpy(tc_slot[KN02BA_LN_INDEX].modulename, "PMAD-BA "); tc_slot[KN02BA_LN_INDEX].slot = 3; tc_slot[KN02BA_LN_INDEX].module_width = 1; tc_slot[KN02BA_LN_INDEX].physaddr = KN02BA_LN_ADDR; tc_slot[KN02BA_LN_INDEX].intr_b4_probe = 0; tc_slot[KN02BA_LN_INDEX].intr_aft_attach = 1; tc_slot[KN02BA_LN_INDEX].adpt_config = 0; strcpy(tc_slot[KN02BA_SCC_INDEX].devname,"scc"); tc_slot[KN02BA_SCC_INDEX].slot = 3; tc_slot[KN02BA_SCC_INDEX].module_width = 1; tc_slot[KN02BA_SCC_INDEX].physaddr = KN02BA_SCC_ADDR; tc_slot[KN02BA_SCC_INDEX].intr_b4_probe = 0; tc_slot[KN02BA_SCC_INDEX].intr_aft_attach = 1; tc_slot[KN02BA_SCC_INDEX].adpt_config = 0; *(u_int *)PHYS_TO_K1(KN02BA_INTR_REG) = 0;/* rpbfix: these should go into their respective drivers */ *(u_int *)(0xbc040160) = 0x3; *(u_int *)(0xbc040170) = 0xe; *(u_int *)(0xbc040180) = 0x14; *(u_int *)(0xbc040190) = 0x16; return (0);}kn02ba_conf(){ extern int cold; extern u_int cpu_systype; extern int icache_size, dcache_size;#ifdef ERRLOG_DEBUG int kn02ba_errlog_testing();#endif cold = 1; /* * Initialize PROM environment entries. */ hwconf_init(); /* * Report what system we are on */ if (kn02ba_model_number != 0) printf("DECstation 5000 Model %d - system rev %d\n", kn02ba_model_number, (GETHRDREV(cpu_systype))); else printf("DECstation 5000 Model 100 Series, Unknown Clock Speed\n"); printf("%dKb Instruction Cache, %dKb Data Cache\n", icache_size/1024, dcache_size/1024); coproc_find(); /* Turn off all interrupts in the SIRM */ *(u_int *)PHYS_TO_K1(KN02BA_SIRM_ADDR) = 0; /* * Probe the TURBOchannel and find all devices */ splextreme(); tc_find(); timeout (kn02ba_pscheck, (caddr_t) 0, kn02ba_psintvl * hz); timeout (kn02ba_transenable, (caddr_t) 0, kn02ba_transintvl * hz);#ifdef ERRLOG_DEBUG timeout (kn02ba_errlog_testing, (caddr_t) 0, 5 * hz);#endif cold = 0; splnone(); return (0); /* tell configure() we have configured */}/* * Check Power Supply over-heat Warning. * If its overheating, warn to shut down the system. * If its gone from overheat to OK, cancel the warning. */kn02ba_pscheck(){ register u_int sir; /* a copy of the real csr */ sir = *(u_int *)PHYS_TO_K1(KN02BA_SIR_ADDR); if (sir & PSWARN) { printf("System Overheating - suggest immediate shutdown and power-off\n"); kn02ba_pswarn = 1; } else { if (kn02ba_pswarn) { printf("System OK - cancel overheat shutdown\n"); kn02ba_pswarn = 0; } } timeout (kn02ba_pscheck, (caddr_t) 0, kn02ba_psintvl * hz);}/* * Enable transient parity memory error logging */kn02ba_transenable(){ kn02ba_translog = 1; timeout (kn02ba_transenable, (caddr_t) 0, kn02ba_transintvl * hz);}/* * Routine to handle trap errors: user-mode ibe & dbe, & all kernel mode traps. * We try to recover from user-mode errors and panic on kernel mode errors. */kn02ba_trap_error(ep, code, sr, cause, signo) register u_int *ep; /* exception frame ptr */ register u_int code; /* trap code (trap type) */ u_int sr, cause; /* status and cause regs */ int *signo; /* set if we want to kill process */{ caddr_t pa; /* the physical addr of the error */ int epc; /* the EPC of the error */ unsigned memreg; /* memory parity error info */ int vaddr; /* virt addr of error */ register struct proc *p; /* ptr to current proc struct */ long currtime; /* current time value */ unsigned ssr; unsigned sir; unsigned sirm; ssr = *(u_int *)(PHYS_TO_K1(KN02BA_SSR_ADDR)); sir = *(u_int *)(PHYS_TO_K1(KN02BA_SIR_ADDR)); sirm = *(u_int *)(PHYS_TO_K1(KN02BA_SIRM_ADDR)); p = u.u_procp; if (USERMODE(sr)) { /* * If address of bus error is in physical memory, then its * a parity memory error. Gather additional info in "memreg", * for the error log & to determine how to recover. * If its a transient error then continue the user process. * If its a hard or soft parity error: * a) on a private process page, terminate the process * (by setting signo = SIGBUS) * b) on a shared page, crash the system. * TBD: on a non-modified page, re-read the page (page fault), * and continue the process. * TBD: on a shared page terminate all proc's sharing the page, * instead of crash system. * TBD: on hard errors map out the page. */ pa = vatophys(ep[EF_BADVADDR]); if ( (int)pa != -1 && (btop((int)pa) < physmem) ) { memreg = kn02ba_isolatepar(pa, ep[EF_BADVADDR], 4); /* * If we get 3 or more in 1 second then disable logging * them for 15 minutes. The variable "kn02ba_translog" * is set by the kn02ba_transenable routine. */ if (((memreg >> TYPEOFF) & TRANSPAR) == TRANSPAR) { if (kn02ba_translog) { currtime = time.tv_sec; if (currtime == kn02ba_trans_errcnt.trans_prev) { kn02ba_translog = 0; mprintf("High rate of transient parity memory errors, logging disabled for 15 minutes\n"); kn02ba_trans_errcnt.trans_last = 0; currtime = 0; } kn02ba_logmempkt(EL_PRIHIGH, ep, memreg, pa); kn02ba_trans_errcnt.trans_prev = kn02ba_trans_errcnt.trans_last; kn02ba_trans_errcnt.trans_last = currtime; } return(0); } if (SHAREDPG(pa)) { kn02ba_logmempkt(EL_PRISEVERE, ep, memreg, pa); kn02ba_consprint(KN02BA_MEMPKT, ep, memreg, pa, 0, 0, 0); panic("memory parity error in shared page"); } else { kn02ba_logmempkt(EL_PRIHIGH, ep, memreg, pa); printf("pid %d (%s) was killed on memory parity error\n", p->p_pid, u.u_comm); uprintf("pid %d (%s) was killed on memory parity error\n", p->p_pid, u.u_comm); } } else { uprintf("pid %d (%s) was killed on bus error\n", p->p_pid, u.u_comm); } } else { /* * Kernel mode errors. * They all panic, its just a matter of what we log * and what panic message we issue. */ switch (code) { case EXC_DBE: case EXC_IBE: /* * Figure out if its a memory parity error * or a read bus timeout error */ pa = vatophys(ep[EF_BADVADDR]); if ( (int)pa != -1 && (btop((int)pa) < physmem) ) { /* * Note that we must save anything "interesting" * from the exception frame, since isolatepar() * may cause additional bus errors which will * stomp on the exception frame in locore. */ vaddr = ep[EF_BADVADDR]; epc = ep[EF_EPC]; memreg = kn02ba_isolatepar(pa, vaddr, 4); ep[EF_BADVADDR] = vaddr; ep[EF_EPC] = epc; kn02ba_logmempkt(EL_PRISEVERE, ep, memreg, pa); kn02ba_consprint(KN02BA_MEMPKT, ep, memreg, pa, 0, 0, 0); panic("memory parity error in kernel mode");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -