/*++
-Copyright (c) 2002-2014 Alexandr A. Telyatnikov (Alter)
+Copyright (c) 2002-2018 Alexandr A. Telyatnikov (Alter)
Module Name:
id_ata.cpp
Abstract:
- This is the miniport driver for ATA/ATAPI IDE controllers
+ This is the miniport driver for ATA/ATAPI IDE/SATA/AHCI controllers
with Busmaster DMA and Serial ATA support
Author:
7. XP support (binary compatibility)
8. Serial ATA (SATA/SATA2/SATA3) support
9. NT 3.51 support (binary compatibility)
+ 10. AHCI support
etc. (See todo.txt)
+Licence:
+ GPLv2
--*/
#endif //UNIATA_CORE
-UCHAR AtaCommands48[256];
-UCHAR AtaCommandFlags[256];
+//UCHAR AtaCommands48[256];
+//UCHAR AtaCommandFlags[256];
ULONG SkipRaids = 1;
ULONG ForceSimplex = 0;
ULONG g_WaitBusyInISR = 1;
+ULONG g_opt_WaitBusyResetCount = 10000; // 20000
ULONG g_opt_WaitBusyCount = 200; // 20000
ULONG g_opt_WaitBusyDelay = 10; // 150
ULONG g_opt_WaitDrqDelay = 10; // 100
ULONG g_opt_WaitBusyLongCount = 2000; // 2000
ULONG g_opt_WaitBusyLongDelay = 250; // 250
-ULONG g_opt_MaxIsrWait = 40; //
+ULONG g_opt_MaxIsrWait = 40;
+
+ULONG g_opt_DriveSelectNanoDelay = 0; // 400; // ns
+
BOOLEAN g_opt_AtapiSendDisableIntr = 0; // 0
BOOLEAN g_opt_AtapiDmaRawRead = 1; // 0
+BOOLEAN g_opt_AtapiNoDma = FALSE;
+BOOLEAN g_opt_BochsDmaReadWorkaround = FALSE;
BOOLEAN hasPCI = FALSE;
ULONG g_opt_VirtualMachine = 0; // Auto
BOOLEAN InDriverEntry = TRUE;
+BOOLEAN g_Dump = FALSE;
BOOLEAN g_opt_Verbose = 0;
BOOLEAN WinVer_WDM_Model = FALSE;
+ULONG CPU_num = 1;
//UCHAR EnableDma = FALSE;
//UCHAR EnableReorder = FALSE;
return; \
} \
if(res->Proc) { \
- } else \
+ KdPrint(("PROC io write request @ ch %x, res* %x\n", chan, _port)); \
+ ASSERT(FALSE); /* We should never get here */ \
+ } \
if(!res->MemIo) { \
- ScsiPortWritePort##_Type((_type*)(res->Addr), data); \
+ ScsiPortWritePort##_Type((_type*)(ULONGIO_PTR)(res->Addr), data); \
} else { \
/*KdPrint(("r_mem @ (%x) %x\n", _port, port));*/ \
- ScsiPortWriteRegister##_Type((_type*)(res->Addr), data); \
+ ScsiPortWriteRegister##_Type((_type*)(ULONG_PTR)(res->Addr), data); \
} \
return; \
}
return; \
} \
if(res->Proc) { \
- } else \
+ KdPrint(("PROC io write request @ ch %x, res* %x, offs %x\n", chan, _port, offs)); \
+ ASSERT(FALSE); /* We should never get here */ \
+ } \
if(!res->MemIo) { \
- ScsiPortWritePort##_Type((_type*)(res->Addr+offs), data); \
+ ScsiPortWritePort##_Type((_type*)(ULONGIO_PTR)(res->Addr+offs), data); \
} else { \
/*KdPrint(("r_mem @ (%x) %x\n", _port, port));*/ \
- ScsiPortWriteRegister##_Type((_type*)(res->Addr+offs), data); \
+ ScsiPortWriteRegister##_Type((_type*)(ULONG_PTR)(res->Addr+offs), data); \
} \
return; \
}
return (_type)(-1); \
} \
if(res->Proc) { \
- return 0; \
- } else \
+ KdPrint(("PROC io read request @ ch %x, res* %x\n", chan, _port)); \
+ ASSERT(FALSE); /* We should never get here */ \
+ } \
if(!res->MemIo) { \
/*KdPrint(("r_io @ (%x) %x\n", _port, res->Addr));*/ \
- return ScsiPortReadPort##_Type((_type*)(res->Addr)); \
+ return ScsiPortReadPort##_Type((_type*)(ULONGIO_PTR)(res->Addr)); \
} else { \
/*KdPrint(("r_mem @ (%x) %x\n", _port, res->Addr));*/ \
- return ScsiPortReadRegister##_Type((_type*)(res->Addr)); \
+ return ScsiPortReadRegister##_Type((_type*)(ULONG_PTR)(res->Addr)); \
} \
}
return (_type)(-1); \
} \
if(res->Proc) { \
- return 0; \
- } else \
+ KdPrint(("PROC io read request @ ch %x, res* %x, offs %x\n", chan, _port, offs)); \
+ ASSERT(FALSE); /* We should never get here */ \
+ } \
if(!res->MemIo) { \
- return ScsiPortReadPort##_Type((_type*)(res->Addr+offs)); \
+ return ScsiPortReadPort##_Type((_type*)(ULONGIO_PTR)(res->Addr+offs)); \
} else { \
/*KdPrint(("r_mem @ (%x) %x\n", _port, port));*/ \
- return ScsiPortReadRegister##_Type((_type*)(res->Addr+offs)); \
+ return ScsiPortReadRegister##_Type((_type*)(ULONG_PTR)(res->Addr+offs)); \
} \
}
} \
if(!res->MemIo) { \
/*KdPrint(("r_io @ (%x) %x\n", _port, res->Addr));*/ \
- ScsiPortReadPortBuffer##_Type((_type*)(res->Addr), (_type*)Buffer, Count); \
+ ScsiPortReadPortBuffer##_Type((_type*)(ULONGIO_PTR)(res->Addr), (_type*)Buffer, Count); \
return; \
} \
while(Count) { \
- (*((_type*)Buffer)) = ScsiPortReadRegister##_Type((_type*)(res->Addr)); \
+ (*((_type*)Buffer)) = ScsiPortReadRegister##_Type((_type*)(ULONG_PTR)(res->Addr)); \
Count--; \
Buffer = ((_type*)Buffer)+1; \
} \
} \
if(!res->MemIo) { \
/*KdPrint(("r_io @ (%x) %x\n", _port, res->Addr));*/ \
- ScsiPortWritePortBuffer##_Type((_type*)(res->Addr), (_type*)Buffer, Count); \
+ ScsiPortWritePortBuffer##_Type((_type*)(ULONGIO_PTR)(res->Addr), (_type*)Buffer, Count); \
return; \
} \
while(Count) { \
- ScsiPortWriteRegister##_Type((_type*)(res->Addr), *((_type*)Buffer)); \
+ ScsiPortWriteRegister##_Type((_type*)(ULONG_PTR)(res->Addr), *((_type*)Buffer)); \
Count--; \
Buffer = ((_type*)Buffer)+1; \
} \
if (statusByte & IDE_STATUS_DRQ) {
// Suck out any remaining bytes and throw away.
AtapiReadPort2(chan, IDX_IO1_i_Data);
+ UniataNanoSleep(PIO0_TIMING);
} else {
break;
}
return statusByte;
} // AtapiSuckPort2()
+ULONG
+DDKFASTAPI
+AtapiSuckPortBuffer2(
+ IN PHW_CHANNEL chan,
+ IN PUSHORT Buffer,
+ IN ULONG Count
+ )
+{
+ UCHAR statusByte;
+ ULONG i;
+ USHORT data;
+ BOOLEAN retry = FALSE;
+
+ // Assume, proper drive is already seleted
+ WaitOnBusyLong(chan);
+ for (i = 0; i < Count; i++) {
+
+ GetStatus(chan, statusByte);
+ if (statusByte & IDE_STATUS_DRQ) {
+ // Suck out any remaining bytes and throw away.
+ data = AtapiReadPort2(chan, IDX_IO1_i_Data);
+ (*Buffer) = data;
+ Count--;
+ Buffer++;
+ UniataNanoSleep(PIO0_TIMING);
+ retry = FALSE;
+ } else {
+ if(i<Count && !retry) {
+ KdPrint2((PRINT_PREFIX " wait...\n"));
+ WaitForDrq(chan);
+ retry = TRUE;
+ }
+ break;
+ }
+ }
+ if(i) {
+ KdPrint2((PRINT_PREFIX "AtapiSuckPortBuffer2: %#x words\n", i ));
+ if(i==Count) {
+ AtapiSuckPort2(chan);
+ }
+ }
+ return i;
+} // AtapiSuckPortBuffer2()
+
+UCHAR
+DDKFASTAPI
+SelectDrive(
+ IN PHW_CHANNEL chan,
+ IN ULONG DeviceNumber
+ )
+{
+ if(!chan) {
+ return 0;
+ }
+/*
+ if(chan->lun[DeviceNumber] &&
+ (chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_ATAPI_CHANGER)) {
+ KdPrint3((" Select %d\n", DeviceNumber));
+ }
+*/
+ if(chan->last_devsel == DeviceNumber) {
+ //KdPrint3((" Selected %d\n", DeviceNumber));
+ return 1;
+ }
+ AtapiWritePort1(chan, IDX_IO1_o_DriveSelect, DeviceNumber ? IDE_DRIVE_SELECT_2 : IDE_DRIVE_SELECT_1); \
+ chan->last_devsel = DeviceNumber ? 1 : 0;
+ if(!g_opt_DriveSelectNanoDelay) {
+ //KdPrint3((" Select %d\n", DeviceNumber));
+ return 2;
+ }
+ //KdPrint3((" Select %d (%d ns)\n", DeviceNumber, g_opt_DriveSelectNanoDelay));
+ UniataNanoSleep(g_opt_DriveSelectNanoDelay);
+ return 2;
+} // end SelectDrive()
+
UCHAR
DDKFASTAPI
WaitOnBusy(
DDKFASTAPI
AtapiSoftReset(
IN PHW_CHANNEL chan,
- ULONG DeviceNumber
+ IN ULONG DeviceNumber
)
{
//ULONG c = chan->lChannel;
ULONG i = 30 * 1000;
UCHAR dma_status = 0;
KdPrint2((PRINT_PREFIX "AtapiSoftReset:\n"));
- UCHAR statusByte2;
+ UCHAR statusByte0, statusByte2;
if(chan->DeviceExtension->HwFlags & UNIATA_AHCI) {
UniataAhciSoftReset(chan->DeviceExtension, chan->lChannel, DeviceNumber);
SelectDrive(chan, DeviceNumber);
if(chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_MANUAL_CHS) {
// For ESDI/MFM
+ KdPrint2((PRINT_PREFIX " ESDI/MFM\n"));
AtapiStallExecution(10000);
for (i = 0; i < 1000; i++) {
AtapiStallExecution(999);
}
+/* } else
+ // Seems to be unnecessary, verified by KtP
+ if(!hasPCI) {
+ // original atapi.sys behavior for old ISA-only hardware
+ AtapiStallExecution(10000);
+ AtapiWritePort1(chan, IDX_IO1_o_Command, IDE_COMMAND_ATAPI_RESET);
+ for (i = 0; i < 1000; i++) {
+ AtapiStallExecution(999);
+ } */
} else {
AtapiStallExecution(500);
GetBaseStatus(chan, statusByte2);
+ statusByte0 = statusByte2;
AtapiWritePort1(chan, IDX_IO1_o_Command, IDE_COMMAND_ATAPI_RESET);
// Do not wait for BUSY assertion if it was initially set, jump to
// BUSY release wait loop
- if(!(statusByte2 & IDE_STATUS_BUSY)) {
+ if(!(statusByte0 & IDE_STATUS_BUSY)) {
// Wait for BUSY assertion, in some cases delay may occure
// 100ms should be enough
- i = 10*1000;
- while (!(AtapiReadPort1(chan, IDX_IO1_i_Status) & IDE_STATUS_BUSY) &&
+ if(g_opt_VirtualMachine == VM_BOCHS) {
+ i = 100;
+ } else {
+ i = 10*1000;
+ }
+ statusByte2 = AtapiReadPort1(chan, IDX_IO1_i_Status);
+ while (!(statusByte2 & IDE_STATUS_BUSY) &&
i--)
{
+ if(!(statusByte0 & IDE_STATUS_ERROR) && (statusByte2 & IDE_STATUS_ERROR)) {
+ KdPrint2((PRINT_PREFIX " Command aborted, statusByte2 %x:\n", statusByte2));
+ break;
+ }
AtapiStallExecution(10);
}
}
{
AtapiStallExecution(30);
}
+ KdPrint2((PRINT_PREFIX " set DFLAGS_REINIT_DMA\n"));
+ chan->lun[DeviceNumber]->DeviceFlags |= DFLAGS_REINIT_DMA;
}
+ chan->last_devsel = -1; // make sure proper drive would be selected
SelectDrive(chan, DeviceNumber);
WaitOnBusy(chan);
GetBaseStatus(chan, statusByte2);
} // end AtapiSoftReset()
+VOID
+DDKFASTAPI
+AtapiHardReset(
+ IN struct _HW_CHANNEL* chan,
+ IN BOOLEAN DisableInterrupts,
+ IN ULONG Delay
+ )
+{
+ KdPrint2((PRINT_PREFIX "AtapiHardReset: %d, dis=%d\n", Delay, DisableInterrupts));
+ AtapiWritePort1(chan, IDX_IO2_o_Control, IDE_DC_RESET_CONTROLLER |
+ (DisableInterrupts ? IDE_DC_DISABLE_INTERRUPTS : 0));
+ chan->last_devsel = -1;
+ AtapiStallExecution(Delay);
+ AtapiWritePort1(chan, IDX_IO2_o_Control, IDE_DC_REENABLE_CONTROLLER);
+} // end AtapiHardReset()
+
/*
Send command to device.
Translate to 48-Lba form if required
AtapiStallExecution(100);
continue;
} else
- if(statusByte == IDE_STATUS_IDLE) {
+ if((statusByte & ~IDE_STATUS_INDEX) == IDE_STATUS_IDLE) {
break;
} else {
//if(deviceExtension->HwFlags & UNIATA_SATA) {
}
KdPrint2((PRINT_PREFIX " try to continue\n"));
statusByte &= ~IDE_STATUS_ERROR;
+
+ } else {
+ //KdPrint2((PRINT_PREFIX " send Status %#x\n", statusByte));
}
UniataExpectChannelInterrupt(chan, TRUE);
// !!!!!
InterlockedExchange(&(chan->CheckIntr),
CHECK_INTR_IDLE);
- statusByte = 0;
+
+ statusByte = IDE_STATUS_SUCCESS;
break;
}
- KdPrint2((PRINT_PREFIX " Status %#x\n", statusByte));
+ //KdPrint2((PRINT_PREFIX " Status %#x\n", statusByte));
return statusByte;
} // end AtaCommand48()
/*
Wrapper for ScsiPort, that implements smart Dpc
queueing. We need it to allow parallel functioning
- of IDE channles with shared interrupt. Standard Dpc mechanism
+ of IDE channels with shared interrupt. Standard Dpc mechanism
cancels previous Dpc request (if any), but we need Dpc queue.
*/
VOID
#endif //UNIATA_CORE
-#if DBG
+#ifdef _DEBUG
VOID
NTAPI
UniataDumpATARegs(
chan->RegTranslation[IDX_IO1+j].Addr,
statusByteAlt));
}
+ if(!chan->RegTranslation[IDX_BM_IO].Addr) {
+ return;
+ }
for(j=0; j<IDX_BM_IO_SZ-1; j++) {
statusByteAlt = AtapiReadPort1(chan, IDX_BM_IO+j);
KdPrint2((PRINT_PREFIX
}
return;
} // end UniataDumpATARegs()
-#endif
+#endif //_DEBUG
VOID
NTAPI
if(use_ahci) {
statusByte = WaitOnBusyLong(chan);
-#if DBG
+#ifdef _DEBUG
if(!chan->AhciInternalAtaReq) {
KdPrint2((PRINT_PREFIX "!AhciInternalAtaReq\n"));
}
statusByte = WaitOnBusyLong(chan);
// Check that the status register makes sense.
GetBaseStatus(chan, statusByte);
+ /*
+ // unnecessary
+ if(!hasPCI) {
+ // original atapi.sys behavior for old ISA-only hardware
+ AtapiStallExecution(100);
+ }
+ */
}
if (Command == IDE_COMMAND_IDENTIFY) {
statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel, Command, (j < 4) ? DEV_BSIZE : 0 /* cyl */, 0, 0, 0, 0, ATA_WAIT_INTR);
// Clear interrupt
+ if (!statusByte) {
+ KdPrint2((PRINT_PREFIX "IssueIdentify: 0-status, not present\n"));
+ return FALSE;
+ } else
if (statusByte & IDE_STATUS_DRQ) {
// Read status to acknowledge any interrupts generated.
KdPrint2((PRINT_PREFIX "IssueIdentify: IDE_STATUS_DRQ (%#x)\n", statusByte));
GetBaseStatus(chan, statusByte);
KdPrint2((PRINT_PREFIX "IssueIdentify: BASE statusByte %#x\n", statusByte));
+#ifdef _DEBUG
+ if(atapiDev) {
+ j = (AtapiReadPort1(chan, IDX_ATAPI_IO1_i_InterruptReason) & ATAPI_IR_Mask);
+ KdPrint3((PRINT_PREFIX "IssueIdentify: iReason %x\n", j));
+
+ j =
+ AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountLow);
+
+ j |=
+ (USHORT)AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountHigh) << 8;
+ KdPrint3((PRINT_PREFIX "IssueIdentify: wCount %x\n", j));
+
+ }
+#endif //_DEBUG
+
if (atapiDev || !(LunExt->DeviceFlags & DFLAGS_DWORDIO_ENABLED) /*!deviceExtension->DWordIO*/) {
KdPrint2((PRINT_PREFIX " use 16bit IO\n"));
-
// ATI/SII chipsets with memory-mapped IO hangs when
// I call ReadBuffer(), probably due to PCI burst/prefetch enabled
// Unfortunately, I don't know yet how to workaround it except
KdPrint2((PRINT_PREFIX "Model: %20.20s\n", deviceExtension->FullIdentifyData.ModelNumber));
KdPrint2((PRINT_PREFIX "FW: %4.4s\n", deviceExtension->FullIdentifyData.FirmwareRevision));
KdPrint2((PRINT_PREFIX "S/N: %20.20s\n", deviceExtension->FullIdentifyData.SerialNumber));
+ if(g_opt_VirtualMachine == VM_AUTO) {
+ if((deviceExtension->FullIdentifyData.FirmwareRevision[0] == 0 ||
+ deviceExtension->FullIdentifyData.FirmwareRevision[0] == ' ') &&
+ (deviceExtension->FullIdentifyData.FirmwareRevision[1] == 0 ||
+ deviceExtension->FullIdentifyData.FirmwareRevision[1] == ' ')) {
+ // Check for BOCHS VM signature. If no additional PCI devices (e.g. VGA)
+ // are declared BOCHS looks like regular PC
+ if (!atapiDev && !AtapiStringCmp ((PCCHAR)(deviceExtension->FullIdentifyData.SerialNumber), "XBDH00", 6)) {
+ KdPrint2((PRINT_PREFIX "IssueIdentify: BOCHS HDD\n"));
+ g_opt_VirtualMachine = VM_BOCHS;
+ } else
+ if (atapiDev && !AtapiStringCmp ((PCCHAR)(deviceExtension->FullIdentifyData.SerialNumber), "XBDC00", 6)) {
+ KdPrint2((PRINT_PREFIX "IssueIdentify: BOCHS CD\n"));
+ g_opt_VirtualMachine = VM_BOCHS;
+ }
+ }
+ }
+
KdPrint2((PRINT_PREFIX "Pio: %x\n", deviceExtension->FullIdentifyData.PioCycleTimingMode));
if(deviceExtension->FullIdentifyData.PioTimingsValid) {
KdPrint2((PRINT_PREFIX "APio: %x\n", deviceExtension->FullIdentifyData.AdvancedPIOModes));
deviceExtension->FullIdentifyData.VendorAcoustic,
deviceExtension->FullIdentifyData.CurrentAcoustic
));
- KdPrint2((PRINT_PREFIX "AdvPowerMode %d, cur %d\n",
+ KdPrint2((PRINT_PREFIX "AdvPowerMode %d\n",
deviceExtension->FullIdentifyData.CfAdvPowerMode
));
+ KdPrint2((PRINT_PREFIX "PowerMngt %d/%d, APM %d/%d\n",
+ deviceExtension->FullIdentifyData.FeaturesEnabled.PowerMngt,
+ deviceExtension->FullIdentifyData.FeaturesSupport.PowerMngt,
+ deviceExtension->FullIdentifyData.FeaturesEnabled.APM,
+ deviceExtension->FullIdentifyData.FeaturesSupport.APM
+ ));
+
// Check out a few capabilities / limitations of the device.
if (deviceExtension->FullIdentifyData.RemovableStatus & 1) {
// Determine if this drive supports the MSN functions.
ULONGLONG NativeNumOfSectors=0;
ULONGLONG cylinders=0;
ULONGLONG tmp_cylinders=0;
+
+ KdPrint2((PRINT_PREFIX "PhysLogSectorSize %#x, %#x, offset %#x\n",
+ deviceExtension->FullIdentifyData.PhysLogSectorSize,
+ deviceExtension->FullIdentifyData.LargeSectorSize,
+ deviceExtension->FullIdentifyData.LogicalSectorOffset
+ ));
+
+ KdPrint2((PRINT_PREFIX "NV PM_Sup %d, PM_En %d, En %d, PM ver %#x ver %#x\n",
+ deviceExtension->FullIdentifyData.NVCache_PM_Supported,
+ deviceExtension->FullIdentifyData.NVCache_PM_Enabled,
+ deviceExtension->FullIdentifyData.NVCache_Enabled,
+ deviceExtension->FullIdentifyData.NVCache_PM_Version,
+ deviceExtension->FullIdentifyData.NVCache_Version
+ ));
+
+ KdPrint2((PRINT_PREFIX "R-rate %d\n",
+ deviceExtension->FullIdentifyData.NominalMediaRotationRate
+ ));
+ KdPrint2((PRINT_PREFIX "WC %d/%d, LA %d/%d, WB %d/%d, RB %d/%d, Q %d/%d\n",
+ deviceExtension->FullIdentifyData.FeaturesEnabled.WriteCache,
+ deviceExtension->FullIdentifyData.FeaturesSupport.WriteCache,
+ deviceExtension->FullIdentifyData.FeaturesEnabled.LookAhead,
+ deviceExtension->FullIdentifyData.FeaturesSupport.LookAhead,
+ deviceExtension->FullIdentifyData.FeaturesEnabled.WriteBuffer,
+ deviceExtension->FullIdentifyData.FeaturesSupport.WriteBuffer,
+ deviceExtension->FullIdentifyData.FeaturesEnabled.ReadBuffer,
+ deviceExtension->FullIdentifyData.FeaturesSupport.ReadBuffer,
+ deviceExtension->FullIdentifyData.FeaturesEnabled.Queued,
+ deviceExtension->FullIdentifyData.FeaturesSupport.Queued
+ ));
+
+ KdPrint2((PRINT_PREFIX "Protected %d/%d status %#x, rev %#x\n",
+ deviceExtension->FullIdentifyData.FeaturesEnabled.Protected,
+ deviceExtension->FullIdentifyData.FeaturesSupport.Protected,
+ deviceExtension->FullIdentifyData.SecurityStatus,
+ deviceExtension->FullIdentifyData.MasterPasswdRevision
+ ));
+
// Read very-old-style drive geometry
KdPrint2((PRINT_PREFIX "CHS %#x:%#x:%#x\n",
deviceExtension->FullIdentifyData.NumberOfCylinders,
// Check for HDDs > 8Gb
if ((deviceExtension->FullIdentifyData.NumberOfCylinders == 0x3fff) &&
/* (deviceExtension->FullIdentifyData.TranslationFieldsValid) &&*/
+ deviceExtension->FullIdentifyData.NumberOfHeads &&
+ deviceExtension->FullIdentifyData.SectorsPerTrack &&
(NumOfSectors < deviceExtension->FullIdentifyData.UserAddressableSectors)) {
KdPrint2((PRINT_PREFIX "NumberOfCylinders == 0x3fff\n"));
cylinders =
}
// Check for LBA mode
KdPrint2((PRINT_PREFIX "SupportLba flag %#x\n", deviceExtension->FullIdentifyData.SupportLba));
+ KdPrint2((PRINT_PREFIX "SupportDMA flag %#x\n", deviceExtension->FullIdentifyData.SupportDma));
+ KdPrint2((PRINT_PREFIX "SoftReset %#x\n", deviceExtension->FullIdentifyData.SoftReset));
+ KdPrint2((PRINT_PREFIX "SupportIordy %#x, DisableIordy %#x\n",
+ deviceExtension->FullIdentifyData.SupportIordy,
+ deviceExtension->FullIdentifyData.DisableIordy
+ ));
KdPrint2((PRINT_PREFIX "MajorRevision %#x\n", deviceExtension->FullIdentifyData.MajorRevision));
KdPrint2((PRINT_PREFIX "UserAddressableSectors %#x\n", deviceExtension->FullIdentifyData.UserAddressableSectors));
if ( deviceExtension->FullIdentifyData.SupportLba
if(LunExt->DeviceFlags & DFLAGS_LBA_ENABLED) {
if(deviceExtension->FullIdentifyData.FeaturesSupport.Address48 &&
deviceExtension->FullIdentifyData.FeaturesEnabled.Address48 &&
+ deviceExtension->FullIdentifyData.NumberOfHeads &&
+ deviceExtension->FullIdentifyData.SectorsPerTrack &&
(deviceExtension->FullIdentifyData.UserAddressableSectors48 > NumOfSectors)
) {
KdPrint2((PRINT_PREFIX "LBA48\n"));
}
}
+ if(NumOfSectors > ATA_MAX_IOLBA28) {
+ KdPrint2((PRINT_PREFIX "2TB threshold, force LBA64 WRITE requirement\n"));
+ LunExt->DeviceFlags |= DFLAGS_LBA32plus;
+ }
} // if(LunExt->DeviceFlags & DFLAGS_LBA_ENABLED)
// fill IdentifyData with bogus geometry
KdPrint2((PRINT_PREFIX "requested LunExt->GeomType=%x\n", LunExt->opt_GeomType));
- tmp_cylinders = NumOfSectors / (deviceExtension->FullIdentifyData.CurrentSectorsPerTrack *
- deviceExtension->FullIdentifyData.NumberOfCurrentHeads);
+ if(deviceExtension->FullIdentifyData.CurrentSectorsPerTrack &&
+ deviceExtension->FullIdentifyData.NumberOfCurrentHeads) {
+ tmp_cylinders = NumOfSectors / (deviceExtension->FullIdentifyData.CurrentSectorsPerTrack *
+ deviceExtension->FullIdentifyData.NumberOfCurrentHeads);
+ } else
+ if(deviceExtension->FullIdentifyData.SectorsPerTrack &&
+ deviceExtension->FullIdentifyData.NumberOfHeads) {
+ KdPrint2((PRINT_PREFIX "Current C/H = %#I64x/%#I64x\n",
+ deviceExtension->FullIdentifyData.CurrentSectorsPerTrack,
+ deviceExtension->FullIdentifyData.NumberOfCurrentHeads));
+ tmp_cylinders = NumOfSectors / (deviceExtension->FullIdentifyData.SectorsPerTrack *
+ deviceExtension->FullIdentifyData.NumberOfHeads);
+ } else {
+ tmp_cylinders = 0;
+ }
KdPrint2((PRINT_PREFIX "tmp_cylinders = %#I64x\n", tmp_cylinders));
if((tmp_cylinders < 0xffff) || (LunExt->opt_GeomType == GEOM_ORIG)) {
// ok, we can keep original values
}
}
+ if(!deviceExtension->FullIdentifyData.SectorsPerTrack ||
+ !deviceExtension->FullIdentifyData.NumberOfHeads) {
+ KdPrint2((PRINT_PREFIX "Zero S/H -> Force Use GEOM_STD\n"));
+ }
+
if(LunExt->opt_GeomType == GEOM_STD) {
deviceExtension->FullIdentifyData.CurrentSectorsPerTrack =
deviceExtension->FullIdentifyData.SectorsPerTrack = 63;
deviceExtension->FullIdentifyData.CurrentSectorsPerTrack
));
- if(NumOfSectors)
+ if(NumOfSectors) {
LunExt->NumOfSectors = NumOfSectors;
-/* if(deviceExtension->FullIdentifyData.MajorRevision &&
+ }
+ if(deviceExtension->FullIdentifyData.MajorRevision &&
deviceExtension->FullIdentifyData.DoubleWordIo) {
LunExt->DeviceFlags |= DFLAGS_DWORDIO_ENABLED;
- }*/
+ KdPrint2((PRINT_PREFIX "IssueIdentify: DWORDIO supported\n"));
+ }
+ } else {
+ // ATAPI
+ if(deviceExtension->FullIdentifyData.MajorRevision &&
+ deviceExtension->FullIdentifyData.DoubleWordIo) {
+ LunExt->DeviceFlags |= DFLAGS_DWORDIO_ENABLED;
+ KdPrint2((PRINT_PREFIX "IssueIdentify: DFLAGS_DWORDIO_ENABLED.\n"));
+ }
+ if(deviceExtension->FullIdentifyData.AtapiDMA.DMADirRequired) {
+ KdPrint2((PRINT_PREFIX "DMADirRequired.\n"));
+ }
+ if(deviceExtension->FullIdentifyData.AtapiByteCount0) {
+ KdPrint2((PRINT_PREFIX "AtapiByteCount0=%x\n", deviceExtension->FullIdentifyData.AtapiByteCount0));
+ }
}
ScsiPortMoveMemory(&LunExt->IdentifyData,
KdPrint2((PRINT_PREFIX "IssueIdentify: ATAPI drive type %#x.\n",
LunExt->IdentifyData.DeviceType));
}
+ KdPrint2((PRINT_PREFIX "IssueIdentify: AtapiCmdSize %#x\n", deviceExtension->FullIdentifyData.AtapiCmdSize));
} else {
KdPrint2((PRINT_PREFIX "IssueIdentify: hard drive.\n"));
}
//ULONG RevID = deviceExtension->RevID;
ULONG ChipFlags = deviceExtension->HwFlags & CHIPFLAG_MASK;
//UCHAR tmp8;
- UCHAR tmp16;
+ USHORT tmp16;
KdPrint2((PRINT_PREFIX "AtapiResetController: Reset IDE %#x/%#x @ %#x\n", VendorID, DeviceID, slotNumber));
- KdPrint2((PRINT_PREFIX "simplexOnly %d\n", deviceExtension->simplexOnly));
+ KdPrint2((PRINT_PREFIX "simplexOnly %d, VM %x\n", deviceExtension->simplexOnly, g_opt_VirtualMachine));
if(!deviceExtension->simplexOnly && (PathId != CHAN_NOT_SPECIFIED)) {
// we shall reset both channels on SimplexOnly devices,
for (; j < numberChannels; j++) {
- KdPrint2((PRINT_PREFIX "AtapiResetController: Reset channel %d\n", j));
+ KdPrint2((PRINT_PREFIX "AtapiResetController: Reset lchannel %d[%d]\n", j, deviceExtension->Channel));
chan = &(deviceExtension->chan[j]);
MaxLuns = chan->NumberLuns;
- KdPrint2((PRINT_PREFIX " CompleteType %#x, Luns %d, chan %#x, sptr %#x\n", CompleteType, MaxLuns, chan, &chan));
+ // Save control flags
+ ChannelCtrlFlags = chan->ChannelCtrlFlags;
+ KdPrint2((PRINT_PREFIX " CompleteType %#x, Luns %d, chan %#x, sptr %#x, flags %#x\n", CompleteType, MaxLuns, chan, &chan, ChannelCtrlFlags));
//MaxLuns = (chan->ChannelCtrlFlags & CTRFLAGS_NO_SLAVE) ? 1 : 2;
if(CompleteType != RESET_COMPLETE_NONE) {
#ifndef UNIATA_CORE
while((CurSrb = UniataGetCurRequest(chan))) {
+ PHW_LU_EXTENSION LunExt;
PATA_REQ AtaReq = (PATA_REQ)(CurSrb->SrbExtension);
+ i = GET_CDEV(CurSrb);
+ KdPrint2((PRINT_PREFIX " Lun %x\n", i));
+ LunExt = chan->lun[i];
+
KdPrint2((PRINT_PREFIX "AtapiResetController: pending SRB %#x, chan %#x\n", CurSrb, chan));
+ if(CurSrb->Cdb[0] == SCSIOP_MECHANISM_STATUS) {
+ KdPrint2((PRINT_PREFIX " was MechStatus\n"));
+
+ if(!(LunExt->DeviceFlags & DFLAGS_CHANGER_INITED)) {
+ LunExt->DeviceFlags |= DFLAGS_CHANGER_INITED;
+ KdPrint2((PRINT_PREFIX " set DFLAGS_CHANGER_INITED\n"));
+ }
+ }
// Check and see if we are processing an internal srb
if (AtaReq->OriginalSrb) {
KdPrint2((PRINT_PREFIX " restore original SRB %#x\n", AtaReq->OriginalSrb));
ASSERT(AtaReq->Srb == CurSrb);
if (CurSrb) {
// Complete outstanding request with SRB_STATUS_BUS_RESET.
- UCHAR PathId = CurSrb->PathId;
+ UCHAR CurPathId = CurSrb->PathId;
UCHAR TargetId = CurSrb->TargetId;
UCHAR Lun = CurSrb->Lun;
if (CurSrb->SenseInfoBuffer) {
PSENSE_DATA senseBuffer = (PSENSE_DATA)CurSrb->SenseInfoBuffer;
- KdPrint2((PRINT_PREFIX " senseBuffer %#x, chan %#x\n", senseBuffer, chan));
+ KdPrint2((PRINT_PREFIX " senseBuffer %#x, chan %#x, ReqFlags %#x\n", senseBuffer, chan, AtaReq->Flags));
senseBuffer->ErrorCode = 0x70;
senseBuffer->Valid = 1;
}
}
+ if(!ATAPI_DEVICE(chan, i) && AtaReq->bcount && AtaReq->retry < MAX_RETRIES) {
+ KdPrint2((PRINT_PREFIX "Save IDE retry status %d\n", AtaReq->retry));
+ LunExt->errLastLba = AtaReq->lba;
+ LunExt->errBCount = AtaReq->bcount;
+ LunExt->errRetry = AtaReq->retry+1;
+ //KdPrint2((PRINT_PREFIX "AtaReq->Flags & REQ_FLAG_RW_MASK = %x (%x)\n", (AtaReq->Flags & REQ_FLAG_RW_MASK), REQ_FLAG_READ));
+ //KdPrint2((PRINT_PREFIX "ChannelCtrlFlags & CTRFLAGS_DMA_OPERATION = %x (%x)\n", ChannelCtrlFlags & CTRFLAGS_DMA_ACTIVE, CTRFLAGS_DMA_OPERATION));
+ //KdPrint2((PRINT_PREFIX "g_opt_VirtualMachine = %x (%x)\n", g_opt_VirtualMachine, VM_BOCHS));
+ if(((AtaReq->Flags & REQ_FLAG_RW_MASK) == REQ_FLAG_READ) &&
+ (ChannelCtrlFlags & CTRFLAGS_DMA_OPERATION) &&
+ (g_opt_VirtualMachine == VM_BOCHS)) {
+ KdPrint2((PRINT_PREFIX "set CTRFLAGS_DMA_BEFORE_R on BOCHS\n"));
+ g_opt_BochsDmaReadWorkaround = TRUE;
+ g_opt_AtapiNoDma = TRUE;
+ } else {
+ KdPrint2((PRINT_PREFIX "do nothing\n"));
+ }
+ } else
+ if(ATAPI_DEVICE(chan, i) && AtaReq->bcount && !AtaReq->retry) {
+ KdPrint2((PRINT_PREFIX "Save ATAPI retry status %d\n", AtaReq->retry));
+ LunExt->errLastLba = AtaReq->lba;
+ LunExt->errBCount = AtaReq->bcount;
+ LunExt->errRetry = AtaReq->retry+1;
+ if(((AtaReq->Flags & REQ_FLAG_RW_MASK) == REQ_FLAG_READ) &&
+ (ChannelCtrlFlags & CTRFLAGS_DMA_OPERATION) &&
+ (g_opt_VirtualMachine == VM_BOCHS)) {
+ KdPrint2((PRINT_PREFIX "set CTRFLAGS_DMA_BEFORE_R on BOCHS ATAPI\n"));
+ //g_opt_BochsDmaReadWorkaround = TRUE;
+ g_opt_AtapiNoDma = TRUE;
+ } else {
+ KdPrint2((PRINT_PREFIX "do nothing\n"));
+ }
+ } else {
+ LunExt->errRetry = 0;
+ }
+
// Clear request tracking fields.
AtaReq->WordsLeft = 0;
AtaReq->DataBuffer = NULL;
// Indicate ready for next request.
ScsiPortNotification(NextLuRequest,
deviceExtension,
- PathId,
+ CurPathId,
TargetId,
Lun);
}
#endif //UNIATA_CORE
} // end if (!CompleteType != RESET_COMPLETE_NONE)
- // Save control flags
- ChannelCtrlFlags = chan->ChannelCtrlFlags;
// Clear expecting interrupt flag.
UniataExpectChannelInterrupt(chan, FALSE);
chan->RDP = FALSE;
- chan->ChannelCtrlFlags = 0;
+ chan->ChannelCtrlFlags = ChannelCtrlFlags & CTRFLAGS_PERMANENT;
InterlockedExchange(&(chan->CheckIntr),
CHECK_INTR_IDLE);
UniataAhciReset(HwDeviceExtension, j);
} else {
KdPrint2((PRINT_PREFIX " skip not implemented\n"));
+ continue;
}
} else {
KdPrint2((PRINT_PREFIX " ATA path, chan %#x\n", chan));
AtapiStallExecution(10000);
}
break; }
- case ATA_SIS_ID:
+ case ATA_SIS_ID: {
+ KdPrint2((PRINT_PREFIX " SIS\n"));
+ if(!(ChipFlags & UNIATA_SATA))
+ goto default_reset;
+ break; }
+#if 0
case ATA_NVIDIA_ID: {
- KdPrint2((PRINT_PREFIX " SIS/nVidia\n"));
+ KdPrint2((PRINT_PREFIX " nVidia\n"));
if(!(ChipFlags & UNIATA_SATA))
goto default_reset;
break; }
+#else
+ case ATA_NVIDIA_ID: {
+ ULONG offs;
+ ULONG Channel = deviceExtension->Channel + j;
+ KdPrint2((PRINT_PREFIX " nVidia\n"));
+ if(!(ChipFlags & UNIATA_SATA)) {
+ goto default_reset;
+ }
+ offs = (ChipFlags & NV4OFF) ? 0x0440 : 0x0010;
+
+ KdPrint2((PRINT_PREFIX " disable Phy intr, offs %#x, c %u\n", offs, Channel));
+ /* disable device and PHY state change interrupts */
+ if(ChipFlags & NVQ) {
+ KdPrint2((PRINT_PREFIX " NVQ, 32bits reg\n"));
+ AtapiWritePortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),offs+4,
+ AtapiReadPortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),offs+4) & ((~(ULONG)0x0000000d) << (!Channel*16)) );
+ } else {
+ AtapiWritePortEx1(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),offs+1,
+ AtapiReadPortEx1(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),offs+1) & ((~(UCHAR)0x0d) << (!Channel*4)) );
+ }
+ tmp16 = UniataSataPhyEnable(HwDeviceExtension, j, 0/* dev0*/, UNIATA_SATA_RESET_ENABLE);
+
+ KdPrint2((PRINT_PREFIX " enable Phy intr, offs %#x\n", offs));
+ /* enable device and PHY state change interrupts */
+ if(ChipFlags & NVQ) {
+ AtapiWritePortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),offs+4,
+ AtapiReadPortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),offs+4) | (((ULONG)0x0000000d) << (!Channel*16)) );
+ } else {
+ AtapiWritePortEx1(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),offs+1,
+ AtapiReadPortEx1(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),offs+1) | (((UCHAR)0x0d) << (!Channel*4)) );
+ }
+
+ KdPrint2((PRINT_PREFIX " dev status %#x\n", tmp16));
+ if(tmp16 != IDE_STATUS_WRONG) {
+ goto default_reset;
+ }
+ break; }
+#endif //0
case ATA_SILICON_IMAGE_ID: {
ULONG offset;
ULONG Channel = deviceExtension->Channel + j;
UniataSataClearErr(HwDeviceExtension, j, UNIATA_SATA_IGNORE_CONNECT, 0);
}
default_reset:
- KdPrint2((PRINT_PREFIX " send reset\n"));
+/*
AtapiWritePort1(chan, IDX_IO2_o_Control, IDE_DC_DISABLE_INTERRUPTS |
IDE_DC_RESET_CONTROLLER );
+ chan->last_devsel = -1;
KdPrint2((PRINT_PREFIX " wait a little\n"));
AtapiStallExecution(10000);
// Disable interrupts
AtapiEnableInterrupts(deviceExtension, j);
KdPrint2((PRINT_PREFIX " wait a little (2)\n"));
AtapiStallExecution(100000);
+*/
+ AtapiHardReset(chan, TRUE, 100000);
+ KdPrint2((PRINT_PREFIX " disable intr\n"));
+ AtapiDisableInterrupts(deviceExtension, j);
+ AtapiStallExecution(100);
+ KdPrint2((PRINT_PREFIX " re-enable intr\n"));
+ AtapiEnableInterrupts(deviceExtension, j);
KdPrint2((PRINT_PREFIX " done\n"));
break;
GetStatus(chan, statusByte);
+ if(statusByte != IDE_STATUS_SUCCESS) {
+ ULONG k;
+ k = UniataAnybodyHome(deviceExtension, j, i);
+ if(k == ATA_AT_HOME_HDD) {
+ // device reset in progress, perform additional wait
+ KdPrint2((PRINT_PREFIX " long reset, wait up to 4.5 s\n"));
+ k = 30 * 1000;
+ while ((AtapiReadPort1(chan, IDX_IO1_i_Status) & IDE_STATUS_BUSY) &&
+ k--)
+ {
+ AtapiStallExecution(150);
+ }
+ KdPrint2((PRINT_PREFIX " exit after %u loops\n", k));
+ GetStatus(chan, statusByte);
+ }
+ }
if(statusByte == IDE_STATUS_SUCCESS) {
IssueIdentify(HwDeviceExtension,
GetBaseStatus(chan, statusByte);
}
// force DMA mode reinit
+ KdPrint2((PRINT_PREFIX " set DFLAGS_REINIT_DMA\n"));
chan->lun[i]->DeviceFlags |= DFLAGS_REINIT_DMA;
}
#endif //0
0, ATA_C_F_DIS_RCACHE, ATA_WAIT_BASE_READY);
LunExt->DeviceFlags &= ~DFLAGS_RCACHE_ENABLED;
}
- if(LunExt->opt_WriteCacheEnable) {
- KdPrint2((PRINT_PREFIX " Try Enable Write Cache\n"));
- // If supported & allowed, setup write cacheing
- statusByte = AtaCommand(deviceExtension, i, lChannel,
- IDE_COMMAND_SET_FEATURES, 0, 0, 0,
- 0, ATA_C_F_ENAB_WCACHE, ATA_WAIT_BASE_READY);
- // Check for errors.
- if (statusByte & IDE_STATUS_ERROR) {
- KdPrint2((PRINT_PREFIX
- "AtapiHwInitialize: Enable write cacheing on Device %d failed\n",
- i));
- LunExt->DeviceFlags &= ~DFLAGS_WCACHE_ENABLED;
+ if(LunExt->IdentifyData.FeaturesSupport.WriteCache) {
+ if(LunExt->opt_WriteCacheEnable) {
+ KdPrint2((PRINT_PREFIX " Try Enable Write Cache\n"));
+ // If supported & allowed, setup write cacheing
+ statusByte = AtaCommand(deviceExtension, i, lChannel,
+ IDE_COMMAND_SET_FEATURES, 0, 0, 0,
+ 0, ATA_C_F_ENAB_WCACHE, ATA_WAIT_BASE_READY);
+ // Check for errors.
+ if (statusByte & IDE_STATUS_ERROR) {
+ KdPrint2((PRINT_PREFIX
+ "AtapiHwInitialize: Enable write cacheing on Device %d failed\n",
+ i));
+ LunExt->DeviceFlags &= ~DFLAGS_WCACHE_ENABLED;
+ } else {
+ LunExt->DeviceFlags |= DFLAGS_WCACHE_ENABLED;
+ }
} else {
- LunExt->DeviceFlags |= DFLAGS_WCACHE_ENABLED;
+ KdPrint2((PRINT_PREFIX " Disable Write Cache\n"));
+ statusByte = AtaCommand(deviceExtension, i, lChannel,
+ IDE_COMMAND_SET_FEATURES, 0, 0, 0,
+ 0, ATA_C_F_DIS_WCACHE, ATA_WAIT_BASE_READY);
+ LunExt->DeviceFlags &= ~DFLAGS_WCACHE_ENABLED;
}
- } else {
- KdPrint2((PRINT_PREFIX " Disable Write Cache\n"));
- statusByte = AtaCommand(deviceExtension, i, lChannel,
- IDE_COMMAND_SET_FEATURES, 0, 0, 0,
- 0, ATA_C_F_DIS_WCACHE, ATA_WAIT_BASE_READY);
- LunExt->DeviceFlags &= ~DFLAGS_WCACHE_ENABLED;
}
- if(LunExt->IdentifyData.FeaturesSupport.PowerMngt ||
+ if(/*LunExt->IdentifyData.FeaturesSupport.PowerMngt ||*/
LunExt->IdentifyData.FeaturesSupport.APM) {
if(LunExt->opt_AdvPowerMode) {
goto ReturnCallback;
}
-#ifdef DBG
+#ifdef _DEBUG
if (!IS_RDP((srb->Cdb[0]))) {
KdPrint2((PRINT_PREFIX "AtapiCallBack: Invalid CDB marked as RDP - %#x\n", srb->Cdb[0]));
}
ULONG hIS;
ULONG checked;
- KdPrint2((PRINT_PREFIX "Intr: VendorID+DeviceID/Rev %#x/%#x (ex %d)\n",
+ KdPrint2((PRINT_PREFIX "Intr: DeviceID+VendorID/Rev %#x/%#x (ex %d)\n",
deviceExtension->DevID, deviceExtension->RevID, deviceExtension->ExpectingInterrupt ));
if(deviceExtension->HwFlags & UNIATA_AHCI) {
//SelectDrive(chan, 0);
//GetBaseStatus(chan, statusByte);
AtapiWritePort1(chan, IDX_IO2_o_Control,
- IDE_DC_A_4BIT );
+ 0 | IDE_DC_A_4BIT );
//if(chan->NumberLuns) {
// SelectDrive(chan, 1);
// GetBaseStatus(chan, statusByte);
}
chan->ChannelCtrlFlags &= ~CTRFLAGS_INTR_DISABLED;
} else {
- AtapiWritePort1(chan, IDX_IO2_o_Control,
+ if(deviceExtension->HwFlags & UNIATA_AHCI) {
+ // keep interrupts disabled
+ UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_IE, 0);
+ } else {
+ AtapiWritePort1(chan, IDX_IO2_o_Control,
IDE_DC_DISABLE_INTERRUPTS /*| IDE_DC_A_4BIT*/ );
+ }
}
return;
} // end AtapiEnableInterrupts()
}
break; }
case ATA_NVIDIA_ID: {
- if(!(ChipFlags & UNIATA_SATA))
+ if(!(ChipFlags & UNIATA_SATA) || (ChipFlags & NVGEN))
break;
KdPrint2((PRINT_PREFIX "NVIDIA\n"));
ULONG offs = (ChipFlags & NV4OFF) ? 0x0440 : 0x0010;
- ULONG shift = Channel << ((ChipFlags & NVQ) ? 4 : 2);
+ ULONG shift = Channel * ((ChipFlags & NVQ) ? 4 : 16);
/* get and clear interrupt status */
if(ChipFlags & NVQ) {
pr_status = AtapiReadPortEx1(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),offs);
AtapiWritePortEx1(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),offs, (0x0f << shift));
}
- KdPrint2((PRINT_PREFIX " pr_status %x\n", pr_status));
+ KdPrint2((PRINT_PREFIX " pr_status %x, shift %x\n", pr_status, shift));
/* check for and handle connect events */
if(((pr_status & (0x0cUL << shift)) == (0x04UL << shift)) ) {
KdPrint2((PRINT_PREFIX " expecting intr + BUSY (3), non ATAPI\n"));
return INTERRUPT_REASON_IGNORE;
}
- if((statusByte & ~IDE_STATUS_DRQ) != (IDE_STATUS_BUSY | IDE_STATUS_DRDY | IDE_STATUS_DSC)) {
+ if((statusByte & ~(IDE_STATUS_DRQ | IDE_STATUS_INDEX)) !=
+ (IDE_STATUS_BUSY | IDE_STATUS_DRDY | IDE_STATUS_DSC)) {
KdPrint3((PRINT_PREFIX " unexpected status, seems it is not our\n"));
return INTERRUPT_REASON_IGNORE;
}
BOOLEAN atapiDev = FALSE;
-#ifdef DBG
+#ifdef _DEBUG
UCHAR Channel;
-#endif //DBG
+#endif //_DEBUG
UCHAR lChannel;
UCHAR DeviceNumber;
BOOLEAN DmaTransfer = FALSE;
lChannel = c;
-#ifdef DBG
+#ifdef _DEBUG
Channel = (UCHAR)(deviceExtension->Channel + lChannel);
KdPrint2((PRINT_PREFIX " cntrlr %#x:%d, irql %#x, c %d\n", deviceExtension->DevIndex, Channel, KeGetCurrentIrql(), c));
-#endif //DBG
+#endif //_DEBUG
if((chan->ChannelCtrlFlags & CTRFLAGS_DMA_ACTIVE) ||
(AtaReq && (AtaReq->Flags & REQ_FLAG_DMA_OPERATION)) ||
return TRUE;
}
- if(!DmaTransfer && !atapiDev) {
+ if((!DmaTransfer && !atapiDev) || deviceExtension->DriverMustPoll) {
KdPrint2((PRINT_PREFIX " service PIO HDD\n"));
UseDpc = FALSE;
}
chan->AhciLastIS & ~(ATA_AHCI_P_IX_DHR | ATA_AHCI_P_IX_PS | ATA_AHCI_P_IX_DS | ATA_AHCI_P_IX_SDB),
chan->AhciLastSError));
if(chan->AhciLastIS & ~ATA_AHCI_P_IX_OF) {
- //KdPrint3((PRINT_PREFIX "Err mask (%#x)\n", chan->AhciLastIS & ~ATA_AHCI_P_IX_OF));
- // We have some other error except Overflow
- // Just signal ERROR, operation will be aborted in ERROR branch.
- statusByte |= IDE_STATUS_ERROR;
- AtaReq->ahci.in_serror = chan->AhciLastSError;
- if(chan->AhciLastSError & (ATA_SE_HANDSHAKE_ERR | ATA_SE_LINKSEQ_ERR | ATA_SE_TRANSPORT_ERR | ATA_SE_UNKNOWN_FIS)) {
- KdPrint2((PRINT_PREFIX "Unrecoverable\n"));
- NoRetry = TRUE;
+
+ if((chan->AhciLastIS == ATA_AHCI_P_IX_INF) &&
+ !(statusByte & IDE_STATUS_ERROR) &&
+ !chan->AhciLastSError &&
+ srb && (srb->SrbFlags & SRB_FLAGS_DATA_IN)
+ ) {
+ KdPrint3((PRINT_PREFIX "ATA_AHCI_P_IX_INF on READ, assume underflow\n"));
+ // continue processing in regular way
+ } else {
+
+ //KdPrint3((PRINT_PREFIX "Err mask (%#x)\n", chan->AhciLastIS & ~ATA_AHCI_P_IX_OF));
+ // We have some other error except Overflow
+ // Just signal ERROR, operation will be aborted in ERROR branch.
+ statusByte |= IDE_STATUS_ERROR;
+ AtaReq->ahci.in_serror = chan->AhciLastSError;
+ if(chan->AhciLastSError & (ATA_SE_HANDSHAKE_ERR | ATA_SE_LINKSEQ_ERR | ATA_SE_TRANSPORT_ERR | ATA_SE_UNKNOWN_FIS)) {
+ KdPrint2((PRINT_PREFIX "Unrecoverable\n"));
+ NoRetry = TRUE;
+ }
}
} else {
// We have only Overflow. Abort operation and continue
if(AtaReq->retry < MAX_RETRIES) {
//fallback_pio:
if(!(deviceExtension->HwFlags & UNIATA_AHCI)) {
- AtaReq->Flags &= ~REQ_FLAG_DMA_OPERATION;
+ //AtaReq->Flags &= ~REQ_FLAG_DMA_OPERATION;
+ // Downrate will happen in AtapiDmaReinit(), try UDMA-2 for HDD only
AtaReq->Flags |= REQ_FLAG_FORCE_DOWNRATE;
-// LunExt->DeviceFlags |= DFLAGS_FORCE_DOWNRATE;
}
AtaReq->ReqState = REQ_STATE_QUEUED;
goto reenqueue_req;
interruptReason = (AtapiReadPort1(chan, IDX_ATAPI_IO1_i_InterruptReason) & ATAPI_IR_Mask);
KdPrint3((PRINT_PREFIX "AtapiInterrupt: ATAPI Error, int reason %x\n", interruptReason));
+ if(UniataIsSATARangeAvailable(deviceExtension, lChannel)) {
+ if(deviceExtension->HwFlags & UNIATA_AHCI) {
+ // Do nothing here
+ } else
+ if(deviceExtension->HwFlags & UNIATA_SATA) {
+ UniataSataClearErr(HwDeviceExtension, lChannel, UNIATA_SATA_IGNORE_CONNECT, 0);
+ }
+ }
+
if(DmaTransfer && (chan->lun[DeviceNumber]->TransferMode > ATA_UDMA2) &&
((error >> 4) == SCSI_SENSE_HARDWARE_ERROR)) {
if(AtaReq->retry < MAX_RETRIES) {
//fallback_pio:
+ // Downrate will happen in AtapiDmaReinit(), use PIO immediately for ATAPI
AtaReq->Flags &= ~REQ_FLAG_DMA_OPERATION;
AtaReq->Flags |= REQ_FLAG_FORCE_DOWNRATE;
// LunExt->DeviceFlags |= DFLAGS_FORCE_DOWNRATE;
LunExt->BlockIoCount
));
LunExt->RecoverCount[AtaReq->retry]++;
- if(LunExt->RecoverCount[AtaReq->retry] >= chan->lun[DeviceNumber]->BlockIoCount/3 ||
+ if(LunExt->RecoverCount[AtaReq->retry] >= LunExt->BlockIoCount/3 ||
(deviceExtension->HwFlags & UNIATA_NO80CHK)
) {
#else
} else {
+ KdPrint2((PRINT_PREFIX "AtapiInterrupt: !DRQ, !BUSY, WordsLeft %#x\n", AtaReq->WordsLeft));
if (AtaReq->WordsLeft) {
// Funky behaviour seen with PCI IDE (not all, just one).
chan->ChannelCtrlFlags &= ~CTRFLAGS_DMA_OPERATION;
goto CompleteRequest;
} else
- if (interruptReason == ATAPI_IR_COD_Cmd && (statusByte & IDE_STATUS_DRQ)) {
+ if ((interruptReason == ATAPI_IR_COD_Cmd) && (statusByte & IDE_STATUS_DRQ)) {
+ if(chan->ChannelCtrlFlags & CTRFLAGS_DMA_OPERATION) {
+ AtapiDmaDBPreSync(HwDeviceExtension, chan, srb);
+ }
// Write the packet.
KdPrint3((PRINT_PREFIX "AtapiInterrupt: Writing Atapi packet.\n"));
// Send CDB to device.
WriteBuffer(chan, (PUSHORT)srb->Cdb,
LunExt->IdentifyData.AtapiCmdSize ? 8 : 6,
- 0);
+ /*0*/ PIO0_TIMING);
AtaReq->ReqState = REQ_STATE_ATAPI_EXPECTING_DATA_INTR;
if(chan->ChannelCtrlFlags & CTRFLAGS_DMA_OPERATION) {
goto ReturnEnableIntr;
- } else if (interruptReason == ATAPI_IR_IO_toDev && (statusByte & IDE_STATUS_DRQ)) {
+ } else if ((interruptReason == ATAPI_IR_IO_toDev) && (statusByte & IDE_STATUS_DRQ)) {
// Write the data.
if (atapiDev) {
statusByte = WaitOnBusy(chan);
- if (atapiDev || !(LunExt->DeviceFlags & DFLAGS_DWORDIO_ENABLED) /*!deviceExtension->DWordIO*/) {
+ if (/*atapiDev || */ !(LunExt->DeviceFlags & DFLAGS_DWORDIO_ENABLED) /*!deviceExtension->DWordIO*/
+ || (wordCount & 1)) {
WriteBuffer(chan,
AtaReq->DataBuffer,
// Fail this request.
status = SRB_STATUS_ERROR;
+ if(!wordCount && atapiDev && (srb->Cdb[0] != SCSIOP_REQUEST_SENSE)) {
+ // some devices feel bad after incorrect commands and may need reset
+ KdPrint2((PRINT_PREFIX
+ "AtapiInterrupt: Try ATAPI reset\n"));
+
+ AtapiDisableInterrupts(deviceExtension, lChannel);
+ AtapiSoftReset(chan, DeviceNumber);
+ AtapiEnableInterrupts(deviceExtension, lChannel);
+ status = SRB_STATUS_BUS_RESET;
+ AtaReq->ReqState = REQ_STATE_TRANSFER_COMPLETE;
+
+// goto IntrPrepareResetController;
+ }
goto CompleteRequest;
}
// Advance data buffer pointer and bytes left.
} else if (interruptReason == ATAPI_IR_IO_toHost && (statusByte & IDE_STATUS_DRQ)) {
+continue_read_drq:
if (atapiDev) {
// Pick up bytes to transfer and convert to words.
wordCount =
- AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountLow) |
- (AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountHigh) << 8);
+ (ULONG)AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountLow) |
+ ((ULONG)AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountHigh) << 8);
// Convert bytes to words.
- wordCount >>= 1;
- KdPrint2((PRINT_PREFIX "AtapiInterrupt: get R wordCount %#x\n", wordCount));
-
+ KdPrint2((PRINT_PREFIX "AtapiInterrupt: get R byteCount %#x\n", wordCount));
+ wordCount >>= 1;
+ /*
+ When ATAPI 64k PIO read is requested we may have 0xfffe byte
+ count reported for 0x10000 bytes in single interrupt.
+ It is not allowed to read entire 64k block with DwordIo intead of
+ wait for last word.
+ */
if (wordCount != AtaReq->WordsLeft) {
KdPrint2((PRINT_PREFIX
"AtapiInterrupt: %d words requested; %d words xferred\n",
statusByte = WaitOnBusy(chan);
- if (atapiDev || !(LunExt->DeviceFlags & DFLAGS_DWORDIO_ENABLED) /*!deviceExtension->DWordIO*/) {
+ if(wordCount&1 && atapiDev && (g_opt_VirtualMachine == VM_BOCHS)) {
+ KdPrint2((PRINT_PREFIX
+ "IdeIntr: unaligned ATAPI %#x Words\n", wordCount));
+ } else
+ if(LunExt->DeviceFlags & DFLAGS_DWORDIO_ENABLED) {
+ KdPrint2((PRINT_PREFIX
+ "IdeIntr: pre-Read %#x Dwords\n", wordCount/2));
+
+ ReadBuffer2(chan,
+ (PULONG)(AtaReq->DataBuffer),
+ wordCount / 2,
+ UniataGetPioTiming(LunExt));
+ // Advance data buffer pointer and bytes left.
+ AtaReq->DataBuffer += wordCount & ~1;
+ AtaReq->WordsLeft -= wordCount & ~1;
+ AtaReq->WordsTransfered += wordCount & ~1;
+ wordCount &= 1;
+ }
+ if (wordCount) {
KdPrint2((PRINT_PREFIX
"IdeIntr: Read %#x words\n", wordCount));
AtaReq->DataBuffer,
wordCount,
UniataGetPioTiming(LunExt));
- KdPrint2(("IdeIntr: PIO Read AtaReq->DataBuffer %#x, srb->DataBuffer %#x\n", AtaReq->DataBuffer, (srb ? srb->DataBuffer : (void*)-1) ));
- //KdDump(AtaReq->DataBuffer, wordCount*2);
- if(srb && atapiDev && srb->Cdb[0] == SCSIOP_REQUEST_SENSE) {
- KdDump(AtaReq->DataBuffer, wordCount*2);
- }
+ }
+
+ KdPrint2(("IdeIntr: PIO Read AtaReq->DataBuffer %#x, srb->DataBuffer %#x\n", AtaReq->DataBuffer, (srb ? srb->DataBuffer : (void*)-1) ));
+ //KdDump(AtaReq->DataBuffer, wordCount*2);
+ if(srb && atapiDev && srb->Cdb[0] == SCSIOP_REQUEST_SENSE) {
+ KdDump(AtaReq->DataBuffer, wordCount*2);
+ }
+ GetBaseStatus(chan, statusByte);
+ KdPrint2((PRINT_PREFIX " status re-check %#x\n", statusByte));
+
+ if(DataOverrun) {
+ KdPrint2((PRINT_PREFIX " DataOverrun\n"));
+ AtapiSuckPort2(chan);
GetBaseStatus(chan, statusByte);
- KdPrint2((PRINT_PREFIX " status re-check %#x\n", statusByte));
+ }
- if(DataOverrun) {
- KdPrint2((PRINT_PREFIX " DataOverrun\n"));
- AtapiSuckPort2(chan);
+ if(statusByte & IDE_STATUS_BUSY) {
+ for (i = 0; i < 2; i++) {
+ AtapiStallExecution(10);
GetBaseStatus(chan, statusByte);
- }
-
- if(statusByte & IDE_STATUS_BUSY) {
- for (i = 0; i < 2; i++) {
- AtapiStallExecution(10);
- GetBaseStatus(chan, statusByte);
- if (!(statusByte & IDE_STATUS_BUSY)) {
- break;
- }
+ if (!(statusByte & IDE_STATUS_BUSY)) {
+ break;
}
}
-
- } else {
- KdPrint2((PRINT_PREFIX
- "IdeIntr: Read %#x Dwords\n", wordCount/2));
-
- ReadBuffer2(chan,
- (PULONG)(AtaReq->DataBuffer),
- wordCount / 2,
- UniataGetPioTiming(LunExt));
}
+
} else {
KdPrint3((PRINT_PREFIX
status = SRB_STATUS_ERROR;
goto CompleteRequest;
}
-
+//continue_atapi_pio_read:
// Advance data buffer pointer and bytes left.
AtaReq->DataBuffer += wordCount;
AtaReq->WordsLeft -= wordCount;
KdPrint2((PRINT_PREFIX "AtapiInterrupt: all transferred, AtaReq->WordsLeft == 0\n"));
if (atapiDev) {
- // Work around to make many atapi devices return correct sector size
- // of 2048. Also certain devices will have sector count == 0x00, check
- // for that also.
- if ((srb->Cdb[0] == SCSIOP_READ_CAPACITY) &&
- (LunExt->IdentifyData.DeviceType == ATAPI_TYPE_CDROM)) {
+ if(LunExt->IdentifyData.DeviceType == ATAPI_TYPE_CDROM) {
- AtaReq->DataBuffer -= wordCount;
- if (AtaReq->DataBuffer[0] == 0x00) {
+ // Work around to make many atapi devices return correct sector size
+ // of 2048. Also certain devices will have sector count == 0x00, check
+ // for that also.
+ if (srb->Cdb[0] == SCSIOP_READ_CAPACITY) {
- *((ULONG *) &(AtaReq->DataBuffer[0])) = 0xFFFFFF7F;
+ AtaReq->DataBuffer -= AtaReq->WordsTransfered;
+ if (AtaReq->DataBuffer[0] == 0x00) {
+ *((ULONG *) &(AtaReq->DataBuffer[0])) = 0xFFFFFF7F;
+ }
+ *((ULONG *) &(AtaReq->DataBuffer[2])) = 0x00080000;
+ AtaReq->DataBuffer += AtaReq->WordsTransfered;
}
+#ifndef UNIATA_INIT_CHANGERS
+ else
+ if (srb->Cdb[0] == SCSIOP_MECHANISM_STATUS) {
- *((ULONG *) &(AtaReq->DataBuffer[2])) = 0x00080000;
- AtaReq->DataBuffer += wordCount;
+ KdPrint3((PRINT_PREFIX "AtapiInterrupt: SCSIOP_MECHANISM_STATUS status %#x\n", status));
+ // Bingo!!
+ AtapiHwInitializeChanger (HwDeviceExtension,
+ srb,
+ (PMECHANICAL_STATUS_INFORMATION_HEADER) srb->DataBuffer);
+ LunExt->DeviceFlags |= DFLAGS_CHANGER_INITED;
+ KdPrint2((PRINT_PREFIX " set DFLAGS_CHANGER_INITED\n"));
+ }
+#endif // UNIATA_INIT_CHANGERS
}
-
GetStatus(chan, statusByte);
if(!(statusByte & IDE_STATUS_BUSY)) {
// Assume command is completed if BUSY is cleared
status = SRB_STATUS_SUCCESS;
goto CompleteRequest;
}
+ } else {
+ if(!atapiDev && !DataOverrun && (srb->SrbFlags & SRB_FLAGS_DATA_IN) &&
+ ((statusByte & ~IDE_STATUS_INDEX) == (IDE_STATUS_IDLE | IDE_STATUS_DRQ))) {
+ KdPrint2((PRINT_PREFIX " HDD read data ready \n"));
+ goto continue_read_drq;
+ }
}
}
} else if (interruptReason == (ATAPI_IR_IO_toHost | ATAPI_IR_COD_Cmd) && !(statusByte & IDE_STATUS_DRQ)) {
KdPrint2((PRINT_PREFIX "AtapiInterrupt: interruptReason = CompleteRequest\n"));
- // Command complete. We exactly know this because os IReason.
+ // Command complete. We exactly know this because of IReason.
if(DmaTransfer) {
KdPrint2((PRINT_PREFIX "AtapiInterrupt: CompleteRequest, was DmaTransfer\n"));
AtaReq->DataBuffer += wordCount;
AtaReq->WordsLeft -= wordCount;
AtaReq->WordsTransfered += wordCount;
+
+ KdPrint2((PRINT_PREFIX "AtapiInterrupt: wordCount %#x, WordsTransfered %#x\n", wordCount, AtaReq->WordsTransfered));
+
}
//if (AtaReq->WordsLeft) {
// status = SRB_STATUS_DATA_OVERRUN;
}
KdPrint(("--\n"));
- KdPrint2(("VendorID+DeviceID/Rev %#x/%#x\n", deviceExtension->DevID, deviceExtension->RevID));
+ KdPrint2(("DeviceID+VendorID/Rev %#x/%#x\n", deviceExtension->DevID, deviceExtension->RevID));
KdPrint2(("P:T:D=%d:%d:%d\n",
Srb->PathId,
Srb->TargetId,
KdPrint2((PRINT_PREFIX "AtapiInterrupt: OriginalSrb != NULL\n"));
if (srb->Cdb[0] == SCSIOP_MECHANISM_STATUS) {
-
+#ifdef UNIATA_INIT_CHANGERS
+ // We can get here only when UNIATA_INIT_CHANGERS is defined
KdPrint3((PRINT_PREFIX "AtapiInterrupt: SCSIOP_MECHANISM_STATUS status %#x\n", status));
if (status == SRB_STATUS_SUCCESS) {
// Bingo!!
AtapiDisableInterrupts(HwDeviceExtension, c);
}
*/
-
+#else
+ KdPrint((PRINT_PREFIX "AtapiInterrupt: ERROR: internal SCSIOP_MECHANISM_STATUS !!!!\n"));
+ ASSERT(FALSE);
+#endif // UNIATA_INIT_CHANGERS
} else { // srb->Cdb[0] == SCSIOP_REQUEST_SENSE)
PSENSE_DATA senseData = (PSENSE_DATA) srb->DataBuffer;
-
+#ifdef __REACTOS__
+ (void)senseData;
+#endif
KdPrint3((PRINT_PREFIX "AtapiInterrupt: ATAPI command status %#x\n", status));
if (status == SRB_STATUS_DATA_OVERRUN) {
// Check to see if we at least get mininum number of bytes
if (status == SRB_STATUS_SUCCESS) {
#ifndef UNIATA_CORE
+#ifdef UNIATA_INIT_CHANGERS
if ((senseData->SenseKey != SCSI_SENSE_ILLEGAL_REQUEST) &&
+ FALSE &&
chan->MechStatusRetryCount) {
KdPrint3((PRINT_PREFIX "AtapiInterrupt: MechStatusRetryCount %#x\n", chan->MechStatusRetryCount));
srb = AtaReq->Srb = BuildMechanismStatusSrb (
HwDeviceExtension,
AtaReq->OriginalSrb);
- } else {
-
- // last request was illegal. No point trying again.
- // Do-nothing call ?
- AtapiHwInitializeChanger (HwDeviceExtension,
- srb,
- (PMECHANICAL_STATUS_INFORMATION_HEADER) NULL);
-
+ } else
+#endif // UNIATA_INIT_CHANGERS
+ {
// Get ready to issue the original srb
srb = AtaReq->Srb = AtaReq->OriginalSrb;
AtaReq->OriginalSrb = NULL;
KdPrint3((PRINT_PREFIX "AtapiInterrupt: Error. complete OriginalSrb\n"));
if (AtaReq->OriginalSrb) {
- KdPrint2((PRINT_PREFIX "AtapiInterrupt: call AtapiHwInitializeChanger()\n"));
- // Do-nothing call ?
- AtapiHwInitializeChanger (HwDeviceExtension,
- srb,
- (PMECHANICAL_STATUS_INFORMATION_HEADER) NULL);
srb = AtaReq->Srb = AtaReq->OriginalSrb;
AtaReq->OriginalSrb = NULL;
}
interruptReason,
statusByte));
+ if(g_opt_VirtualMachine == VM_QEMU) {
+ if(interruptReason == ATAPI_IR_IO_toDev && !(statusByte & IDE_STATUS_DRQ) && !DmaTransfer) {
+ statusByte = WaitForDrq(chan);
+ if(statusByte & IDE_STATUS_DRQ) {
+ goto continue_PIO;
+ }
+ }
+ }
+
if(OldReqState == REQ_STATE_DPC_WAIT_BUSY0 &&
AtaReq->WordsLeft == 0) {
KdPrint2((PRINT_PREFIX "AtapiInterrupt: pending WAIT_BUSY0. Complete.\n"));
ULONG tmp;
if(LunExt->DeviceFlags & DFLAGS_LBA_ENABLED) {
+ (*max_bcount) = 0;
if(LunExt->LimitedTransferMode >= ATA_DMA) {
if(LunExt->DeviceExtension) {
(*max_bcount) = LunExt->DeviceExtension->MaximumDmaTransferLength / DEV_BSIZE;
KdPrint2((PRINT_PREFIX "UniAtaCalculateLBARegs: C:H:S=%#x:%#x:%#x, max_bc %#x\n",
cylinder, drvSelect, sectorNumber, (*max_bcount)));
}
- (*max_bcount) = 0;
return (ULONG)(sectorNumber&0xff) | (((ULONG)cylinder&0xffff)<<8) | (((ULONG)drvSelect&0xf)<<24);
} // end UniAtaCalculateLBARegs()
//ULONG ldev = GET_LDEV(Srb);
UCHAR DeviceNumber = GET_CDEV(Srb);;
ULONGLONG startingSector=0;
- ULONG max_bcount;
+ ULONG max_bcount = 0;
ULONG wordCount = 0;
UCHAR statusByte,statusByte2;
UCHAR cmd;
AtaReq->TransferLength = Srb->DataTransferLength;
// Set up 1st block.
switch(Srb->Cdb[0]) {
- case SCSIOP_READ:
case SCSIOP_WRITE:
+ if(LunExt->DeviceFlags & DFLAGS_LBA32plus) {
+ KdPrint2((PRINT_PREFIX "Attention: SCSIOP_WRITE on 2TB\n"));
+ //return SRB_STATUS_ERROR;
+ }
+ // FALLTHROUGH
+ case SCSIOP_READ:
MOV_DD_SWP(startingSector, ((PCDB)Srb->Cdb)->CDB10.LBA);
MOV_SWP_DW2DD(AtaReq->bcount, ((PCDB)Srb->Cdb)->CDB10.TransferBlocks);
break;
- case SCSIOP_READ12:
case SCSIOP_WRITE12:
+ if(LunExt->DeviceFlags & DFLAGS_LBA32plus) {
+ KdPrint2((PRINT_PREFIX "Attention: SCSIOP_WRITE12 on 2TB\n"));
+ //return SRB_STATUS_ERROR;
+ }
+ // FALLTHROUGH
+ case SCSIOP_READ12:
MOV_DD_SWP(startingSector, ((PCDB)Srb->Cdb)->CDB12READWRITE.LBA);
MOV_DD_SWP(AtaReq->bcount, ((PCDB)Srb->Cdb)->CDB12READWRITE.NumOfBlocks);
break;
AtaReq->bcount));
AtaReq->lba = lba;
+ if(LunExt->errRetry &&
+ lba == LunExt->errLastLba &&
+ /* AtaReq->bcount && */ // errRetry can be set only for non-zero bcount
+ AtaReq->bcount == LunExt->errBCount) {
+ KdPrint3((PRINT_PREFIX "IdeReadWrite: Retry after BUS_RESET %d @%#I64x (%#x)\n",
+ LunExt->errRetry, LunExt->errLastLba, LunExt->errBCount));
+ if(AtaReq->retry < MAX_RETRIES) {
+ AtaReq->retry = LunExt->errRetry;
+ AtaReq->Flags |= REQ_FLAG_FORCE_DOWNRATE;
+ }
+ LunExt->errRetry = 0;
+ }
// assume best case here
// we cannot reinit Dma until previous request is completed
if ((Srb->SrbFlags & SRB_FLAGS_DATA_IN) ||
use_dma) {
+ if(use_dma) {
+ AtapiDmaDBPreSync(HwDeviceExtension, chan, Srb);
+ if(g_opt_BochsDmaReadWorkaround &&
+ (Srb->SrbFlags & SRB_FLAGS_DATA_IN)) {
+ KdPrint2((PRINT_PREFIX "CTRFLAGS_DMA_BEFORE_R on BOCHS\n"));
+ AtapiDmaStart(HwDeviceExtension, DeviceNumber, lChannel, Srb);
+ }
+ }
statusByte2 = AtaCommand48(deviceExtension, DeviceNumber, lChannel,
cmd, lba,
(USHORT)(AtaReq->bcount),
// (UCHAR)((wordCount*2 + DEV_BSIZE-1) / DEV_BSIZE),
0, ATA_IMMEDIATE);
- if(statusByte2 != IDE_STATUS_WRONG) {
+/* if(statusByte2 != IDE_STATUS_WRONG) {
GetStatus(chan, statusByte2);
- }
+ }*/
if(statusByte2 & IDE_STATUS_ERROR) {
+ // Unfortunately, we cannot handle errors in such a way in real life (except known bad blocks).
+ // Because some devices doesn't reset ERR from previous command immediately after getting new one.
+ // On the other hand we cannot wait here because of possible timeout condition
statusByte = AtapiReadPort1(chan, IDX_IO1_i_Error);
KdPrint2((PRINT_PREFIX "IdeReadWrite: status %#x, error %#x\n", statusByte2, statusByte));
return SRB_STATUS_ERROR;
}
if(use_dma) {
- AtapiDmaStart(HwDeviceExtension, DeviceNumber, lChannel, Srb);
+ if(!g_opt_BochsDmaReadWorkaround ||
+ !(Srb->SrbFlags & SRB_FLAGS_DATA_IN)) {
+ //GetStatus(chan, statusByte2);
+ AtapiDmaStart(HwDeviceExtension, DeviceNumber, lChannel, Srb);
+ }
}
return SRB_STATUS_PENDING;
}
CHECK_INTR_IDLE);
// Write next DEV_BSIZE/2*N words.
- if (!(LunExt->DeviceFlags & DFLAGS_DWORDIO_ENABLED)) {
+ if (!(LunExt->DeviceFlags & DFLAGS_DWORDIO_ENABLED) || (wordCount & 1)) {
KdPrint2((PRINT_PREFIX
"IdeReadWrite: Write %#x words\n", wordCount));
// Adjust buffer address and words left count.
AtaReq->WordsLeft -= wordCount;
AtaReq->DataBuffer += wordCount;
+ AtaReq->WordsTransfered += wordCount;
// Wait for interrupt.
return SRB_STATUS_PENDING;
}
KdPrint2((PRINT_PREFIX
- "IdeVerify: Total sectors %#x\n",
+ "IdeVerify: Total sectors %#I64x\n",
sectors));
// Get starting sector number from CDB.
if(!(statusByte & IDE_STATUS_ERROR)) {
// Wait for interrupt.
+ UniataExpectChannelInterrupt(chan, TRUE);
return SRB_STATUS_PENDING;
}
return SRB_STATUS_ERROR;
ULONG DeviceNumber = GET_CDEV(Srb);
ULONG flags;
UCHAR statusByte,statusByte0,byteCountLow,byteCountHigh;
+ UCHAR interruptReason;
BOOLEAN use_dma = FALSE;
BOOLEAN dma_reinited = FALSE;
BOOLEAN retried = FALSE;
- ULONG fis_size;
+ ULONG fis_size, i;
UCHAR FeatureReg=0;
LunExt = chan->lun[DeviceNumber];
}
KdPrint(("--\n"));
- KdPrint2(("VendorID+DeviceID/Rev %#x/%#x\n", deviceExtension->DevID, deviceExtension->RevID));
+ KdPrint2(("DeviceID+VendorID/Rev %#x/%#x\n", deviceExtension->DevID, deviceExtension->RevID));
KdPrint2(("P:T:D=%d:%d:%d\n",
Srb->PathId,
Srb->TargetId,
case SCSIOP_WRITE16:
// all right
break;
+ case SCSIOP_READ_CD:
+ case SCSIOP_READ_CD_MSF:
+ if(deviceExtension->opt_AtapiDmaRawRead) {
+ // all right
+ break;
+ }
+ /* FALL THROUGH */
default:
KdPrint2((PRINT_PREFIX "AtapiSendCommand: SRB_STATUS_BUSY\n"));
return SRB_STATUS_BUSY;
}
//
+#ifdef UNIATA_INIT_CHANGERS
if (!(LunExt->DeviceFlags & DFLAGS_CHANGER_INITED) &&
!AtaReq->OriginalSrb) {
KdPrint2((PRINT_PREFIX "AtapiSendCommand: SRB_STATUS_BUSY (2)\n"));
return SRB_STATUS_BUSY;
}
+#endif // UNIATA_INIT_CHANGERS
}
#ifndef UNIATA_CORE
+ // standard atapi.sys claims:
+
// We need to know how many platters our atapi cd-rom device might have.
// Before anyone tries to send a srb to our target for the first time,
// we must "secretly" send down a separate mechanism status srb in order to
// initialize our device extension changer data. That's how we know how
// many platters our target has.
+ // BUT!
+ // some devices freeze (sometimes) forever on this command
+ // Let CD-ROM driver send this command itself, if it find it necessary
+ // We shall just parse output (if any)
+
+#ifdef UNIATA_INIT_CHANGERS
if (!(LunExt->DeviceFlags & DFLAGS_CHANGER_INITED) &&
!AtaReq->OriginalSrb) {
}
// failed again ? should not get here
-
AtaReq->Srb = AtaReq->OriginalSrb;
AtaReq->OriginalSrb = NULL;
-
- KdPrint2((PRINT_PREFIX "AtapiSendCommand: AtapiHwInitializeChanger()\n"));
- // Do-nothing call ?
- AtapiHwInitializeChanger (HwDeviceExtension, Srb,
- (PMECHANICAL_STATUS_INFORMATION_HEADER) NULL);
// fall out
}
}
+#endif // UNIATA_INIT_CHANGERS
#endif //UNIATA_CORE
if((CmdAction & CMD_ACTION_PREPARE) &&
}
// check if DMA read/write
+ if(g_opt_AtapiNoDma) {
+ KdPrint2((PRINT_PREFIX "AtapiSendCommand: CTRFLAGS_DMA_BEFORE_R => no dma\n"));
+ use_dma = FALSE;
+ } else
if(deviceExtension->HwFlags & UNIATA_AHCI) {
KdPrint2((PRINT_PREFIX "AtapiSendCommand: force use dma (ahci)\n"));
use_dma = TRUE;
if(Srb->Cdb[0] == SCSIOP_REQUEST_SENSE) {
KdPrint2((PRINT_PREFIX "AtapiSendCommand: SCSIOP_REQUEST_SENSE, no DMA setup\n"));
} else
- if(AtaReq->TransferLength) {
- // try use DMA
+ if(AtaReq->TransferLength && !(AtaReq->TransferLength & 0x0f)) {
+ KdPrint2((PRINT_PREFIX "AtapiSendCommand: try DMA setup\n"));
+ // try use DMA if TransferLength is 16-byte aligned
switch(Srb->Cdb[0]) {
case SCSIOP_WRITE:
case SCSIOP_WRITE12:
}
break;
case SCSIOP_READ_CD:
+ case SCSIOP_READ_CD_MSF:
if(deviceExtension->opt_AtapiDmaRawRead)
goto call_dma_setup;
break;
}
}
} else {
- KdPrint2((PRINT_PREFIX "AtapiSendCommand: zero transfer, no DMA setup\n"));
+ KdPrint2((PRINT_PREFIX "AtapiSendCommand: zero/unaligned transfer %x, no DMA setup\n", AtaReq->TransferLength));
}
AtaReq->Flags &= ~REQ_FLAG_DMA_OPERATION;
} else {
FeatureReg |= ATA_F_DMA;
- if(LunExt->IdentifyData.AtapiDMA.DMADirRequired &&
- (Srb->SrbFlags & SRB_FLAGS_DATA_IN)) {
- FeatureReg |= ATA_F_DMAREAD;
+ if(LunExt->IdentifyData.AtapiDMA.DMADirRequired) {
+ if(Srb->SrbFlags & SRB_FLAGS_DATA_IN) {
+ KdPrint2((PRINT_PREFIX "Set DMADir.\n"));
+ FeatureReg |= ATA_F_DMAREAD;
+ }
}
}
}
*/
if (statusByte & IDE_STATUS_DRQ) {
+ KdPrint3((PRINT_PREFIX "AtapiSendCommand: DRQ still asserted. Status (%#x)\n", statusByte));
make_reset:
- KdPrint3((PRINT_PREFIX "AtapiSendCommand: DRQ still asserted.Status (%#x)\n", statusByte));
-
AtapiDisableInterrupts(deviceExtension, lChannel);
AtapiSoftReset(chan, DeviceNumber);
if(use_dma) {
FeatureReg |= ATA_F_DMA;
- if(LunExt->IdentifyData.AtapiDMA.DMADirRequired &&
- (Srb->SrbFlags & SRB_FLAGS_DATA_IN)) {
- FeatureReg |= ATA_F_DMAREAD;
+ if(LunExt->IdentifyData.AtapiDMA.DMADirRequired) {
+ if(Srb->SrbFlags & SRB_FLAGS_DATA_IN) {
+ FeatureReg |= ATA_F_DMAREAD;
+ }
}
}
- AtapiWritePort1(chan, IDX_IO1_o_Feature, FeatureReg);
-
// Write transfer byte count to registers.
- byteCountLow = (UCHAR)(Srb->DataTransferLength & 0xFF);
- byteCountHigh = (UCHAR)(Srb->DataTransferLength >> 8);
-
if (Srb->DataTransferLength >= 0x10000) {
byteCountLow = byteCountHigh = 0xFF;
+ } else {
+ byteCountLow = (UCHAR)(Srb->DataTransferLength & 0xFF);
+ byteCountHigh = (UCHAR)(Srb->DataTransferLength >> 8);
}
- AtapiWritePort1(chan, IDX_ATAPI_IO1_o_ByteCountLow, byteCountLow);
- AtapiWritePort1(chan, IDX_ATAPI_IO1_o_ByteCountHigh, byteCountHigh);
+ KdPrint3((PRINT_PREFIX "AtapiSendCommand: F:%#x, CntHL:%#x:%#x.\n", FeatureReg, byteCountHigh, byteCountLow));
if (flags & DFLAGS_INT_DRQ) {
-
// This device interrupts when ready to receive the packet.
-
KdPrint3((PRINT_PREFIX "AtapiSendCommand: Wait for int. to send packet. Status (%#x)\n",
statusByte));
AtaReq->ReqState = REQ_STATE_ATAPI_EXPECTING_CMD_INTR;
InterlockedExchange(&(chan->CheckIntr),
CHECK_INTR_IDLE);
+ // inform driver that packet command must be sent in ISR
+ flags |= DFLAGS_INT_DRQ;
+ } else {
+ // This device quickly sets DRQ when ready to receive the packet.
+ KdPrint2((PRINT_PREFIX "AtapiSendCommand: Poll for int. to send packet. Status (%#x)\n",
+ statusByte));
- // Write ATAPI packet command.
- AtapiWritePort1(chan, IDX_IO1_o_Command, IDE_COMMAND_ATAPI_PACKET);
-
- KdPrint3((PRINT_PREFIX "AtapiSendCommand: return SRB_STATUS_PENDING (DRQ)\n"));
- return SRB_STATUS_PENDING;
+ UniataExpectChannelInterrupt(chan, TRUE);
+ AtaReq->ReqState = REQ_STATE_ATAPI_DO_NOTHING_INTR;
+ InterlockedExchange(&(chan->CheckIntr),
+ CHECK_INTR_IDLE);
+ if(g_opt_AtapiSendDisableIntr) {
+ AtapiDisableInterrupts(deviceExtension, lChannel);
+ }
+ // remember status. Later we may check if error appeared after cmd packet
+ statusByte0 = statusByte;
}
- // This device quickly sets DRQ when ready to receive the packet.
-
- KdPrint2((PRINT_PREFIX "AtapiSendCommand: Poll for int. to send packet. Status (%#x)\n",
- statusByte));
-
- UniataExpectChannelInterrupt(chan, TRUE);
- AtaReq->ReqState = REQ_STATE_ATAPI_DO_NOTHING_INTR;
- InterlockedExchange(&(chan->CheckIntr),
- CHECK_INTR_IDLE);
+ // must be already selected, experimental for ROS BUG-9119
+ //AtapiWritePort1(chan, IDX_IO1_o_DriveSelect, IDE_USE_LBA | (DeviceNumber ? IDE_DRIVE_2 : IDE_DRIVE_1) );
+ AtapiWritePort1(chan, IDX_IO2_o_Control , 0);
+ AtapiWritePort1(chan, IDX_ATAPI_IO1_o_Feature /*IDX_IO1_o_Feature*/, FeatureReg);
+ //AtapiWritePort1(chan, IDX_ATAPI_IO1_o_Unused0, 0); // experimental for ROS BUG-9119
+ //AtapiWritePort1(chan, IDX_ATAPI_IO1_o_Unused1, 0); // experimental for ROS BUG-9119
+ AtapiWritePort1(chan, IDX_ATAPI_IO1_o_ByteCountLow, byteCountLow);
+ AtapiWritePort1(chan, IDX_ATAPI_IO1_o_ByteCountHigh, byteCountHigh);
+ // Write ATAPI packet command.
+ AtapiWritePort1(chan, IDX_ATAPI_IO1_o_Command /*IDX_IO1_o_Command*/, IDE_COMMAND_ATAPI_PACKET);
- if(g_opt_AtapiSendDisableIntr) {
- AtapiDisableInterrupts(deviceExtension, lChannel);
+ if (flags & DFLAGS_INT_DRQ) {
+ // Wait for interrupt and send PACKET there
+ KdPrint3((PRINT_PREFIX "AtapiSendCommand: return SRB_STATUS_PENDING (DRQ)\n"));
+ return SRB_STATUS_PENDING;
}
- // remember status. Later we may check if error appeared after cmd packet
- statusByte0 = statusByte;
- // Write ATAPI packet command.
- AtapiWritePort1(chan, IDX_IO1_o_Command, IDE_COMMAND_ATAPI_PACKET);
-
- // Wait for DRQ.
WaitOnBusy(chan);
+/*
+ // Wait for DRQ.
statusByte = WaitForDrq(chan);
// Need to read status register and clear interrupt (if any)
GetBaseStatus(chan, statusByte);
if (!(statusByte & IDE_STATUS_DRQ)) {
-
if(g_opt_AtapiSendDisableIntr) {
AtapiEnableInterrupts(deviceExtension, lChannel);
}
AtaReq->ReqState = REQ_STATE_TRANSFER_COMPLETE;
return SRB_STATUS_ERROR;
}
-
+*/
GetStatus(chan, statusByte);
KdPrint3((PRINT_PREFIX "AtapiSendCommand: status (%#x)\n", statusByte));
- // Send CDB to device.
- statusByte = WaitOnBaseBusy(chan);
+ //statusByte = WaitOnBaseBusy(chan);
// Indicate expecting an interrupt and wait for it.
UniataExpectChannelInterrupt(chan, TRUE);
- InterlockedExchange(&(chan->CheckIntr),
- CHECK_INTR_IDLE);
- AtaReq->ReqState = REQ_STATE_ATAPI_EXPECTING_DATA_INTR;
+ for(i=0; i<5000; i++) {
+ if(g_opt_AtapiSendDisableIntr) {
+ GetStatus(chan, statusByte);
+ } else {
+ GetBaseStatus(chan, statusByte);
+ }
+ interruptReason = AtapiReadPort1(chan, IDX_ATAPI_IO1_i_InterruptReason);
+ //KdPrint3((PRINT_PREFIX "AtapiSendCommand: iReason %x (%d)\n", interruptReason, i));
+ if(((interruptReason & ATAPI_IR_COD) == ATAPI_IR_COD_Cmd) &&
+ (((statusByte & (IDE_STATUS_BUSY | IDE_STATUS_DRQ)) == IDE_STATUS_DRQ))) {
+ break;
+ }
+ AtapiStallExecution(g_opt_WaitDrqDelay*2);
+#ifdef _DEBUG
+// KdPrint3((PRINT_PREFIX "AtapiSendCommand: wait CoD, status (%#x)\n", interruptReason));
+#endif // _DEBUG
+ }
+ if(((interruptReason & ATAPI_IR_COD) != ATAPI_IR_COD_Cmd) ||
+ (((statusByte & (IDE_STATUS_BUSY | IDE_STATUS_DRQ)) != IDE_STATUS_DRQ)) ) {
+ KdPrint3((PRINT_PREFIX "AtapiSendCommand: no CoD raised, abort cmd\n"));
+ KdPrint3((PRINT_PREFIX "AtapiSendCommand: iReason %x (%d)\n", interruptReason, i));
+ KdPrint3((PRINT_PREFIX "AtapiSendCommand: status (%#x)\n", statusByte));
+ if(g_opt_AtapiSendDisableIntr) {
+ AtapiEnableInterrupts(deviceExtension, lChannel);
+ }
+ KdPrint3((PRINT_PREFIX "AtapiSendCommand: DRQ+CoD never asserted\n"));
+ statusByte = AtapiReadPort1(chan, IDX_IO1_i_Error);
+ KdPrint3((PRINT_PREFIX "AtapiSendCommand: Err on cmd: (%#x)\n", statusByte));
+ if(statusByte >> 4) {
+ GetBaseStatus(chan, statusByte);
+ AtaReq->ReqState = REQ_STATE_TRANSFER_COMPLETE;
+ return MapError(deviceExtension, Srb);
+ }
+ goto make_reset;
+// AtaReq->ReqState = REQ_STATE_TRANSFER_COMPLETE;
+// return SRB_STATUS_ERROR;
+ } else {
+ KdPrint3((PRINT_PREFIX "AtapiSendCommand: ready for packet, status %#x, i=%d\n", interruptReason, i));
+ }
+ // clear interrupt
GetBaseStatus(chan, statusByte);
+ if(chan->ChannelCtrlFlags & CTRFLAGS_DMA_OPERATION) {
+ AtapiDmaDBPreSync(HwDeviceExtension, chan, Srb);
+ }
if(g_opt_AtapiSendDisableIntr) {
AtapiEnableInterrupts(deviceExtension, lChannel);
}
+ // Send CDB to device.
WriteBuffer(chan,
(PUSHORT)Srb->Cdb,
LunExt->IdentifyData.AtapiCmdSize ? 8 : 6,
- 0);
+ /*0*/ PIO0_TIMING);
GetStatus(chan, statusByte);
KdPrint3((PRINT_PREFIX "AtapiSendCommand: cmd status (%#x)\n", statusByte));
// When we operate in DMA mode, we should not start transfer when there is an error on entry
// Interrupt may never come in such case.
if(statusByte & IDE_STATUS_ERROR) {
- UCHAR interruptReason;
GetBaseStatus(chan, statusByte);
KdPrint3((PRINT_PREFIX "AtapiSendCommand: Error on cmd: (%#x)\n", statusByte));
AtaReq->ReqState = REQ_STATE_TRANSFER_COMPLETE;
return MapError(deviceExtension, Srb);
}
-/* if(statusByte & IDE_STATUS_DSC) {
- KdPrint3((PRINT_PREFIX "AtapiSendCommand: DSC on cmd: (%#x)\n", statusByte));
+ if(statusByte & IDE_STATUS_DRQ) {
+ // Some devices require this. If error condition is not checked in such a way,
+ // device may not operate correctly and would be treated as failed
+ // (and finally invisible for OS)
+ KdPrint3((PRINT_PREFIX "AtapiSendCommand: DRQ on cmd: (%#x)\n", statusByte));
// Read the error reg. to clear it and fail this request.
statusByte = AtapiReadPort1(chan, IDX_IO1_i_Error);
KdPrint3((PRINT_PREFIX "AtapiSendCommand: Err on cmd: (%#x)\n", statusByte));
return MapError(deviceExtension, Srb);
}
}
-*/
+
if(chan->ChannelCtrlFlags & CTRFLAGS_DMA_OPERATION) {
AtapiDmaStart(HwDeviceExtension, DeviceNumber, lChannel, Srb);
}
+ InterlockedExchange(&(chan->CheckIntr),
+ CHECK_INTR_IDLE);
+ AtaReq->ReqState = REQ_STATE_ATAPI_EXPECTING_DATA_INTR;
+
KdPrint3((PRINT_PREFIX "AtapiSendCommand: ExpectingInterrupt (%#x)\n", chan->ExpectingInterrupt));
KdPrint2((PRINT_PREFIX "AtapiSendCommand: return SRB_STATUS_PENDING (3)\n"));
} else {
RtlZeroMemory(modeData, sizeof(MODE_POWER_CONDITION_PAGE));
modeData->PageCode = MODE_PAGE_POWER_CONDITION;
+#ifdef __REACTOS__
modeData->PageLength = sizeof(MODE_POWER_CONDITION_PAGE)-sizeof(MODE_PARAMETER_HEADER);
+#else
+ modeData->PageLength = sizeof(MODE_PAGE_POWER_CONDITION)-sizeof(MODE_PARAMETER_HEADER);
+#endif
modeData->Byte3.Fields.Idle = LunExt->PowerState <= StartStop_Power_Idle;
modeData->Byte3.Fields.Standby = LunExt->PowerState == StartStop_Power_Standby;
Srb->DataTransferLength = sizeof(MODE_POWER_CONDITION_PAGE);
AtapiWritePort1(chan, IDX_IO1_o_DriveSelect, regs->bDriveHeadReg);
AtapiStallExecution(10);
+ if(use_dma) {
+ AtapiDmaDBPreSync(HwDeviceExtension, chan, Srb);
+ }
if((regs->bOpFlags & ATA_FLAGS_48BIT_COMMAND) == 0) { // execute ATA command
AtapiWritePort1(chan, IDX_IO1_o_Feature, regs->bFeaturesReg);
KdPrint2((PRINT_PREFIX
"** AtapiStartIo: Function %#x, PATH:LUN:TID = %#x:%#x:%#x\n",
Srb->Function, Srb->PathId, Srb->Lun, Srb->TargetId));
- KdPrint2((PRINT_PREFIX " VendorID+DeviceID/Rev %#x/%#x\n", deviceExtension->DevID, deviceExtension->RevID));
+ KdPrint2((PRINT_PREFIX " DeviceID+VendorID/Rev %#x/%#x\n", deviceExtension->DevID, deviceExtension->RevID));
if(lChannel == deviceExtension->NumberChannels &&
!Srb->Lun && !Srb->TargetId &&
} // end AtapiStartIo__()
-
+#if 0
void
NTAPI
UniataInitAtaCommands()
case IDE_COMMAND_WRITE_LOG_DMA48:
case IDE_COMMAND_TRUSTED_RCV_DMA:
case IDE_COMMAND_TRUSTED_SEND_DMA:
- case IDE_COMMAND_DATA_SET_MGMT:
+ case IDE_COMMAND_DATA_SET_MGMT: // TRIM
//KdPrint2((PRINT_PREFIX "DMA "));
flags |= ATA_CMD_FLAG_DMA;
}
AtaCommandFlags[i] = flags;
}
} // end UniataInitAtaCommands()
+#endif
/*++
{
HW_INITIALIZATION_DATA_COMMON hwInitializationData;
ULONG adapterCount;
- ULONG i, c, alt;
+ ULONG i, c, alt, pref_alt;
ULONG statusToReturn, newStatus;
PUNICODE_STRING RegistryPath = (PUNICODE_STRING)Argument2;
BOOLEAN ReEnter = FALSE;
PCONFIGURATION_INFORMATION GlobalConfig = IoGetConfigurationInformation();
BOOLEAN PrimaryClaimed = FALSE;
BOOLEAN SecondaryClaimed = FALSE;
+ BOOLEAN IgnoreIsaCompatiblePci = FALSE;
+ BOOLEAN IgnoreNativePci = FALSE;
LARGE_INTEGER t0, t1;
- Connect_DbgPrint();
KdPrint2((PRINT_PREFIX "%s", (PCCHAR)ver_string));
//a = (WCHAR)strlen(ver_string);
- g_opt_Verbose = (BOOLEAN)AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"PrintLogo", 0);
- if(g_opt_Verbose) {
- _PrintNtConsole("Universal ATA driver v 0." UNIATA_VER_STR "\n");
+ statusToReturn = 0xffffffff;
+
+ // Zero out structure.
+ RtlZeroMemory(((PCHAR)&hwInitializationData), sizeof(hwInitializationData));
+
+ // Set size of hwInitializationData.
+ hwInitializationData.comm.HwInitializationDataSize =
+ sizeof(hwInitializationData.comm) +
+// sizeof(hwInitializationData.nt4) +
+ ((WinVer_Id() <= WinVer_NT) ? 0 : sizeof(hwInitializationData.w2k));
+ KdPrint(("HwInitializationDataSize = %x\n", hwInitializationData.comm.HwInitializationDataSize));
+
+ // Set entry points.
+ hwInitializationData.comm.HwInitialize = (PHW_INITIALIZE)AtapiHwInitialize;
+ hwInitializationData.comm.HwResetBus = (PHW_RESET_BUS)AtapiResetController;
+ hwInitializationData.comm.HwStartIo = (PHW_STARTIO)AtapiStartIo;
+ hwInitializationData.comm.HwInterrupt = (PHW_INTERRUPT)AtapiInterrupt;
+
+ // Specify size of extensions.
+ hwInitializationData.comm.DeviceExtensionSize = sizeof(HW_DEVICE_EXTENSION);
+ hwInitializationData.comm.SpecificLuExtensionSize = sizeof(HW_LU_EXTENSION);
+ hwInitializationData.comm.SrbExtensionSize = sizeof(ATA_REQ);
+
+ // Indicate PIO device.
+ hwInitializationData.comm.MapBuffers = TRUE;
+
+ // Request and parse arument string.
+ KdPrint2((PRINT_PREFIX "\n\nUniATA: parse ArgumentString\n"));
+ // Zero out structure.
+ hwInitializationData.comm.NumberOfAccessRanges = 2;
+ hwInitializationData.comm.HwFindAdapter = AtapiReadArgumentString;
+ ScsiPortInitialize(DriverObject,
+ Argument2,
+ &hwInitializationData.comm,
+ &adapterCount);
+
+ if(!g_Dump) {
+ Connect_DbgPrint();
+ g_opt_Verbose = (BOOLEAN)AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"PrintLogo", 0);
+ if(g_opt_Verbose) {
+ _PrintNtConsole("Universal ATA driver v 0." UNIATA_VER_STR "\n");
+ }
+ IgnoreIsaCompatiblePci = (BOOLEAN)AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"IgnoreIsaCompatiblePci", IgnoreIsaCompatiblePci) ? TRUE : FALSE;
+ IgnoreNativePci = (BOOLEAN)AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"IgnoreNativePci", IgnoreNativePci) ? TRUE : FALSE;
+ } else {
+ KdPrint(("crashdump mode\n"));
}
if(!SavedDriverObject) {
MajorVersion=0x04;
MinorVersion=0x01;
BuildNumber=1;
+ CPU_num = KeNumberProcessors;
#else
// we are here for the 1st time
// init CrossNT and get OS version
//HalDisplayString((PUCHAR)"DbgPrnHkInitialize: CrNtInit failed\n");
return status;
}
+ CPU_num = *KeNumberProcessors;
#endif // USE_REACTOS_DDK
- KdPrint(("UniATA Init: OS ver %x.%x (%d), %d CPU(s)\n", MajorVersion, MinorVersion, BuildNumber, KeNumberProcessors));
+ KdPrint(("UniATA Init: OS ver %x.%x (%d), %d CPU(s)\n", MajorVersion, MinorVersion, BuildNumber, CPU_num));
KeQuerySystemTime(&t0);
do {
if(!ReEnter) {
// init ATA command translation table
- UniataInitAtaCommands();
+ //UniataInitAtaCommands();
+
// get registry path to settings
RtlCopyMemory(&SavedRegPath, RegistryPath, sizeof(UNICODE_STRING));
SavedRegPath.Buffer = (PWCHAR)&SavedRegPathBuffer;
g_LogToDisplay = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"LogToDisplay", 0);
#endif //_DEBUG
- statusToReturn = 0xffffffff;
-
- // Zero out structure.
- RtlZeroMemory(((PCHAR)&hwInitializationData), sizeof(hwInitializationData));
-
- // Set size of hwInitializationData.
- hwInitializationData.comm.HwInitializationDataSize =
- sizeof(hwInitializationData.comm) +
-// sizeof(hwInitializationData.nt4) +
- ((WinVer_Id() <= WinVer_NT) ? 0 : sizeof(hwInitializationData.w2k));
- KdPrint(("HwInitializationDataSize = %x\n", hwInitializationData.comm.HwInitializationDataSize));
-
- // Set entry points.
- hwInitializationData.comm.HwInitialize = (PHW_INITIALIZE)AtapiHwInitialize;
- hwInitializationData.comm.HwResetBus = (PHW_RESET_BUS)AtapiResetController;
- hwInitializationData.comm.HwStartIo = (PHW_STARTIO)AtapiStartIo;
- hwInitializationData.comm.HwInterrupt = (PHW_INTERRUPT)AtapiInterrupt;
-
- // Specify size of extensions.
- hwInitializationData.comm.DeviceExtensionSize = sizeof(HW_DEVICE_EXTENSION);
- hwInitializationData.comm.SpecificLuExtensionSize = sizeof(HW_LU_EXTENSION);
- hwInitializationData.comm.SrbExtensionSize = sizeof(ATA_REQ);
-
- // Indicate PIO device.
- hwInitializationData.comm.MapBuffers = TRUE;
// Set PnP-specific API
if(WinVer_Id() > WinVer_NT) {
KdPrint(("set NeedPhysicalAddresses = TRUE\n"));
hwInitializationData.w2k.HwAdapterControl = (PHW_ADAPTER_CONTROL)AtapiAdapterControl;
}
- KdPrint2((PRINT_PREFIX "\n\nATAPI IDE enum supported BusMaster Devices\n"));
-
+ KdPrint2((PRINT_PREFIX "\n\nUniATA init... (%d)\n", ReEnter));
if(!ReEnter) {
g_opt_VirtualMachine = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"VirtualMachineType", g_opt_VirtualMachine);
g_opt_VirtualMachine = VM_VBOX;
}
// Pre-scan PCI bus, also check if we are under VM
- UniataEnumBusMasterController(DriverObject, Argument2);
+ // But do not perform scan if PCI bus is claimed as unused
+ if(!IgnoreIsaCompatiblePci || !IgnoreNativePci) {
+ KdPrint2((PRINT_PREFIX "\nATAPI IDE enum supported PCI BusMaster Devices\n"));
+ UniataEnumBusMasterController(DriverObject, Argument2);
+ }
switch(g_opt_VirtualMachine) {
case VM_VBOX:
g_opt_WaitDrqDelay = 100;
g_opt_WaitBusyLongCount = 20000;
g_opt_MaxIsrWait = 200;
- g_opt_AtapiSendDisableIntr = 0;
+ g_opt_AtapiSendDisableIntr = FALSE;
g_opt_AtapiDmaRawRead = FALSE;
break;
+ case VM_BOCHS:
+ KdPrint2((PRINT_PREFIX "adjust options for Bochs\n"));
+ g_opt_AtapiNoDma = TRUE;
}
if(!hasPCI) {
KdPrint2((PRINT_PREFIX "old slow machine, adjust timings\n"));
- // old slow machine, adjust timings
+ // old slow machine, adjust timings (us)
+ g_opt_WaitBusyResetCount = 20000;
g_opt_WaitBusyCount = 20000;
g_opt_WaitBusyDelay = 150;
g_opt_WaitDrqDelay = 100;
g_opt_WaitBusyLongCount = 20000;
g_opt_MaxIsrWait = 200;
+ g_opt_DriveSelectNanoDelay = 400;
+ }
+ if(g_opt_VirtualMachine > VM_NONE) {
+ g_opt_DriveSelectNanoDelay = 0;
+ }
+ if(CPU_num > 1) {
+ g_opt_AtapiSendDisableIntr = TRUE;
}
g_opt_WaitBusyCount = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"WaitBusyCount", g_opt_WaitBusyCount); // 200 vs 20000
g_opt_WaitDrqDelay = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"WaitDrqDelay", g_opt_WaitDrqDelay); // 10 vs 100
g_opt_WaitBusyLongCount = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"WaitBusyLongCount", g_opt_WaitBusyLongCount); // 2000 vs 20000
g_opt_WaitBusyLongDelay = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"WaitBusyLongDelay", g_opt_WaitBusyLongDelay); // 250 vs 250
- g_opt_AtapiSendDisableIntr = (BOOLEAN)AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"AtapiSendDisableIntr", g_opt_AtapiSendDisableIntr); // 1 vs 0
- g_opt_AtapiDmaRawRead = (BOOLEAN)AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"AtapiDmaRawRead", g_opt_AtapiDmaRawRead); // 1 vs 0
- g_opt_MaxIsrWait = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"MaxIsrWait", g_opt_MaxIsrWait); // 40 vs xxx
- }
+ g_opt_AtapiSendDisableIntr = (BOOLEAN)AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"AtapiSendDisableIntr", g_opt_AtapiSendDisableIntr) ? TRUE : FALSE; // 1 vs 0
+ g_opt_AtapiDmaRawRead = (BOOLEAN)AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"AtapiDmaRawRead", g_opt_AtapiDmaRawRead) ? TRUE : FALSE; // 1 vs 0
+ g_opt_AtapiNoDma = (BOOLEAN)AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"AtapiNoDma", g_opt_AtapiNoDma) ? TRUE : FALSE; // 1 vs 0
+ g_opt_MaxIsrWait = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"MaxIsrWait", g_opt_MaxIsrWait); // 40 vs xxx
+ g_opt_DriveSelectNanoDelay = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"DriveSelectNanoDelay", g_opt_DriveSelectNanoDelay);
+ } // end !re-enter
// Look for legacy ISA-bridged PCI IDE controller (onboard)
KdPrint2((PRINT_PREFIX "\n\nATAPI IDE: Look for legacy ISA-bridged PCI IDE controller (onboard)\n"));
KdPrint2((PRINT_PREFIX "!BMList[i].MasterDev\n"));
break;
}
- if(AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"IgnoreIsaCompatiblePci", 0)) {
+ if(IgnoreIsaCompatiblePci) {
break;
}
if(ReEnter) {
PrimaryClaimed = TRUE;
if(GlobalConfig->AtDiskSecondaryAddressClaimed)
SecondaryClaimed = TRUE;
+ pref_alt = 0;
- if(!WinVer_WDM_Model && !PrimaryClaimed && !SecondaryClaimed &&
+ if(!WinVer_WDM_Model && !PrimaryClaimed && !SecondaryClaimed && !g_Dump &&
!(BMList[i].ChanInitOk & 0x80)) {
- newStatus = UniataClaimLegacyPCIIDE(i);
+
+ // We just want to claim our PCI device in compatible mode, since we shall not
+ // tell system that we use it inside HwInitialize
+ // Even more, we shall cheat system, that work with ISA
+ // Note: this call may (but not 'must' or 'can') cause IO resource
+ // reallocation and switch to native mode if HAL supports this
+ newStatus = (ULONG)UniataClaimLegacyPCIIDE(i);
+ // Special check for NT3.51/NT4 (not ReactOS !!!)
+ if(((NTSTATUS)newStatus == STATUS_CONFLICTING_ADDRESSES) &&
+ //(BMList[i].ChanInitOk & 0x40) &&
+ /*CPU_num > 1 &&*/
+ (WinVer_Id() <= WinVer_NT)) {
+ // Some NT3/4 SMP (but not only) HALs cannot reallocate IO resources of
+ // BusMaster PCI controller
+ // Since nobody claimed Primary/Secondary yet, try init and claim them
+ // However it is not 100% safe way, especially under ReactOS, which doesn't resolve
+ // conflicts yet.
+ // We relay on ScsiPort internal checks
+ KdPrint2((PRINT_PREFIX "Can't acquire PCI part of BusMaster on SMP NT3/4 system, try init anyway.\n"));
+ newStatus = STATUS_SUCCESS;
+ // Prefer alternative init method (try to change Isa -> PCI in ConfigInfo first)
+ pref_alt = 1;
+ }
if(newStatus != STATUS_SUCCESS) {
KdPrint2((PRINT_PREFIX "Can't acquire PCI part of BusMaster, try as pure ISA later.\n"));
break;
_PrintNtConsole("Init standard Dual-channel PCI ATA controller:");
}
-
for(alt = 0; alt < (ULONG)(WinVer_WDM_Model ? 1 : 2) ; alt++) {
for(c=0; c<2; c++) {
-
+ // check is channel is manually excluded
if(AtapiRegCheckDevValue(NULL, c, DEVNUM_NOT_SPECIFIED, L"IgnoreIsaCompatiblePci", 0)) {
break;
}
newStatus = ScsiPortInitialize(DriverObject,
Argument2,
&hwInitializationData.comm,
- (PVOID)(i | (alt ? 0x80000000 : 0)));
+ UlongToPtr(i | ((alt ^ pref_alt) ? 0x80000000 : 0)));
KdPrint2((PRINT_PREFIX "ScsiPortInitialize Status %#x\n", newStatus));
if (newStatus < statusToReturn) {
statusToReturn = newStatus;
KdPrint2((PRINT_PREFIX "\n\nATAPI IDE: i %d, BMListLen %d\n", i, BMListLen));
for (; i <BMListLen; i++) {
- if(AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"IgnoreNativePci", 0)) {
+ if(IgnoreNativePci) {
break;
}
/* if(BMList[i].MasterDev)
newStatus = ScsiPortInitialize(DriverObject,
Argument2,
&hwInitializationData.comm,
- (PVOID)i);
+ UlongToPtr(i));
KdPrint2((PRINT_PREFIX "ScsiPortInitialize Status %#x\n", newStatus));
if(newStatus == (ULONG)STATUS_DEVICE_DOES_NOT_EXIST && BMList[i].NeedAltInit) {
// Note: this is actually a BUG in scsiport.sys
newStatus = ScsiPortInitialize(DriverObject,
Argument2,
&hwInitializationData.comm,
- (PVOID)(i | 0x80000000));
+ UlongToPtr(i | 0x80000000));
KdPrint2((PRINT_PREFIX "ScsiPortInitialize Status %#x (2)\n", newStatus));
}
if (newStatus < statusToReturn)
// Indicate 2 access ranges and reset FindAdapter.
hwInitializationData.comm.NumberOfAccessRanges = 2;
- hwInitializationData.comm.HwFindAdapter = AtapiFindController;
+ hwInitializationData.comm.HwFindAdapter = AtapiFindIsaController;
if(!AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"IgnoreIsa", 0)) {
// Indicate ISA bustype.
IN ULONG VendorID;
IN ULONG DeviceID;
IN ULONG SlotNumber;
+ IN ULONG HwFlags;
ULONG val = Default;
VendorID = deviceExtension->DevID & 0xffff;
DeviceID = (deviceExtension->DevID >> 16) & 0xffff;
SlotNumber = deviceExtension->slotNumber;
+ HwFlags = deviceExtension->HwFlags;
} else {
VendorID = 0xffff;
DeviceID = 0xffff;
SlotNumber = 0xffffffff;
+ HwFlags = 0;
}
val = AtapiRegCheckDevLunValue(
HwDeviceExtension, L"Parameters", chan, dev, Name, val);
if(deviceExtension) {
+
+ if(HwFlags & UNIATA_SATA) {
+ swprintf(namev, L"\\SATA");
+ swprintf(namex, L"Parameters%s", namev);
+ val = AtapiRegCheckDevLunValue(
+ HwDeviceExtension, namex, chan, dev, Name, val);
+ }
+ if(HwFlags & UNIATA_AHCI) {
+ swprintf(namev, L"\\AHCI");
+ swprintf(namex, L"Parameters%s", namev);
+ val = AtapiRegCheckDevLunValue(
+ HwDeviceExtension, namex, chan, dev, Name, val);
+ }
+ if(!(HwFlags & (UNIATA_SATA | UNIATA_AHCI))) {
+ swprintf(namev, L"\\PATA");
+ swprintf(namex, L"Parameters%s", namev);
+ val = AtapiRegCheckDevLunValue(
+ HwDeviceExtension, namex, chan, dev, Name, val);
+ }
+
if(deviceExtension->AdapterInterfaceType == PCIBus) {
// PCI
swprintf(namev, L"\\IDE_%d", deviceExtension->DevIndex);
UNICODE_STRING paramPath;
+ if(g_Dump) {
+ goto failed;
+ }
+
// <SavedRegPath>\<PathSuffix> -> <Name>
// KdPrint(( "AtapiCheckRegValue: %ws -> %ws\n", PathSuffix, Name));
// KdPrint(( "AtapiCheckRegValue: RegistryPath %ws\n", RegistryPath->Buffer));
ExFreePool(paramPath.Buffer);
if(!NT_SUCCESS(status)) {
+failed:
doRun = Default;
}