NT4/private/ntos/nthals/halalpha/lca4err.c
2020-09-30 17:12:29 +02:00

1154 lines
31 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1994 Digital Equipment Corporation
Module Name:
lca4err.c
Abstract:
This module implements error handling (machine checks and error
interrupts) for machines based on the DECchip 21066
microprocessor.
Author:
Joe Notarangelo 8-Feb-1994
Environment:
Kernel mode only.
Revision History:
--*/
#include "halp.h"
#include "axp21066.h"
#include "lca4.h"
#include "stdio.h"
//
// Declare the extern variable UncorrectableError declared in
// inithal.c.
//
extern PERROR_FRAME PUncorrectableError;
//
// MAX_RETRYABLE_ERRORS is the number of times to retry machine checks before
// just giving up.
//
#define MAX_RETRYABLE_ERRORS 32
//
//jnfix - temporary counts
//
ULONG CorrectableErrors = 0;
ULONG RetryableErrors = 0;
VOID
HalpDisplayLogout21066 (
IN ESR_21066 Esr,
IN IOC_STAT0_21066 IoStat0,
IN PLOGOUT_FRAME_21066 LogoutFrame
);
VOID
HalpClearMachineCheck(
VOID
);
ULONG
HalpBankError(
ULONG PhysicalAddress,
PLOGOUT_FRAME_21066 LogoutFrame
);
//jnfix - should be exported from platform-specific
ULONG
HalpSimmError(
ULONG PhysicalAddress,
PLOGOUT_FRAME_21066 LogoutFrame
);
VOID
HalpClearAllErrors(
IN BOOLEAN SignalMemoryCorrectables
)
/*++
Routine Description:
This routine clears all of the error bits in the LCA4 memory
controller and I/O controller.
Arguments:
SignalMemoryCorrectables - Supplies a boolean value which specifies
if correctable error reporting should be
enabled in the memory controller.
Return Value:
None.
--*/
{
ESR_21066 ErrorStatus;
IOC_STAT0_21066 IoStat0;
//
// The error status bits of the ESR are all write one to clear.
// Clear the value and then set all of the error bits. Then set
// correctable enable according to specified input.
//
ErrorStatus.all.QuadPart = (ULONGLONG)0;
ErrorStatus.Eav = 1;
ErrorStatus.Cee = 1;
ErrorStatus.Uee = 1;
ErrorStatus.Cte = 1;
ErrorStatus.Mse = 1;
ErrorStatus.Mhe = 1;
ErrorStatus.Nxm = 1;
if( SignalMemoryCorrectables == TRUE ){
ErrorStatus.Ice = 0;
} else {
ErrorStatus.Ice = 1;
}
WRITE_MEMC_REGISTER( &((PLCA4_MEMC_CSRS)(0))->ErrorStatus,
ErrorStatus.all.QuadPart );
//
// The ERR and LOST bits of the IO_STAT0 are write one to clear.
//
IoStat0.all.QuadPart = (ULONGLONG)0;
IoStat0.Err = 1;
IoStat0.Lost = 1;
WRITE_IOC_REGISTER( &((PLCA4_IOC_CSRS)(LCA4_IOC_BASE_QVA))->IocStat0,
IoStat0.all.QuadPart );
return;
}
VOID
HalpBuildLCAUncorrectableErrorFrame(
VOID
)
{
PPROCESSOR_LCA_UNCORRECTABLE LcaUncorrerr = NULL;
PEXTENDED_ERROR PExtErr;
EAR_21066 Ear;
if(PUncorrectableError){
LcaUncorrerr = (PPROCESSOR_LCA_UNCORRECTABLE)
PUncorrectableError->UncorrectableFrame.RawProcessorInformation;
//
// first fill in some generic processor Information.
// For the Current (Reporting) Processor.
//
HalpGetProcessorInfo(
&PUncorrectableError->UncorrectableFrame.ReportingProcessor);
PUncorrectableError->
UncorrectableFrame.Flags.ProcessorInformationValid = 1;
PExtErr = &PUncorrectableError->UncorrectableFrame.ErrorInformation;
}
if(LcaUncorrerr) {
PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1;
sprintf(PUncorrectableError->UncorrectableFrame.ErrorString,
"Uncorrectable Error From "
"LCA4 Detected");
LcaUncorrerr->IocStat0 = (ULONGLONG)
READ_IOC_REGISTER(&((PLCA4_IOC_CSRS)(LCA4_IOC_BASE_QVA))->IocStat0);
LcaUncorrerr->IocStat1 = (ULONGLONG)
READ_IOC_REGISTER(&((PLCA4_IOC_CSRS)(LCA4_IOC_BASE_QVA))->IocStat1);
LcaUncorrerr->Esr = (ULONGLONG)
READ_MEMC_REGISTER(&((PLCA4_MEMC_CSRS)(0))->ErrorStatus);
Ear.all.QuadPart = LcaUncorrerr->Ear = (ULONGLONG)
READ_MEMC_REGISTER(&((PLCA4_MEMC_CSRS)(0))->ErrorAddress);
PUncorrectableError->UncorrectableFrame.Flags.PhysicalAddressValid = 1;
PUncorrectableError->UncorrectableFrame.PhysicalAddress =
Ear.ErrorAddress;
LcaUncorrerr->BankConfig0 =
READ_MEMC_REGISTER(&((PLCA4_MEMC_CSRS)(0))->BankConfiguration0);
LcaUncorrerr->BankConfig1 =
READ_MEMC_REGISTER(&((PLCA4_MEMC_CSRS)(0))->BankConfiguration1);
LcaUncorrerr->BankConfig2 =
READ_MEMC_REGISTER(&((PLCA4_MEMC_CSRS)(0))->BankConfiguration2);
LcaUncorrerr->BankConfig3 =
READ_MEMC_REGISTER(&((PLCA4_MEMC_CSRS)(0))->BankConfiguration3);
LcaUncorrerr->BankMask0 =
READ_MEMC_REGISTER(&((PLCA4_MEMC_CSRS)(0))->BankMask0);
LcaUncorrerr->BankMask1 =
READ_MEMC_REGISTER(&((PLCA4_MEMC_CSRS)(0))->BankMask1);
LcaUncorrerr->BankMask2 =
READ_MEMC_REGISTER(&((PLCA4_MEMC_CSRS)(0))->BankMask2);
LcaUncorrerr->BankMask3 =
READ_MEMC_REGISTER(&((PLCA4_MEMC_CSRS)(0))->BankMask3);
LcaUncorrerr->Car =
READ_MEMC_REGISTER(&((PLCA4_MEMC_CSRS)(0))->CacheControl);
LcaUncorrerr->Gtr =
READ_MEMC_REGISTER(&((PLCA4_MEMC_CSRS)(0))->GlobalTiming);
}
}
BOOLEAN
HalMachineCheck (
IN PEXCEPTION_RECORD ExceptionRecord,
IN PKEXCEPTION_FRAME ExceptionFrame,
IN PKTRAP_FRAME TrapFrame
)
/*++
Routine Description:
This function fields machine checks for 21066-based machines.
The following errors may be the cause of the machine check:
(a) Uncorrectable Dcache error
(b) Uncorrectable Load from Memory Controller
(c) Uncorrectable Load from I/O Controller
(d) Non-existent device in PCI Configuration Space (I/O Controller)
(e) Retryable Icache parity error
Arguments:
ExceptionRecord - Supplies a pointer to the exception record for the
machine check. Included in the exception information
is the pointer to the logout frame.
ExceptionFrame - Supplies a pointer to the kernel exception frame.
TrapFrame - Supplies a pointer to the kernel trap frame.
Return Value:
A value of TRUE is returned if the machine check has been
handled by the HAL. If it has been handled then execution may
resume at the faulting address. Otherwise, a value of FALSE
is returned.
N.B. - When a fatal error is recognized this routine does not
return at all.
--*/
{
PMCHK_STATUS MachineCheckStatus;
ESR_21066 ErrorStatus;
IOC_STAT0_21066 IoStat0;
PPROCESSOR_LCA_UNCORRECTABLE LcaUncorrerr = NULL;
MachineCheckStatus =
(PMCHK_STATUS)&ExceptionRecord->ExceptionInformation[0];
//
// Print an error message if a correctable machine check is signalled.
// Correctable machine checks are not possible on the 21066.
//
if( MachineCheckStatus->Correctable == 1 ){
#if DBG
DbgPrint( "Illegal correctable error for LCA4\n" );
#endif //DBG
}
//
// If the machine check is retryable then log the error and
// and restart the operation.
//
if( MachineCheckStatus->Retryable == 1 ){
//
// jnfix Log the error, interface undefined.
//
//
// Increment the number of retryable machine checks.
//
RetryableErrors += 1;
#if (DBG) || (HALDBG)
DbgPrint( "HAL Retryable Errors = %d\n", RetryableErrors );
// if( (RetryableErrors % 32) == 0 ){
// DbgPrint( "HAL Retryable Errors = %d\n", RetryableErrors );
// }
#endif //DBG || HALDBG
//
// We'll retry MAX_RETRYABLE_ERRORS times and then give up. We
// do this to avoid infinite retry loops.
//
if( RetryableErrors > MAX_RETRYABLE_ERRORS ){
//
// Acknowledge receipt of the retryable machine check.
//
DbgPrint("Got too many Retryable Errors errors\n");
}
//
// Clear the machine check in the MCES register.
//
HalpClearMachineCheck();
//
// Attempt to retry the operation.
//
return TRUE;
}
//
// The machine check is uncorrectable according to the processor.
// Read the error registers in the Memory and I/O Controller.
// If the operation was a read to PCI configuration space and no
// device is the error then we will fix up the operation and continue,
// otherwise the machine has taken a fatal error.
//
//jnfix - code here to check for dcache parity error?
ErrorStatus.all.QuadPart =
READ_MEMC_REGISTER(
&((PLCA4_MEMC_CSRS)(0))->ErrorStatus );
IoStat0.all.QuadPart =
READ_IOC_REGISTER( &((PLCA4_IOC_CSRS)(LCA4_IOC_BASE_QVA))->IocStat0 );
//
// If any of the following errors are indicated in the memory controller
// then process a fatal error:
// Uncorrectable Error
// Cache Tag Error
// Multiple Hard Errors
// Non-existent Memory
//
if( (ErrorStatus.Uee == 1) ||
(ErrorStatus.Cte == 1) ||
(ErrorStatus.Mhe == 1) ||
(ErrorStatus.Nxm == 1) ){
goto FatalError;
}
//
// Check for a PCI configuration read error. An error is a
// candidate if the I/O controller has signalled an error, there
// are no lost errors and the error was a no device error on the PCI.
//
if( (IoStat0.Err == 1) && (IoStat0.Code == IocErrorNoDevice) &&
(IoStat0.Lost == 0) ){
//
// So far, the error looks like a PCI configuration space read
// that accessed a device that does not exist. In order to fix
// this up we expect that the faulting instruction or the instruction
// previous to the faulting instruction must be a load with v0 as
// the destination register. If this condition is met then simply
// update v0 in the register set and return. However, be careful
// not to re-execute the load.
//
// jnfix - add condition to check if Rb contains the superpage
// address for config space?
ALPHA_INSTRUCTION FaultingInstruction;
BOOLEAN PreviousInstruction = FALSE;
FaultingInstruction.Long = *(PULONG)((ULONG)TrapFrame->Fir);
if( (FaultingInstruction.Memory.Ra != V0_REG) ||
(FaultingInstruction.Memory.Opcode != LDL_OP) ){
//
// Faulting instruction did not match, try the previous
// instruction.
//
PreviousInstruction = TRUE;
FaultingInstruction.Long = *(PULONG)((ULONG)TrapFrame->Fir - 4);
if( (FaultingInstruction.Memory.Ra != V0_REG) ||
(FaultingInstruction.Memory.Opcode != LDL_OP) ){
//
// No match, we can't fix this up.
//
goto FatalError;
}
}
//
// The error has matched all of our conditions. Fix it up by
// writing the value 0xffffffff into the destination of the load.
//
TrapFrame->IntV0 = (ULONGLONG)0xffffffffffffffff;
//
// Clear the machine check condition in the processor.
//
HalpClearMachineCheck();
//
// Clear the error condition in the io controller.
// The Err bit is write one to clear.
//
IoStat0.all.QuadPart = (ULONGLONG)0;
IoStat0.Err = 1;
WRITE_IOC_REGISTER( &((PLCA4_IOC_CSRS)(LCA4_IOC_BASE_QVA))->IocStat0,
IoStat0.all.QuadPart );
//
// If the faulting instruction was the load the restart execution
// at the instruction after the load.
//
if( PreviousInstruction == FALSE ){
TrapFrame->Fir += 4;
}
return TRUE;
} //end if (IoStat0.Err == 1) && (IoStat0.Code == IocErrorNoDevice) ){
//
// The system is not well and cannot continue reliable execution.
// Print some useful messages and shutdown the machine.
//
FatalError:
HalpBuildLCAUncorrectableErrorFrame();
if(PUncorrectableError){
LcaUncorrerr = (PPROCESSOR_LCA_UNCORRECTABLE)
PUncorrectableError->UncorrectableFrame.RawProcessorInformation;
LcaUncorrerr->AboxCtl = (ULONGLONG)
((PLOGOUT_FRAME_21066)
(ExceptionRecord->ExceptionInformation[1] ))->AboxCtl.all.QuadPart;
LcaUncorrerr->CStat = (ULONGLONG)
((PLOGOUT_FRAME_21066)
(ExceptionRecord->ExceptionInformation[1] ))->DcStat.all.QuadPart;
LcaUncorrerr->MmCsr = (ULONGLONG)
((PLOGOUT_FRAME_21066)
(ExceptionRecord->ExceptionInformation[1] ))->MmCsr.all.QuadPart;
}
//
// Display the logout frame.
//
HalpDisplayLogout21066(
ErrorStatus,
IoStat0,
(PLOGOUT_FRAME_21066)(ExceptionRecord->ExceptionInformation[1]) );
//
//
// Bugcheck to dump the rest of the machine state, this will help
// if the machine check is software-related.
//
KeBugCheckEx( DATA_BUS_ERROR,
(ULONG)MachineCheckStatus->Correctable,
(ULONG)MachineCheckStatus->Retryable,
0,
(ULONG)PUncorrectableError );
}
VOID
HalpClearMachineCheck(
VOID
)
/*++
Routine Description:
Clear the machine check which is currently pending. Clearing the
pending machine check bit will allow us to take machine checks in
the future without detecting a double machine check condition.
The machine check pending bit must be cleared in the MCES register
within the PALcode.
Arguments:
None.
Return Value:
None.
--*/
{
MCES MachineCheckSummary;
MachineCheckSummary.MachineCheck = 1;
MachineCheckSummary.SystemCorrectable = 0;
MachineCheckSummary.ProcessorCorrectable = 0;
MachineCheckSummary.DisableProcessorCorrectable = 0;
MachineCheckSummary.DisableSystemCorrectable = 0;
MachineCheckSummary.DisableMachineChecks = 0;
HalpWriteMces( MachineCheckSummary );
return;
}
#define MAX_ERROR_STRING 100
VOID
HalpDisplayLogout21066 (
IN ESR_21066 Esr,
IN IOC_STAT0_21066 IoStat0,
IN PLOGOUT_FRAME_21066 LogoutFrame
)
/*++
Routine Description:
This function displays the logout frame for a 21066.
Arguments:
Esr - Supplies the value of the memory controller error status register.
IoStat0 - Supplies the value of the i/o controller status register 0.
LogoutFrame - Supplies a pointer to the logout frame generated
by the 21066.
Return Value:
None.
--*/
{
UCHAR OutBuffer[ MAX_ERROR_STRING ];
EAR_21066 Ear;
CAR_21066 Car;
IOC_STAT1_21066 IoStat1;
ULONG Index;
PKPRCB Prcb;
extern HalpLogicalToPhysicalProcessor[HAL_MAXIMUM_PROCESSOR+1];
PCHAR parityErrString = NULL;
PEXTENDED_ERROR exterr;
if(PUncorrectableError) {
exterr = &PUncorrectableError->UncorrectableFrame.ErrorInformation;
parityErrString = PUncorrectableError->UncorrectableFrame.ErrorString;
}
//
// Capture other useful registers, EAR, CAR, and IO_STAT1.
//
Ear.all.QuadPart =
READ_MEMC_REGISTER(
&((PLCA4_MEMC_CSRS)(0))->ErrorAddress );
Car.all.QuadPart =
READ_MEMC_REGISTER(
&((PLCA4_MEMC_CSRS)(0))->CacheControl );
IoStat1.all.QuadPart =
READ_IOC_REGISTER( &((PLCA4_IOC_CSRS)(LCA4_IOC_BASE_QVA))->IocStat1);
//
// Acquire ownership of the display. This is done here in case we take
// a machine check before the display has been taken away from the HAL.
// When the HAL begins displaying strings after it has lost the
// display ownership then the HAL will be careful not to scroll information
// off of the screen.
//
HalAcquireDisplayOwnership(NULL);
//
// Display the machine state via the logout frame.
//
HalDisplayString( "\nFatal system hardware error.\n\n" );
sprintf( OutBuffer, "MEMC_ESR: %16Lx MEMC_EAR: %16Lx CAR: %16Lx\n",
Esr.all.QuadPart,
Ear.all.QuadPart,
Car.all.QuadPart );
HalDisplayString( OutBuffer );
sprintf( OutBuffer, "IO_STAT0: %16Lx IO_STAT1: %16Lx\n",
IoStat0.all.QuadPart,
IoStat1.all.QuadPart );
HalDisplayString( OutBuffer );
sprintf( OutBuffer, "ICCSR : %016Lx ABOX_CTL: %016Lx DC_STAT: %016Lx\n",
ICCSR_ALL_21064(LogoutFrame->Iccsr),
ABOXCTL_ALL_21064(LogoutFrame->AboxCtl),
DCSTAT_ALL_21064(LogoutFrame->DcStat) );
HalDisplayString( OutBuffer );
sprintf( OutBuffer, "EXC_ADDR : %016Lx VA : %016Lx MM_CSR : %016Lx\n",
LogoutFrame->ExcAddr.QuadPart,
LogoutFrame->Va.QuadPart,
MMCSR_ALL_21064(LogoutFrame->MmCsr) );
HalDisplayString( OutBuffer );
sprintf( OutBuffer, "HIRR : %016Lx HIER : %016Lx PS : %016Lx\n",
IRR_ALL_21064(LogoutFrame->Hirr),
IER_ALL_21064(LogoutFrame->Hier),
PS_ALL_21064(LogoutFrame->Ps) );
HalDisplayString( OutBuffer );
sprintf( OutBuffer, "PAL_BASE : %016Lx \n",
LogoutFrame->PalBase.QuadPart );
HalDisplayString( OutBuffer );
sprintf( OutBuffer, "Waiting 15 seconds...\n");
HalDisplayString( OutBuffer );
for( Index=0; Index<1500; Index++)
KeStallExecutionProcessor( 10000 ); // ~15 second delay
//
// Print out interpretation of the error.
//
//
// First print the processor on which we saw the error
//
Prcb = PCR->Prcb;
sprintf( OutBuffer, "Error on processor number: %d\n",
HalpLogicalToPhysicalProcessor[Prcb->Number] );
HalDisplayString( OutBuffer );
//
// If we got a Data Cache Parity Error print a message on screen.
//
if( DCSTAT_DCPARITY_ERROR_21064(LogoutFrame->DcStat) ){
PUncorrectableError->UncorrectableFrame.Flags.AddressSpace =
MEMORY_SPACE;
PUncorrectableError->UncorrectableFrame.Flags.
MemoryErrorSource = PROCESSOR_CACHE;
PUncorrectableError->UncorrectableFrame.Flags.
ExtendedErrorValid = 1;
PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1;
sprintf( parityErrString,
"Data Cache Parity Error.\n");
HalpGetProcessorInfo(&exterr->CacheError.ProcessorInfo);
sprintf( OutBuffer, "Data Cache Parity Error.\n" );
HalDisplayString( OutBuffer );
}
//
// Check for uncorrectable error.
//
if( Esr.Uee == 1 ){
if( Esr.Sor == 0 ){
//
// Uncorrectable error from cache.
//
PUncorrectableError->UncorrectableFrame.Flags.AddressSpace =
MEMORY_SPACE;
PUncorrectableError->UncorrectableFrame.Flags.
MemoryErrorSource = PROCESSOR_CACHE;
PUncorrectableError->UncorrectableFrame.Flags.
ExtendedErrorValid = 1;
HalpGetProcessorInfo(&exterr->CacheError.ProcessorInfo);
PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1;
sprintf( parityErrString,
"Uncorrectable error from cache on %s, Tag: 0x%x\n",
Esr.Wre ? "write" : "read",
Car.Tag );
HalDisplayString( parityErrString );
} else {
//
// Uncorrectable error from memory.
//
PUncorrectableError->UncorrectableFrame.Flags.AddressSpace =
MEMORY_SPACE;
PUncorrectableError->UncorrectableFrame.Flags.
MemoryErrorSource = SYSTEM_MEMORY;
PUncorrectableError->UncorrectableFrame.Flags.
ExtendedErrorValid = 1;
HalpGetProcessorInfo(&exterr->MemoryError.ProcessorInfo);
PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1;
sprintf( parityErrString,
"Uncorrectable error from memory on %s\n",
Esr.Wre ? "write" : "read" );
HalDisplayString( parityErrString );
PUncorrectableError->UncorrectableFrame.Flags.
PhysicalAddressValid = 1;
PUncorrectableError->UncorrectableFrame.PhysicalAddress =
Ear.ErrorAddress;
exterr->MemoryError.Flags.MemorySimmValid = 1;
exterr->MemoryError.MemorySimm =
HalpSimmError( Ear.ErrorAddress, LogoutFrame );
sprintf( OutBuffer,
"Physical Address: 0x%x, Bank: %d, SIMM: %d\n",
Ear.ErrorAddress,
HalpBankError( Ear.ErrorAddress, LogoutFrame ),
HalpSimmError( Ear.ErrorAddress, LogoutFrame ) );
HalDisplayString( OutBuffer );
} //end if( Esr.Sor == 0 )
} //end if( Esr.Uee == 1 )
//
// Check for cache tag errors.
//
if( Esr.Cte == 1 ){
PUncorrectableError->UncorrectableFrame.Flags.AddressSpace =
MEMORY_SPACE;
PUncorrectableError->UncorrectableFrame.Flags.
MemoryErrorSource = PROCESSOR_CACHE;
PUncorrectableError->UncorrectableFrame.Flags.
ExtendedErrorValid = 1;
HalpGetProcessorInfo(&exterr->CacheError.ProcessorInfo);
PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1;
sprintf( parityErrString,
"Cache Tag Error, Tag: 0x%x, Hit: %d\n",
Car.Tag, Car.Hit );
HalDisplayString( parityErrString );
}
//
// Check for non-existent memory error.
//
if( Esr.Nxm == 1 ){
PUncorrectableError->UncorrectableFrame.Flags.AddressSpace =
MEMORY_SPACE;
PUncorrectableError->UncorrectableFrame.Flags.
MemoryErrorSource = SYSTEM_MEMORY;
PUncorrectableError->UncorrectableFrame.Flags.
ExtendedErrorValid = 1;
HalpGetProcessorInfo(&exterr->MemoryError.ProcessorInfo);
PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1;
sprintf( parityErrString,
"Non-existent memory accessed\n" );
sprintf( OutBuffer,
"Non-existent memory accessed, Physical Address: 0x%x.\n",
Ear.ErrorAddress );
HalDisplayString( OutBuffer );
}
//
// Check for multiple hard errors.
//
if( Esr.Mhe == 1 ){
PUncorrectableError->UncorrectableFrame.Flags.AddressSpace =
MEMORY_SPACE;
PUncorrectableError->UncorrectableFrame.Flags.
MemoryErrorSource = SYSTEM_MEMORY;
PUncorrectableError->UncorrectableFrame.Flags.
ExtendedErrorValid = 1;
HalpGetProcessorInfo(&exterr->MemoryError.ProcessorInfo);
PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1;
sprintf( parityErrString,
"Multiple hard errors detected\n" );
sprintf( OutBuffer,
"Multiple hard errors detected.\n" );
HalDisplayString( OutBuffer );
}
//
// If an I/O Error was pending print the interpretation.
//
if( IoStat0.Err == 1 ){
PUncorrectableError->UncorrectableFrame.Flags.AddressSpace =
IO_SPACE;
PUncorrectableError->UncorrectableFrame.Flags.
ExtendedErrorValid = 1;
exterr->IoError.Interface = PCIBus;
exterr->IoError.BusNumber = 0;
exterr->IoError.BusAddress.QuadPart = IoStat1.Address;
PUncorrectableError->UncorrectableFrame.Flags.PhysicalAddressValid =
1;
PUncorrectableError->UncorrectableFrame.PhysicalAddress =
IoStat1.Address;
PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1;
switch( IoStat0.Code ){
//
// Retry Limit.
//
case IocErrorRetryLimit:
sprintf(parityErrString,
"Retry Limit Error, PCI Cmd 0x%x\n",
IoStat0.Cmd );
sprintf( OutBuffer,
"Retry Limit Error, PCI Address 0x%x PCI Cmd 0x%x\n",
IoStat1.Address,
IoStat0.Cmd );
break;
//
// No device error.
//
case IocErrorNoDevice:
sprintf(parityErrString,
"No Device Error, PCI Cmd 0x%x\n",
IoStat0.Cmd );
sprintf( OutBuffer,
"No Device Error, PCI Address 0x%x PCI Cmd 0x%x\n",
IoStat1.Address,
IoStat0.Cmd );
break;
//
// Bad data parity.
//
case IocErrorBadDataParity:
sprintf(parityErrString,
"Bad Data Parity Error, PCI Cmd 0x%x\n",
IoStat0.Cmd );
sprintf( OutBuffer,
"Bad Data Parity Error, PCI Address 0x%x PCI Cmd 0x%x\n",
IoStat1.Address,
IoStat0.Cmd );
break;
//
// Target abort.
//
case IocErrorTargetAbort:
sprintf(parityErrString,
"Target Abort, PCI Cmd 0x%x\n",
IoStat0.Cmd );
sprintf( OutBuffer,
"Target Abort, PCI Address 0x%x PCI Cmd 0x%x\n",
IoStat1.Address,
IoStat0.Cmd );
break;
//
// Bad address parity.
//
case IocErrorBadAddressParity:
sprintf(parityErrString,
"Bad Address Parity, PCI Cmd 0x%x\n",
IoStat0.Cmd );
sprintf( OutBuffer,
"Bad Address Parity, PCI Address 0x%x PCI Cmd 0x%x\n",
IoStat1.Address,
IoStat0.Cmd );
break;
//
// Page Table Read Error.
//
case IocErrorPageTableReadError:
sprintf(parityErrString,
"Page Table Read Error, PCI Cmd 0x%x\n",
IoStat0.Cmd );
sprintf( OutBuffer,
"Page Table Read Error, PCI Pfn 0x%x PCI Cmd 0x%x\n",
IoStat0.PageNumber,
IoStat0.Cmd );
break;
//
// Invalid page.
//
case IocErrorInvalidPage:
sprintf(parityErrString,
"Invalid Page Error, PCI Cmd 0x%x\n",
IoStat0.Cmd );
sprintf( OutBuffer,
"Invalid Page Error, PCI Pfn 0x%x PCI Cmd 0x%x\n",
IoStat0.PageNumber,
IoStat0.Cmd );
break;
//
// Data error.
//
case IocErrorDataError:
sprintf(parityErrString,
"Data Error, PCI Cmd 0x%x\n",
IoStat0.Cmd );
sprintf( OutBuffer,
"Data Error, PCI Address 0x%x PCI Cmd 0x%x\n",
IoStat1.Address,
IoStat0.Cmd );
break;
//
// Unrecognized error code.
//
default:
sprintf(parityErrString,
"Unrecognized I/O Error.\n" );
sprintf( OutBuffer, "Unrecognized I/O Error.\n" );
break;
} //end switch (IoStat0.Code)
HalDisplayString( OutBuffer );
if( IoStat0.Lost == 1 ){
sprintf(parityErrString,
"Additional I/O errors were lost.\n" );
HalDisplayString( "Additional I/O errors were lost.\n" );
}
} //end if( IoStat0.Err == 1 )
//
// return to caller
//
return;
}
ULONG
HalpBankError(
ULONG PhysicalAddress,
PLOGOUT_FRAME_21066 LogoutFrame
)
/*++
Routine Description:
Return the bank of memory that the physical address fails within.
Arguments:
PhysicalAddress - Supplies the physical address to locate.
LogoutFrame - Supplies a pointer to the logout frame that contains the
bank configuration information.
Return Value:
Returns the number of the bank that contains the physical address.
Returns 0xffffffff if the physical address is not contained within any of
the banks.
--*/
{
ULONG Bank;
for( Bank=0; Bank < MEMORY_BANKS_21066; Bank++ ){
//
// If the bank is valid and the physical address is within the
// bank then we have found the correct bank.
//
if( (LogoutFrame->BankConfig[Bank].Bav == 1) &&
((PhysicalAddress >> 20) &
(~LogoutFrame->BankMask[Bank].BankAddressMask)) ==
LogoutFrame->BankConfig[Bank].BankBase ){
return Bank;
}
}
//
// Did not find a bank which contains physical address.
//
return (0xffffffff);
}
//jnfix - this should be move to platform-specific
//jnfix - and made real depending upon how memory is configured
//jnfix - this current code is a simple guess which provides a model
ULONG
HalpSimmError(
ULONG PhysicalAddress,
PLOGOUT_FRAME_21066 LogoutFrame
)
/*++
Routine Description:
Return the SIMM number that the physical address fails within.
Arguments:
PhysicalAddress - Supplies the physical address to locate.
LogoutFrame - Supplies a pointer to the logout frame that contains the
bank configuration information.
Return Value:
Returns the number of the SIMM that contains the physical address.
Returns 0xffffffffif the physical address is not contained within any of
the SIMMs.
--*/
{
ULONG Bank;
ULONG Simm;
for( Bank=0; Bank < MEMORY_BANKS_21066; Bank++ ){
//
// If the bank is valid and the physical address is within the
// bank then we have found the correct bank.
//
if( (LogoutFrame->BankConfig[Bank].Bav == 1) &&
((PhysicalAddress >> 20) &
(~LogoutFrame->BankMask[Bank].BankAddressMask)) ==
LogoutFrame->BankConfig[Bank].BankBase ){
//
// Assume that each bank contains 2 SIMMs and that they are
// numbered 0..N. We need to determine which SIMM within the
// bank. We will guess that the SIMMs are 32-bits wide and
// that the low 32-bits are in the low SIMM while the high
// 32-bits are in the high SIMM. So addresses 0..3 are low
// and 4..7 are high.
//
Simm = Bank * 2;
if( PhysicalAddress & 4 ) Simm += 1;
return Simm;
}
}
//
// Did not find a bank which contains physical address.
//
return (0xffffffff);
}