1591 lines
39 KiB
C
1591 lines
39 KiB
C
/*++
|
||
|
||
Copyright (C) 1997-99 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
hack.c
|
||
|
||
Abstract:
|
||
|
||
--*/
|
||
|
||
#include "ideport.h"
|
||
#include "hack.h"
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGE, IdePortSlaveIsGhost)
|
||
#pragma alloc_text(PAGE, IdePortGetFlushCommand)
|
||
#pragma alloc_text(PAGE, IdePortMustBePio)
|
||
#pragma alloc_text(PAGE, IdePortPioByDefaultDevice)
|
||
#pragma alloc_text(PAGE, IdePortDeviceHasNonRemovableMedia)
|
||
#pragma alloc_text(PAGE, IdePortDeviceIsLs120)
|
||
#pragma alloc_text(PAGE, IdePortNoPowerDown)
|
||
#pragma alloc_text(PAGE, IdePortVerifyDma)
|
||
#pragma alloc_text(NONPAGE, IdePortFudgeAtaIdentifyData)
|
||
#pragma alloc_text(PAGE, IdePortIsThisAPanasonicPCMCIACard)
|
||
#pragma alloc_text(PAGE, IdeFindSpecialDevice)
|
||
/*
|
||
#pragma alloc_text(PAGE, IdePortIsThisASonyMemorystickPCMCIACard)
|
||
#pragma alloc_text(PAGE, IdePortSonyMemoryStick)
|
||
#pragma alloc_text(PAGE, IdePortReuseIdent)
|
||
#pragma alloc_text(PAGE, IdePortBadCdrom)
|
||
*/
|
||
#endif // ALLOC_PRAGMA
|
||
|
||
#if defined (FAKE_BMSETUP_FAILURE)
|
||
ULONG FailBmSetupCount = 0;
|
||
#endif // FAKE_BMSETUP_FAILURE
|
||
|
||
#if DBG
|
||
|
||
ULONG IdeDebugRescanBusFreq = 0;
|
||
ULONG IdeDebugRescanBusCounter = 0;
|
||
|
||
ULONG IdeDebugHungControllerFreq = 0;
|
||
ULONG IdeDebugHungControllerCounter = 0;
|
||
|
||
ULONG IdeDebugTimeoutAllCacheFlush = 0;
|
||
|
||
ULONG IdeDebugForceSmallCrashDumpBlockSize = 0;
|
||
|
||
PDEVICE_OBJECT IdeDebugDevObjTimeoutAllDmaSrb = 0;
|
||
|
||
ULONG IdeDebug = 0;
|
||
ULONG IdeDebugPrintControl = DBG_ALWAYS;
|
||
UCHAR IdeBuffer[0x1000];
|
||
|
||
|
||
VOID
|
||
IdeDebugPrint(
|
||
ULONG DebugPrintLevel,
|
||
PCCHAR DebugMessage,
|
||
...
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Debug print for all SCSI drivers
|
||
|
||
Arguments:
|
||
|
||
Debug print level between 0 and 3, with 3 being the most verbose.
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
|
||
{
|
||
BOOLEAN print = FALSE;
|
||
va_list ap;
|
||
|
||
va_start(ap, DebugMessage);
|
||
|
||
if (DebugPrintLevel & DBG_BIT_CONTROL) {
|
||
|
||
if (DebugPrintLevel == DBG_ALWAYS) {
|
||
|
||
print = TRUE;
|
||
|
||
} else if ((DebugPrintLevel & ~DBG_BIT_CONTROL) & IdeDebugPrintControl) {
|
||
|
||
print = TRUE;
|
||
}
|
||
|
||
} else {
|
||
|
||
if (DebugPrintLevel <= IdeDebug) {
|
||
|
||
print = TRUE;
|
||
}
|
||
}
|
||
|
||
if (print) {
|
||
|
||
vsprintf(IdeBuffer, DebugMessage, ap);
|
||
|
||
#ifdef ENABLE_DBG_PRINT
|
||
DbgPrint(IdeBuffer);
|
||
#else
|
||
DbgPrintEx(DPFLTR_IDEP_ID,
|
||
DPFLTR_INFO_LEVEL,
|
||
IdeBuffer
|
||
);
|
||
#endif
|
||
}
|
||
|
||
va_end(ap);
|
||
|
||
} // end IdeDebugPrint()
|
||
#endif
|
||
|
||
//
|
||
// if we see one of these slave device that looks like
|
||
// the master device, we will ignore the slave device
|
||
//
|
||
BOOLEAN
|
||
IdePortSlaveIsGhost (
|
||
IN OUT PFDO_EXTENSION FdoExtension,
|
||
IN PIDENTIFY_DATA MasterIdentifyData,
|
||
IN PIDENTIFY_DATA SlaveIdentifyData
|
||
)
|
||
{
|
||
ULONG length;
|
||
ULONG i;
|
||
|
||
PAGED_CODE();
|
||
|
||
length = sizeof (MasterIdentifyData->ModelNumber);
|
||
if (length == RtlCompareMemory (
|
||
MasterIdentifyData->ModelNumber,
|
||
SlaveIdentifyData->ModelNumber,
|
||
length)) {
|
||
|
||
if (IdePortSearchDeviceInRegMultiSzList (
|
||
FdoExtension,
|
||
MasterIdentifyData,
|
||
GHOST_SLAVE_DEVICE)) {
|
||
|
||
DebugPrint ((DBG_WARNING, "ATAPI: Found a ghost slave\n"));
|
||
return TRUE;
|
||
}
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
UCHAR
|
||
IdePortGetFlushCommand (
|
||
IN OUT PFDO_EXTENSION FdoExtension,
|
||
IN OUT PPDO_EXTENSION PdoExtension,
|
||
IN PIDENTIFY_DATA IdentifyData
|
||
)
|
||
{
|
||
ULONG i;
|
||
UCHAR flushCommand;
|
||
BOOLEAN done;
|
||
|
||
PAGED_CODE();
|
||
|
||
ASSERT (FdoExtension);
|
||
ASSERT (PdoExtension);
|
||
ASSERT (IdentifyData);
|
||
|
||
done = FALSE;
|
||
|
||
//
|
||
// in hall of shame list?
|
||
//
|
||
if (IdePortSearchDeviceInRegMultiSzList (
|
||
FdoExtension,
|
||
IdentifyData,
|
||
NO_FLUSH_DEVICE)) {
|
||
|
||
DebugPrint ((DBG_WARNING, "ATAPI: found a device that couldn't handle any flush command\n"));
|
||
|
||
flushCommand = IDE_COMMAND_NO_FLUSH;
|
||
done = TRUE;
|
||
|
||
} else if (IdePortSearchDeviceInRegMultiSzList (
|
||
FdoExtension,
|
||
IdentifyData,
|
||
CHECK_POWER_FLUSH_DEVICE)) {
|
||
|
||
DebugPrint ((DBG_WARNING, "ATAPI: found a device that has to use check power mode command to flush\n"));
|
||
|
||
flushCommand = IDE_COMMAND_CHECK_POWER;
|
||
done = TRUE;
|
||
}
|
||
|
||
if (!done) {
|
||
|
||
//
|
||
// real ATA-4 drive?
|
||
//
|
||
|
||
if ((IdentifyData->MajorRevision != 0x0000) &&
|
||
(IdentifyData->MajorRevision != 0xffff)) {
|
||
|
||
USHORT version;
|
||
|
||
version = IdentifyData->MajorRevision & ATA_VERSION_MASK;
|
||
if (version & ~(ATA1_COMPLIANCE | ATA2_COMPLIANCE | ATA3_COMPLIANCE)) {
|
||
|
||
//
|
||
// ATA-4 Flush Command
|
||
//
|
||
flushCommand = IDE_COMMAND_FLUSH_CACHE;
|
||
done = TRUE;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (!done) {
|
||
|
||
ATA_PASS_THROUGH ataPassThroughData;
|
||
NTSTATUS status;
|
||
|
||
//
|
||
// try the ATA-4 flush command. maybe it will work.
|
||
//
|
||
RtlZeroMemory (&ataPassThroughData, sizeof (ataPassThroughData));
|
||
|
||
ataPassThroughData.IdeReg.bCommandReg = IDE_COMMAND_FLUSH_CACHE;
|
||
ataPassThroughData.IdeReg.bReserved = ATA_PTFLAGS_STATUS_DRDY_REQUIRED | ATA_PTFLAGS_ENUM_PROBING;
|
||
|
||
status = IssueSyncAtaPassThroughSafe (
|
||
FdoExtension,
|
||
PdoExtension,
|
||
&ataPassThroughData,
|
||
FALSE,
|
||
FALSE,
|
||
15,
|
||
FALSE
|
||
);
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
if (!(ataPassThroughData.IdeReg.bCommandReg & IDE_STATUS_ERROR)) {
|
||
|
||
flushCommand = IDE_COMMAND_FLUSH_CACHE;
|
||
done = TRUE;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (!done) {
|
||
|
||
// out of idea!
|
||
// choose the default
|
||
|
||
flushCommand = IDE_COMMAND_CHECK_POWER;
|
||
}
|
||
|
||
return flushCommand;
|
||
}
|
||
|
||
#if 0
|
||
BOOLEAN
|
||
IdePortReuseIdent(
|
||
IN PFDO_EXTENSION FdoExtension,
|
||
IN PIDENTIFY_DATA IdentifyData
|
||
)
|
||
{
|
||
PAGED_CODE();
|
||
//
|
||
// Determine if we can re-use the identify data
|
||
//
|
||
if (IdePortSearchDeviceInRegMultiSzList (
|
||
FdoExtension,
|
||
IdentifyData,
|
||
NEED_IDENT_DEVICE)) {
|
||
return TRUE;
|
||
}
|
||
return FALSE;
|
||
}
|
||
#endif
|
||
|
||
BOOLEAN
|
||
IdePortMustBePio (
|
||
IN PFDO_EXTENSION FdoExtension,
|
||
IN PIDENTIFY_DATA IdentifyData
|
||
)
|
||
{
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// query pio only device from the registry
|
||
//
|
||
if (IdePortSearchDeviceInRegMultiSzList (
|
||
FdoExtension,
|
||
IdentifyData,
|
||
PIO_ONLY_DEVICE)) {
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
return FALSE;
|
||
} // IdePortMustBePio
|
||
|
||
|
||
BOOLEAN
|
||
IdePortPioByDefaultDevice (
|
||
IN PFDO_EXTENSION FdoExtension,
|
||
IN PIDENTIFY_DATA IdentifyData
|
||
)
|
||
{
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// query pio only device from the registry
|
||
//
|
||
if (IdePortSearchDeviceInRegMultiSzList (
|
||
FdoExtension,
|
||
IdentifyData,
|
||
DEFAULT_PIO_DEVICE)) {
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
return FALSE;
|
||
} // IdePortMustBePio
|
||
|
||
BOOLEAN
|
||
IdePortDeviceHasNonRemovableMedia (
|
||
IN OUT PFDO_EXTENSION FdoExtension,
|
||
IN PIDENTIFY_DATA IdentifyData
|
||
)
|
||
{
|
||
BOOLEAN removableMediaOverride;
|
||
PAGED_CODE();
|
||
|
||
if (IsNEC_98) {
|
||
return ((IdentifyData->GeneralConfiguration & (1 << 7))? TRUE :
|
||
(!Is98LegacyIde(&FdoExtension->HwDeviceExtension->BaseIoAddress1)? TRUE : FALSE));
|
||
}
|
||
|
||
return (IdentifyData->GeneralConfiguration & (1 << 7)) ? TRUE : FALSE;
|
||
|
||
/*
|
||
removableMediaOverride = FALSE;
|
||
if (IdePortSearchDeviceInRegMultiSzList (
|
||
FdoExtension,
|
||
IdentifyData,
|
||
NONREMOVABLE_MEDIA_OVERRIDE)) {
|
||
|
||
removableMediaOverride = TRUE;
|
||
}
|
||
|
||
if (removableMediaOverride) {
|
||
|
||
return FALSE;
|
||
|
||
} else {
|
||
|
||
return (IdentifyData->GeneralConfiguration & (1 << 7)) ? TRUE : FALSE;
|
||
}
|
||
*/
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
IdePortDeviceIsLs120 (
|
||
IN PFDO_EXTENSION FdoExtension,
|
||
IN PIDENTIFY_DATA IdentifyData
|
||
)
|
||
{
|
||
UCHAR modelNumber[41];
|
||
ULONG i;
|
||
UCHAR ls120NameString[] = "LS-120";
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// byte swap model number
|
||
//
|
||
for (i=0; i<40; i+=2) {
|
||
modelNumber[i + 0] = IdentifyData->ModelNumber[i + 1];
|
||
modelNumber[i + 1] = IdentifyData->ModelNumber[i + 0];
|
||
}
|
||
modelNumber[i] = 0;
|
||
|
||
return strstr(_strupr(modelNumber), ls120NameString) ? TRUE : FALSE;
|
||
} // IdePortDeviceIsLs120
|
||
|
||
|
||
BOOLEAN
|
||
IdePortNoPowerDown (
|
||
IN PFDO_EXTENSION FdoExtension,
|
||
IN PIDENTIFY_DATA IdentifyData
|
||
)
|
||
{
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// query no power down device from the registry
|
||
//
|
||
if (IdePortSearchDeviceInRegMultiSzList (
|
||
FdoExtension,
|
||
IdentifyData,
|
||
NO_POWER_DOWN_DEVICE)) {
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
return FALSE;
|
||
} // IdePortNoPowerDown
|
||
|
||
BOOLEAN
|
||
IdePortVerifyDma (
|
||
IN PPDO_EXTENSION pdoExtension,
|
||
IN IDE_DEVICETYPE ideDeviceType
|
||
)
|
||
{
|
||
NTSTATUS status;
|
||
ULONG oldDmaTransferTimeoutCount;
|
||
BOOLEAN dmaOk;
|
||
|
||
|
||
dmaOk = TRUE;
|
||
|
||
if (pdoExtension->DmaTransferTimeoutCount >= PDO_DMA_TIMEOUT_LIMIT) {
|
||
|
||
dmaOk = FALSE;
|
||
|
||
} else if (ideDeviceType == DeviceIsAtapi) {
|
||
|
||
INQUIRYDATA DmaInquiryData;
|
||
INQUIRYDATA PioInquiryData;
|
||
|
||
status = IssueInquirySafe(
|
||
pdoExtension->ParentDeviceExtension,
|
||
pdoExtension,
|
||
&DmaInquiryData,
|
||
FALSE);
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
//
|
||
// force a pio transfer
|
||
//
|
||
oldDmaTransferTimeoutCount = InterlockedExchange(
|
||
&pdoExtension->DmaTransferTimeoutCount,
|
||
PDO_DMA_TIMEOUT_LIMIT
|
||
);
|
||
status = IssueInquirySafe(
|
||
pdoExtension->ParentDeviceExtension,
|
||
pdoExtension,
|
||
&PioInquiryData,
|
||
FALSE);
|
||
|
||
if (NT_SUCCESS(status) &&
|
||
(RtlCompareMemory (&DmaInquiryData, &PioInquiryData,
|
||
sizeof(DmaInquiryData)) != sizeof(DmaInquiryData))) {
|
||
|
||
|
||
dmaOk = FALSE;
|
||
|
||
//
|
||
// dma is not ok, leave the dma error count as PDO_DMA_TIMEOUT_LIMIT
|
||
// so that we are not going to use dma with this device
|
||
//
|
||
} else {
|
||
|
||
InterlockedExchange(
|
||
&pdoExtension->DmaTransferTimeoutCount,
|
||
oldDmaTransferTimeoutCount
|
||
);
|
||
}
|
||
}
|
||
|
||
} else if (ideDeviceType == DeviceIsAta) {
|
||
|
||
PUCHAR dmaDataBuffer;
|
||
PUCHAR pioDataBuffer;
|
||
CDB cdb;
|
||
|
||
//
|
||
// the only non-desctrutive way to test dma on a
|
||
// ata device is to perform a pio read and a dma read and
|
||
// compare the data.
|
||
//
|
||
// this technique does not work if the device has a removable
|
||
// media and it is removed.
|
||
//
|
||
|
||
dmaDataBuffer = ExAllocatePool (
|
||
NonPagedPool,
|
||
512 * 2
|
||
);
|
||
if (dmaDataBuffer) {
|
||
|
||
pioDataBuffer = dmaDataBuffer + 512;
|
||
|
||
//
|
||
// setup dma pass through
|
||
//
|
||
RtlZeroMemory(&cdb, sizeof(CDB));
|
||
cdb.CDB10.OperationCode = SCSIOP_READ;
|
||
cdb.CDB10.TransferBlocksLsb = 1;
|
||
|
||
status = IssueSyncAtapiCommandSafe (
|
||
pdoExtension->ParentDeviceExtension,
|
||
pdoExtension,
|
||
&cdb,
|
||
dmaDataBuffer,
|
||
512,
|
||
TRUE,
|
||
2,
|
||
FALSE
|
||
);
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
//
|
||
// setup pio pass through
|
||
//
|
||
RtlZeroMemory(&cdb, sizeof(CDB));
|
||
cdb.CDB10.OperationCode = SCSIOP_READ;
|
||
cdb.CDB10.TransferBlocksLsb = 1;
|
||
|
||
//
|
||
// force a pio transfer
|
||
//
|
||
oldDmaTransferTimeoutCount = InterlockedExchange(
|
||
&pdoExtension->DmaTransferTimeoutCount,
|
||
PDO_DMA_TIMEOUT_LIMIT
|
||
);
|
||
|
||
status = IssueSyncAtapiCommand (
|
||
pdoExtension->ParentDeviceExtension,
|
||
pdoExtension,
|
||
&cdb,
|
||
pioDataBuffer,
|
||
512,
|
||
TRUE,
|
||
2,
|
||
FALSE
|
||
);
|
||
|
||
if (NT_SUCCESS(status) &&
|
||
(RtlCompareMemory (
|
||
dmaDataBuffer,
|
||
pioDataBuffer,
|
||
512) != 512)) {
|
||
|
||
dmaOk = FALSE;
|
||
|
||
//
|
||
// dma is not ok, leave the dma error count as PDO_DMA_TIMEOUT_LIMIT
|
||
// so that we are not going to use dma with this device
|
||
//
|
||
} else {
|
||
|
||
InterlockedExchange(
|
||
&pdoExtension->DmaTransferTimeoutCount,
|
||
oldDmaTransferTimeoutCount
|
||
);
|
||
}
|
||
}
|
||
}
|
||
|
||
if (dmaDataBuffer) {
|
||
ExFreePool (dmaDataBuffer);
|
||
}
|
||
}
|
||
|
||
#if DBG
|
||
#if defined (FAKE_BROKEN_DMA_DEVICE)
|
||
InterlockedExchange(
|
||
&pdoExtension->DmaTransferTimeoutCount,
|
||
PDO_DMA_TIMEOUT_LIMIT
|
||
);
|
||
dmaOk = FALSE;
|
||
#endif // FAKE_BROKEN_DMA_DEVICE
|
||
#endif // DBG
|
||
|
||
if (!dmaOk) {
|
||
|
||
ERROR_LOG_ENTRY errorLogEntry;
|
||
|
||
errorLogEntry.ErrorCode = SP_BAD_FW_ERROR;
|
||
errorLogEntry.MajorFunctionCode = IRP_MJ_SCSI;
|
||
errorLogEntry.PathId = pdoExtension->PathId;
|
||
errorLogEntry.TargetId = pdoExtension->TargetId;
|
||
errorLogEntry.Lun = pdoExtension->Lun;
|
||
errorLogEntry.UniqueId = ERRLOGID_LYING_DMA_SYSTEM;
|
||
errorLogEntry.ErrorLogRetryCount = 0;
|
||
errorLogEntry.SequenceNumber = 0;
|
||
|
||
LogErrorEntry(
|
||
pdoExtension->ParentDeviceExtension,
|
||
&errorLogEntry
|
||
);
|
||
|
||
DebugPrint ((
|
||
DBG_ALWAYS,
|
||
"ATAPI: system and/or device lies about its dma capability. pdoe = 0x%x\n",
|
||
pdoExtension
|
||
));
|
||
}
|
||
|
||
return dmaOk;
|
||
}
|
||
|
||
VOID
|
||
IdePortFudgeAtaIdentifyData(
|
||
IN OUT PIDENTIFY_DATA IdentifyData
|
||
)
|
||
{
|
||
if (IdentifyData->GeneralConfiguration == 0xffff) {
|
||
|
||
//
|
||
// guessing we have a really old ATA drive
|
||
// fake the GeneralConfiguration value
|
||
//
|
||
CLRMASK (
|
||
IdentifyData->GeneralConfiguration,
|
||
(IDE_IDDATA_REMOVABLE | (1 << 15))
|
||
);
|
||
}
|
||
|
||
}
|
||
|
||
#define PANASONIC_PCMCIA_IDE_DEVICE L"PCMCIA\\KME-KXLC005-A99E"
|
||
|
||
BOOLEAN
|
||
IdePortIsThisAPanasonicPCMCIACard(
|
||
IN PFDO_EXTENSION FdoExtension
|
||
)
|
||
{
|
||
IO_STATUS_BLOCK ioStatus;
|
||
KEVENT pnpEvent;
|
||
NTSTATUS status;
|
||
PDEVICE_OBJECT targetObject;
|
||
PIO_STACK_LOCATION irpStack;
|
||
PIRP pnpIrp;
|
||
BOOLEAN result = FALSE;
|
||
|
||
PAGED_CODE();
|
||
|
||
targetObject = FdoExtension->AttacheeDeviceObject;
|
||
|
||
//
|
||
// Initialize the event
|
||
//
|
||
KeInitializeEvent( &pnpEvent, SynchronizationEvent, FALSE );
|
||
|
||
//
|
||
// Build an Irp
|
||
//
|
||
pnpIrp = IoBuildSynchronousFsdRequest(
|
||
IRP_MJ_PNP,
|
||
FdoExtension->AttacheeDeviceObject,
|
||
NULL,
|
||
0,
|
||
NULL,
|
||
&pnpEvent,
|
||
&ioStatus
|
||
);
|
||
if (pnpIrp == NULL) {
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// Pnp Irps all begin life as STATUS_NOT_SUPPORTED;
|
||
//
|
||
pnpIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
|
||
pnpIrp->IoStatus.Information = 0;
|
||
|
||
//
|
||
// Set the top of stack
|
||
//
|
||
irpStack = IoGetNextIrpStackLocation( pnpIrp );
|
||
RtlZeroMemory( irpStack, sizeof(IO_STACK_LOCATION ) );
|
||
irpStack->MajorFunction = IRP_MJ_PNP;
|
||
irpStack->MinorFunction = IRP_MN_QUERY_ID;
|
||
irpStack->Parameters.QueryId.IdType = BusQueryDeviceID;
|
||
|
||
//
|
||
// Make sure that there are no completion routines set
|
||
//
|
||
IoSetCompletionRoutine(
|
||
pnpIrp,
|
||
NULL,
|
||
NULL,
|
||
FALSE,
|
||
FALSE,
|
||
FALSE
|
||
);
|
||
|
||
//
|
||
// Call the driver
|
||
//
|
||
status = IoCallDriver( targetObject, pnpIrp );
|
||
if (status == STATUS_PENDING) {
|
||
|
||
//
|
||
// Block until the irp comes back
|
||
//
|
||
KeWaitForSingleObject(
|
||
&pnpEvent,
|
||
Executive,
|
||
KernelMode,
|
||
FALSE,
|
||
NULL
|
||
);
|
||
status = ioStatus.Status;
|
||
|
||
}
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
UNICODE_STRING panasonicDeviceId;
|
||
UNICODE_STRING deviceId;
|
||
|
||
RtlInitUnicodeString (&panasonicDeviceId, PANASONIC_PCMCIA_IDE_DEVICE);
|
||
RtlInitUnicodeString (&deviceId, (PWCHAR) ioStatus.Information);
|
||
|
||
if (!RtlCompareUnicodeString(
|
||
&deviceId,
|
||
&panasonicDeviceId,
|
||
TRUE)) {
|
||
|
||
result = TRUE;
|
||
}
|
||
|
||
ExFreePool ((PVOID) ioStatus.Information);
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
|
||
//
|
||
// Timing Code
|
||
//
|
||
#if defined (ENABLE_TIME_LOG)
|
||
|
||
TIME_LOG TimeLog[TimeMax] = {0};
|
||
VOID
|
||
LogStartTime(
|
||
TIME_ID id,
|
||
PLARGE_INTEGER timer
|
||
)
|
||
{
|
||
*timer = KeQueryPerformanceCounter(NULL);
|
||
}
|
||
|
||
VOID
|
||
LogStopTime(
|
||
TIME_ID id,
|
||
PLARGE_INTEGER timer,
|
||
ULONG waterMark
|
||
)
|
||
{
|
||
LARGE_INTEGER freq;
|
||
LARGE_INTEGER stopTime;
|
||
LARGE_INTEGER diffTime;
|
||
LARGE_INTEGER diffTimeInMicroSec;
|
||
|
||
stopTime = KeQueryPerformanceCounter(&freq);
|
||
diffTime.QuadPart = stopTime.QuadPart - timer->QuadPart;
|
||
diffTimeInMicroSec.QuadPart = (diffTime.QuadPart * 1000000) / freq.QuadPart;
|
||
|
||
// need a spinlock
|
||
|
||
if (TimeLog[id].min.QuadPart == 0) {
|
||
|
||
TimeLog[id].min.QuadPart = 0x7fffffffffffffffL;
|
||
}
|
||
|
||
if (diffTime.QuadPart < TimeLog[id].min.QuadPart) {
|
||
TimeLog[id].min = diffTime;
|
||
}
|
||
|
||
if (diffTime.QuadPart > TimeLog[id].max.QuadPart) {
|
||
TimeLog[id].max = diffTime;
|
||
}
|
||
|
||
TimeLog[id].totalTimeInMicroSec.QuadPart += diffTimeInMicroSec.QuadPart;
|
||
TimeLog[id].numLog.QuadPart++;
|
||
|
||
if (waterMark) {
|
||
if (diffTimeInMicroSec.LowPart > waterMark) {
|
||
|
||
DebugPrint ((DBG_ALWAYS, "IdePort: timerID 0x%d took %d us\n", id, (ULONG) diffTimeInMicroSec.LowPart));
|
||
}
|
||
}
|
||
}
|
||
|
||
#endif // ENABLE_TIME_LOG
|
||
|
||
|
||
#if defined (IDE_BUS_TRACE)
|
||
|
||
ULONG IdePortBusTraceTableMaxEntries = 0x20000;
|
||
BUS_TRACE_LOG IdePortBusTaceLog = {0, 0, 0, FALSE};
|
||
|
||
VOID InitBusTraceLogTable (
|
||
VOID
|
||
)
|
||
{
|
||
ASSERT (IdePortBusTaceLog.LogTable == NULL);
|
||
|
||
//
|
||
// make sure MAX_ULONG + 1 is a multiple of total log entries
|
||
// so that when the index wraps, we don't skin any log entry
|
||
//
|
||
ASSERT(!((((ULONGLONG) 0xffffffff) + 1) % IdePortBusTraceTableMaxEntries));
|
||
|
||
IdePortBusTaceLog.LogTable =
|
||
ExAllocatePool (NonPagedPool, IdePortBusTraceTableMaxEntries * sizeof(BUS_TRACE_RECORD));
|
||
|
||
if (IdePortBusTaceLog.LogTable) {
|
||
IdePortBusTaceLog.NumLogTableEntries = IdePortBusTraceTableMaxEntries;
|
||
IdePortBusTaceLog.LastLogTableEntry = -1;
|
||
IdePortBusTaceLog.TableWrapped = FALSE;
|
||
|
||
KeInitializeSpinLock(&IdePortBusTaceLog.SpinLock);
|
||
}
|
||
}
|
||
|
||
VOID FreeBusTraceLogTable (
|
||
VOID
|
||
)
|
||
{
|
||
if (IdePortBusTaceLog.LogTable) {
|
||
|
||
ExFreePool (IdePortBusTaceLog.LogTable);
|
||
RtlZeroMemory(&IdePortBusTaceLog, sizeof(IdePortBusTaceLog));
|
||
}
|
||
}
|
||
|
||
|
||
VOID
|
||
IdepUpdateTraceLog (
|
||
IO_TYPE IoType,
|
||
PVOID PortAddress,
|
||
ULONG Data
|
||
)
|
||
{
|
||
KIRQL currentIrql;
|
||
ULONG lastEntry;
|
||
|
||
if (IdePortBusTaceLog.LogTable) {
|
||
|
||
lastEntry = InterlockedIncrement(&IdePortBusTaceLog.LastLogTableEntry);
|
||
lastEntry--;
|
||
lastEntry %= IdePortBusTaceLog.NumLogTableEntries;
|
||
IdePortBusTaceLog.LogTable[lastEntry].IoType = IoType;
|
||
IdePortBusTaceLog.LogTable[lastEntry].Address = PortAddress;
|
||
IdePortBusTaceLog.LogTable[lastEntry].Data = Data;
|
||
IdePortBusTaceLog.LogTable[lastEntry].Count = 1;
|
||
}
|
||
}
|
||
|
||
UCHAR
|
||
IdepPortInPortByte (
|
||
PUCHAR PortAddress
|
||
)
|
||
{
|
||
KIRQL currentIrql;
|
||
UCHAR data;
|
||
|
||
data = READ_PORT_UCHAR(PortAddress);
|
||
IdepUpdateTraceLog (InPortByte, PortAddress, (ULONG) data);
|
||
return data;
|
||
}
|
||
|
||
VOID
|
||
IdepPortOutPortByte (
|
||
PUCHAR PortAddress,
|
||
UCHAR Data
|
||
)
|
||
{
|
||
WRITE_PORT_UCHAR(PortAddress, Data);
|
||
IdepUpdateTraceLog (OutPortByte, PortAddress, (ULONG) Data);
|
||
return;
|
||
}
|
||
|
||
USHORT
|
||
IdepPortInPortWord (
|
||
PUSHORT PortAddress
|
||
)
|
||
{
|
||
KIRQL currentIrql;
|
||
USHORT data;
|
||
|
||
data = READ_PORT_USHORT(PortAddress);
|
||
IdepUpdateTraceLog (InPortWord, PortAddress, (ULONG) data);
|
||
return data;
|
||
}
|
||
|
||
VOID
|
||
IdepPortOutPortWord (
|
||
PUSHORT PortAddress,
|
||
USHORT Data
|
||
)
|
||
{
|
||
WRITE_PORT_USHORT(PortAddress, Data);
|
||
IdepUpdateTraceLog (OutPortWord, PortAddress, (ULONG) Data);
|
||
return;
|
||
}
|
||
|
||
VOID
|
||
IdepPortInPortWordBuffer (
|
||
PUSHORT PortAddress,
|
||
PUSHORT Buffer,
|
||
ULONG Count
|
||
)
|
||
{
|
||
ULONG i;
|
||
for (i=0; i<Count; i++) {
|
||
Buffer[i] = IdepPortInPortWord (PortAddress);
|
||
}
|
||
return;
|
||
}
|
||
|
||
|
||
VOID
|
||
IdepPortOutPortWordBuffer (
|
||
PUSHORT PortAddress,
|
||
PUSHORT Buffer,
|
||
ULONG Count
|
||
)
|
||
{
|
||
ULONG i;
|
||
for (i=0; i<Count; i++) {
|
||
IdepPortOutPortWord (PortAddress, Buffer[i]);
|
||
}
|
||
return;
|
||
}
|
||
|
||
#endif // IDE_BUS_TRACE
|
||
|
||
|
||
|
||
SPECIAL_ACTION_FLAG
|
||
IdeFindSpecialDevice(
|
||
IN PUCHAR VendorProductId,
|
||
IN PUCHAR ProductRevisionId
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine will search the IDE special device table to determine whether
|
||
any special behavior should be enabled for this device. The match is made upto
|
||
the strlen of VendorProductId in the table.
|
||
|
||
Arguments:
|
||
|
||
VendorProductId - the full vendor & product ID of the device in question.
|
||
ProductRevisionId - the full product revision ID of the device in question.
|
||
|
||
ReturnValue:
|
||
|
||
an ulong which describes the limitations of the device
|
||
in question.
|
||
|
||
--*/
|
||
|
||
{
|
||
IDE_SPECIAL_DEVICE IdeSpecialDeviceTable[] = {
|
||
{"TOSHIBA CD-ROM XM-1702B", NULL, disableSerialNumber},
|
||
{"TOSHIBA CD-ROM XM-6202B", NULL, disableSerialNumber},
|
||
{"COMPAQ DVD-ROM DRD-U424", NULL, disableSerialNumber},
|
||
{" " , NULL, disableSerialNumber},
|
||
{"KENWOOD CD-ROM", NULL, skipModeSense},
|
||
{"MEMORYSTICK", NULL, setFlagSonyMemoryStick},
|
||
{NULL, NULL, noSpecialAction}
|
||
};
|
||
|
||
ULONG i;
|
||
ULONG length;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// if both the arguments are null, then just return no special action
|
||
//
|
||
if (VendorProductId == NULL &&
|
||
ProductRevisionId == NULL) {
|
||
return noSpecialAction;
|
||
}
|
||
|
||
for(i = 0; IdeSpecialDeviceTable[i].VendorProductId != NULL; i++) {
|
||
|
||
//
|
||
// Match only upto the strlen of the productID in the table
|
||
// This will allow special action for all the models from a particular vendor.
|
||
//
|
||
length=strlen(IdeSpecialDeviceTable[i].VendorProductId);
|
||
|
||
if (length != RtlCompareMemory(IdeSpecialDeviceTable[i].VendorProductId,
|
||
VendorProductId, length)) {
|
||
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// Partial matches are not acceptable for revision Ids.
|
||
//
|
||
if((IdeSpecialDeviceTable[i].Revision != NULL) &&
|
||
(strcmp(IdeSpecialDeviceTable[i].Revision,
|
||
ProductRevisionId) != 0)) {
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// We've got a match. Break out.
|
||
//
|
||
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Return whatever entry we're pointing at. If we matched based on the
|
||
// id's then this will be the matching entry. If we broke out of the
|
||
// loop then this will be the last entry in the list which is the
|
||
// benign, "nothing special about this device" entry that we return
|
||
// for a failed match.
|
||
//
|
||
|
||
return (IdeSpecialDeviceTable[i].RequiredAction);
|
||
}
|
||
|
||
#ifdef ENABLE_COMMAND_LOG
|
||
|
||
VOID
|
||
IdeLogOpenCommandLog(
|
||
PSRB_DATA SrbData
|
||
)
|
||
{
|
||
if (SrbData->IdeCommandLog == NULL) {
|
||
SrbData->IdeCommandLog = ExAllocatePool(
|
||
NonPagedPool,
|
||
MAX_COMMAND_LOG_ENTRIES*sizeof(COMMAND_LOG)
|
||
);
|
||
if (SrbData->IdeCommandLog != NULL) {
|
||
RtlZeroMemory(SrbData->IdeCommandLog, MAX_COMMAND_LOG_ENTRIES*sizeof(COMMAND_LOG));
|
||
}
|
||
|
||
SrbData->IdeCommandLogIndex = 0;
|
||
}
|
||
return;
|
||
}
|
||
|
||
VOID
|
||
IdeLogStartCommandLog(
|
||
PSRB_DATA SrbData
|
||
)
|
||
{
|
||
PCOMMAND_LOG cmdLog = &(SrbData->IdeCommandLog[SrbData->IdeCommandLogIndex]);
|
||
PSCSI_REQUEST_BLOCK srb = SrbData->CurrentSrb;
|
||
|
||
ASSERT(srb);
|
||
|
||
if (cmdLog == NULL) {
|
||
return;
|
||
}
|
||
|
||
UpdateStartTimeStamp(cmdLog);
|
||
|
||
if (srb->Function == SRB_FUNCTION_ATA_PASS_THROUGH ||
|
||
srb->Function == SRB_FUNCTION_ATA_POWER_PASS_THROUGH) {
|
||
|
||
PATA_PASS_THROUGH ataPassThroughData = srb->DataBuffer;
|
||
cmdLog->Cdb[0]= srb->Function;
|
||
RtlCopyMemory(&(cmdLog->Cdb[1]), &(ataPassThroughData->IdeReg), sizeof(IDEREGS));
|
||
|
||
} else {
|
||
|
||
RtlCopyMemory(&(cmdLog->Cdb), &(srb->Cdb), sizeof(CDB));
|
||
}
|
||
return;
|
||
}
|
||
|
||
VOID
|
||
IdeLogStopCommandLog(
|
||
PSRB_DATA SrbData
|
||
)
|
||
{
|
||
PCOMMAND_LOG cmdLog = &(SrbData->IdeCommandLog[SrbData->IdeCommandLogIndex]);
|
||
PSCSI_REQUEST_BLOCK srb = SrbData->CurrentSrb;
|
||
PSENSE_DATA senseBuffer = NULL;
|
||
ULONG senseInfoBufferLength;
|
||
|
||
ASSERT(srb);
|
||
|
||
if (cmdLog == NULL) {
|
||
return;
|
||
}
|
||
|
||
UpdateStopTimeStamp(cmdLog);
|
||
|
||
if (srb->Cdb[0] == SCSIOP_REQUEST_SENSE) {
|
||
senseBuffer = srb->DataBuffer;
|
||
senseInfoBufferLength = srb->DataTransferLength;
|
||
} else if (srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) {
|
||
senseBuffer = srb->SenseInfoBuffer;
|
||
senseInfoBufferLength = (ULONG) srb->SenseInfoBufferLength;
|
||
}
|
||
|
||
if (senseBuffer && (senseInfoBufferLength > FIELD_OFFSET(SENSE_DATA, AdditionalSenseCodeQualifier))) {
|
||
cmdLog->SenseData[0] = senseBuffer->SenseKey;
|
||
cmdLog->SenseData[1] = senseBuffer->AdditionalSenseCode;
|
||
cmdLog->SenseData[2] = senseBuffer->AdditionalSenseCodeQualifier;
|
||
}else {
|
||
cmdLog->SenseData[0] = 0;
|
||
cmdLog->SenseData[1] = 0;
|
||
cmdLog->SenseData[2] = 0;
|
||
}
|
||
|
||
SrbData->IdeCommandLogIndex = ( SrbData->IdeCommandLogIndex + 1) % MAX_COMMAND_LOG_ENTRIES;
|
||
return;
|
||
}
|
||
|
||
VOID
|
||
IdeLogSaveTaskFile(
|
||
PSRB_DATA SrbData,
|
||
PIDE_REGISTERS_1 BaseIoAddress
|
||
)
|
||
{
|
||
PCOMMAND_LOG cmdLog = &(SrbData->IdeCommandLog[SrbData->IdeCommandLogIndex]);
|
||
|
||
if (cmdLog == NULL) {
|
||
return;
|
||
}
|
||
|
||
AtapiTaskRegisterSnapshot(BaseIoAddress, &(cmdLog->FinalTaskFile));
|
||
return;
|
||
}
|
||
|
||
VOID
|
||
IdeLogBmStatus(
|
||
PSCSI_REQUEST_BLOCK Srb,
|
||
BMSTATUS BmStatus
|
||
)
|
||
{
|
||
PSRB_DATA srbData = IdeGetSrbData(NULL, Srb);
|
||
PCOMMAND_LOG cmdLog;
|
||
|
||
if (srbData == NULL) {
|
||
return;
|
||
}
|
||
|
||
cmdLog = &(srbData->IdeCommandLog[srbData->IdeCommandLogIndex]);
|
||
if (cmdLog == NULL) {
|
||
return;
|
||
}
|
||
|
||
cmdLog->BmStatus = BmStatus;
|
||
return;
|
||
}
|
||
|
||
VOID
|
||
IdeLogFreeCommandLog(
|
||
PSRB_DATA SrbData
|
||
)
|
||
{
|
||
PCOMMAND_LOG cmdLog = SrbData->IdeCommandLog;
|
||
|
||
if (cmdLog) {
|
||
ExFreePool(cmdLog);
|
||
}
|
||
SrbData->IdeCommandLog = NULL;
|
||
SrbData->IdeCommandLogIndex = 0;
|
||
}
|
||
#endif
|
||
|
||
#ifdef ENABLE_ATAPI_VERIFIER
|
||
|
||
PVOID ViIdeExtensionTable[2];
|
||
|
||
#define VFLAGS_FORCE_TIMEOUT (1<<0)
|
||
#define VFLAGS_DMA_TIMEOUT (1<<1)
|
||
#define VFLAGS_CFLUSH_TIMEOUT (1<<2)
|
||
#define VFLAGS_DEVICE_CHANGE (1<<3)
|
||
#define VFLAGS_MISSING_DEVICE (1<<4)
|
||
#define VFLAGS_ACTUAL_ERROR (1<<5)
|
||
#define VFLAGS_CRC_ERROR (1<<6)
|
||
#define VFLAGS_BUSY_ERROR (1<<7)
|
||
#define VFLAGS_RW_ERROR (1<<8)
|
||
|
||
VOID
|
||
ViIdeInitVerifierSettings(
|
||
IN PFDO_EXTENSION FdoExtension
|
||
)
|
||
{
|
||
}
|
||
|
||
BOOLEAN
|
||
ViIdeGenerateDmaTimeout(
|
||
IN PVOID HwDeviceExtension,
|
||
IN BOOLEAN DmaInProgress
|
||
)
|
||
{
|
||
PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
|
||
PFDO_EXTENSION fdoExtension = ((PFDO_EXTENSION)HwDeviceExtension - 1);
|
||
PSCSI_REQUEST_BLOCK srb = hwDeviceExtension->CurrentSrb;
|
||
ULONG ideInternalVerifierFlags ;
|
||
|
||
ASSERT(srb);
|
||
|
||
ideInternalVerifierFlags = fdoExtension->IdeInternalVerifierFlags[srb->TargetId];
|
||
|
||
if (ideInternalVerifierFlags & VFLAGS_FORCE_TIMEOUT) {
|
||
return TRUE;
|
||
}
|
||
|
||
if (DmaInProgress && (ideInternalVerifierFlags & VFLAGS_DMA_TIMEOUT)) {
|
||
return TRUE;
|
||
}
|
||
|
||
if ((srb->Function == SRB_FUNCTION_ATA_PASS_THROUGH) ||
|
||
(srb->Function == SRB_FUNCTION_ATA_POWER_PASS_THROUGH)) {
|
||
|
||
PATA_PASS_THROUGH ataPassThroughData;
|
||
PIDEREGS pIdeReg;
|
||
|
||
ataPassThroughData = srb->DataBuffer;
|
||
pIdeReg = &ataPassThroughData->IdeReg;
|
||
|
||
if ((ideInternalVerifierFlags & VFLAGS_CFLUSH_TIMEOUT) &&
|
||
(pIdeReg->bCommandReg == hwDeviceExtension->DeviceParameters[srb->TargetId].IdeFlushCommand )) {
|
||
return TRUE;
|
||
}
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
ULONG
|
||
ViIdeFakeDeviceChange(
|
||
IN PFDO_EXTENSION FdoExtension,
|
||
ULONG Target
|
||
)
|
||
{
|
||
ULONG ideInternalVerifierFlags = FdoExtension->IdeDebugVerifierFlags[Target];
|
||
|
||
if (ideInternalVerifierFlags & VFLAGS_DEVICE_CHANGE) {
|
||
return 1;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
BOOLEAN
|
||
ViIdeFakeMissingDevice(
|
||
IN PFDO_EXTENSION FdoExtension,
|
||
ULONG Target
|
||
)
|
||
{
|
||
ULONG ideInternalVerifierFlags = FdoExtension->IdeDebugVerifierFlags[Target];
|
||
|
||
if (ideInternalVerifierFlags & VFLAGS_MISSING_DEVICE) {
|
||
return TRUE;
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
VOID
|
||
ViAtapiInterrupt(
|
||
IN PFDO_EXTENSION FdoExtension
|
||
)
|
||
{
|
||
PHW_DEVICE_EXTENSION hwDeviceExtension = FdoExtension->HwDeviceExtension;
|
||
PIDE_REGISTERS_1 baseIoAddress = &(hwDeviceExtension->BaseIoAddress1);
|
||
PSCSI_REQUEST_BLOCK srb = hwDeviceExtension->CurrentSrb;
|
||
ULONG target;
|
||
|
||
//DebugPrint((0, "verifier interrupt fdoe = %x, b=%x\n", FdoExtension, baseIoAddress->RegistersBaseAddress));
|
||
|
||
if ((ULONG)(baseIoAddress->RegistersBaseAddress) == 0x1f0) {
|
||
ViIdeExtensionTable[0]=FdoExtension;
|
||
} else {
|
||
ViIdeExtensionTable[1]=FdoExtension;
|
||
}
|
||
|
||
if (srb == NULL) {
|
||
return ;
|
||
}
|
||
|
||
target = srb->TargetId;
|
||
|
||
//
|
||
// Generate timeouts
|
||
//
|
||
if (FdoExtension->IdeDebugVerifierFlags[target] & VFLAGS_DMA_TIMEOUT) {
|
||
FdoExtension->IdeInternalVerifierFlags[target] |= VFLAGS_DMA_TIMEOUT;
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Generate CRC errors
|
||
//
|
||
if (FdoExtension->IdeDebugVerifierFlags[target] & VFLAGS_CRC_ERROR) {
|
||
if (FdoExtension->IdeVerifierEventCount[target][CrcEvent] >= FdoExtension->IdeVerifierEventFrequency[target][CrcEvent]) {
|
||
FdoExtension->IdeInternalVerifierFlags[target] |= VFLAGS_CRC_ERROR;
|
||
FdoExtension->IdeVerifierEventCount[target][CrcEvent]=0;
|
||
return;
|
||
} else {
|
||
FdoExtension->IdeVerifierEventCount[target][RwEvent]++;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Generate Busy errors
|
||
//
|
||
if (FdoExtension->IdeDebugVerifierFlags[target] & VFLAGS_BUSY_ERROR) {
|
||
if (FdoExtension->IdeVerifierEventCount[target][BusyEvent] >= FdoExtension->IdeVerifierEventFrequency[target][BusyEvent]) {
|
||
FdoExtension->IdeInternalVerifierFlags[target] |= VFLAGS_BUSY_ERROR;
|
||
FdoExtension->IdeVerifierEventCount[target][BusyEvent]=0;
|
||
return;
|
||
} else {
|
||
FdoExtension->IdeVerifierEventCount[target][BusyEvent]++;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Generate Read write errors
|
||
//
|
||
if (FdoExtension->IdeDebugVerifierFlags[target] & VFLAGS_RW_ERROR) {
|
||
if (FdoExtension->IdeVerifierEventCount[target][RwEvent] >= FdoExtension->IdeVerifierEventFrequency[target][RwEvent]) {
|
||
FdoExtension->IdeInternalVerifierFlags[target] |= VFLAGS_RW_ERROR;
|
||
FdoExtension->IdeVerifierEventCount[target][RwEvent]=0;
|
||
return;
|
||
} else {
|
||
FdoExtension->IdeVerifierEventCount[target][RwEvent]++;
|
||
}
|
||
}
|
||
// ViIdeGenerateReadWriteErrors(FdoExtension);
|
||
|
||
// ViIdeGenerateDmaErrors(FdoExtension);
|
||
// ViIdeFakeHungController(FdoExtension);
|
||
return ;
|
||
}
|
||
|
||
UCHAR
|
||
ViIdeGetBaseStatus(
|
||
PIDE_REGISTERS_1 BaseIoAddress
|
||
)
|
||
{
|
||
UCHAR status = IdePortInPortByte((BaseIoAddress)->Command);
|
||
/*
|
||
UCHAR deviceSelect = IdePortInPortByte(BaseIoAddress->DriveSelect);
|
||
UCHAR channel = ((ULONG)(BaseIoAddress->RegistersBaseAddress) == 0x1f0) ? 0: 1;
|
||
PFDO_EXTENSION fdoExtension = ViIdeExtensionTable[channel];
|
||
ULONG target = (deviceSelect == 0xA0)? 0: 1;
|
||
ULONG ideInternalVerifierFlags;
|
||
ULONG dFlags;
|
||
|
||
if (fdoExtension == NULL) {
|
||
return status;
|
||
}
|
||
|
||
ideInternalVerifierFlags = fdoExtension->IdeInternalVerifierFlags[target];
|
||
dFlags = fdoExtension->HwDeviceExtension->DeviceFlags[target];
|
||
|
||
if (status & IDE_STATUS_ERROR) {
|
||
SETMASK(fdoExtension->IdeInternalVerifierFlags[target], VFLAGS_ACTUAL_ERROR);
|
||
return status;
|
||
}
|
||
|
||
if (ideInternalVerifierFlags & VFLAGS_CRC_ERROR) {
|
||
return IDE_STATUS_ERROR;
|
||
}
|
||
|
||
if (ideInternalVerifierFlags & VFLAGS_BUSY_ERROR) {
|
||
return IDE_STATUS_BUSY;
|
||
}
|
||
|
||
if (ideInternalVerifierFlags & VFLAGS_RW_ERROR) {
|
||
return IDE_STATUS_ERROR;
|
||
}
|
||
*/
|
||
return status;
|
||
}
|
||
|
||
UCHAR
|
||
ViIdeGetErrorByte(
|
||
PIDE_REGISTERS_1 BaseIoAddress
|
||
)
|
||
/**++
|
||
Description:
|
||
Depending on the internalVerifier flag (set by the other verifier routines),
|
||
this function will return the appropriate error value. However, if the device
|
||
reports an actual error (as indicated by the internalverifier flag),
|
||
it is returned unchanged.
|
||
|
||
Arguments:
|
||
BaseIoAddress : Task file registers
|
||
|
||
Return Value:
|
||
The error byte.
|
||
--**/
|
||
{
|
||
UCHAR error = IdePortInPortByte(BaseIoAddress->Error);
|
||
/*
|
||
UCHAR deviceSelect = IdePortInPortByte(BaseIoAddress->DriveSelect);
|
||
UCHAR channel = ((ULONG)(BaseIoAddress->RegistersBaseAddress) == 0x1f0) ? 0: 1;
|
||
PFDO_EXTENSION fdoExtension = ViIdeExtensionTable[channel];
|
||
ULONG target = (deviceSelect == 0xA0)? 0: 1;
|
||
ULONG ideInternalVerifierFlags;
|
||
ULONG dFlags;
|
||
|
||
if (fdoExtension == NULL ) {
|
||
return error;
|
||
}
|
||
|
||
ideInternalVerifierFlags = fdoExtension->IdeInternalVerifierFlags[target];
|
||
dFlags = fdoExtension->HwDeviceExtension->DeviceFlags[target];
|
||
|
||
//
|
||
// return error if an actual error was reproted
|
||
//
|
||
if (ideInternalVerifierFlags & VFLAGS_ACTUAL_ERROR) {
|
||
CLRMASK(fdoExtension->IdeInternalVerifierFlags[target], VFLAGS_ACTUAL_ERROR);
|
||
return error;
|
||
}
|
||
|
||
if (ideInternalVerifierFlags & VFLAGS_CRC_ERROR) {
|
||
|
||
if (dFlags & DFLAGS_ATAPI_DEVICE) {
|
||
error = SCSI_SENSE_HARDWARE_ERROR << 4;
|
||
} else {
|
||
error = IDE_ERROR_CRC_ERROR | IDE_ERROR_COMMAND_ABORTED;
|
||
}
|
||
return error;
|
||
}
|
||
*/
|
||
return error;
|
||
}
|
||
|
||
#endif
|
||
|
||
#ifdef IDE_MEASURE_BUSSCAN_SPEED
|
||
VOID
|
||
LogBusScanStartTimer(
|
||
PLARGE_INTEGER TickCount
|
||
)
|
||
{
|
||
KeQueryTickCount(TickCount);
|
||
return;
|
||
}
|
||
|
||
ULONG
|
||
LogBusScanStopTimer(
|
||
PLARGE_INTEGER TickCount
|
||
)
|
||
{
|
||
LARGE_INTEGER tickCount2;
|
||
LARGE_INTEGER numMs;
|
||
KeQueryTickCount(&tickCount2);
|
||
numMs.QuadPart = ((tickCount2.QuadPart - TickCount->QuadPart) * KeQueryTimeIncrement()) / (10 * 1000);
|
||
|
||
return(numMs.u.LowPart);
|
||
}
|
||
|
||
#endif
|
||
|
||
VOID
|
||
FASTCALL
|
||
IdePortLogNoMemoryErrorFn(
|
||
IN PVOID DeviceExtension,
|
||
IN ULONG TargetId,
|
||
IN POOL_TYPE PoolType,
|
||
IN SIZE_T Size,
|
||
IN ULONG FailureLocationId,
|
||
IN ULONG Tag
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine writes a message to the event log indicating that an
|
||
allocation failure has occurred.
|
||
|
||
Arguments:
|
||
|
||
DeviceExtension - Fdo Extension
|
||
|
||
TargetId - The target Id of the device that the request was to be sent to
|
||
|
||
PoolType - identifies the pool the failed allocation attempt was from.
|
||
|
||
Size - indicates the number of bytes that the failed allocation
|
||
attempt tried to obtain.
|
||
|
||
Tag - identifies the pool tag associated with the failed
|
||
allocation.
|
||
|
||
LocationId - identifies the location in the source code where it failed
|
||
|
||
Return Value:
|
||
|
||
VOID
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status;
|
||
PFDO_EXTENSION deviceExtension = (PFDO_EXTENSION) (DeviceExtension);
|
||
PIO_ERROR_LOG_PACKET errorLogEntry;
|
||
PIO_ERROR_LOG_PACKET currentValue;
|
||
|
||
InterlockedIncrement(&deviceExtension->NumMemoryFailure);
|
||
|
||
//
|
||
// Try to allocate a new error log event.
|
||
//
|
||
errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
|
||
deviceExtension->DeviceObject,
|
||
ALLOC_FAILURE_LOGSIZE
|
||
);
|
||
|
||
|
||
//
|
||
// If we could not allocate a log event, we check the device extension to
|
||
// see if it has a reserve event we can use. If we cannot get the device
|
||
// extension or if it does not contain a reserve event, we return
|
||
// without logging the allocation failure.
|
||
//
|
||
|
||
if (errorLogEntry == NULL) {
|
||
|
||
//
|
||
// Get the reserve event in the device extension. The reserve event
|
||
// may have already been used, so it's possible that it is NULL. If
|
||
// this is the case, we give up and return.
|
||
//
|
||
errorLogEntry = (PIO_ERROR_LOG_PACKET)
|
||
deviceExtension->ReserveAllocFailureLogEntry[TargetId];
|
||
|
||
|
||
if (errorLogEntry == NULL) {
|
||
DebugPrint((1, "IdePortLogAllocationFailureFn: no reserve packet\n"));
|
||
return;
|
||
}
|
||
|
||
//
|
||
// We have to ensure that we are the only instance to use this
|
||
// event. To do so, we attempt to NULL the event in the driver
|
||
// extension. If somebody else beats us to it, they own the
|
||
// event and we have to give up.
|
||
//
|
||
|
||
currentValue = InterlockedCompareExchangePointer(
|
||
&(deviceExtension->ReserveAllocFailureLogEntry[TargetId]),
|
||
NULL,
|
||
errorLogEntry
|
||
);
|
||
|
||
if (errorLogEntry != currentValue) {
|
||
DebugPrint((1, "IdePortLogAllocationFailureFn: someone already owns packet\n"));
|
||
return;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Log the error
|
||
//
|
||
errorLogEntry->ErrorCode = IO_WARNING_ALLOCATION_FAILED;
|
||
errorLogEntry->SequenceNumber = 0;
|
||
errorLogEntry->MajorFunctionCode = 0;
|
||
errorLogEntry->RetryCount = 0;
|
||
errorLogEntry->UniqueErrorValue = 0x10;
|
||
errorLogEntry->FinalStatus = STATUS_INSUFFICIENT_RESOURCES;
|
||
errorLogEntry->DumpDataSize = 4 * sizeof(ULONG);
|
||
errorLogEntry->DumpData[0] = TargetId;
|
||
errorLogEntry->DumpData[1] = FailureLocationId;
|
||
errorLogEntry->DumpData[2] = PtrToUlong((PVOID)Size);
|
||
errorLogEntry->DumpData[3] = Tag;
|
||
IoWriteErrorLogEntry(errorLogEntry);
|
||
}
|