/*++ 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; iIdeCommandLog == 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); }