/*++
-Copyright (c) 2002-2011 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:
Some parts of code were taken from FreeBSD 4.3-6.1 ATA driver by
Søren Schmidt, Copyright (c) 1998-2007
- All parts of code are greatly changed/updated by
- Alter, Copyright (c) 2002-2007:
+ All parts of code are significantly changed/updated by
+ Alter, Copyright (c) 2002-2014:
1. Internal command queueing/reordering
2. Drive identification
5. W2k support (binary compatibility)
6. HDD hot swap under NT4
7. XP support (binary compatibility)
- 8. Serial ATA (SATA/SATA2) support
+ 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
-BOOLEAN g_opt_AtapiSendDisableIntr = 1; // 0
+ULONG g_opt_WaitBusyLongCount = 2000; // 2000
+ULONG g_opt_WaitBusyLongDelay = 250; // 250
+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;
IN ULONG lChannel
);
+VOID
+NTAPI
+UniataUserDeviceReset(
+ PHW_DEVICE_EXTENSION deviceExtension,
+ PHW_LU_EXTENSION LunExt,
+ ULONG lChannel
+ );
+
#define RESET_COMPLETE_CURRENT 0x00
#define RESET_COMPLETE_ALL 0x01
#define RESET_COMPLETE_NONE 0x02
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; \
} \
UCHAR statusByte;
ULONG i;
+ // Assume, proper drive is already seleted
WaitOnBusyLong(chan);
for (i = 0; i < 0x10000; i++) {
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(
{
ULONG i;
UCHAR Status;
- for (i=0; i<200; i++) {
- GetStatus(chan, Status);
+
+ GetStatus(chan, Status);
+ for (i=0; i<g_opt_WaitBusyCount; i++) {
if (Status & IDE_STATUS_BUSY) {
- AtapiStallExecution(10);
+ AtapiStallExecution(g_opt_WaitBusyDelay);
+ GetStatus(chan, Status);
continue;
} else {
break;
Status = WaitOnBusy(chan);
if(!(Status & IDE_STATUS_BUSY))
return Status;
- for (i=0; i<2000; i++) {
+ for (i=0; i<g_opt_WaitBusyLongCount; i++) {
GetStatus(chan, Status);
if (Status & IDE_STATUS_BUSY) {
- AtapiStallExecution(250);
+ AtapiStallExecution(g_opt_WaitBusyLongDelay);
continue;
} else {
break;
)
{
ULONG i;
- UCHAR Status = 0xff;
+ UCHAR Status = IDE_STATUS_WRONG;
for (i=0; i<g_opt_WaitBusyCount; i++) {
GetBaseStatus(chan, Status);
if (Status & IDE_STATUS_BUSY) {
{
UCHAR Status2;
- if(Status == 0xff) {
- return 0xff;
+ if(Status == IDE_STATUS_WRONG) {
+ return IDE_STATUS_WRONG;
}
if(Status & IDE_STATUS_BUSY) {
return Status;
for (i=0; i<20000; i++) {
GetStatus(chan, Status);
Status2 = UniataIsIdle(chan->DeviceExtension, Status);
- if(Status2 == 0xff) {
+ if(Status2 == IDE_STATUS_WRONG) {
// no drive ?
break;
} else
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);
GetBaseStatus(chan, statusByte2);
KdPrint2((PRINT_PREFIX " statusByte2 %x:\n", statusByte2));
SelectDrive(chan, DeviceNumber);
- AtapiStallExecution(500);
- AtapiWritePort1(chan, IDX_IO1_o_Command, IDE_COMMAND_ATAPI_RESET);
-
- // ReactOS modification: Already stop looping when we know that the drive has finished resetting.
- // Not all controllers clear the IDE_STATUS_BUSY flag (e.g. not the VMware one), so ensure that
- // the maximum waiting time (30 * i = 0.9 seconds) does not exceed the one of the original
- // implementation. (which is around 1 second)
- while ((AtapiReadPort1(chan, IDX_IO1_i_Status) & IDE_STATUS_BUSY) &&
- i--)
- {
- AtapiStallExecution(30);
+ 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(!(statusByte0 & IDE_STATUS_BUSY)) {
+ // Wait for BUSY assertion, in some cases delay may occure
+ // 100ms should be enough
+ 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);
+ }
+ }
+
+ i = 30 * 1000;
+ // ReactOS modification: Already stop looping when we know that the drive has finished resetting.
+ // Not all controllers clear the IDE_STATUS_BUSY flag (e.g. not the VMware one), so ensure that
+ // the maximum waiting time (30 * i = 0.9 seconds) does not exceed the one of the original
+ // implementation. (which is around 1 second)
+ while ((AtapiReadPort1(chan, IDX_IO1_i_Status) & IDE_STATUS_BUSY) &&
+ i--)
+ {
+ 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
IN ULONGLONG lba,
IN USHORT count,
IN USHORT feature,
- IN ULONG flags
+ IN ULONG wait_flags
)
{
- PHW_CHANNEL chan = &deviceExtension->chan[lChannel];
+ PHW_CHANNEL chan = &(deviceExtension->chan[lChannel]);
UCHAR statusByte;
ULONG i;
PUCHAR plba;
deviceExtension->DevIndex, deviceExtension->Channel, DeviceNumber, command, lba, count, feature ));
if(deviceExtension->HwFlags & UNIATA_AHCI) {
- PIDE_AHCI_CMD AHCI_CMD = &(chan->AhciCtlBlock->cmd);
+ //PIDE_AHCI_CMD AHCI_CMD = &(chan->AhciCtlBlock->cmd);
KdPrint3((" (ahci)\n"));
- RtlZeroMemory(AHCI_CMD->cfis, sizeof(AHCI_CMD->cfis));
+ statusByte = UniataAhciSendPIOCommand(deviceExtension, lChannel, DeviceNumber,
+ (PSCSI_REQUEST_BLOCK)NULL,
+ NULL,
+ 0,
+ command,
+ lba, count,
+ feature,
+ 0 /* ahci flags */ ,
+ wait_flags,
+ 1000 /* timeout 1 sec */
+ );
- if(!UniataAhciSetupFIS_H2D(deviceExtension, DeviceNumber, lChannel,
- &(AHCI_CMD->cfis[0]),
- command,
- lba,
- count,
- feature,
- ATA_IMMEDIATE
- )) {
- return 0xff;
- }
- if(UniataAhciSendCommand(deviceExtension, lChannel, DeviceNumber, 0, 3000) == 0xff) {
- KdPrint2((" timeout\n"));
- return 0xff;
- }
- return IDE_STATUS_IDLE;
+ return statusByte;
}
SelectDrive(chan, DeviceNumber);
// and not cleared after SELECT
//>>>>>> NV: 2006/08/03
- if((AtaCommandFlags[command] & ATA_CMD_FLAG_LBAIOsupp) &&
+ if(((AtaCommandFlags[command] & (ATA_CMD_FLAG_LBAIOsupp|ATA_CMD_FLAG_FUA)) == ATA_CMD_FLAG_LBAIOsupp) &&
CheckIfBadBlock(chan->lun[DeviceNumber], lba, count)) {
KdPrint3((PRINT_PREFIX ": artificial bad block, lba %#I64x count %#x\n", lba, count));
return IDE_STATUS_ERROR;
// write command code to device
AtapiWritePort1(chan, IDX_IO1_o_Command, command);
- switch (flags) {
+ switch (wait_flags) {
case ATA_WAIT_INTR:
// caller requested wait for interrupt
GetStatus(chan, statusByte);
statusByte = UniataIsIdle(deviceExtension, statusByte);
- if(statusByte == 0xff) {
+ if(statusByte == IDE_STATUS_WRONG) {
// no drive ?
break;
} else
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));
}
- chan->ExpectingInterrupt = TRUE;
+ 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()
IN UCHAR sector,
IN UCHAR count,
IN UCHAR feature,
- IN ULONG flags
+ IN ULONG wait_flags
)
{
if(!(deviceExtension->HwFlags & UNIATA_AHCI)) {
return AtaCommand48(deviceExtension, DeviceNumber, lChannel,
command,
(ULONG)sector | ((ULONG)cylinder << 8) | ((ULONG)(head & 0x0f) << 24),
- count, feature, flags);
+ count, feature, wait_flags);
} else {
- PHW_CHANNEL chan = &deviceExtension->chan[lChannel];
- PIDE_AHCI_CMD AHCI_CMD = &(chan->AhciCtlBlock->cmd);
-
- KdPrint3(("AtaCommand(ahci)\n"));
+ return UniataAhciSendPIOCommand(deviceExtension, lChannel, DeviceNumber,
+ (PSCSI_REQUEST_BLOCK)NULL,
+ NULL,
+ 0,
+ command,
+ (ULONG)sector | ((ULONG)cylinder << 8) | ((ULONG)(head & 0x0f) << 24),
+ count,
+ feature,
+ 0 /* ahci flags */ ,
+ wait_flags,
+ 1000 /* timeout 1 sec */
+ );
- RtlZeroMemory(AHCI_CMD->cfis, sizeof(AHCI_CMD->cfis));
-
- if(!UniataAhciSetupFIS_H2D(deviceExtension, DeviceNumber, lChannel,
- &(AHCI_CMD->cfis[0]),
- command,
- (ULONG)sector | ((ULONG)cylinder << 8) | ((ULONG)(head & 0x0f) << 24),
- count,
- feature,
- ATA_IMMEDIATE
- )) {
- return 0xff;
- }
- if(UniataAhciSendCommand(deviceExtension, lChannel, DeviceNumber, 0, 3000) == 0xff) {
- KdPrint2((" timeout\n"));
- return 0xff;
- }
- return IDE_STATUS_IDLE;
}
} // end AtaCommand()
return 1;
if (ident->PioCycleTimingMode == 0)
return 0;
- return -1;
+ return IOMODE_NOT_SPECIFIED;
} // end AtaPioMode()
LONG
return 1;
if (ident->MultiWordDMASupport & 0x01)
return 0;
- return -1;
+ return IOMODE_NOT_SPECIFIED;
} // end AtaWmode()
LONG
AtaUmode(PIDENTIFY_DATA2 ident)
{
if (!ident->UdmaModesValid)
- return -1;
+ return IOMODE_NOT_SPECIFIED;
if (ident->UltraDMASupport & 0x40)
return 6;
if (ident->UltraDMASupport & 0x20)
return 1;
if (ident->UltraDMASupport & 0x01)
return 0;
- return -1;
+ return IOMODE_NOT_SPECIFIED;
} // end AtaUmode()
+LONG
+NTAPI
+AtaSAmode(PIDENTIFY_DATA2 ident) {
+ if(!ident->SataCapabilities ||
+ ident->SataCapabilities == 0xffff) {
+ return IOMODE_NOT_SPECIFIED;
+ }
+ if(ident->SataCapabilities & ATA_SATA_GEN3) {
+ return ATA_SA600;
+ } else
+ if(ident->SataCapabilities & ATA_SATA_GEN2) {
+ return ATA_SA300;
+ } else
+ if(ident->SataCapabilities & ATA_SATA_GEN1) {
+ return ATA_SA150;
+ }
+ return IOMODE_NOT_SPECIFIED;
+} // end AtaSAmode()
#ifndef UNIATA_CORE
KdPrint2((PRINT_PREFIX "AtapiTimerDpc: no items\n"));
return;
}
- chan = &deviceExtension->chan[lChannel];
+ chan = &(deviceExtension->chan[lChannel]);
while(TRUE) {
/*
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
chan = prev_chan = NULL;
while(i != CHAN_NOT_SPECIFIED) {
prev_chan = chan;
- chan = &deviceExtension->chan[i];
+ chan = &(deviceExtension->chan[i]);
if(chan->DpcTime > time.QuadPart) {
break;
}
i = chan->NextDpcChan;
}
- chan = &deviceExtension->chan[lChannel];
+ chan = &(deviceExtension->chan[lChannel]);
if(!prev_chan) {
deviceExtension->FirstDpcChan = lChannel;
} else {
#endif //UNIATA_CORE
+#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 //_DEBUG
+
+VOID
+NTAPI
+UniataSnapAtaRegs(
+ IN PHW_CHANNEL chan,
+ IN ULONG DeviceNumber,
+ IN OUT PIDEREGS_EX regs
+ )
+{
+ if(chan->DeviceExtension->HwFlags & UNIATA_AHCI) {
+ // AHCI
+ UniataAhciSnapAtaRegs(chan, DeviceNumber, regs);
+ } else {
+ // SATA/PATA, assume drive is selected
+ ULONG j;
+ UCHAR statusByteAlt;
+
+ if((regs->bOpFlags & ATA_FLAGS_48BIT_COMMAND) == 0) {
+ for(j=IDX_IO1_i_Error; j<=IDX_IO1_i_Status; j++) {
+ statusByteAlt = AtapiReadPort1(chan, IDX_IO1+j);
+ ((PUCHAR)regs)[j-1] = statusByteAlt;
+ }
+ regs->bOpFlags = 0;
+ } else {
+ regs->bDriveHeadReg = AtapiReadPort1(chan, IDX_IO1_i_DriveSelect);
+ for(j=IDX_IO1_i_Error; j<IDX_IO1_i_DriveSelect; j++) {
+ statusByteAlt = AtapiReadPort1(chan, IDX_IO1+j);
+ ((PUCHAR)regs)[j-1] = statusByteAlt;
+ statusByteAlt = AtapiReadPort1(chan, IDX_IO1+j);
+ ((PUCHAR)regs)[j+8-1] = statusByteAlt;
+ }
+ regs->bCommandReg = AtapiReadPort1(chan, IDX_IO1_i_Status);
+ }
+ }
+ return;
+} // end UniataSnapAtaRegs()
/*++
)
{
PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
- PHW_CHANNEL chan = &deviceExtension->chan[lChannel];
+ PHW_CHANNEL chan = &(deviceExtension->chan[lChannel]);
ULONG waitCount = 50000;
ULONG j;
UCHAR statusByte;
- UCHAR statusByte2;
+ //UCHAR statusByte2;
UCHAR signatureLow,
signatureHigh;
BOOLEAN atapiDev = FALSE;
+ BOOLEAN use_ahci = FALSE;
PHW_LU_EXTENSION LunExt = chan->lun[DeviceNumber];
+ use_ahci = UniataIsSATARangeAvailable(deviceExtension, lChannel) &&
+ (deviceExtension->HwFlags & UNIATA_AHCI);
+
if(chan->ChannelCtrlFlags & CTRFLAGS_AHCI_PM) {
if(chan->PmLunMap & (1 << DeviceNumber)) {
// OK
return FALSE;
}
- if(deviceExtension->HwFlags & UNIATA_AHCI) {
+ if(use_ahci) {
statusByte = WaitOnBusyLong(chan);
+#ifdef _DEBUG
+ if(!chan->AhciInternalAtaReq) {
+ KdPrint2((PRINT_PREFIX "!AhciInternalAtaReq\n"));
+ }
+#endif
} else {
SelectDrive(chan, DeviceNumber);
AtapiStallExecution(10);
statusByte = WaitOnBusyLong(chan);
// Check that the status register makes sense.
- GetBaseStatus(chan, statusByte2);
-
- UniataDumpATARegs(chan);
+ GetBaseStatus(chan, statusByte);
+ /*
+ // unnecessary
+ if(!hasPCI) {
+ // original atapi.sys behavior for old ISA-only hardware
+ AtapiStallExecution(100);
+ }
+ */
}
if (Command == IDE_COMMAND_IDENTIFY) {
// Wait for Busy to drop.
AtapiStallExecution(100);
GetStatus(chan, statusByte);
+ if(statusByte == IDE_STATUS_WRONG) {
+ KdPrint2((PRINT_PREFIX "IssueIdentify: IDE_STATUS_WRONG (dev %d)\n", DeviceNumber));
+ return FALSE;
+ }
} while ((statusByte & IDE_STATUS_BUSY) && waitCount--);
- GetBaseStatus(chan, statusByte2);
+ GetBaseStatus(chan, statusByte);
SelectDrive(chan, DeviceNumber);
} else {
- GetBaseStatus(chan, statusByte2);
+ GetBaseStatus(chan, statusByte);
}
// Another check for signature, to deal with one model Atapi that doesn't assert signature after
// a soft reset.
}
} else {
KdPrint2((PRINT_PREFIX "IssueIdentify: Checking for ATAPI. Status (%#x)\n", statusByte));
+ if(statusByte == IDE_STATUS_WRONG) {
+ return FALSE;
+ }
//if(!(deviceExtension->HwFlags & UNIATA_SATA)) {
if(!UniataIsSATARangeAvailable(deviceExtension, lChannel)) {
statusByte = WaitForIdleLong(chan);
}
// if(deviceExtension->HwFlags & UNIATA_SATA) {
+ if(use_ahci) {
+ statusByte = UniataAhciSendPIOCommand(HwDeviceExtension, lChannel, DeviceNumber,
+ (PSCSI_REQUEST_BLOCK)NULL,
+ (PUCHAR)(&deviceExtension->FullIdentifyData),
+ DEV_BSIZE,
+ Command,
+ 0, 0,
+ 0,
+ 0 /* ahci flags */ ,
+ ATA_WAIT_INTR,
+ 1000 /* timeout 1 sec */
+ );
+ j = 9; // AHCI is rather different, skip loop at all
+ } else
+ if(LunExt->DeviceFlags & DFLAGS_MANUAL_CHS) {
+ j = 9; // don't send IDENTIFY, assume it is not supported
+ KdPrint2((PRINT_PREFIX "IssueIdentify: Manual CHS\n"));
+ RtlZeroMemory(&(deviceExtension->FullIdentifyData), sizeof(deviceExtension->FullIdentifyData));
+ RtlCopyMemory(&(deviceExtension->FullIdentifyData), &(LunExt->IdentifyData), sizeof(LunExt->IdentifyData));
+ } else
if(UniataIsSATARangeAvailable(deviceExtension, lChannel)) {
j = 4; // skip old-style checks
} else {
}
for (; j < 4*2; j++) {
// Send IDENTIFY command.
- statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel, Command, 0, 0, 0, (j >= 4) ? 0x200 : 0, 0, ATA_WAIT_INTR);
+
+ // Load CylinderHigh and CylinderLow with number bytes to transfer for old devices, use 0 for newer.
+
+ 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));
break;
}
}
- // Device didn't respond correctly. It will be given one more chances.
+ // Device didn't respond correctly. It will be given one more chance.
KdPrint2((PRINT_PREFIX "IssueIdentify: DRQ never asserted (%#x). Error reg (%#x)\n",
statusByte, AtapiReadPort1(chan, IDX_IO1_i_Error)));
GetBaseStatus(chan, statusByte);
return FALSE;
}
- KdPrint2((PRINT_PREFIX "IssueIdentify: Status before read words %#x\n", statusByte));
- // Suck out 256 words. After waiting for one model that asserts busy
- // after receiving the Packet Identify command.
- statusByte = WaitForDrq(chan);
- statusByte = WaitOnBusyLong(chan);
- KdPrint2((PRINT_PREFIX "IssueIdentify: statusByte %#x\n", statusByte));
+ if(use_ahci) {
+ // everything should already be done by controller
+ } else
+ if(LunExt->DeviceFlags & DFLAGS_MANUAL_CHS) {
+ j = 9; // don't send IDENTIFY, assume it is not supported
+ KdPrint2((PRINT_PREFIX "IssueIdentify: Manual CHS (2)\n"));
+ statusByte = WaitForDrq(chan);
+ statusByte = WaitOnBusyLong(chan);
+ KdPrint2((PRINT_PREFIX "IssueIdentify: statusByte %#x\n", statusByte));
+ GetBaseStatus(chan, statusByte);
+ } else {
- if (!(statusByte & IDE_STATUS_DRQ)) {
- KdPrint2((PRINT_PREFIX "IssueIdentify: !IDE_STATUS_DRQ (2) (%#x)\n", statusByte));
+ KdPrint2((PRINT_PREFIX "IssueIdentify: Status before read words %#x\n", statusByte));
+ // Suck out 256 words. After waiting for one model that asserts busy
+ // after receiving the Packet Identify command.
+ statusByte = WaitForDrq(chan);
+ statusByte = WaitOnBusyLong(chan);
+ KdPrint2((PRINT_PREFIX "IssueIdentify: statusByte %#x\n", statusByte));
+
+ if (!(statusByte & IDE_STATUS_DRQ)) {
+ KdPrint2((PRINT_PREFIX "IssueIdentify: !IDE_STATUS_DRQ (2) (%#x)\n", statusByte));
+ GetBaseStatus(chan, statusByte);
+ return FALSE;
+ }
GetBaseStatus(chan, statusByte);
- return FALSE;
- }
- GetBaseStatus(chan, statusByte);
- KdPrint2((PRINT_PREFIX "IssueIdentify: BASE statusByte %#x\n", statusByte));
+ KdPrint2((PRINT_PREFIX "IssueIdentify: BASE statusByte %#x\n", statusByte));
- if (atapiDev || !(LunExt->DeviceFlags & DFLAGS_DWORDIO_ENABLED) /*!deviceExtension->DWordIO*/) {
+#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));
- KdPrint2((PRINT_PREFIX " use 16bit IO\n"));
-#if 0
- USHORT w;
- ULONG i;
- // 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 the way you see below.
- KdPrint2((PRINT_PREFIX
- " IO_%#x (%#x), %s:\n",
- IDX_IO1_i_Data,
- chan->RegTranslation[IDX_IO1_i_Data].Addr,
- chan->RegTranslation[IDX_IO1_i_Data].MemIo ? "Mem" : "IO"));
- for(i=0; i<256; i++) {
-/*
- KdPrint2((PRINT_PREFIX
- " IO_%#x (%#x):\n",
- IDX_IO1_i_Data,
- chan->RegTranslation[IDX_IO1_i_Data].Addr));
-*/
- w = AtapiReadPort2(chan, IDX_IO1_i_Data);
- KdPrint2((PRINT_PREFIX
- " %x\n", w));
- AtapiStallExecution(1);
- ((PUSHORT)&deviceExtension->FullIdentifyData)[i] = w;
}
-#else
- ReadBuffer(chan, (PUSHORT)&deviceExtension->FullIdentifyData, 256, PIO0_TIMING);
-#endif
- // Work around for some IDE and one model Atapi that will present more than
- // 256 bytes for the Identify data.
- KdPrint2((PRINT_PREFIX "IssueIdentify: suck data port\n", statusByte));
- statusByte = AtapiSuckPort2(chan);
- } else {
- KdPrint2((PRINT_PREFIX " use 32bit IO\n"));
- ReadBuffer2(chan, (PUSHORT)&deviceExtension->FullIdentifyData, 256/2, PIO0_TIMING);
- }
+#endif //_DEBUG
- KdPrint2((PRINT_PREFIX "IssueIdentify: statusByte %#x\n", statusByte));
- statusByte = WaitForDrq(chan);
- KdPrint2((PRINT_PREFIX "IssueIdentify: statusByte %#x\n", statusByte));
- GetBaseStatus(chan, statusByte);
+ 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
+ // spacifying manual delay in the way you see below.
+ ReadBuffer(chan, (PUSHORT)&deviceExtension->FullIdentifyData, 256, PIO0_TIMING);
+
+ // Work around for some IDE and one model Atapi that will present more than
+ // 256 bytes for the Identify data.
+ KdPrint2((PRINT_PREFIX "IssueIdentify: suck data port\n", statusByte));
+ statusByte = AtapiSuckPort2(chan);
+ } else {
+ KdPrint2((PRINT_PREFIX " use 32bit IO\n"));
+ ReadBuffer2(chan, (PULONG)&deviceExtension->FullIdentifyData, 256/2, PIO0_TIMING);
+ }
+ KdPrint2((PRINT_PREFIX "IssueIdentify: statusByte %#x\n", statusByte));
+ statusByte = WaitForDrq(chan);
+ KdPrint2((PRINT_PREFIX "IssueIdentify: statusByte %#x\n", statusByte));
+ GetBaseStatus(chan, statusByte);
+ }
KdPrint2((PRINT_PREFIX "IssueIdentify: Status after read words %#x\n", statusByte));
if(NoSetup) {
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));
KdPrint2((PRINT_PREFIX "SWDMA: %x\n", deviceExtension->FullIdentifyData.SingleWordDMAActive));
KdPrint2((PRINT_PREFIX "MWDMA: %x\n", deviceExtension->FullIdentifyData.MultiWordDMAActive));
if(deviceExtension->FullIdentifyData.UdmaModesValid) {
- KdPrint2((PRINT_PREFIX "UDMA: %x\n", deviceExtension->FullIdentifyData.UltraDMAActive));
+ KdPrint2((PRINT_PREFIX "UDMA: %x/%x\n", deviceExtension->FullIdentifyData.UltraDMAActive, deviceExtension->FullIdentifyData.UltraDMASupport));
}
KdPrint2((PRINT_PREFIX "SATA: %x\n", deviceExtension->FullIdentifyData.SataEnable));
+ KdPrint2((PRINT_PREFIX "SATA support: %x, CAPs %#x\n",
+ deviceExtension->FullIdentifyData.SataSupport,
+ deviceExtension->FullIdentifyData.SataCapabilities));
+
+ LunExt->LimitedTransferMode =
+ LunExt->OrigTransferMode =
+ (UCHAR)ata_cur_mode_from_ident(&(deviceExtension->FullIdentifyData), IDENT_MODE_MAX);
+ LunExt->TransferMode =
+ (UCHAR)ata_cur_mode_from_ident(&(deviceExtension->FullIdentifyData), IDENT_MODE_ACTIVE);
+
+ KdPrint2((PRINT_PREFIX "OrigTransferMode: %x, Active: %x\n", LunExt->OrigTransferMode, LunExt->TransferMode));
+ KdPrint2((PRINT_PREFIX "Accoustic %d, cur %d\n",
+ deviceExtension->FullIdentifyData.VendorAcoustic,
+ deviceExtension->FullIdentifyData.CurrentAcoustic
+ ));
+ 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) {
deviceExtension->FullIdentifyData.RemovableStatus));
LunExt->DeviceFlags |= DFLAGS_REMOVABLE_DRIVE;
}
+ if(use_ahci) {
+ // AHCI doesn't recommend using PIO and multiblock
+ LunExt->MaximumBlockXfer = 0;
+ } else
if (deviceExtension->FullIdentifyData.MaximumBlockTransfer) {
// Determine max. block transfer for this device.
LunExt->MaximumBlockXfer =
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"));
IDE_COMMAND_READ_NATIVE_SIZE48, 0, 0, 0, ATA_WAIT_READY);
if(!(statusByte & IDE_STATUS_ERROR)) {
- NativeNumOfSectors = (ULONG)AtapiReadPort1(chan, IDX_IO1_i_BlockNumber) |
- ((ULONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderLow) << 8) |
- ((ULONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh) << 16) ;
-
- AtapiWritePort1(chan, IDX_IO2_o_Control,
- IDE_DC_USE_HOB );
-
- KdPrint2((PRINT_PREFIX "Read high order bytes\n"));
- NativeNumOfSectors |=
- ((ULONG)AtapiReadPort1(chan, IDX_IO1_i_BlockNumber) << 24 );
- hNativeNumOfSectors=
- (ULONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderLow) |
- ((ULONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh) << 8) ;
- ((PULONG)&NativeNumOfSectors)[1] = hNativeNumOfSectors;
-
+ if(use_ahci) {
+ NativeNumOfSectors = chan->AhciInternalAtaReq->ahci.in_lba;
+ } else {
+ NativeNumOfSectors = (ULONG)AtapiReadPort1(chan, IDX_IO1_i_BlockNumber) |
+ ((ULONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderLow) << 8) |
+ ((ULONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh) << 16) ;
+
+ AtapiWritePort1(chan, IDX_IO2_o_Control,
+ IDE_DC_USE_HOB );
+
+ KdPrint2((PRINT_PREFIX "Read high order bytes\n"));
+ NativeNumOfSectors |=
+ (ULONG)((ULONG)AtapiReadPort1(chan, IDX_IO1_i_BlockNumber) << 24 );
+ hNativeNumOfSectors=
+ (ULONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderLow) |
+ ((ULONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh) << 8) ;
+ ((PULONG)&NativeNumOfSectors)[1] = hNativeNumOfSectors;
+ }
KdPrint2((PRINT_PREFIX "NativeNumOfSectors %#I64x\n", NativeNumOfSectors));
// Some drives report LBA48 capability while has capacity below 128Gb
IDE_COMMAND_READ_NATIVE_SIZE48, 0, 0, 0, ATA_WAIT_READY);
if(!(statusByte & IDE_STATUS_ERROR)) {
- NativeNumOfSectors = (ULONGLONG)AtapiReadPort1(chan, IDX_IO1_i_BlockNumber) |
+ if(use_ahci) {
+ NativeNumOfSectors = chan->AhciInternalAtaReq->ahci.in_lba;
+ } else {
+ NativeNumOfSectors = (ULONGLONG)AtapiReadPort1(chan, IDX_IO1_i_BlockNumber) |
((ULONGLONG)AtapiReadPort1(chan, IDX_IO1_i_BlockNumber) << 24) |
((ULONGLONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderLow) << 8 ) |
((ULONGLONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderLow) << 32) |
((ULONGLONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh) << 16) |
((ULONGLONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh) << 40)
;
+ }
}
if((NativeNumOfSectors & 0xffffff) == ((NativeNumOfSectors >> 24) & 0xffffff)) {
NumOfSectors = NativeNumOfSectors;
}
}
- }
+ } // !error
}
if(NumOfSectors < 0x2100000 /*&& NumOfSectors > 31*1000*1000*/) {
0, IDE_USE_LBA, 0, 0, 0, ATA_WAIT_READY);
if(!(statusByte & IDE_STATUS_ERROR)) {
- NativeNumOfSectors = (ULONG)AtapiReadPort1(chan, IDX_IO1_i_BlockNumber) |
- ((ULONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderLow) << 8) |
- ((ULONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh) << 16) |
- (((ULONG)AtapiReadPort1(chan, IDX_IO1_i_DriveSelect) & 0xf) << 24);
-
+ if(use_ahci) {
+ NativeNumOfSectors = chan->AhciInternalAtaReq->ahci.in_lba;
+ } else {
+ NativeNumOfSectors = (ULONG)AtapiReadPort1(chan, IDX_IO1_i_BlockNumber) |
+ ((ULONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderLow) << 8) |
+ ((ULONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh) << 16) |
+ (((ULONG)AtapiReadPort1(chan, IDX_IO1_i_DriveSelect) & 0xf) << 24);
+ }
KdPrint2((PRINT_PREFIX "NativeNumOfSectors %#I64x\n", NativeNumOfSectors));
if(NativeNumOfSectors > NumOfSectors) {
}
}
+ 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
}
}
}
- KdPrint2((PRINT_PREFIX "final LunExt->opt_GeomType=%x\n", LunExt->opt_GeomType));
+
+ 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.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"));
}
PHW_LU_EXTENSION LunExt
)
{
+ // keep only DFLAGS_HIDDEN flag
LunExt->DeviceFlags &= DFLAGS_HIDDEN;
+ LunExt->AtapiReadyWaitDelay = 0;
} // end UniataForgetDevice()
Routine Description:
Reset IDE controller and/or Atapi device.
+ ->HwResetBus
Arguments:
HwDeviceExtension - HBA miniport driver's adapter data storage
IN ULONG PathId
)
{
- KdPrint2((PRINT_PREFIX "AtapiResetController()\n"));
+ KdPrint2((PRINT_PREFIX "AtapiResetController(%x)\n", PathId));
return AtapiResetController__(HwDeviceExtension, PathId, RESET_COMPLETE_ALL);
} // end AtapiResetController()
-
BOOLEAN
NTAPI
AtapiResetController__(
//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, 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));
- chan = &deviceExtension->chan[j];
- KdPrint2((PRINT_PREFIX " CompleteType %#x\n", CompleteType));
- //MaxLuns = (chan->ChannelCtrlFlags & CTRFLAGS_NO_SLAVE) ? 1 : 2;
+ KdPrint2((PRINT_PREFIX "AtapiResetController: Reset lchannel %d[%d]\n", j, deviceExtension->Channel));
+ chan = &(deviceExtension->chan[j]);
MaxLuns = chan->NumberLuns;
+ // 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);
- KdPrint2((PRINT_PREFIX "AtapiResetController: pending SRB %#x\n", CurSrb));
+ 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));
AtaReq->Srb = AtaReq->OriginalSrb;
+ CurSrb->SrbExtension = NULL;
AtaReq->OriginalSrb = NULL;
// NOTE: internal SRB doesn't get to SRB queue !!!
CurSrb = AtaReq->Srb;
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, 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;
AtaReq->TransferLength = 0;
+ KdPrint2((PRINT_PREFIX "chan %#x\n", chan));
ScsiPortNotification(RequestComplete,
deviceExtension,
// 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.
- chan->ExpectingInterrupt = FALSE;
+ UniataExpectChannelInterrupt(chan, FALSE);
chan->RDP = FALSE;
- chan->ChannelCtrlFlags = 0;
+ chan->ChannelCtrlFlags = ChannelCtrlFlags & CTRFLAGS_PERMANENT;
InterlockedExchange(&(chan->CheckIntr),
CHECK_INTR_IDLE);
+ for (i = 0; i < MaxLuns; i++) {
+ chan->lun[i]->PowerState = 0;
+ }
// Reset controller
if(ChipFlags & UNIATA_AHCI) {
KdPrint2((PRINT_PREFIX " AHCI path\n"));
- UniataAhciReset(HwDeviceExtension, j);
+ if(UniataAhciChanImplemented(deviceExtension, j)) {
+#ifdef _DEBUG
+ UniataDumpAhciPortRegs(chan);
+#endif
+ AtapiDisableInterrupts(deviceExtension, j);
+ UniataAhciReset(HwDeviceExtension, j);
+ } else {
+ KdPrint2((PRINT_PREFIX " skip not implemented\n"));
+ continue;
+ }
} else {
- KdPrint2((PRINT_PREFIX " ATA path\n"));
+ KdPrint2((PRINT_PREFIX " ATA path, chan %#x\n", chan));
KdPrint2((PRINT_PREFIX " disable intr (0)\n"));
AtapiDisableInterrupts(deviceExtension, j);
KdPrint2((PRINT_PREFIX " done\n"));
switch(VendorID) {
case ATA_INTEL_ID: {
ULONG mask;
+ ULONG pshift;
ULONG timeout;
- if(!(ChipFlags & UNIATA_SATA))
+ if(!(ChipFlags & UNIATA_SATA)) {
goto default_reset;
+ }
if(!UniataIsSATARangeAvailable(deviceExtension, j)) {
goto default_reset;
}
#else
mask = 1 << chan->lun[0]->SATA_lun_map;
if (MaxLuns > 1) {
- mask |= (1 << chan->lun[1]->SATA_lun_map);
+ mask |= (1 << chan->lun[1]->SATA_lun_map);
}
#endif
ChangePciConfig2(0x92, a & ~mask);
timeout = 100;
/* Wait up to 1 sec for "connect well". */
- if (ChipFlags & (I6CH | I6CH2))
- mask = mask << 8;
- else
- mask = mask << 4;
-
+ if (ChipFlags & (I6CH | I6CH2)) {
+ pshift = 8;
+ } else {
+ pshift = 4;
+ }
while (timeout--) {
- AtapiStallExecution(10000);
GetPciConfig2(0x92, tmp16);
- if ((tmp16 & mask) == mask) {
- AtapiStallExecution(10000);
- break;
+ if (((tmp16 >> pshift) & mask) == mask) {
+ GetBaseStatus(chan, statusByte);
+ if(statusByte != IDE_STATUS_WRONG) {
+ break;
+ }
}
+ 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;
// all these shall be performed inside AtapiHwInitialize__() ?
#if 1
- KdPrint2((PRINT_PREFIX " process connected devices\n"));
+ KdPrint2((PRINT_PREFIX " process connected devices 0 - %d\n", MaxLuns-1));
// Do special processing for ATAPI and IDE disk devices.
for (i = 0; i < MaxLuns; i++) {
// Check if device present.
+ KdPrint2((PRINT_PREFIX " Chan %#x\n", chan));
+ KdPrint2((PRINT_PREFIX " Lun %#x\n", i));
+ KdPrint2((PRINT_PREFIX " Lun ptr %#x\n", chan->lun[i]));
if (!(chan->lun[i]->DeviceFlags & DFLAGS_DEVICE_PRESENT)) {
if(ChipFlags & UNIATA_AHCI) {
// everything is done in UniataAhciReset()
if(!IssueIdentify(HwDeviceExtension,
i, j,
- (chan->lun[i]->DeviceFlags & DFLAGS_ATAPI_DEVICE) ?
+ ATAPI_DEVICE(chan, i) ?
IDE_COMMAND_ATAPI_IDENTIFY : IDE_COMMAND_IDENTIFY,
FALSE)) {
KdPrint2((PRINT_PREFIX " identify failed !\n"));
AtapiStallExecution(10);
statusByte = WaitOnBusyLong(chan);
statusByte = UniataIsIdle(deviceExtension, statusByte);
- if(statusByte == 0xff) {
+ if(statusByte == IDE_STATUS_WRONG) {
KdPrint2((PRINT_PREFIX
"no drive, status %#x\n",
statusByte));
UniataForgetDevice(chan->lun[i]);
} else
// Check for ATAPI disk.
- if (chan->lun[i]->DeviceFlags & DFLAGS_ATAPI_DEVICE) {
+ if (ATAPI_DEVICE(chan, i)) {
// Issue soft reset and issue identify.
GetStatus(chan, statusByte);
KdPrint2((PRINT_PREFIX "AtapiResetController: Status before Atapi reset (%#x).\n",
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
- // Enable interrupts, note, the we can have here recursive disable
+ // Enable interrupts, note, we can have here recursive disable
AtapiStallExecution(10);
KdPrint2((PRINT_PREFIX "AtapiResetController: deviceExtension->chan[%d].DisableIntr %d -> 1\n",
j,
ULONG lChannel = GET_CHANNEL(Srb);
PHW_CHANNEL chan = &(deviceExtension->chan[lChannel]);
// ULONG i;
- UCHAR errorByte;
+ UCHAR errorByte = 0;
UCHAR srbStatus = SRB_STATUS_SUCCESS;
UCHAR scsiStatus;
ULONG DeviceNumber = GET_CDEV(Srb);
// Read the error register.
- errorByte = AtapiReadPort1(chan, IDX_IO1_i_Error);
+ if(deviceExtension->HwFlags & UNIATA_AHCI) {
+ PATA_REQ AtaReq = (PATA_REQ)(Srb->SrbExtension);
+ if(AtaReq) {
+ errorByte = AtaReq->ahci.in_error;
+ } else {
+ }
+ } else {
+ errorByte = AtapiReadPort1(chan, IDX_IO1_i_Error);
+ }
KdPrint2((PRINT_PREFIX
"MapError: Error register is %#x\n",
errorByte));
UCHAR statusByte;
if (LunExt->DeviceFlags & DFLAGS_DEVICE_PRESENT &&
- !(LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE)) {
+ !(LunExt->DeviceFlags & (DFLAGS_ATAPI_DEVICE | DFLAGS_MANUAL_CHS))) {
statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel, IDE_COMMAND_SET_MULTIPLE, 0, 0, 0, 0, 0, ATA_WAIT_BASE_READY);
Arguments:
HwDeviceExtension - HBA miniport driver's adapter data storage
+ ->HwInitialize
Return Value:
TRUE - if initialization successful.
if(WinVer_WDM_Model) {
AtapiResetController__(HwDeviceExtension, CHAN_NOT_SPECIFIED, RESET_COMPLETE_ALL);
}
+ if(deviceExtension->MasterDev) {
+ KdPrint2((PRINT_PREFIX " mark chan %d of master controller [%x] as inited\n",
+ deviceExtension->Channel, deviceExtension->DevIndex));
+ BMList[deviceExtension->DevIndex].ChanInitOk |= 0x01 << deviceExtension->Channel;
+ }
/* do extra chipset specific setups */
AtapiChipInit(HwDeviceExtension, DEVNUM_NOT_SPECIFIED, CHAN_NOT_SPECIFIED);
// ULONG tmp32;
ULONG PreferedMode = 0xffffffff;
+ if((deviceExtension->HwFlags & UNIATA_AHCI) &&
+ !UniataAhciChanImplemented(deviceExtension, lChannel)) {
+ return;
+ }
+
AtapiChipInit(deviceExtension, DEVNUM_NOT_SPECIFIED, lChannel);
FindDevices(deviceExtension, 0, lChannel);
AtapiDisableInterrupts(deviceExtension, lChannel);
AtapiStallExecution(1);
- if (!(LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE)) {
+ if (!(LunExt->DeviceFlags & (DFLAGS_ATAPI_DEVICE | DFLAGS_MANUAL_CHS))) {
KdPrint2((PRINT_PREFIX "AtapiHwInitialize: IDE branch\n"));
// Enable media status notification
statusByte = AtaCommand(deviceExtension, i, lChannel,
IDE_COMMAND_SET_MULTIPLE, 0, 0, 0,
- LunExt->MaximumBlockXfer, 0, ATA_WAIT_BASE_READY);
+ 0, 0, ATA_WAIT_BASE_READY);
if (statusByte & IDE_STATUS_ERROR) {
// Read the error register.
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
+ 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 {
+ 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 ||*/
+ LunExt->IdentifyData.FeaturesSupport.APM) {
+
+ if(LunExt->opt_AdvPowerMode) {
+ KdPrint2((PRINT_PREFIX " Try Enable Adv. Power Mgmt\n"));
+ // setup APM
+ statusByte = AtaCommand(deviceExtension, i, lChannel,
+ IDE_COMMAND_SET_FEATURES, 0, 0, 0,
+ LunExt->opt_AdvPowerMode, ATA_C_F_ENAB_APM, ATA_WAIT_BASE_READY);
+ // Check for errors.
+ if (statusByte & IDE_STATUS_ERROR) {
+ KdPrint2((PRINT_PREFIX
+ "AtapiHwInitialize: Enable APM on Device %d failed\n",
+ i));
+ }
+ } else {
+ KdPrint2((PRINT_PREFIX " Disable Adv. Power Mgmt\n"));
+ statusByte = AtaCommand(deviceExtension, i, lChannel,
+ IDE_COMMAND_SET_FEATURES, 0, 0, 0,
+ 0, ATA_C_F_DIS_APM, ATA_WAIT_BASE_READY);
+ }
+ }
+ if(LunExt->IdentifyData.FeaturesSupport.AutoAcoustic) {
+ if(LunExt->opt_AcousticMode) {
+ KdPrint2((PRINT_PREFIX " Try Enable Acoustic Mgmt\n"));
+ // setup acoustic mgmt
+ statusByte = AtaCommand(deviceExtension, i, lChannel,
+ IDE_COMMAND_SET_FEATURES, 0, 0, 0,
+ LunExt->opt_AcousticMode, ATA_C_F_ENAB_ACOUSTIC, ATA_WAIT_BASE_READY);
+ // Check for errors.
+ if (statusByte & IDE_STATUS_ERROR) {
+ KdPrint2((PRINT_PREFIX
+ "AtapiHwInitialize: Enable Acoustic Mgmt on Device %d failed\n",
+ i));
+ }
+ } else {
+ KdPrint2((PRINT_PREFIX " Disable Acoustic Mgmt\n"));
+ statusByte = AtaCommand(deviceExtension, i, lChannel,
+ IDE_COMMAND_SET_FEATURES, 0, 0, 0,
+ 0, ATA_C_F_DIS_ACOUSTIC, ATA_WAIT_BASE_READY);
+ }
+ }
+ if(LunExt->IdentifyData.FeaturesSupport.Standby) {
+ KdPrint2((PRINT_PREFIX " Try init standby timer: %d\n"));
+ // setup standby timer
statusByte = AtaCommand(deviceExtension, i, lChannel,
- IDE_COMMAND_SET_FEATURES, 0, 0, 0,
- 0, ATA_C_F_ENAB_WCACHE, ATA_WAIT_BASE_READY);
+ IDE_COMMAND_IDLE, 0, 0, 0,
+ LunExt->opt_StandbyTimer, 0, ATA_WAIT_BASE_READY);
// Check for errors.
if (statusByte & IDE_STATUS_ERROR) {
KdPrint2((PRINT_PREFIX
- "AtapiHwInitialize: Enable write cacheing on Device %d failed\n",
+ "AtapiHwInitialize: standby timer on Device %d failed\n",
i));
- LunExt->DeviceFlags &= ~DFLAGS_WCACHE_ENABLED;
- } else {
- 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_ENAB_WCACHE, ATA_WAIT_BASE_READY);
- LunExt->DeviceFlags &= ~DFLAGS_WCACHE_ENABLED;
}
}
} else if (!(LunExt->DeviceFlags & DFLAGS_CHANGER_INITED)){
ULONG j;
- BOOLEAN isSanyo = FALSE;
+ //BOOLEAN isSanyo = FALSE;
CCHAR vendorId[26];
KdPrint2((PRINT_PREFIX "AtapiHwInitialize: ATAPI/Changer branch\n"));
// acting like 1) a multi-lun device and 2) building the 'special' TUR's.
LunExt->DeviceFlags |= (DFLAGS_CHANGER_INITED | DFLAGS_SANYO_ATAPI_CHANGER);
LunExt->DiscsPresent = 3;
- isSanyo = TRUE;
+ //isSanyo = TRUE;
}
}
}
PreferedMode = LunExt->opt_MaxTransferMode;
- if(PreferedMode == 0xffffffff) {
+ if((PreferedMode == 0xffffffff) || (PreferedMode > chan->MaxTransferMode)) {
KdPrint2((PRINT_PREFIX "MaxTransferMode (overriden): %#x\n", chan->MaxTransferMode));
PreferedMode = chan->MaxTransferMode;
}
}
KdPrint2((PRINT_PREFIX " try mode %#x\n", PreferedMode));
- LunExt->OrigTransferMode =
LunExt->LimitedTransferMode =
LunExt->TransferMode =
(CHAR)PreferedMode;
AtapiDmaInit__(deviceExtension, LunExt);
- LunExt->OrigTransferMode =
LunExt->LimitedTransferMode =
LunExt->TransferMode;
KdPrint2((PRINT_PREFIX "Using %#x mode\n", LunExt->TransferMode));
// 10000 * 100us = 1000,000us = 1000ms = 1s
waitCount = 10000;
GetStatus(chan, statusByte);
+ if(statusByte == IDE_STATUS_WRONG) {
+ waitCount = 0;
+ }
while ((statusByte & IDE_STATUS_BUSY) && waitCount) {
- KdPrint2((PRINT_PREFIX "Wait for ATAPI (status %x\n)", statusByte));
+ KdPrint2((PRINT_PREFIX "Wait for ATAPI (status %x)\n", statusByte));
// Wait for Busy to drop.
AtapiStallExecution(100);
GetStatus(chan, statusByte);
}
// 5000 * 100us = 500,000us = 500ms = 0.5s
- waitCount = 5000;
- do {
- AtapiStallExecution(100);
- } while (waitCount--);
+ if(statusByte != IDE_STATUS_WRONG) {
+ waitCount = 5000;
+ do {
+ AtapiStallExecution(100);
+ } while (waitCount--);
+ }
}
GetBaseStatus(chan, statusByte);
AtapiEnableInterrupts(deviceExtension, lChannel);
return;
-} // end AtapiHwInitialize()
+} // end AtapiHwInitialize__()
#ifndef UNIATA_CORE
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]));
}
// Check other channel
// In simplex mode no interrupts must appear on other channels
- for(_c=0; _c<deviceExtension->NumberChannels-1; _c++) {
+ for(_c=0; _c<deviceExtension->NumberChannels; _c++) {
c = (_c+deviceExtension->FirstChannelToCheck) % deviceExtension->NumberChannels;
+ if(c == lChannel) {
+ continue;
+ }
+
chan = &(deviceExtension->chan[c]);
if((ULONG)CrNtInterlockedCompareExchange(CRNT_ILK_PTYPE &(chan->CheckIntr),
)
{
AtapiCallBack__(HwDeviceExtension, (UCHAR)((PHW_DEVICE_EXTENSION)HwDeviceExtension)->ActiveDpcChan);
-}
+} // end AtapiCallBack_X()
#endif //UNIATA_CORE
ULONG c_state;
ULONG i_res = 0;
ULONG pass;
- BOOLEAN checked[AHCI_MAX_PORT];
+ //BOOLEAN checked[AHCI_MAX_PORT];
ULONG hIS;
+ ULONG checked;
- KdPrint2((PRINT_PREFIX "Intr: VendorID+DeviceID/Rev %#x/%#x\n", deviceExtension->DevID, deviceExtension->RevID));
+ KdPrint2((PRINT_PREFIX "Intr: DeviceID+VendorID/Rev %#x/%#x (ex %d)\n",
+ deviceExtension->DevID, deviceExtension->RevID, deviceExtension->ExpectingInterrupt ));
if(deviceExtension->HwFlags & UNIATA_AHCI) {
+ // AHCI may generate state change notification, never skip this check
hIS = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_IS);
- KdPrint2((PRINT_PREFIX "AtapiInterrupt2: AHCI: hIS=%x cntrlr %#x chan %#x\n",hIS, deviceExtension->DevIndex, deviceExtension->Channel));
+ KdPrint2((PRINT_PREFIX "AtapiInterrupt(base): AHCI: hIS=%x cntrlr %#x chan %#x\n",hIS, deviceExtension->DevIndex, deviceExtension->Channel));
if(!hIS) {
return FALSE;
}
+ // assume all non-interrupted ports to be already checked
+ checked = ~hIS;
+ // assume all not implemented ports to be already checked
+ checked |= ~deviceExtension->AHCI_PI;
+ } else {
+ checked = 0; // assume all ports are not checked
}
- for(_c=0; _c<deviceExtension->NumberChannels; _c++) {
- checked[_c] = FALSE;
+ if(!deviceExtension->ExpectingInterrupt) {
+ // if we do not expect interrupt, exit now,
+ // but keep in mind that it can be unexpected one
+ // Note: this is just a hint, not exact counter
+ KdPrint2((PRINT_PREFIX "unexpected, 1st chance\n"));
+ //deviceExtension->ExpectingInterrupt++;
+ //return FALSE;
}
+ // clear this flag now, it can be set again in sub-calls
+ deviceExtension->ExpectingInterrupt=0;
+
+
+// for(_c=0; _c<deviceExtension->NumberChannels; _c++) {
+// checked[_c] = (UCHAR)((hIS >> _c) & 0x01);
+// }
// fc =
for(pass=0; pass<2; pass++) {
+ //KdPrint2((PRINT_PREFIX "AtapiInterrupt(base): pass %d\n", pass));
+ if(status && pass) {
+ // we catched some expected interrupts now.
+ // do not touch unexpected until next ISR call
+ break;
+ }
for(_c=0; _c<deviceExtension->NumberChannels; _c++) {
c = (_c+deviceExtension->FirstChannelToCheck) % deviceExtension->NumberChannels;
- if(checked[c])
+ if((checked>>c) & 0x01)
continue;
// check non-empty and expecting interrupt channels first
if(!pass && !deviceExtension->chan[c].ExpectingInterrupt)
continue;
- checked[c] = TRUE;
+ checked |= (ULONG)1 << c;
KdPrint2((PRINT_PREFIX "AtapiInterrupt(base): cntrlr %#x chan %#x\n",deviceExtension->DevIndex, c));
if(CrNtInterlockedExchangeAdd(&(deviceExtension->chan[c].DisableIntr), 0)) {
+ // we get here on idle channels or when ISR is posted to DPC
KdPrint2((PRINT_PREFIX "AtapiInterrupt(base): disabled INTR on ch %d\n", c));
continue;
}
if(i_res == INTERRUPT_REASON_UNEXPECTED) {
KdPrint2((PRINT_PREFIX "AtapiInterrupt(base): Catch unexpected\n"));
InterlockedExchange(&(deviceExtension->chan[c].CheckIntr), CHECK_INTR_IDLE);
- return TRUE;
+ //return TRUE;
+ status = TRUE;
+ continue;
}
// disable interrupts on other channel of legacy mode
// ISA-bridged onboard controller
IN PVOID Isr2HwDeviceExtension
)
{
+ // This ISR is intended to catch interrupts when we are already in other ISR instance
+ // for the same device. This may happen when we have multiple channels,
+ // especially on SMP machines
PISR2_DEVICE_EXTENSION Isr2DeviceExtension = (PISR2_DEVICE_EXTENSION)Isr2HwDeviceExtension;
PHW_DEVICE_EXTENSION deviceExtension = Isr2DeviceExtension->HwDeviceExtension;
ULONG c_count = 0;
ULONG i_res;
ULONG hIS;
+ ULONG checked;
// we should never get here for ISA/MCA
if(!BMList[deviceExtension->DevIndex].Isr2Enable) {
}
if(deviceExtension->HwFlags & UNIATA_AHCI) {
+ // AHCI may generate state change notification, never skip this check
hIS = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_IS);
KdPrint2((PRINT_PREFIX "AtapiInterrupt2: AHCI: hIS=%x cntrlr %#x chan %#x\n",hIS, deviceExtension->DevIndex, deviceExtension->Channel));
if(!hIS) {
return FALSE;
}
+ // assume all non-interrupted ports to be already checked
+ checked = ~hIS;
+ // assume all not implemented ports to be already checked
+ checked |= ~deviceExtension->AHCI_PI;
+
+ } else {
+ checked = 0; // assume all ports are not checked
+ }
+ if(!deviceExtension->ExpectingInterrupt) {
+ KdPrint2((PRINT_PREFIX "AtapiInterrupt2: !deviceExtension->ExpectingInterrupt\n"));
+ deviceExtension->ExpectingInterrupt++;
+ return FALSE;
}
+ //deviceExtension->ExpectingInterrupt = 0;
for(c=0; c<deviceExtension->NumberChannels; c++) {
KdPrint2((PRINT_PREFIX "AtapiInterrupt2: cntrlr %#x chan %#x\n",deviceExtension->DevIndex, c));
+ if((checked>>c) & 0x01)
+ continue;
+
+ checked |= (ULONG)1 << c;
+
if(CrNtInterlockedExchangeAdd(&(deviceExtension->chan[c].DisableIntr), 0)) {
KdPrint2((PRINT_PREFIX "AtapiInterrupt2: disabled INTR\n"));
continue;
{
PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
PHW_CHANNEL chan;
+ //UCHAR statusByte;
+
if(c >= deviceExtension->NumberChannels) {
KdPrint2((PRINT_PREFIX "AtapiEnableInterrupts_%d: WRONG CHANNEL\n",c));
return;
}
+ if((deviceExtension->HwFlags & UNIATA_AHCI) &&
+ !UniataAhciChanImplemented(deviceExtension, c)) {
+ KdPrint2((PRINT_PREFIX "AtapiEnableInterrupts_%d: not imp. CHANNEL\n",c));
+ return;
+ }
+
chan = &(deviceExtension->chan[c]);
KdPrint2((PRINT_PREFIX "AtapiEnableInterrupts_%d: %d\n",c, chan->DisableIntr));
if(!InterlockedDecrement(&chan->DisableIntr)) {
if(deviceExtension->HwFlags & UNIATA_AHCI) {
- UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_IE, 0);
+ UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_IE,
+ (ATA_AHCI_P_IX_CPD | ATA_AHCI_P_IX_TFE | ATA_AHCI_P_IX_HBF |
+ ATA_AHCI_P_IX_HBD | ATA_AHCI_P_IX_INF | ATA_AHCI_P_IX_IF | ATA_AHCI_P_IX_OF |
+ ((/*ch->pm_level == */0) ? ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC : 0) |
+ ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC | /* DEBUG */
+ ATA_AHCI_P_IX_DI |
+ ATA_AHCI_P_IX_DP | ATA_AHCI_P_IX_UF | ATA_AHCI_P_IX_SDB |
+ ATA_AHCI_P_IX_DS | ATA_AHCI_P_IX_PS | ATA_AHCI_P_IX_DHR)
+ );
} else {
+ //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);
+ // AtapiWritePort1(chan, IDX_IO2_o_Control,
+ // IDE_DC_A_4BIT );
+ // SelectDrive(chan, chan->cur_cdev);
+ //}
}
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()
// mark channel as busy
if(InterlockedIncrement(&chan->DisableIntr)) {
if(deviceExtension->HwFlags & UNIATA_AHCI) {
- UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_IE,
- (ATA_AHCI_P_IX_CPD | ATA_AHCI_P_IX_TFE | ATA_AHCI_P_IX_HBF |
- ATA_AHCI_P_IX_HBD | ATA_AHCI_P_IX_IF | ATA_AHCI_P_IX_OF |
- ((/*ch->pm_level == */0) ? ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC : 0) |
- ATA_AHCI_P_IX_DP | ATA_AHCI_P_IX_UF | ATA_AHCI_P_IX_SDB |
- ATA_AHCI_P_IX_DS | ATA_AHCI_P_IX_PS | ATA_AHCI_P_IX_DHR)
- );
+ UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_IE, 0);
} else {
+ //SelectDrive(chan, 0);
AtapiWritePort1(chan, IDX_IO2_o_Control,
IDE_DC_DISABLE_INTERRUPTS /*| IDE_DC_A_4BIT*/ );
+ //if(chan->NumberLuns) {
+ // SelectDrive(chan, 1);
+ // AtapiWritePort1(chan, IDX_IO2_o_Control,
+ // IDE_DC_DISABLE_INTERRUPTS /*| IDE_DC_A_4BIT*/ );
+ // SelectDrive(chan, chan->cur_cdev);
+ //}
}
chan->ChannelCtrlFlags |= CTRFLAGS_INTR_DISABLED;
}
return;
} // end AtapiDisableInterrupts()
+VOID
+UniataExpectChannelInterrupt(
+ IN struct _HW_CHANNEL* chan,
+ IN BOOLEAN Expecting
+ )
+{
+ chan->ExpectingInterrupt = Expecting;
+ if(Expecting) {
+ chan->DeviceExtension->ExpectingInterrupt++;
+ } else
+ if(chan->DeviceExtension->ExpectingInterrupt) {
+ chan->DeviceExtension->ExpectingInterrupt--;
+ }
+ return;
+} // end UniataExpectChannelInterrupt()
/*
Check hardware for interrupt state
UCHAR dma_status = 0;
UCHAR reg8 = 0;
ULONG reg32 = 0;
- UCHAR statusByte;
+ UCHAR statusByte = 0;
ULONG slotNumber = deviceExtension->slotNumber;
ULONG SystemIoBusNumber = deviceExtension->SystemIoBusNumber;
ULONG ChipFlags = deviceExtension->HwFlags & CHIPFLAG_MASK;
UCHAR lChannel;
BOOLEAN DmaTransfer = FALSE;
BOOLEAN OurInterrupt = FALSE;
+ BOOLEAN StatusValid = FALSE;
// ULONG k;
UCHAR interruptReason;
BOOLEAN EarlyIntr = FALSE;
+ BOOLEAN SingleBlockIntr = FALSE;
KdPrint2((PRINT_PREFIX "AtapiCheckInterrupt__:\n"));
lChannel = c;
Channel = (UCHAR)(deviceExtension->Channel + lChannel);
+ LunExt = chan->lun[chan->cur_cdev];
+
+ //KdPrint2((PRINT_PREFIX "AtapiCheckInterrupt__ chan %#x:\n", chan));
+ //KdPrint2((PRINT_PREFIX "AtapiCheckInterrupt__ (%d/%d):\n", Channel, chan->cur_cdev));
if((ChipFlags & UNIATA_AHCI) &&
UniataIsSATARangeAvailable(deviceExtension, lChannel)) {
- OurInterrupt = UniataAhciStatus(HwDeviceExtension, lChannel, -1);
+
+ if(!UniataAhciChanImplemented(deviceExtension, lChannel)) {
+ return OurInterrupt;
+ }
+
+ OurInterrupt = UniataAhciStatus(HwDeviceExtension, lChannel, DEVNUM_NOT_SPECIFIED);
+ if((OurInterrupt == INTERRUPT_REASON_UNEXPECTED) &&
+ (LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE)) {
+ UniataAhciWaitCommandReady(chan, 2 /* ms */ );
+ statusByte = (UCHAR)UniataAhciWaitReady(chan, 0 /* immediate */);
+ if(!(statusByte & (IDE_STATUS_BUSY)) ) {
+ KdPrint2((PRINT_PREFIX "ATAPI special case READY\n"));
+ //deviceExtension->ExpectingInterrupt++; // will be updated in ISR on ReturnEnableInterrupts
+ OurInterrupt = INTERRUPT_REASON_OUR;
+ } else
+ if((statusByte & (IDE_STATUS_BUSY | IDE_STATUS_DRDY)) == (IDE_STATUS_BUSY | IDE_STATUS_DRDY) ) {
+ KdPrint2((PRINT_PREFIX "ATAPI special case pre ERR-READY\n"));
+ OurInterrupt = INTERRUPT_REASON_OUR;
+ } else
+ if(statusByte & IDE_STATUS_ERROR) {
+ KdPrint2((PRINT_PREFIX "ATAPI special case ERR-READY\n"));
+ OurInterrupt = INTERRUPT_REASON_OUR;
+ } else {
+ KdPrint2((PRINT_PREFIX "ATAPI special case ? %x\n", statusByte));
+ OurInterrupt = INTERRUPT_REASON_OUR;
+ }
+ }
return OurInterrupt;
}
return INTERRUPT_REASON_IGNORE;
}
break;
- case PRMIO:
- status = AtapiReadPortEx4(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressBM_0),0x0040);
- if(ChipFlags & PRSATA) {
- pr_status = AtapiReadPortEx4(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressBM_0),0x006c);
- AtapiWritePortEx4(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressBM_0),0x006c, pr_status & 0x000000ff);
+ case PRMIO: {
+ ULONG stat_reg = (ChipFlags & PRG2) ? 0x60 : 0x6c;
+ status = AtapiReadPortEx4(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressBM_0),0x40);
+ AtapiWritePortEx4(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressBM_0),0x40, status);
+
+ if(status & (1 << (Channel+1))) {
+ // our
+ } else {
+ KdPrint2((PRINT_PREFIX " Promise mio unexpected\n"));
+ return INTERRUPT_REASON_IGNORE;
}
+
+ if(!(ChipFlags & UNIATA_SATA))
+ break;
+
+ pr_status = AtapiReadPortEx4(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressBM_0),stat_reg);
+ AtapiWritePortEx4(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressBM_0),stat_reg, (pr_status & (0x11 << Channel)));
if(pr_status & (0x11 << Channel)) {
// TODO: reset channel
KdPrint2((PRINT_PREFIX " Promise mio unexpected + reset req\n"));
- return INTERRUPT_REASON_IGNORE;
+ UniataSataEvent(deviceExtension, lChannel, UNIATA_SATA_EVENT_DETACH, 0);
}
if(!(status & (0x01 << Channel))) {
- KdPrint2((PRINT_PREFIX " Promise mio unexpected\n"));
+ // Connect event
+ KdPrint2((PRINT_PREFIX " Promise mio unexpected attach\n"));
+ UniataSataEvent(deviceExtension, lChannel, UNIATA_SATA_EVENT_ATTACH, 0);
+ }
+ if(UniataSataClearErr(HwDeviceExtension, c, UNIATA_SATA_DO_CONNECT, 0)) {
+ OurInterrupt = INTERRUPT_REASON_UNEXPECTED;
+ } else {
return INTERRUPT_REASON_IGNORE;
}
+
AtapiWritePort4(chan, IDX_BM_DeviceSpecific0, 0x00000001);
- break;
+ break; }
}
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)) ) {
} else {
KdPrint2((PRINT_PREFIX " getting status...\n"));
GetStatus(chan, statusByte);
+ StatusValid = 1;
KdPrint2((PRINT_PREFIX " status %#x\n", statusByte));
if(statusByte & IDE_STATUS_ERROR) {
KdPrint2((PRINT_PREFIX " IDE_STATUS_ERROR -> our\n", statusByte));
OurInterrupt = INTERRUPT_REASON_UNEXPECTED;
+ } else
+ if ((statusByte & IDE_STATUS_DSC) &&
+ (LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) &&
+ (dma_status == BM_STATUS_ACTIVE)) {
+ KdPrint2((PRINT_PREFIX " special case DMA + ATAPI + IDE_STATUS_DSC -> our\n", statusByte));
+ // some devices interrupts on each block transfer even in DMA mode
+ if(LunExt->TransferMode >= ATA_SDMA && LunExt->TransferMode <= ATA_WDMA2) {
+ KdPrint2((PRINT_PREFIX " wait for completion\n"));
+ ///* clear interrupt and get status */
+ //GetBaseStatus(chan, statusByte);
+ //return INTERRUPT_REASON_IGNORE;
+ SingleBlockIntr = TRUE;
+ }
} else {
return INTERRUPT_REASON_IGNORE;
}
}
}
skip_dma_stat_check:
- if(!(ChipFlags & UNIATA_SATA)) {
+ if(!(ChipFlags & UNIATA_SATA) && chan->ExpectingInterrupt) {
AtapiStallExecution(1);
}
- LunExt = chan->lun[chan->cur_cdev];
/* if drive is busy it didn't interrupt */
/* the exception is DCS + BSY state of ATAPI devices */
- KdPrint2((PRINT_PREFIX " getting status...\n"));
- GetStatus(chan, statusByte);
+ if(!StatusValid) {
+ KdPrint2((PRINT_PREFIX " getting status...\n"));
+ GetStatus(chan, statusByte);
+ }
if(LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) {
KdPrint3((PRINT_PREFIX " ATAPI status %#x\n", statusByte));
} else {
KdPrint2((PRINT_PREFIX " IDE status %#x\n", statusByte));
}
- if (statusByte == 0xff) {
+ if (statusByte == IDE_STATUS_WRONG) {
// interrupt from empty controller ?
} else
if (statusByte & IDE_STATUS_BUSY) {
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;
}
KdPrint3((PRINT_PREFIX " our interrupt with BSY set, try wait in ISR or post to DPC\n"));
/* clear interrupt and get status */
GetBaseStatus(chan, statusByte);
+ if(!(dma_status & BM_STATUS_ACTIVE)) {
+ AtapiDmaDone(deviceExtension, DEVNUM_NOT_SPECIFIED ,lChannel, NULL);
+ }
KdPrint3((PRINT_PREFIX " base status %#x (+BM_STATUS_INTR)\n", statusByte));
return INTERRUPT_REASON_OUR;
}
/* clear interrupt and get status */
GetBaseStatus(chan, statusByte);
KdPrint2((PRINT_PREFIX " base status %#x\n", statusByte));
- if (statusByte == 0xff) {
+ if (statusByte == IDE_STATUS_WRONG) {
// interrupt from empty controller ?
} else
if(!(statusByte & (IDE_STATUS_DRQ | IDE_STATUS_DRDY))) {
#ifndef UNIATA_PIO_ONLY
if(DmaTransfer) {
- if(!EarlyIntr || g_WaitBusyInISR) {
+ if(!SingleBlockIntr && (!EarlyIntr || g_WaitBusyInISR)) {
dma_status = AtapiDmaDone(HwDeviceExtension, DEVNUM_NOT_SPECIFIED, lChannel, NULL/*srb*/);
} else {
PSCSI_REQUEST_BLOCK srb = UniataGetCurRequest(chan);
//ASSERT(AtaReq);
- KdPrint2((PRINT_PREFIX " set REQ_STATE_EARLY_INTR.\n"));
+ if(SingleBlockIntr) {
+ KdPrint2((PRINT_PREFIX " set REQ_STATE_ATAPI_EXPECTING_DATA_INTR2.\n"));
+ } else {
+ KdPrint2((PRINT_PREFIX " set REQ_STATE_EARLY_INTR.\n"));
+ }
if(AtaReq) {
- AtaReq->ReqState = REQ_STATE_EARLY_INTR;
+ AtaReq->ReqState = SingleBlockIntr ? REQ_STATE_ATAPI_EXPECTING_DATA_INTR2 : REQ_STATE_EARLY_INTR;
}
}
}
KdPrint2((PRINT_PREFIX " OurInterrupt = %d\n", OurInterrupt));
return OurInterrupt;
}
- interruptReason = (AtapiReadPort1(chan, IDX_ATAPI_IO1_i_InterruptReason) & 0x3);
+ interruptReason = (AtapiReadPort1(chan, IDX_ATAPI_IO1_i_InterruptReason) & ATAPI_IR_Mask);
KdPrint3((PRINT_PREFIX "AtapiCheckInterrupt__: ATAPI int reason %x\n", interruptReason));
return OurInterrupt;
}
BOOLEAN atapiDev = FALSE;
+#ifdef _DEBUG
UCHAR Channel;
+#endif //_DEBUG
UCHAR lChannel;
UCHAR DeviceNumber;
BOOLEAN DmaTransfer = FALSE;
UCHAR error = 0;
ULONG TimerValue = 1000;
+ ULONG TotalTimerValue = 0;
#ifdef UNIATA_USE_XXableInterrupts
BOOLEAN InDpc = (KeGetCurrentIrql() == DISPATCH_LEVEL);
#else
// BOOLEAN RestoreUseDpc = FALSE;
BOOLEAN DataOverrun = FALSE;
BOOLEAN NoStartIo = TRUE;
+ BOOLEAN NoRetry = FALSE;
KdPrint2((PRINT_PREFIX "AtapiInterrupt:\n"));
if(InDpc) {
PHW_LU_EXTENSION LunExt;
lChannel = c;
+
+#ifdef _DEBUG
Channel = (UCHAR)(deviceExtension->Channel + lChannel);
KdPrint2((PRINT_PREFIX " cntrlr %#x:%d, irql %#x, c %d\n", deviceExtension->DevIndex, Channel, KeGetCurrentIrql(), c));
+#endif //_DEBUG
if((chan->ChannelCtrlFlags & CTRFLAGS_DMA_ACTIVE) ||
- (AtaReq && (AtaReq->Flags & REQ_FLAG_DMA_OPERATION)) ) {
+ (AtaReq && (AtaReq->Flags & REQ_FLAG_DMA_OPERATION)) ||
+ (deviceExtension->HwFlags & UNIATA_AHCI)) {
DmaTransfer = TRUE;
KdPrint2((PRINT_PREFIX " DmaTransfer = TRUE\n"));
}
case REQ_STATE_ATAPI_EXPECTING_CMD_INTR:
KdPrint3((PRINT_PREFIX " EXPECTING_CMD_INTR\n"));
case REQ_STATE_ATAPI_EXPECTING_DATA_INTR:
+ case REQ_STATE_ATAPI_EXPECTING_DATA_INTR2:
case REQ_STATE_DPC_WAIT_BUSY0:
case REQ_STATE_DPC_WAIT_BUSY1:
KdPrint2((PRINT_PREFIX " continue service interrupt\n"));
return TRUE;
}
- if(!DmaTransfer && !atapiDev) {
+ if((!DmaTransfer && !atapiDev) || deviceExtension->DriverMustPoll) {
KdPrint2((PRINT_PREFIX " service PIO HDD\n"));
UseDpc = FALSE;
}
// disable interrupts for this channel,
// but avoid recursion and double-disable
if(OldReqState != REQ_STATE_DPC_WAIT_BUSY1) {
+ UniataExpectChannelInterrupt(chan, FALSE);
AtapiDisableInterrupts(deviceExtension, lChannel);
}
// go to ISR DPC
CallTimerDpc:
AtaReq->ReqState = REQ_STATE_PROCESSING_INTR;
CallTimerDpc2:
+ if(!InDpc && OldReqState != REQ_STATE_DPC_WAIT_BUSY1) {
+ // we must block interrupts from this channel
+ // If device generate new interrupt before we get to DPC,
+ // ISR will assume, that it is NOT our interrupt
+ AtapiDisableInterrupts(deviceExtension, lChannel);
+ // We should not clean ExpectingInterrupt flag on channel, since it is used in DPC
+ }
// Will raise IRQL to DIRQL
AtapiQueueTimerDpc(HwDeviceExtension, c,
AtapiCallBack_X,
AtapiStallExecution(10);
}
*/
- /* clear interrupt and get status */
+ /* clear interrupt and get status */
if(deviceExtension->HwFlags & UNIATA_AHCI) {
UniataAhciEndTransaction(HwDeviceExtension, lChannel, DeviceNumber, srb);
- statusByte = (UCHAR)(AtaReq->ahci.in_status & 0xff);
+ statusByte = (UCHAR)(AtaReq->ahci.in_status & IDE_STATUS_MASK);
+
+ if(chan->AhciLastIS & ~(ATA_AHCI_P_IX_DHR | ATA_AHCI_P_IX_PS | ATA_AHCI_P_IX_DS | ATA_AHCI_P_IX_SDB)) {
+ KdPrint3((PRINT_PREFIX "Err intr (%#x), SE (%#x)\n",
+ 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) {
+
+ 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
+#ifdef _DEBUG
+ UniataDumpAhciPortRegs(chan);
+#endif
+ if(!UniataAhciAbortOperation(chan)) {
+ KdPrint2((PRINT_PREFIX "need UniataAhciReset\n"));
+ }
+#ifdef _DEBUG
+ UniataDumpAhciPortRegs(chan);
+#endif
+ UniataAhciWaitCommandReady(chan, 10);
+ }
+ }
+
} else {
GetBaseStatus(chan, statusByte);
}
InDpc = TRUE;
}
- if(deviceExtension->HwFlags & UNIATA_AHCI) {
- KdPrint3((PRINT_PREFIX " AHCI branch\n"));
- } else
if (!atapiDev) {
// IDE
+ if(deviceExtension->HwFlags & UNIATA_AHCI) {
+ KdPrint3((PRINT_PREFIX " AHCI branch (IDE)\n"));
+ } else
if (statusByte & IDE_STATUS_BUSY) {
if (deviceExtension->DriverMustPoll) {
// Crashdump is polling and we got caught with busy asserted.
// ATAPI
if(!LunExt->IdentifyData.MajorRevision &&
InDpc &&
- !atapiDev &&
+ /*!atapiDev &&*/
!(deviceExtension->HwFlags & UNIATA_SATA)
) {
- KdPrint2((PRINT_PREFIX " additional delay 10us for old devices (2)\n"));
- AtapiStallExecution(10);
+ //KdPrint2((PRINT_PREFIX " additional delay 10us for old devices (2)\n"));
+ //AtapiStallExecution(10);
+ }
+ if(deviceExtension->HwFlags & UNIATA_AHCI) {
+ KdPrint3((PRINT_PREFIX " AHCI branch (ATAPI)\n"));
+ } else {
+ interruptReason = (AtapiReadPort1(chan, IDX_ATAPI_IO1_i_InterruptReason) & ATAPI_IR_Mask);
+ KdPrint3((PRINT_PREFIX "AtapiInterrupt: iReason %x\n", interruptReason));
}
+
if (statusByte & IDE_STATUS_BUSY) {
//if(chan->ChannelCtrlFlags & CTRFLAGS_DSC_BSY) {}
- KdPrint3((PRINT_PREFIX " BUSY on ATAPI device, waiting\n"));
+/*
+#ifndef UNIATA_CORE
+ // This is just workaround
+ // We should DISABLE interrupts before entering WAIT state
+ UniataExpectChannelInterrupt(chan, TRUE);
+#endif //UNIATA_CORE
+*/
+ KdPrint3((PRINT_PREFIX " BUSY on ATAPI device, waiting %d us\n", LunExt->AtapiReadyWaitDelay));
+#ifndef UNIATA_CORE
+ if(LunExt->AtapiReadyWaitDelay && (LunExt->AtapiReadyWaitDelay > g_opt_MaxIsrWait) && !InDpc && UseDpc) {
+ TimerValue = LunExt->AtapiReadyWaitDelay;
+ KdPrint2((PRINT_PREFIX " too long wait: ISR -> DPC (0)\n"));
+ AtaReq->ReqState = REQ_STATE_DPC_WAIT_BUSY0;
+ goto CallTimerDpc2;
+ }
+#endif //UNIATA_CORE
+ TimerValue = 10;
for(k=20; k; k--) {
- GetStatus(chan, statusByte);
+ GetBaseStatus(chan, statusByte);
KdPrint3((PRINT_PREFIX " status re-check %#x\n", statusByte));
KdPrint3((PRINT_PREFIX " Error reg (%#x)\n",
- AtapiReadPort1(chan, IDX_IO1_i_Error)));
+ AtapiReadPort1(chan, IDX_ATAPI_IO1_i_Error)));
if (!(statusByte & IDE_STATUS_BUSY)) {
KdPrint2((PRINT_PREFIX " expecting intr + cleared BUSY\n"));
break;
}
- if(k <= 18) {
+ TotalTimerValue += TimerValue;
+ if(k <= 1) {
KdPrint3((PRINT_PREFIX " too long wait -> DPC\n"));
if(!InDpc) {
KdPrint2((PRINT_PREFIX " too long wait: ISR -> DPC\n"));
AtaReq->ReqState = REQ_STATE_DPC_WAIT_BUSY1;
}
#ifndef UNIATA_CORE
- goto CallTimerDpc2;
-#else //UNIATA_CORE
- AtapiStallExecution(TimerValue);
+ if(UseDpc) {
+ if(!LunExt->AtapiReadyWaitDelay) {
+ LunExt->AtapiReadyWaitDelay = TotalTimerValue*2/3;
+ }
+ goto CallTimerDpc2;
+ }
#endif //UNIATA_CORE
}
- AtapiStallExecution(10);
+ AtapiStallExecution(TimerValue);
+ TimerValue += 10;
+ }
+ if(!LunExt->AtapiReadyWaitDelay) {
+ LunExt->AtapiReadyWaitDelay = TotalTimerValue*2/3;
+ KdPrint2((PRINT_PREFIX " store AtapiReadyWaitDelay: %d\n", LunExt->AtapiReadyWaitDelay));
}
if (statusByte & IDE_STATUS_BUSY) {
KdPrint3((PRINT_PREFIX " expecting intr + BUSY (2), try DPC wait\n"));
(dma_status & BM_STATUS_ERR)) {
if(deviceExtension->HwFlags & UNIATA_AHCI) {
- error = (UCHAR)((AtaReq->ahci.in_status >> 8) && 0xff);
+ error = AtaReq->ahci.in_error;
+ // wait ready
+#ifdef _DEBUG
+ UniataDumpAhciPortRegs(chan);
+#endif
+ if(!UniataAhciAbortOperation(chan)) {
+ KdPrint2((PRINT_PREFIX "need UniataAhciReset\n"));
+ }
+ // clear interrupts again
+ UniataAhciWaitCommandReady(chan, 10);
+#ifdef _DEBUG
+ UniataDumpAhciPortRegs(chan);
+#endif
+ UniataAhciStatus(HwDeviceExtension, lChannel, DEVNUM_NOT_SPECIFIED);
+ if(NoRetry) {
+ AtaReq->retry += MAX_RETRIES;
+ if(!error && (statusByte & IDE_STATUS_ERROR)) {
+ KdPrint2((PRINT_PREFIX "AtapiInterrupt: force error status\n"));
+ error |= IDE_STATUS_ERROR;
+ }
+ }
+#ifdef _DEBUG
+ UniataDumpAhciPortRegs(chan);
+#endif
} else {
error = AtapiReadPort1(chan, IDX_IO1_i_Error);
}
KdPrint2((PRINT_PREFIX " Bad Lba unknown\n"));
}
-
+ if(deviceExtension->HwFlags & UNIATA_AHCI) {
+ KdPrint2((PRINT_PREFIX " no wait ready after error\n"));
+ } else
if(!atapiDev) {
KdPrint2((PRINT_PREFIX " wait 100 ready after IDE error\n"));
AtapiStallExecution(100);
LunExt->DeviceFlags & DFLAGS_INT_DRQ));
for (k = atapiDev ? 0 : 200; k; k--) {
- GetStatus(chan, statusByte);
+ GetBaseStatus(chan, statusByte);
if (!(statusByte & IDE_STATUS_DRQ)) {
AtapiStallExecution(50);
} else {
#endif //IO_STATISTICS
if(DmaTransfer /*&&
(error & IDE_ERROR_ICRC)*/) {
+ KdPrint2((PRINT_PREFIX "Errors in DMA mode\n"));
if(AtaReq->retry < MAX_RETRIES) {
//fallback_pio:
- AtaReq->Flags &= ~REQ_FLAG_DMA_OPERATION;
- AtaReq->Flags |= REQ_FLAG_FORCE_DOWNRATE;
-// LunExt->DeviceFlags |= DFLAGS_FORCE_DOWNRATE;
+ if(!(deviceExtension->HwFlags & UNIATA_AHCI)) {
+ //AtaReq->Flags &= ~REQ_FLAG_DMA_OPERATION;
+ // Downrate will happen in AtapiDmaReinit(), try UDMA-2 for HDD only
+ AtaReq->Flags |= REQ_FLAG_FORCE_DOWNRATE;
+ }
AtaReq->ReqState = REQ_STATE_QUEUED;
goto reenqueue_req;
}
}
}
} else {
- interruptReason = (AtapiReadPort1(chan, IDX_ATAPI_IO1_i_InterruptReason) & 0x3);
+ 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;
KdPrint2((PRINT_PREFIX "Some higher mode doesn't work right :((\n"));
KdPrint2((PRINT_PREFIX "Recovery stats[%d]: %d vs %d\n",
AtaReq->retry,
- chan->lun[DeviceNumber]->RecoverCount[AtaReq->retry],
- chan->lun[DeviceNumber]->BlockIoCount
+ LunExt->RecoverCount[AtaReq->retry],
+ LunExt->BlockIoCount
));
- chan->lun[DeviceNumber]->RecoverCount[AtaReq->retry]++;
- if(chan->lun[DeviceNumber]->RecoverCount[AtaReq->retry] >= chan->lun[DeviceNumber]->BlockIoCount/3 ||
+ LunExt->RecoverCount[AtaReq->retry]++;
+ if(LunExt->RecoverCount[AtaReq->retry] >= LunExt->BlockIoCount/3 ||
(deviceExtension->HwFlags & UNIATA_NO80CHK)
) {
#else
if(deviceExtension->HwFlags & UNIATA_NO80CHK) {
#endif //IO_STATISTICS
- KdPrint2((PRINT_PREFIX "Limit transfer rate to %x\n", deviceExtension->lun[DeviceNumber].TransferMode));
- deviceExtension->lun[DeviceNumber].LimitedTransferMode =
- deviceExtension->lun[DeviceNumber].TransferMode;
+ KdPrint2((PRINT_PREFIX "Limit transfer rate to %x\n", LunExt->TransferMode));
+ LunExt->LimitedTransferMode =
+ LunExt->TransferMode;
}
}
#ifdef IO_STATISTICS
if(AtaReq->bcount) {
// we need stats for Read/Write operations
- chan->lun[DeviceNumber]->BlockIoCount++;
+ LunExt->BlockIoCount++;
}
- chan->lun[DeviceNumber]->IoCount++;
+ LunExt->IoCount++;
#endif //IO_STATISTICS
continue_PIO:
KdPrint2((PRINT_PREFIX "AtapiInterrupt: ATAPI branch\n"));
// ATAPI branch
- interruptReason = (AtapiReadPort1(chan, IDX_ATAPI_IO1_i_InterruptReason) & 0x3);
+ interruptReason = (AtapiReadPort1(chan, IDX_ATAPI_IO1_i_InterruptReason) & ATAPI_IR_Mask);
KdPrint3((PRINT_PREFIX "AtapiInterrupt: iReason %x\n", interruptReason));
if(DmaTransfer) {
wordsThisInterrupt = DEV_BSIZE/2*512;
if (srb->SrbFlags & SRB_FLAGS_DATA_IN) {
- interruptReason = 0x2;
+ interruptReason = ATAPI_IR_IO_toHost;
} else if (srb->SrbFlags & SRB_FLAGS_DATA_OUT) {
- interruptReason = 0x0;
+ interruptReason = ATAPI_IR_IO_toDev;
} else {
status = SRB_STATUS_ERROR;
} 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).
PIO_wait_DRQ0:
// The ISR hits with DRQ low, but comes up later.
for (k = 0; k < 5000; k++) {
- GetStatus(chan, statusByte);
+ GetBaseStatus(chan, statusByte);
if (statusByte & IDE_STATUS_DRQ) {
break;
}
goto ReturnEnableIntr;
} else {
- interruptReason = (srb->SrbFlags & SRB_FLAGS_DATA_IN) ? 0x2 : 0x0;
+ interruptReason = (srb->SrbFlags & SRB_FLAGS_DATA_IN) ? ATAPI_IR_IO_toHost : ATAPI_IR_IO_toDev;
}
} else {
// Command complete - verify, write, or the SMART enable/disable.
// Also get_media_status
- interruptReason = 0x3;
+ interruptReason = ATAPI_IR_IO_toHost | ATAPI_IR_COD_Cmd;
}
}
}
KdPrint2((PRINT_PREFIX "AtapiInterrupt: i-reason=%d, status=%#x\n", interruptReason, statusByte));
if(deviceExtension->HwFlags & UNIATA_AHCI) {
- KdPrint2((PRINT_PREFIX " AHCI path\n"));
- goto ReturnEnableIntr;
+ KdPrint2((PRINT_PREFIX " AHCI path, WordsTransfered %x, WordsLeft %x\n", AtaReq->WordsTransfered, AtaReq->WordsLeft));
+/* if(chan->AhciLastIS & ATA_AHCI_P_IX_OF) {
+ //status = SRB_STATUS_DATA_OVERRUN;
+ DataOverrun = TRUE;
+ } else {
+ status = SRB_STATUS_SUCCESS;
+ }*/
+ if(AtaReq->WordsTransfered >= AtaReq->WordsLeft) {
+ AtaReq->WordsLeft = 0;
+ } else {
+ AtaReq->WordsLeft -= AtaReq->WordsTransfered;
+ }
+ //if(AtaReq->WordsLeft && (status == SRB_STATUS_SUCCESS)) {
+ // status = SRB_STATUS_DATA_OVERRUN;
+ //}
+ status = SRB_STATUS_SUCCESS;
+ chan->ChannelCtrlFlags &= ~CTRFLAGS_DMA_OPERATION;
+ goto CompleteRequest;
} else
- if (interruptReason == 0x1 && (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, 6, 0);
+ WriteBuffer(chan, (PUSHORT)srb->Cdb,
+ LunExt->IdentifyData.AtapiCmdSize ? 8 : 6,
+ /*0*/ PIO0_TIMING);
AtaReq->ReqState = REQ_STATE_ATAPI_EXPECTING_DATA_INTR;
if(chan->ChannelCtrlFlags & CTRFLAGS_DMA_OPERATION) {
goto ReturnEnableIntr;
- } else if (interruptReason == 0x0 && (statusByte & IDE_STATUS_DRQ)) {
+ } else if ((interruptReason == ATAPI_IR_IO_toDev) && (statusByte & IDE_STATUS_DRQ)) {
// Write the data.
if (atapiDev) {
AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountLow);
wordCount |=
- AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountHigh) << 8;
+ (USHORT)AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountHigh) << 8;
// Covert bytes to words.
wordCount >>= 1;
}
}
- if (DmaTransfer && (chan->ChannelCtrlFlags & CTRFLAGS_DMA_OPERATION)) {
+ if (DmaTransfer &&
+ (chan->ChannelCtrlFlags & CTRFLAGS_DMA_OPERATION)) {
//ASSERT(AtaReq->WordsLeft == wordCount);
+ if(AtaReq->ReqState == REQ_STATE_ATAPI_EXPECTING_DATA_INTR2) {
+ KdPrint2((PRINT_PREFIX
+ "IdeIntr: DMA tmp INTR %#x vs %#x\n", AtaReq->WordsLeft, wordCount));
+ if(AtaReq->WordsLeft > wordCount) {
+ AtaReq->WordsLeft -= wordCount;
+ AtaReq->WordsTransfered += wordCount;
+ AtaReq->ReqState = REQ_STATE_ATAPI_EXPECTING_DATA_INTR;
+ goto ReturnEnableIntr;
+ }
+ dma_status = AtapiDmaDone(HwDeviceExtension, DEVNUM_NOT_SPECIFIED, lChannel, NULL/*srb*/);
+ }
+ AtaReq->WordsTransfered = AtaReq->WordsLeft;
AtaReq->WordsLeft = 0;
status = SRB_STATUS_SUCCESS;
chan->ChannelCtrlFlags &= ~CTRFLAGS_DMA_OPERATION;
goto CompleteRequest;
}
+
// Ensure that this is a write command.
if (srb->SrbFlags & SRB_FLAGS_DATA_OUT) {
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,
} else {
KdPrint3((PRINT_PREFIX
- "AtapiInterrupt: Int reason %#x, but srb is for a write %#x.\n",
+ "AtapiInterrupt: Int reason %#x, but srb is for a read %#x.\n",
interruptReason,
srb));
// Fail this request.
status = SRB_STATUS_ERROR;
- goto CompleteRequest;
- }
+ 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"));
- // Advance data buffer pointer and bytes left.
+ 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.
AtaReq->DataBuffer += wordCount;
AtaReq->WordsLeft -= wordCount;
+ AtaReq->WordsTransfered += wordCount;
if (atapiDev) {
AtaReq->ReqState = REQ_STATE_ATAPI_EXPECTING_DATA_INTR;
goto ReturnEnableIntr;
- } else if (interruptReason == 0x2 && (statusByte & IDE_STATUS_DRQ)) {
+ } 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);
-
- // Covert bytes to words.
- wordCount /= 2;
- KdPrint2((PRINT_PREFIX "AtapiInterrupt: get R wordCount %#x\n", wordCount));
+ (ULONG)AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountLow) |
+ ((ULONG)AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountHigh) << 8);
+ // Convert bytes to words.
+ 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",
}
}
- if (DmaTransfer && (chan->ChannelCtrlFlags & CTRFLAGS_DMA_OPERATION)) {
+ if(DmaTransfer &&
+ (chan->ChannelCtrlFlags & CTRFLAGS_DMA_OPERATION)) {
+ if(AtaReq->ReqState == REQ_STATE_ATAPI_EXPECTING_DATA_INTR2) {
+ KdPrint2((PRINT_PREFIX
+ "IdeIntr: DMA tmp INTR %#x vs %#x\n", AtaReq->WordsLeft, wordCount));
+ if(AtaReq->WordsLeft > wordCount) {
+ AtaReq->WordsLeft -= wordCount;
+ AtaReq->WordsTransfered += wordCount;
+ AtaReq->ReqState = REQ_STATE_ATAPI_EXPECTING_DATA_INTR;
+ goto ReturnEnableIntr;
+ }
+ dma_status = AtapiDmaDone(HwDeviceExtension, DEVNUM_NOT_SPECIFIED, lChannel, NULL/*srb*/);
+ }
//ASSERT(AtaReq->WordsLeft == wordCount);
+ AtaReq->WordsTransfered = AtaReq->WordsLeft;
AtaReq->WordsLeft = 0;
status = SRB_STATUS_SUCCESS;
chan->ChannelCtrlFlags &= ~CTRFLAGS_DMA_OPERATION;
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);
- }
+ }
- GetStatus(chan, statusByte);
- KdPrint2((PRINT_PREFIX " status re-check %#x\n", statusByte));
+ 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);
+ }
- if(DataOverrun) {
- KdPrint2((PRINT_PREFIX " DataOverrun\n"));
- AtapiSuckPort2(chan);
- }
+ GetBaseStatus(chan, statusByte);
+ KdPrint2((PRINT_PREFIX " status re-check %#x\n", statusByte));
- } else {
- KdPrint2((PRINT_PREFIX
- "IdeIntr: Read %#x Dwords\n", wordCount/2));
+ if(DataOverrun) {
+ KdPrint2((PRINT_PREFIX " DataOverrun\n"));
+ AtapiSuckPort2(chan);
+ GetBaseStatus(chan, statusByte);
+ }
- ReadBuffer2(chan,
- (PULONG)(AtaReq->DataBuffer),
- wordCount / 2,
- UniataGetPioTiming(LunExt));
+ if(statusByte & IDE_STATUS_BUSY) {
+ for (i = 0; i < 2; i++) {
+ AtapiStallExecution(10);
+ GetBaseStatus(chan, statusByte);
+ if (!(statusByte & IDE_STATUS_BUSY)) {
+ break;
+ }
+ }
}
+
} 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;
+ AtaReq->WordsTransfered += wordCount;
// Check for read command complete.
if (AtaReq->WordsLeft == 0) {
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) {
+ 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
+ // and all data read
+ // Optionally, we may receive COMPLETE interrupt later and
+ // treat it as unexpected
+ KdPrint2((PRINT_PREFIX "AtapiInterrupt: early complete ? status %x\n", statusByte));
- *((ULONG *) &(AtaReq->DataBuffer[2])) = 0x00080000;
- AtaReq->DataBuffer += wordCount;
+ status = SRB_STATUS_SUCCESS;
+ goto CompleteRequest;
}
+
} else {
/*
} else {
if (atapiDev) {
AtaReq->ReqState = REQ_STATE_ATAPI_EXPECTING_DATA_INTR;
+ GetStatus(chan, statusByte);
+ if(!(statusByte & IDE_STATUS_BUSY)) {
+ // Assume command is completed if BUSY is cleared
+ // even if NOT all data read
+ // Optionally, we may receive COMPLETE interrupt later and
+ // treat it as unexpected
+ KdPrint2((PRINT_PREFIX "AtapiInterrupt: early complete + underrun ? status %x\n", statusByte));
+
+ 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;
+ }
}
}
goto ReturnEnableIntr;
- } else if (interruptReason == 0x3 && !(statusByte & IDE_STATUS_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.
+ // Command complete. We exactly know this because of IReason.
+
if(DmaTransfer) {
KdPrint2((PRINT_PREFIX "AtapiInterrupt: CompleteRequest, was DmaTransfer\n"));
+ AtaReq->WordsTransfered += AtaReq->WordsLeft;
AtaReq->WordsLeft = 0;
- }
- if (AtaReq->WordsLeft) {
- status = SRB_STATUS_DATA_OVERRUN;
} else {
- status = SRB_STATUS_SUCCESS;
+ KdPrint2((PRINT_PREFIX "AtapiInterrupt: CompleteRequest, was PIO\n"));
+
+ wordCount = AtaReq->WordsLeft;
+ // Advance data buffer pointer and bytes left.
+ 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;
+ //} else {
+ status = SRB_STATUS_SUCCESS;
+ //}
#ifdef UNIATA_DUMP_ATAPI
if(srb &&
}
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,
CompleteRequest:
- KdPrint2((PRINT_PREFIX "AtapiInterrupt: CompleteRequest\n"));
+ KdPrint2((PRINT_PREFIX "AtapiInterrupt: CompleteRequest, srbstatus %x\n", status));
// Check and see if we are processing our secret (mechanism status/request sense) srb
+
+ if(AtaReq->WordsLeft && (status == SRB_STATUS_SUCCESS)) {
+ KdPrint2((PRINT_PREFIX "WordsLeft %#x -> SRB_STATUS_DATA_OVERRUN\n", AtaReq->WordsLeft));
+ status = SRB_STATUS_DATA_OVERRUN;
+ }
+
if (AtaReq->OriginalSrb) {
ULONG srbStatus;
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));
// The sense key doesn't say the last request is illegal, so try again
chan->MechStatusRetryCount--;
srb = AtaReq->Srb = BuildMechanismStatusSrb (
HwDeviceExtension,
AtaReq->OriginalSrb);
- } else {
-
- // last request was illegal. No point trying again
- 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"));
- AtapiHwInitializeChanger (HwDeviceExtension,
- srb,
- (PMECHANICAL_STATUS_INFORMATION_HEADER) NULL);
srb = AtaReq->Srb = AtaReq->OriginalSrb;
AtaReq->OriginalSrb = NULL;
}
KdPrint2((PRINT_PREFIX "AtapiInterrupt: PIO completion, wait BUSY\n"));
// Wait for busy to drop.
for (i = 0; i < 5*30; i++) {
- GetStatus(chan, statusByte);
+ GetBaseStatus(chan, statusByte);
if (!(statusByte & IDE_STATUS_BUSY)) {
break;
}
PIO_wait_DRQ:
KdPrint2((PRINT_PREFIX "AtapiInterrupt: PIO_wait_DRQ\n"));
for (i = 0; i < 200; i++) {
- GetStatus(chan, statusByte);
+ GetBaseStatus(chan, statusByte);
if (!(statusByte & IDE_STATUS_DRQ)) {
break;
}
}
// Clear interrupt expecting flag.
- chan->ExpectingInterrupt = FALSE;
+ UniataExpectChannelInterrupt(chan, FALSE);
+ // clear this flag now, it can be set again in sub-calls
InterlockedExchange(&(chan->CheckIntr),
CHECK_INTR_IDLE);
}
}
if(status == SRB_STATUS_SUCCESS) {
- AtaReq->WordsTransfered += AtaReq->bcount * DEV_BSIZE/2;
+ //if(!(deviceExtension->HwFlags & UNIATA_AHCI) && !atapiDev) {
+ // // This should be set in UniataAhciEndTransaction() for AHCI
+ // AtaReq->WordsTransfered += AtaReq->bcount * DEV_BSIZE/2;
+ //}
if(!atapiDev &&
AtaReq->WordsTransfered*2 < AtaReq->TransferLength) {
KdPrint2((PRINT_PREFIX "AtapiInterrupt: more I/O required (%x of %x bytes) -> reenqueue\n",
} else {
KdPrint2((PRINT_PREFIX "AtapiInterrupt: IOCTL completion\n"));
- PSENDCMDOUTPARAMS cmdOutParameters = (PSENDCMDOUTPARAMS)(((PUCHAR)srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
if (status != SRB_STATUS_SUCCESS) {
error = AtapiReadPort1(chan, IDX_IO1_i_Error);
KdPrint2((PRINT_PREFIX "AtapiInterrupt: error %#x\n", error));
}
- // Build the SMART status block depending upon the completion status.
- cmdOutParameters->cBufferSize = wordCount;
- cmdOutParameters->DriverStatus.bDriverError = (error) ? SMART_IDE_ERROR : 0;
- cmdOutParameters->DriverStatus.bIDEError = error;
+ if(!AtapiStringCmp( (PCHAR)(((PSRB_IO_CONTROL)(srb->DataBuffer))->Signature),"SCSIDISK",sizeof("SCSIDISK")-1)) {
- // If the sub-command is return smart status, jam the value from cylinder low and high, into the
- // data buffer.
- if (chan->SmartCommand == RETURN_SMART_STATUS) {
- cmdOutParameters->bBuffer[0] = RETURN_SMART_STATUS;
- cmdOutParameters->bBuffer[1] = AtapiReadPort1(chan, IDX_ATAPI_IO1_i_InterruptReason);
- cmdOutParameters->bBuffer[2] = AtapiReadPort1(chan, IDX_ATAPI_IO1_i_Unused1);
- cmdOutParameters->bBuffer[3] = AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountLow);
- cmdOutParameters->bBuffer[4] = AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountHigh);
- cmdOutParameters->bBuffer[5] = AtapiReadPort1(chan, IDX_ATAPI_IO1_i_DriveSelect);
- cmdOutParameters->bBuffer[6] = SMART_CMD;
- cmdOutParameters->cBufferSize = 8;
- }
+ PSENDCMDOUTPARAMS cmdOutParameters = (PSENDCMDOUTPARAMS)(((PUCHAR)srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
+ // Build the SMART status block depending upon the completion status.
+ cmdOutParameters->cBufferSize = wordCount;
+ cmdOutParameters->DriverStatus.bDriverError = (error) ? SMART_IDE_ERROR : 0;
+ cmdOutParameters->DriverStatus.bIDEError = error;
+
+ // If the sub-command is return smart status, jam the value from cylinder low and high, into the
+ // data buffer.
+ if (chan->SmartCommand == RETURN_SMART_STATUS) {
+ PIDEREGS_EX regs = (PIDEREGS_EX)&(cmdOutParameters->bBuffer);
+ regs->bOpFlags = 0;
+ UniataSnapAtaRegs(chan, 0, regs);
+
+ regs->bCommandReg = SMART_CMD;
+ regs->bFeaturesReg = RETURN_SMART_STATUS;
+
+ cmdOutParameters->cBufferSize = 8;
+ }
+ chan->SmartCommand = 0; // cleanup after execution
+ }
// Indicate command complete.
goto IntrCompleteReq;
}
if (chan->RDP) {
// Check DSC
for (i = 0; i < 5; i++) {
- GetStatus(chan, statusByte);
+ GetBaseStatus(chan, statusByte);
if(!(statusByte & IDE_STATUS_BUSY)) {
KdPrint2((PRINT_PREFIX "AtapiInterrupt: RDP + cleared BUSY\n"));
chan->RDP = FALSE;
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"));
+ status = SRB_STATUS_SUCCESS;
+ chan->ChannelCtrlFlags &= ~CTRFLAGS_DMA_OPERATION;
+ goto CompleteRequest;
+ }
}
ReturnEnableIntr:
KdPrint2((PRINT_PREFIX "AtapiInterrupt: ReturnEnableIntr\n",srb));
+ //UniataExpectChannelInterrupt(chan, TRUE); // device may interrupt
+ deviceExtension->ExpectingInterrupt = TRUE;
if(UseDpc) {
if(CrNtInterlockedExchangeAdd(&(chan->DisableIntr), 0)) {
KdPrint2((PRINT_PREFIX "AtapiInterrupt: call AtapiEnableInterrupts__()\n"));
NTAPI
IdeSendSmartCommand(
IN PVOID HwDeviceExtension,
- IN PSCSI_REQUEST_BLOCK Srb
+ IN PSCSI_REQUEST_BLOCK Srb,
+ IN ULONG targetId // assume it is always valid
)
{
PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
- ULONG c = GET_CHANNEL(Srb);
- PHW_CHANNEL chan = &(deviceExtension->chan[c]);
+ ULONG c ; // = GET_CHANNEL(Srb); may be invalid
+ PHW_CHANNEL chan ; // = &(deviceExtension->chan[c]);
PATA_REQ AtaReq = (PATA_REQ)(Srb->SrbExtension);
PSENDCMDOUTPARAMS cmdOutParameters = (PSENDCMDOUTPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
SENDCMDINPARAMS cmdInParameters = *(PSENDCMDINPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
PIDEREGS regs = &cmdInParameters.irDriveRegs;
// ULONG i;
- UCHAR statusByte,targetId;
-
+ UCHAR statusByte;
+ ULONG DeviceNumber;
if (regs->bCommandReg != SMART_CMD) {
KdPrint2((PRINT_PREFIX
return SRB_STATUS_INVALID_REQUEST;
}
- targetId = cmdInParameters.bDriveNumber;
+ c = targetId / deviceExtension->NumberLuns;
+ DeviceNumber = targetId % deviceExtension->NumberLuns;
+ KdPrint2((PRINT_PREFIX " c %d, dev %d\n", c, DeviceNumber));
- //TODO optimize this check
- if ((!(deviceExtension->lun[targetId].DeviceFlags & DFLAGS_DEVICE_PRESENT)) ||
- (deviceExtension->lun[targetId].DeviceFlags & DFLAGS_ATAPI_DEVICE)) {
-
- return SRB_STATUS_SELECTION_TIMEOUT;
- }
+ chan = &(deviceExtension->chan[c]);
chan->SmartCommand = regs->bFeaturesReg;
switch(regs->bFeaturesReg) {
case READ_ATTRIBUTES:
case READ_THRESHOLDS:
+ case READ_LOG_SECTOR:
+ case WRITE_LOG_SECTOR:
+
+ if(Srb->DataTransferLength < sizeof(SRB_IO_CONTROL)+sizeof(SENDCMDOUTPARAMS) + READ_ATTRIBUTE_BUFFER_SIZE - 1) {
+ KdPrint2((PRINT_PREFIX
+ "IdeSendSmartCommand: wrong buffer size\n"));
+ return SRB_STATUS_DATA_OVERRUN;
+ }
statusByte = WaitOnBusy(chan);
AtaReq->DataBuffer = (PUSHORT)cmdOutParameters->bBuffer;
AtaReq->WordsLeft = READ_ATTRIBUTE_BUFFER_SIZE / 2;
- statusByte = AtaCommand(deviceExtension, targetId & 0x1, c,
+ statusByte = AtaCommand(deviceExtension, DeviceNumber, c,
regs->bCommandReg,
(USHORT)(regs->bCylLowReg) | (((USHORT)(regs->bCylHighReg)) << 8),
0,
case ENABLE_DISABLE_AUTOSAVE:
case EXECUTE_OFFLINE_DIAGS:
case SAVE_ATTRIBUTE_VALUES:
+ case AUTO_OFFLINE:
statusByte = WaitOnBusy(chan);
AtaReq->DataBuffer = (PUSHORT)cmdOutParameters->bBuffer;
AtaReq->WordsLeft = 0;
- statusByte = AtaCommand(deviceExtension, targetId & 0x1, c,
+ statusByte = AtaCommand(deviceExtension, DeviceNumber, c,
regs->bCommandReg,
(USHORT)(regs->bCylLowReg) | (((USHORT)(regs->bCylHighReg)) << 8),
0,
if(!(statusByte & IDE_STATUS_ERROR)) {
// Wait for interrupt.
+ UniataExpectChannelInterrupt(chan, TRUE); // device may interrupt
return SRB_STATUS_PENDING;
}
return SRB_STATUS_ERROR;
NTAPI
UniAtaCalculateLBARegs(
PHW_LU_EXTENSION LunExt,
- ULONG startingSector,
+ ULONGLONG startingSector,
PULONG max_bcount
)
{
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()
PATA_REQ AtaReq = (PATA_REQ)(Srb->SrbExtension);
//ULONG ldev = GET_LDEV(Srb);
UCHAR DeviceNumber = GET_CDEV(Srb);;
- ULONG startingSector;
- ULONG max_bcount;
+ ULONGLONG startingSector=0;
+ ULONG max_bcount = 0;
ULONG wordCount = 0;
UCHAR statusByte,statusByte2;
UCHAR cmd;
if(AtaReq->WordsTransfered) {
AtaReq->DataBuffer = ((PUSHORT)(Srb->DataBuffer)) + AtaReq->WordsTransfered;
- startingSector = (ULONG)(UniAtaCalculateLBARegsBack(LunExt, AtaReq->lba)) /* latest lba */ + AtaReq->bcount /* previous bcount */;
+ startingSector = (UniAtaCalculateLBARegsBack(LunExt, AtaReq->lba)) /* latest lba */ + AtaReq->bcount /* previous bcount */;
AtaReq->bcount = (AtaReq->TransferLength - AtaReq->WordsTransfered*2 + DEV_BSIZE-1) / DEV_BSIZE;
- KdPrint2((PRINT_PREFIX "IdeReadWrite (Chained REQ): Starting sector %#x, OrigWordsRequested %#x, WordsTransfered %#x, DevSize %#x\n",
+ KdPrint2((PRINT_PREFIX "IdeReadWrite (Chained REQ): Starting sector %I64x, OrigWordsRequested %#x, WordsTransfered %#x, DevSize %#x\n",
startingSector,
AtaReq->TransferLength/2,
AtaReq->WordsTransfered,
AtaReq->DataBuffer = (PUSHORT)(Srb->DataBuffer);
AtaReq->TransferLength = Srb->DataTransferLength;
// Set up 1st block.
- MOV_DD_SWP(startingSector, ((PCDB)Srb->Cdb)->CDB10.LBA);
- MOV_SWP_DW2DD(AtaReq->bcount, ((PCDB)Srb->Cdb)->CDB10.TransferBlocks);
- KdPrint2((PRINT_PREFIX "IdeReadWrite (Orig REQ): Starting sector %#x, OrigWordsRequested %#x, DevSize %#x\n",
+ switch(Srb->Cdb[0]) {
+ 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_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;
+ case SCSIOP_READ16:
+ case SCSIOP_WRITE16:
+ MOV_QD_SWP(startingSector, ((PCDB)Srb->Cdb)->CDB16READWRITE.LBA);
+ MOV_DD_SWP(AtaReq->bcount, ((PCDB)Srb->Cdb)->CDB16READWRITE.NumOfBlocks);
+ break;
+ }
+ KdPrint2((PRINT_PREFIX "IdeReadWrite (Orig REQ): Starting sector %I64x, OrigWordsRequested %#x, DevSize %#x\n",
startingSector,
AtaReq->TransferLength/2,
AtaReq->bcount));
AtaReq->WordsLeft = min(AtaReq->TransferLength - AtaReq->WordsTransfered*2,
AtaReq->bcount * DEV_BSIZE) / 2;
- KdPrint2((PRINT_PREFIX "IdeReadWrite (REQ): Starting sector is %#x, Number of WORDS %#x, DevSize %#x\n",
+ KdPrint2((PRINT_PREFIX "IdeReadWrite (REQ): Starting sector is %I64x, Number of WORDS %#x, DevSize %#x\n",
startingSector,
AtaReq->WordsLeft,
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(deviceExtension->HwFlags & UNIATA_AHCI) {
+ UniataAhciSetupCmdPtr(AtaReq);
+ if(!AtapiDmaSetup(HwDeviceExtension, DeviceNumber, lChannel, Srb,
+ (PUCHAR)(AtaReq->DataBuffer),
+ AtaReq->bcount * DEV_BSIZE)) {
+ KdPrint3((PRINT_PREFIX "IdeReadWrite: AHCI !DMA\n"));
+ return SRB_STATUS_ERROR;
+ }
+ } else
if ((LunExt->LimitedTransferMode >= ATA_DMA)) {
use_dma = TRUE;
// this will set REQ_FLAG_DMA_OPERATION in AtaReq->Flags on success
}
}
- if(use_dma && (deviceExtension->HwFlags & UNIATA_AHCI)) {
- UniataAhciSetupCmdPtr(AtaReq);
- KdPrint2((PRINT_PREFIX "AtapiSendCommand: setup AHCI FIS\n"));
+ if(deviceExtension->HwFlags & UNIATA_AHCI) {
+ KdPrint2((PRINT_PREFIX "IdeReadWrite: setup AHCI FIS\n"));
RtlZeroMemory(&(AtaReq->ahci.ahci_cmd_ptr->cfis), sizeof(AtaReq->ahci_cmd0.cfis));
fis_size = UniataAhciSetupFIS_H2D(deviceExtension, DeviceNumber, lChannel,
&(AtaReq->ahci.ahci_cmd_ptr->cfis[0]),
- (AtaReq->Flags & REQ_FLAG_READ) ? IDE_COMMAND_READ_DMA : /*IDE_COMMAND_WRITE_DMA*/ IDE_COMMAND_READ_DMA,
+ (AtaReq->Flags & REQ_FLAG_READ) ? IDE_COMMAND_READ_DMA : IDE_COMMAND_WRITE_DMA,
lba,
(USHORT)(AtaReq->bcount),
- 0,
- ATA_IMMEDIATE
+ 0
+ /*,(AtaReq->Flags & REQ_FLAG_READ) ? 0 : ATA_AHCI_CMD_WRITE*/
);
if(!fis_size) {
- KdPrint3((PRINT_PREFIX "AtapiSendCommand: AHCI !FIS\n"));
+ KdPrint3((PRINT_PREFIX "IdeReadWrite: AHCI !FIS\n"));
return SRB_STATUS_ERROR;
}
- AtaReq->ahci.io_cmd_flags = (USHORT)(((AtaReq->Flags & REQ_FLAG_READ) ? 0 : ATA_AHCI_CMD_WRITE) |
- /*((LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) ? (ATA_AHCI_CMD_ATAPI | ATA_AHCI_CMD_PREFETCH) : 0) |*/
- (fis_size / sizeof(ULONG)) |
- (DeviceNumber << 12));
+ AtaReq->ahci.io_cmd_flags = UniAtaAhciAdjustIoFlags(0, (AtaReq->Flags & REQ_FLAG_READ) ? 0 : ATA_AHCI_CMD_WRITE, fis_size, DeviceNumber);
KdPrint2((PRINT_PREFIX "IdeReadWrite ahci io flags %x: \n", AtaReq->ahci.io_cmd_flags));
}
chan->ChannelCtrlFlags &= ~CTRFLAGS_DMA_OPERATION;
}
- if(use_dma && (deviceExtension->HwFlags & UNIATA_AHCI)) {
+ if(deviceExtension->HwFlags & UNIATA_AHCI) {
+ // AHCI doesn't distinguish DMA and PIO
//AtapiDmaStart(HwDeviceExtension, DeviceNumber, lChannel, Srb);
- UniataAhciBeginTransaction(HwDeviceExtension, DeviceNumber, lChannel, Srb);
+ UniataAhciBeginTransaction(HwDeviceExtension, lChannel, DeviceNumber, Srb);
+ UniataExpectChannelInterrupt(chan, TRUE); // device may interrupt
+ InterlockedExchange(&(chan->CheckIntr),
+ CHECK_INTR_IDLE);
return SRB_STATUS_PENDING;
}
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 != 0xff) {
+/* 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;
}
0, ATA_WAIT_INTR);
if (!(statusByte & IDE_STATUS_DRQ) ||
- statusByte == 0xff) {
+ statusByte == IDE_STATUS_WRONG) {
- if(statusByte == 0xff) {
+ if(statusByte == IDE_STATUS_WRONG) {
KdPrint2((PRINT_PREFIX
"IdeReadWrite: error sending command (%#x)\n",
statusByte));
AtaReq->WordsLeft = 0;
// Clear interrupt expecting flag.
- chan->ExpectingInterrupt = FALSE;
+ UniataExpectChannelInterrupt(chan, FALSE);
InterlockedExchange(&(chan->CheckIntr),
CHECK_INTR_IDLE);
// Clear current SRB.
UniataRemoveRequest(chan, Srb);
- return (statusByte == 0xff) ? SRB_STATUS_ERROR : SRB_STATUS_TIMEOUT;
+ return (statusByte == IDE_STATUS_WRONG) ? SRB_STATUS_ERROR : SRB_STATUS_TIMEOUT;
}
- chan->ExpectingInterrupt = TRUE;
+ UniataExpectChannelInterrupt(chan, TRUE);
InterlockedExchange(&(chan->CheckIntr),
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;
//ULONG ldev = GET_LDEV(Srb);
ULONG DeviceNumber = GET_CDEV(Srb);
UCHAR statusByte;
- ULONG startingSector;
+ ULONGLONG startingSector=0;
ULONG max_bcount;
- ULONG sectors;
- ULONG endSector;
- USHORT sectorCount;
+ ULONGLONG sectors;
+ ULONGLONG endSector;
+ ULONG sectorCount=0;
ULONGLONG lba;
LunExt = chan->lun[DeviceNumber];
}
KdPrint2((PRINT_PREFIX
- "IdeVerify: Total sectors %#x\n",
+ "IdeVerify: Total sectors %#I64x\n",
sectors));
// Get starting sector number from CDB.
- MOV_DD_SWP(startingSector, ((PCDB)Srb->Cdb)->CDB10.LBA);
- MOV_DW_SWP(sectorCount, ((PCDB)Srb->Cdb)->CDB10.TransferBlocks);
+ switch(Srb->Cdb[0]) {
+ case SCSIOP_VERIFY:
+ MOV_DD_SWP(startingSector, ((PCDB)Srb->Cdb)->CDB10.LBA);
+ MOV_SWP_DW2DD(sectorCount, ((PCDB)Srb->Cdb)->CDB10.TransferBlocks);
+ break;
+ case SCSIOP_VERIFY12:
+ MOV_DD_SWP(startingSector, ((PCDB)Srb->Cdb)->CDB12READWRITE.LBA);
+ MOV_DD_SWP(sectorCount, ((PCDB)Srb->Cdb)->CDB12READWRITE.NumOfBlocks);
+ break;
+ case SCSIOP_VERIFY16:
+ MOV_QD_SWP(startingSector, ((PCDB)Srb->Cdb)->CDB16READWRITE.LBA);
+ MOV_DD_SWP(sectorCount, ((PCDB)Srb->Cdb)->CDB16READWRITE.NumOfBlocks);
+ break;
+ }
KdPrint2((PRINT_PREFIX
- "IdeVerify: Starting sector %#x. Number of blocks %#x\n",
+ "IdeVerify: Starting sector %#I64x. Number of blocks %#x\n",
startingSector,
sectorCount));
endSector = startingSector + sectorCount;
KdPrint2((PRINT_PREFIX
- "IdeVerify: Ending sector %#x\n",
+ "IdeVerify: Ending sector %#I64x\n",
endSector));
if (endSector > sectors) {
"IdeVerify: Truncating request to %#x blocks\n",
sectors - startingSector - 1));
- sectorCount = (USHORT)(sectors - startingSector - 1);
+ sectorCount = (ULONG)(sectors - startingSector - 1);
} else {
statusByte = AtaCommand48(deviceExtension, LunExt->Lun, GET_CHANNEL(Srb),
IDE_COMMAND_VERIFY, lba,
- sectorCount,
+ (USHORT)sectorCount,
0, ATA_IMMEDIATE);
if(!(statusByte & IDE_STATUS_ERROR)) {
// Wait for interrupt.
+ UniataExpectChannelInterrupt(chan, TRUE);
return SRB_STATUS_PENDING;
}
return SRB_STATUS_ERROR;
PHW_LU_EXTENSION LunExt;
//ULONG ldev = GET_LDEV(Srb);
ULONG DeviceNumber = GET_CDEV(Srb);
- ULONG i;
ULONG flags;
- UCHAR statusByte,byteCountLow,byteCountHigh;
+ 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];
if(AtaReq->ReqState < REQ_STATE_PREPARE_TO_TRANSFER)
AtaReq->ReqState = REQ_STATE_PREPARE_TO_TRANSFER;
+
#ifdef UNIATA_DUMP_ATAPI
if(CmdAction & CMD_ACTION_PREPARE) {
UCHAR ScsiCommand;
}
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,
Cdb->CDB12READWRITE.LBA[3]
));
} else
+ if(ScsiCommand == SCSIOP_WRITE16) {
+ KdPrint(("Write16, LBA %2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n",
+ Cdb->CDB16READWRITE.LBA[0],
+ Cdb->CDB16READWRITE.LBA[1],
+ Cdb->CDB16READWRITE.LBA[2],
+ Cdb->CDB16READWRITE.LBA[3],
+ Cdb->CDB16READWRITE.LBA[4],
+ Cdb->CDB16READWRITE.LBA[5],
+ Cdb->CDB16READWRITE.LBA[6],
+ Cdb->CDB16READWRITE.LBA[7]
+ ));
+ } else
if(ScsiCommand == SCSIOP_MODE_SELECT) {
KdPrint(("ModeSelect 6\n"));
PMODE_PARAMETER_HEADER ParamHdr = (PMODE_PARAMETER_HEADER)CdbData;
if(CmdAction == CMD_ACTION_PREPARE) {
- KdPrint2((PRINT_PREFIX "AtapiSendCommand: CMD_ACTION_PREPARE\n"));
+ KdPrint2((PRINT_PREFIX "AtapiSendCommand: CMD_ACTION_PREPARE, Cdb %x\n", &(Srb->Cdb)));
+
switch (Srb->Cdb[0]) {
+ case SCSIOP_RECEIVE:
+ case SCSIOP_SEND:
case SCSIOP_READ:
case SCSIOP_WRITE:
case SCSIOP_READ12:
case SCSIOP_WRITE12:
+ case SCSIOP_READ16:
+ 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) {
+
+ ULONG srbStatus;
+
+ KdPrint3((PRINT_PREFIX "AtapiSendCommand: BuildMechanismStatusSrb()\n"));
+ // Set this flag now. If the device hangs on the mech. status
+ // command, we will not have the chance to set it.
+ LunExt->DeviceFlags |= DFLAGS_CHANGER_INITED;
+
+ chan->MechStatusRetryCount = 3;
+ AtaReq->OriginalSrb = Srb;
+ AtaReq->Srb = BuildMechanismStatusSrb (
+ HwDeviceExtension,
+ Srb);
+
+ KdPrint3((PRINT_PREFIX "AtapiSendCommand: AtapiSendCommand recursive\n"));
+ srbStatus = AtapiSendCommand(HwDeviceExtension, AtaReq->Srb, CMD_ACTION_ALL);
+ if (srbStatus == SRB_STATUS_PENDING) {
+ KdPrint2((PRINT_PREFIX "AtapiSendCommand: SRB_STATUS_PENDING (2)\n"));
+ return srbStatus;
+ } else {
+
+ // failed! Get the sense key and maybe try again
+ AtaReq->Srb = BuildRequestSenseSrb ( HwDeviceExtension,
+ AtaReq->OriginalSrb);
+
+ srbStatus = AtapiSendCommand(HwDeviceExtension, AtaReq->Srb, CMD_ACTION_ALL);
+
+ KdPrint3((PRINT_PREFIX "AtapiSendCommand: chan->ExpectingInterrupt %d (1)\n", chan->ExpectingInterrupt));
+
+ if (srbStatus == SRB_STATUS_PENDING) {
+ KdPrint2((PRINT_PREFIX "AtapiSendCommand: send orig SRB_STATUS_PENDING (2.1)\n"));
+ return srbStatus;
+ }
+
+ // failed again ? should not get here
+ AtaReq->Srb = AtaReq->OriginalSrb;
+ AtaReq->OriginalSrb = NULL;
+ // fall out
+ }
}
+#endif // UNIATA_INIT_CHANGERS
+#endif //UNIATA_CORE
if((CmdAction & CMD_ACTION_PREPARE) &&
(AtaReq->ReqState != REQ_STATE_READY_TO_TRANSFER)) {
- KdPrint2((PRINT_PREFIX "AtapiSendCommand: prepare..., ATAPI CMD %x\n", Srb->Cdb[0]));
+ KdPrint2((PRINT_PREFIX "AtapiSendCommand: prepare..., ATAPI CMD %x (Cdb %x)\n", Srb->Cdb[0], &(Srb->Cdb)));
+
+ if(!LunExt->IdentifyData.AtapiCmdSize &&
+ (Srb->CdbLength > 12)) {
+ KdPrint2((PRINT_PREFIX "Cdb16 not supported\n"));
+ return SRB_STATUS_INVALID_REQUEST;
+ }
+
// Set data buffer pointer and words left.
AtaReq->DataBuffer = (PUSHORT)Srb->DataBuffer;
AtaReq->WordsLeft = Srb->DataTransferLength / 2;
AtaReq->TransferLength = Srb->DataTransferLength;
AtaReq->Flags &= ~REQ_FLAG_DMA_OPERATION;
+ // reset this to force PRD init. May be already setup by recursive SRB
+ AtaReq->dma_entries = 0;
// check if reorderable
switch(Srb->Cdb[0]) {
+ case SCSIOP_READ16:
+ case SCSIOP_WRITE16:
+
+ MOV_DD_SWP(AtaReq->bcount, ((PCDB)Srb->Cdb)->CDB16READWRITE.NumOfBlocks);
+ MOV_QD_SWP(AtaReq->lba, ((PCDB)Srb->Cdb)->CDB16READWRITE.LBA);
+ goto GetLba2;
+
case SCSIOP_READ12:
case SCSIOP_WRITE12:
MOV_SWP_DW2DD(AtaReq->bcount, ((PCDB)Srb->Cdb)->CDB10.TransferBlocks);
GetLba:
MOV_DD_SWP(AtaReq->lba, ((PCDB)Srb->Cdb)->CDB10.LBA);
-
+GetLba2:
AtaReq->Flags |= REQ_FLAG_REORDERABLE_CMD;
AtaReq->Flags &= ~REQ_FLAG_RW_MASK;
- AtaReq->Flags |= (Srb->Cdb[0] == SCSIOP_WRITE || Srb->Cdb[0] == SCSIOP_WRITE12) ?
+ AtaReq->Flags |= (Srb->Cdb[0] == SCSIOP_WRITE ||
+ Srb->Cdb[0] == SCSIOP_WRITE12 ||
+ Srb->Cdb[0] == SCSIOP_WRITE16) ?
REQ_FLAG_WRITE : REQ_FLAG_READ;
break;
+ default:
+ AtaReq->Flags &= ~REQ_FLAG_RW_MASK;
+ if(!AtaReq->TransferLength) {
+ KdPrint((" assume 0-transfer\n"));
+ } else
+ if(Srb->SrbFlags & SRB_FLAGS_DATA_OUT) {
+ KdPrint((" assume OUT\n"));
+ AtaReq->Flags |= REQ_FLAG_WRITE;
+ } else
+ if(Srb->SrbFlags & SRB_FLAGS_DATA_IN) {
+ KdPrint((" assume IN\n"));
+ AtaReq->Flags |= REQ_FLAG_READ;
+ }
+ break;
}
// 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;
+ goto setup_dma;
+ } else
+/* if((deviceExtension->HwFlags & UNIATA_SATA) && (LunExt->OrigTransferMode >= ATA_DMA)) {
+ KdPrint2((PRINT_PREFIX "AtapiSendCommand: force use dma (sata)\n"));
+ use_dma = TRUE;
+ goto setup_dma;
+ } else*/
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:
+ case SCSIOP_WRITE16:
+ case SCSIOP_SEND:
if(chan->ChannelCtrlFlags & CTRFLAGS_DMA_RO)
break;
/* FALLTHROUGH */
+ case SCSIOP_RECEIVE:
case SCSIOP_READ:
case SCSIOP_READ12:
+ case SCSIOP_READ16:
if(deviceExtension->opt_AtapiDmaReadWrite) {
call_dma_setup:
+ if(deviceExtension->HwFlags & UNIATA_AHCI) {
+ KdPrint2((PRINT_PREFIX "AtapiSendCommand: use dma (ahci)\n"));
+ use_dma = TRUE;
+ } else
if(AtapiDmaSetup(HwDeviceExtension, DeviceNumber, lChannel, Srb,
(PUCHAR)(AtaReq->DataBuffer),
Srb->DataTransferLength
}
break;
case SCSIOP_READ_CD:
+ case SCSIOP_READ_CD_MSF:
if(deviceExtension->opt_AtapiDmaRawRead)
goto call_dma_setup;
break;
break;
}
// try setup DMA
+setup_dma:
if(use_dma) {
+ if(deviceExtension->HwFlags & UNIATA_AHCI) {
+ KdPrint2((PRINT_PREFIX "AtapiSendCommand: use dma (ahci)\n"));
+ //use_dma = TRUE;
+ } else
if(!AtapiDmaSetup(HwDeviceExtension, DeviceNumber, lChannel, Srb,
(PUCHAR)(AtaReq->DataBuffer),
Srb->DataTransferLength)) {
}
}
} 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));
}
if(deviceExtension->HwFlags & UNIATA_AHCI) {
- UniataAhciSetupCmdPtr(AtaReq);
- KdPrint2((PRINT_PREFIX "AtapiSendCommand: setup AHCI FIS\n"));
- RtlZeroMemory(&(AtaReq->ahci.ahci_cmd_ptr->cfis), sizeof(AtaReq->ahci_cmd0.cfis));
- RtlCopyMemory(&(AtaReq->ahci.ahci_cmd_ptr->acmd), Srb->Cdb, 16);
- fis_size = UniataAhciSetupFIS_H2D(deviceExtension, DeviceNumber, lChannel,
- &(AtaReq->ahci.ahci_cmd_ptr->cfis[0]),
- IDE_COMMAND_ATAPI_PACKET /* command */,
- 0 /* lba */,
- (Srb->DataTransferLength >= 0x10000) ? (USHORT)(0xffff) : (USHORT)(Srb->DataTransferLength),
- use_dma ? ATA_F_DMA : 0/* feature */,
- ATA_IMMEDIATE /* flags */
- );
+ UniataAhciSetupCmdPtr(AtaReq);
- if(!fis_size) {
- KdPrint3((PRINT_PREFIX "AtapiSendCommand: AHCI !FIS\n"));
- return SRB_STATUS_ERROR;
- }
+ if(!Srb->DataTransferLength) {
+ KdPrint2((PRINT_PREFIX "zero-transfer\n"));
+ use_dma = FALSE;
+ } else
+ if(!AtapiDmaSetup(HwDeviceExtension, DeviceNumber, lChannel, Srb,
+ (PUCHAR)(AtaReq->DataBuffer),
+ Srb->DataTransferLength)) {
+ KdPrint2((PRINT_PREFIX "AtapiSendCommand: no AHCI dma!\n"));
+ return SRB_STATUS_ERROR;
+ }
+ if(!use_dma) {
+ AtaReq->Flags &= ~REQ_FLAG_DMA_OPERATION;
+ } else {
+ FeatureReg |= ATA_F_DMA;
+ if(LunExt->IdentifyData.AtapiDMA.DMADirRequired) {
+ if(Srb->SrbFlags & SRB_FLAGS_DATA_IN) {
+ KdPrint2((PRINT_PREFIX "Set DMADir.\n"));
+ FeatureReg |= ATA_F_DMAREAD;
+ }
+ }
+ }
+
+ KdPrint2((PRINT_PREFIX "AtapiSendCommand: setup AHCI FIS\n"));
+ // this is done in UniataAhciSetupFIS_H2D()
+ //RtlZeroMemory(&(AtaReq->ahci.ahci_cmd_ptr->cfis), sizeof(AtaReq->ahci_cmd0.cfis));
+ RtlCopyMemory(&(AtaReq->ahci.ahci_cmd_ptr->acmd), Srb->Cdb, Srb->CdbLength);
+
+ fis_size = UniataAhciSetupFIS_H2D(deviceExtension, DeviceNumber, lChannel,
+ &(AtaReq->ahci.ahci_cmd_ptr->cfis[0]),
+ IDE_COMMAND_ATAPI_PACKET /* command */,
+ 0 /* lba */,
+ (Srb->DataTransferLength >= 0x10000) ? (USHORT)(0xffff) : (USHORT)(Srb->DataTransferLength),
+ FeatureReg/* feature */
+ );
+
+ if(!fis_size) {
+ KdPrint3((PRINT_PREFIX "AtapiSendCommand: AHCI !FIS\n"));
+ return SRB_STATUS_ERROR;
+ }
+
+ AtaReq->ahci.io_cmd_flags = UniAtaAhciAdjustIoFlags(0,
+ ((Srb->DataTransferLength && (Srb->SrbFlags & SRB_FLAGS_DATA_OUT)) ? ATA_AHCI_CMD_WRITE : 0) |
+ (ATA_AHCI_CMD_ATAPI | ATA_AHCI_CMD_PREFETCH),
+ fis_size, DeviceNumber);
- AtaReq->ahci.io_cmd_flags = (USHORT)(((AtaReq->Flags & REQ_FLAG_READ) ? 0 : ATA_AHCI_CMD_WRITE) |
- /*((LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) ? (ATA_AHCI_CMD_ATAPI | ATA_AHCI_CMD_PREFETCH) : 0) |*/
- (ATA_AHCI_CMD_ATAPI | ATA_AHCI_CMD_PREFETCH) |
- (fis_size / sizeof(ULONG)) |
- (DeviceNumber << 12));
KdPrint2((PRINT_PREFIX "AtapiSendCommand ahci io flags %x: \n", AtaReq->ahci.io_cmd_flags));
}
KdPrint2((PRINT_PREFIX "AtapiSendCommand: !CMD_ACTION_EXEC => SRB_STATUS_PENDING\n"));
return SRB_STATUS_PENDING;
}
- KdPrint3((PRINT_PREFIX "AtapiSendCommand: use_dma=%d\n", use_dma));
+ KdPrint3((PRINT_PREFIX "AtapiSendCommand: use_dma=%d, Cmd %x\n", use_dma, Srb->Cdb[0]));
if(AtaReq->Flags & REQ_FLAG_DMA_OPERATION) {
KdPrint2((PRINT_PREFIX " REQ_FLAG_DMA_OPERATION\n"));
}
- if(Srb->Cdb[0] == SCSIOP_REQUEST_SENSE) {
+ if((Srb->Cdb[0] == SCSIOP_REQUEST_SENSE) && !(deviceExtension->HwFlags & UNIATA_SATA)) {
KdPrint2((PRINT_PREFIX "AtapiSendCommand: SCSIOP_REQUEST_SENSE -> no dma setup (2)\n"));
use_dma = FALSE;
AtaReq->Flags &= ~REQ_FLAG_DMA_OPERATION;
- //AtapiDmaReinit(deviceExtension, LunExt, AtaReq);
+ AtapiDmaReinit(deviceExtension, LunExt, AtaReq);
} if(AtaReq->TransferLength) {
if(!dma_reinited) {
KdPrint2((PRINT_PREFIX "AtapiSendCommand: AtapiDmaReinit()\n"));
KdPrint2((PRINT_PREFIX "AtapiSendCommand: zero transfer\n"));
use_dma = FALSE;
AtaReq->Flags &= ~REQ_FLAG_DMA_OPERATION;
- if(!deviceExtension->opt_AtapiDmaZeroTransfer) {
+ if(!deviceExtension->opt_AtapiDmaZeroTransfer && !(deviceExtension->HwFlags & UNIATA_SATA)) {
KdPrint2((PRINT_PREFIX "AtapiSendCommand: AtapiDmaReinit() to PIO\n"));
AtapiDmaReinit(deviceExtension, LunExt, AtaReq);
}
KdPrint2((PRINT_PREFIX "AtapiSendCommand: CMD_ACTION_EXEC\n"));
-#ifndef UNIATA_CORE
- // 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.
-
- if (!(LunExt->DeviceFlags & DFLAGS_CHANGER_INITED) &&
- !AtaReq->OriginalSrb) {
-
- ULONG srbStatus;
-
- KdPrint3((PRINT_PREFIX "AtapiSendCommand: BuildMechanismStatusSrb()\n"));
- // Set this flag now. If the device hangs on the mech. status
- // command, we will not have the chance to set it.
- LunExt->DeviceFlags |= DFLAGS_CHANGER_INITED;
-
- chan->MechStatusRetryCount = 3;
- AtaReq->OriginalSrb = Srb;
- AtaReq->Srb = BuildMechanismStatusSrb (
- HwDeviceExtension,
- Srb);
-
- KdPrint3((PRINT_PREFIX "AtapiSendCommand: AtapiSendCommand recursive\n"));
- srbStatus = AtapiSendCommand(HwDeviceExtension, AtaReq->Srb, CMD_ACTION_ALL);
- if (srbStatus == SRB_STATUS_PENDING) {
- KdPrint2((PRINT_PREFIX "AtapiSendCommand: SRB_STATUS_PENDING (2)\n"));
- return srbStatus;
- } else {
- AtaReq->Srb = AtaReq->OriginalSrb;
- AtaReq->OriginalSrb = NULL;
- KdPrint2((PRINT_PREFIX "AtapiSendCommand: AtapiHwInitializeChanger()\n"));
- AtapiHwInitializeChanger (HwDeviceExtension, Srb,
- (PMECHANICAL_STATUS_INFORMATION_HEADER) NULL);
- // fall out
- }
- }
-#endif //UNIATA_CORE
-
- KdPrint3((PRINT_PREFIX "AtapiSendCommand: Command %#x to TargetId %d lun %d\n",
- Srb->Cdb[0], Srb->TargetId, Srb->Lun));
+ KdPrint3((PRINT_PREFIX "AtapiSendCommand: Cdb %x Command %#x to TargetId %d lun %d\n",
+ &(Srb->Cdb), Srb->Cdb[0], Srb->TargetId, Srb->Lun));
// Make sure command is to ATAPI device.
flags = LunExt->DeviceFlags;
return SRB_STATUS_SELECTION_TIMEOUT;
}
retry:
- if(deviceExtension->HwFlags & UNIATA_AHCI) {
- KdPrint2((PRINT_PREFIX "AtapiSendCommand: AHCI, begin transaction\n"));
- if(use_dma) {
- chan->ChannelCtrlFlags |= CTRFLAGS_DMA_OPERATION;
- } else {
- chan->ChannelCtrlFlags &= ~CTRFLAGS_DMA_OPERATION;
- }
- UniataAhciBeginTransaction(HwDeviceExtension, DeviceNumber, lChannel, Srb);
- return SRB_STATUS_PENDING;
- }
-
- // Select device 0 or 1.
+ // Select device 0 or 1. Or more for PM
SelectDrive(chan, DeviceNumber);
// Verify that controller is ready for next command.
GetStatus(chan, statusByte);
KdPrint3((PRINT_PREFIX "AtapiSendCommand: Entered with status %#x\n", statusByte));
- if(statusByte == 0xff) {
+ if(statusByte == IDE_STATUS_WRONG) {
KdPrint2((PRINT_PREFIX "AtapiSendCommand: bad status 0xff on entry\n"));
goto make_reset;
}
goto make_reset;
}
}
+ if(deviceExtension->HwFlags & UNIATA_AHCI) {
+ ULONG CI;
+ // Check if command list is free
+ CI = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_CI);
+ if(CI) {
+ // controller is busy, however we expect it to be free
+ KdPrint2((PRINT_PREFIX "AtapiSendCommand: Controller busy (CI=%#x) -> reset\n", CI));
+ goto make_reset;
+ }
+ }
if(statusByte & IDE_STATUS_ERROR) {
if (Srb->Cdb[0] != SCSIOP_REQUEST_SENSE) {
// Try to drain the data that one preliminary device thinks that it has
// to transfer. Hopefully this random assertion of DRQ will not be present
// in production devices.
+ statusByte = AtapiSuckPort2(chan);
+/*
for (i = 0; i < 0x10000; i++) {
GetStatus(chan, statusByte);
if(statusByte & IDE_STATUS_DRQ) {
break;
}
}
-
- if (i == 0x10000) {
+*/
+ 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);
// Inform the port driver that the bus has been reset.
ScsiPortNotification(ResetDetected, HwDeviceExtension, 0);
// Clean up device extension fields that AtapiStartIo won't.
- chan->ExpectingInterrupt = FALSE;
+ UniataExpectChannelInterrupt(chan, FALSE);
chan->RDP = FALSE;
InterlockedExchange(&(deviceExtension->chan[GET_CHANNEL(Srb)].CheckIntr),
CHECK_INTR_IDLE);
chan->ChannelCtrlFlags &= ~CTRFLAGS_DMA_OPERATION;
}
+ if(deviceExtension->HwFlags & UNIATA_AHCI) {
+ KdPrint2((PRINT_PREFIX "AtapiSendCommand: AHCI, begin transaction\n"));
+ //AtaReq->Flags = ~REQ_FLAG_DMA_OPERATION; // keep proped DMA flag for proper RETRY handling
+ UniataExpectChannelInterrupt(chan, TRUE);
+ UniataAhciBeginTransaction(HwDeviceExtension, lChannel, DeviceNumber, Srb);
+ return SRB_STATUS_PENDING;
+ }
+
statusByte = WaitOnBusy(chan);
KdPrint3((PRINT_PREFIX "AtapiSendCommand: Entry Status (%#x)\n",
statusByte));
- AtapiWritePort1(chan, IDX_IO1_o_Feature,
- use_dma ? ATA_F_DMA : 0);
+ if(use_dma) {
+ FeatureReg |= ATA_F_DMA;
+ if(LunExt->IdentifyData.AtapiDMA.DMADirRequired) {
+ if(Srb->SrbFlags & SRB_FLAGS_DATA_IN) {
+ FeatureReg |= ATA_F_DMAREAD;
+ }
+ }
+ }
// 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));
- chan->ExpectingInterrupt = TRUE;
+ UniataExpectChannelInterrupt(chan, TRUE);
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));
-
- chan->ExpectingInterrupt = 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;
}
- // 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.
- chan->ExpectingInterrupt = TRUE;
- InterlockedExchange(&(chan->CheckIntr),
- CHECK_INTR_IDLE);
- AtaReq->ReqState = REQ_STATE_ATAPI_EXPECTING_DATA_INTR;
+ UniataExpectChannelInterrupt(chan, TRUE);
+ 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,
- 6,
- 0);
+ LunExt->IdentifyData.AtapiCmdSize ? 8 : 6,
+ /*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) {
+
+ GetBaseStatus(chan, statusByte);
+ KdPrint3((PRINT_PREFIX "AtapiSendCommand: Error on cmd: (%#x)\n", statusByte));
+
+ interruptReason = (AtapiReadPort1(chan, IDX_ATAPI_IO1_i_InterruptReason) & ATAPI_IR_Mask);
+ KdPrint3((PRINT_PREFIX "AtapiSendCommand: iReason %x\n", interruptReason));
+
+ // TODO: we should check interruptReason and decide what to do now
+
+ // Read the error reg. to clear it and fail this request.
+ AtaReq->ReqState = REQ_STATE_TRANSFER_COMPLETE;
+ return MapError(deviceExtension, Srb);
+ }
+ 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));
+ if(statusByte >> 4) {
+ GetBaseStatus(chan, statusByte);
+ AtaReq->ReqState = REQ_STATE_TRANSFER_COMPLETE;
+ 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"));
UCHAR lChannel;
PHW_CHANNEL chan;
PCDB cdb;
+ PHW_LU_EXTENSION LunExt;
SetCheckPoint(4);
UCHAR statusByte,errorByte;
- ULONG status;
+ ULONG status = SRB_STATUS_INVALID_REQUEST;
ULONG i;
+ ULONGLONG lba;
PMODE_PARAMETER_HEADER modeData;
//ULONG ldev;
ULONG DeviceNumber;
PATA_REQ AtaReq;
+ UCHAR command;
+
SetCheckPoint(5);
//ULONG __ebp__ = 0;
chan = &(deviceExtension->chan[lChannel]);
//ldev = GET_LDEV(Srb);
DeviceNumber = GET_CDEV(Srb);
+ LunExt = chan->lun[DeviceNumber];
SetCheckPoint(0x40);
if(AtaReq->ReqState < REQ_STATE_PREPARE_TO_TRANSFER)
AtaReq->ReqState = REQ_STATE_PREPARE_TO_TRANSFER;
+ cdb = (PCDB)(Srb->Cdb);
+
if(CmdAction == CMD_ACTION_PREPARE) {
switch (Srb->Cdb[0]) {
+ case SCSIOP_SERVICE_ACTION16:
+ if( cdb->SERVICE_ACTION16.ServiceAction==SCSIOP_SA_READ_CAPACITY16 ) {
+ // ok
+ } else {
+ goto default_no_prep;
+ }
#ifdef NAVO_TEST
case SCSIOP_INQUIRY: // now it requires device access
#endif //NAVO_TEST
case SCSIOP_READ_CAPACITY:
case SCSIOP_READ:
case SCSIOP_WRITE:
+ case SCSIOP_READ12:
+ case SCSIOP_WRITE12:
+ case SCSIOP_READ16:
+ case SCSIOP_WRITE16:
case SCSIOP_REQUEST_SENSE:
// all right
KdPrint2((PRINT_PREFIX "** Ide: Command continue prep\n"));
SetCheckPoint(50);
break;
default:
+default_no_prep:
SetCheckPoint(0);
KdPrint2((PRINT_PREFIX "** Ide: Command break prep\n"));
return SRB_STATUS_BUSY;
KdPrint2((PRINT_PREFIX
"IdeSendCommand: SCSIOP_INQUIRY PATH:LUN:TID = %#x:%#x:%#x\n",
Srb->PathId, Srb->Lun, Srb->TargetId));
- // Filter out all TIDs but 0 and 1 since this is an IDE interface
- // which support up to two devices.
+ // Filter out wrong TIDs.
if ((Srb->Lun != 0) ||
(Srb->PathId >= deviceExtension->NumberChannels) ||
- (Srb->TargetId > deviceExtension->NumberLuns)) {
+ (Srb->TargetId >= deviceExtension->NumberLuns)) {
KdPrint2((PRINT_PREFIX
"IdeSendCommand: SCSIOP_INQUIRY rejected\n"));
KdPrint2((PRINT_PREFIX
"IdeSendCommand: SCSIOP_INQUIRY ok\n"));
PINQUIRYDATA inquiryData = (PINQUIRYDATA)(Srb->DataBuffer);
- PIDENTIFY_DATA2 identifyData = &(chan->lun[DeviceNumber]->IdentifyData);
+ PIDENTIFY_DATA2 identifyData = &(LunExt->IdentifyData);
if (!(chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_DEVICE_PRESENT)) {
inquiryData->DeviceType = DIRECT_ACCESS_DEVICE;
// Set the removable bit, if applicable.
- if (chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_REMOVABLE_DRIVE) {
+ if (LunExt->DeviceFlags & DFLAGS_REMOVABLE_DRIVE) {
KdPrint2((PRINT_PREFIX
"RemovableMedia\n"));
inquiryData->RemovableMedia = 1;
}
// Set the Relative Addressing (LBA) bit, if applicable.
- if (chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_LBA_ENABLED) {
+ if (LunExt->DeviceFlags & DFLAGS_LBA_ENABLED) {
inquiryData->RelativeAddressing = 1;
KdPrint2((PRINT_PREFIX
"RelativeAddressing\n"));
// Fill in vendor identification fields.
for (i = 0; i < 24; i += 2) {
- MOV_DW_SWP(inquiryData->VendorId[i], ((PUCHAR)identifyData->ModelNumber)[i]);
+ MOV_DW_SWP(inquiryData->DeviceIdentificationString[i], ((PUCHAR)identifyData->ModelNumber)[i]);
}
/*
// Initialize unused portion of product id.
break;
+ case SCSIOP_REPORT_LUNS: {
+
+ ULONG alen;
+ PREPORT_LUNS_INFO_HDR LunInfo;
+
+ KdPrint2((PRINT_PREFIX
+ "IdeSendCommand: SCSIOP_REPORT_LUNS PATH:LUN:TID = %#x:%#x:%#x\n",
+ Srb->PathId, Srb->Lun, Srb->TargetId));
+
+ MOV_DD_SWP(alen, cdb->REPORT_LUNS.AllocationLength);
+
+ if(alen < 16) {
+ goto invalid_cdb;
+ }
+ alen = 8;
+
+ LunInfo = (PREPORT_LUNS_INFO_HDR)(Srb->DataBuffer);
+ RtlZeroMemory(LunInfo, 16);
+
+ MOV_DD_SWP( LunInfo->ListLength, alen );
+ Srb->DataTransferLength = 16;
+ status = SRB_STATUS_SUCCESS;
+
+ break; }
+
case SCSIOP_MODE_SENSE:
KdPrint2((PRINT_PREFIX
"IdeSendCommand: SCSIOP_MODE_SENSE PATH:LUN:TID = %#x:%#x:%#x\n",
Srb->PathId, Srb->Lun, Srb->TargetId));
- // This is used to determine if the media is write-protected.
- // Since IDE does not support mode sense then we will modify just the portion we need
- // so the higher level driver can determine if media is protected.
- if (chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED) {
+
+ if(cdb->MODE_SENSE.PageCode == MODE_PAGE_POWER_CONDITION) {
+ PMODE_POWER_CONDITION_PAGE modeData;
- SelectDrive(chan, DeviceNumber);
- AtapiWritePort1(chan, IDX_IO1_o_Command,IDE_COMMAND_GET_MEDIA_STATUS);
- statusByte = WaitOnBusy(chan);
+ KdPrint2((PRINT_PREFIX "MODE_PAGE_POWER_CONDITION\n"));
+ modeData = (PMODE_POWER_CONDITION_PAGE)(Srb->DataBuffer);
+ if(cdb->MODE_SENSE.AllocationLength < sizeof(MODE_POWER_CONDITION_PAGE)) {
+ status = SRB_STATUS_DATA_OVERRUN;
+ } 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);
+ status = SRB_STATUS_SUCCESS;
+ }
+ } else
+ if(cdb->MODE_SENSE.PageCode == MODE_PAGE_CACHING) {
+ PMODE_CACHING_PAGE modeData;
- if (!(statusByte & IDE_STATUS_ERROR)){
+ KdPrint2((PRINT_PREFIX "MODE_PAGE_CACHING\n"));
+ modeData = (PMODE_CACHING_PAGE)(Srb->DataBuffer);
+ if(cdb->MODE_SENSE.AllocationLength < sizeof(MODE_CACHING_PAGE)) {
+ status = SRB_STATUS_DATA_OVERRUN;
+ } else {
+ RtlZeroMemory(modeData, sizeof(MODE_CACHING_PAGE));
+ modeData->PageCode = MODE_PAGE_CACHING;
+ modeData->PageLength = sizeof(MODE_CACHING_PAGE)-sizeof(MODE_PARAMETER_HEADER);
+ modeData->ReadDisableCache = (LunExt->DeviceFlags & DFLAGS_RCACHE_ENABLED) ? 0 : 1;
+ modeData->WriteCacheEnable = (LunExt->DeviceFlags & DFLAGS_WCACHE_ENABLED) ? 1 : 0;
+ Srb->DataTransferLength = sizeof(MODE_CACHING_PAGE);
+ status = SRB_STATUS_SUCCESS;
+ }
+ } else
+ if (LunExt->DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED) {
+
+ // This is used to determine if the media is write-protected.
+ // Since IDE does not support mode sense then we will modify just the portion we need
+ // so the higher level driver can determine if media is protected.
+
+ //SelectDrive(chan, DeviceNumber);
+ //AtapiWritePort1(chan, IDX_IO1_o_Command,IDE_COMMAND_GET_MEDIA_STATUS);
+ //statusByte = WaitOnBusy(chan);
+ statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel, IDE_COMMAND_GET_MEDIA_STATUS, 0, 0, 0, 0, 0, ATA_WAIT_READY);
+
+ if (!(statusByte & IDE_STATUS_ERROR)) {
// no error occured return success, media is not protected
- chan->ExpectingInterrupt = FALSE;
+ UniataExpectChannelInterrupt(chan, FALSE);
InterlockedExchange(&(chan->CheckIntr),
CHECK_INTR_IDLE);
status = SRB_STATUS_SUCCESS;
errorByte = AtapiReadPort1(chan, IDX_IO1_i_Error);
GetBaseStatus(chan, statusByte);
- chan->ExpectingInterrupt = FALSE;
+ UniataExpectChannelInterrupt(chan, FALSE);
InterlockedExchange(&(chan->CheckIntr),
CHECK_INTR_IDLE);
status = SRB_STATUS_SUCCESS;
if (chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED) {
// Select device 0 or 1.
- SelectDrive(chan, DeviceNumber);
- AtapiWritePort1(chan, IDX_IO1_o_Command,IDE_COMMAND_GET_MEDIA_STATUS);
-
+ //SelectDrive(chan, DeviceNumber);
+ //AtapiWritePort1(chan, IDX_IO1_o_Command,IDE_COMMAND_GET_MEDIA_STATUS);
// Wait for busy. If media has not changed, return success
- statusByte = WaitOnBusy(chan);
+ //statusByte = WaitOnBusy(chan);
+ statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel, IDE_COMMAND_GET_MEDIA_STATUS, 0, 0, 0, 0, 0, ATA_WAIT_READY);
if (!(statusByte & IDE_STATUS_ERROR)){
- chan->ExpectingInterrupt = FALSE;
+ UniataExpectChannelInterrupt(chan, FALSE);
InterlockedExchange(&(chan->CheckIntr),
CHECK_INTR_IDLE);
status = SRB_STATUS_SUCCESS;
// the 0xDA command will always fail since the write-protect bit
// is sticky,so we can ignore this error
GetBaseStatus(chan, statusByte);
- chan->ExpectingInterrupt = FALSE;
+ UniataExpectChannelInterrupt(chan, FALSE);
InterlockedExchange(&(chan->CheckIntr),
CHECK_INTR_IDLE);
status = SRB_STATUS_SUCCESS;
} else {
// Request sense buffer to be build
- chan->ExpectingInterrupt = TRUE;
+ UniataExpectChannelInterrupt(chan, TRUE);
InterlockedExchange(&(chan->CheckIntr),
CHECK_INTR_IDLE);
status = SRB_STATUS_PENDING;
// Claim 512 byte blocks (big-endian).
//((PREAD_CAPACITY_DATA)Srb->DataBuffer)->BytesPerBlock = 0x20000;
i = DEV_BSIZE;
+ RtlZeroMemory(Srb->DataBuffer, sizeof(READ_CAPACITY_DATA));
MOV_DD_SWP( ((PREAD_CAPACITY_DATA)Srb->DataBuffer)->BytesPerBlock, i );
// Calculate last sector.
- if(!(i = (ULONG)chan->lun[DeviceNumber]->NumOfSectors)) {
- i = chan->lun[DeviceNumber]->IdentifyData.SectorsPerTrack *
- chan->lun[DeviceNumber]->IdentifyData.NumberOfHeads *
- chan->lun[DeviceNumber]->IdentifyData.NumberOfCylinders;
+ if(!(i = (ULONG)LunExt->NumOfSectors)) {
+ i = LunExt->IdentifyData.SectorsPerTrack *
+ LunExt->IdentifyData.NumberOfHeads *
+ LunExt->IdentifyData.NumberOfCylinders;
}
i--;
KdPrint2((PRINT_PREFIX
"** IDE disk %#x - #sectors %#x, #heads %#x, #cylinders %#x\n",
Srb->TargetId,
- chan->lun[DeviceNumber]->IdentifyData.SectorsPerTrack,
- chan->lun[DeviceNumber]->IdentifyData.NumberOfHeads,
- chan->lun[DeviceNumber]->IdentifyData.NumberOfCylinders));
+ LunExt->IdentifyData.SectorsPerTrack,
+ LunExt->IdentifyData.NumberOfHeads,
+ LunExt->IdentifyData.NumberOfCylinders));
status = SRB_STATUS_SUCCESS;
break;
+ case SCSIOP_SERVICE_ACTION16:
+
+ if( cdb->SERVICE_ACTION16.ServiceAction==SCSIOP_SA_READ_CAPACITY16 ) {
+ KdPrint2((PRINT_PREFIX
+ "** IdeSendCommand: SCSIOP_READ_CAPACITY PATH:LUN:TID = %#x:%#x:%#x\n",
+ Srb->PathId, Srb->Lun, Srb->TargetId));
+ // Claim 512 byte blocks (big-endian).
+ //((PREAD_CAPACITY_DATA)Srb->DataBuffer)->BytesPerBlock = 0x20000;
+ i = DEV_BSIZE;
+ RtlZeroMemory(Srb->DataBuffer, sizeof(READ_CAPACITY16_DATA));
+ MOV_DD_SWP( ((PREAD_CAPACITY16_DATA)Srb->DataBuffer)->BytesPerBlock, i );
+
+ // Calculate last sector.
+ if(!(lba = LunExt->NumOfSectors)) {
+ lba = LunExt->IdentifyData.SectorsPerTrack *
+ LunExt->IdentifyData.NumberOfHeads *
+ LunExt->IdentifyData.NumberOfCylinders;
+ }
+ lba--;
+ MOV_QD_SWP( ((PREAD_CAPACITY16_DATA)Srb->DataBuffer)->LogicalBlockAddress, lba );
+
+ KdPrint2((PRINT_PREFIX
+ "** IDE disk %#x - #sectors %#x, #heads %#x, #cylinders %#x (16)\n",
+ Srb->TargetId,
+ LunExt->IdentifyData.SectorsPerTrack,
+ LunExt->IdentifyData.NumberOfHeads,
+ LunExt->IdentifyData.NumberOfCylinders));
+
+ status = SRB_STATUS_SUCCESS;
+ } else {
+ goto default_abort;
+ }
+ break;
+
case SCSIOP_VERIFY:
+ case SCSIOP_VERIFY12:
+ case SCSIOP_VERIFY16:
KdPrint2((PRINT_PREFIX
"IdeSendCommand: SCSIOP_VERIFY PATH:LUN:TID = %#x:%#x:%#x\n",
case SCSIOP_READ:
case SCSIOP_WRITE:
+ case SCSIOP_READ12:
+ case SCSIOP_WRITE12:
+ case SCSIOP_READ16:
+ case SCSIOP_WRITE16:
KdPrint2((PRINT_PREFIX
"IdeSendCommand: SCSIOP_%s PATH:LUN:TID = %#x:%#x:%#x\n",
(Srb->Cdb[0] == SCSIOP_WRITE) ? "WRITE" : "READ",
Srb->PathId, Srb->Lun, Srb->TargetId));
AtaReq->Flags &= ~REQ_FLAG_RW_MASK;
- AtaReq->Flags |= (Srb->Cdb[0] == SCSIOP_WRITE) ? REQ_FLAG_WRITE : REQ_FLAG_READ;
+ AtaReq->Flags |= (Srb->Cdb[0] == SCSIOP_WRITE ||
+ Srb->Cdb[0] == SCSIOP_WRITE12 ||
+ Srb->Cdb[0] == SCSIOP_WRITE16) ? REQ_FLAG_WRITE : REQ_FLAG_READ;
status = IdeReadWrite(HwDeviceExtension,
Srb, CmdAction);
break;
case SCSIOP_START_STOP_UNIT:
KdPrint2((PRINT_PREFIX
- "IdeSendCommand: SCSIOP_START_STOP_UNIT PATH:LUN:TID = %#x:%#x:%#x\n",
- Srb->PathId, Srb->Lun, Srb->TargetId));
+ "IdeSendCommand: SCSIOP_START_STOP_UNIT immed %d PATH:LUN:TID = %#x:%#x:%#x\n",
+ cdb->START_STOP.Immediate, Srb->PathId, Srb->Lun, Srb->TargetId));
//Determine what type of operation we should perform
- cdb = (PCDB)Srb->Cdb;
- if (cdb->START_STOP.LoadEject == 1){
+ command = 0;
- statusByte = WaitOnBaseBusy(chan);
+ if(cdb->START_STOP.FL ||
+ cdb->START_STOP.FormatLayerNumber ||
+ cdb->START_STOP.Reserved2 ||
+ cdb->START_STOP.Reserved2_2 ||
+ cdb->START_STOP.Reserved3 ||
+ FALSE) {
+ goto invalid_cdb;
+ }
+
+ if (cdb->START_STOP.PowerConditions) {
+ KdPrint2((PRINT_PREFIX "START_STOP Power %d\n", cdb->START_STOP.PowerConditions));
+ switch(cdb->START_STOP.PowerConditions) {
+ case StartStop_Power_Idle:
+ command = IDE_COMMAND_IDLE_IMMED;
+ break;
+ case StartStop_Power_Standby:
+ command = IDE_COMMAND_STANDBY_IMMED;
+ break;
+ case StartStop_Power_Sleep:
+ // TODO: we should save power state in order to know
+ // that RESET sould be issued to revert device into
+ // operable state
+
+ command = IDE_COMMAND_SLEEP;
+ break;
+ default:
+ goto invalid_cdb;
+ }
+ LunExt->PowerState = cdb->START_STOP.PowerConditions;
+ } else
+ if (cdb->START_STOP.LoadEject == 1) {
+ KdPrint2((PRINT_PREFIX "START_STOP eject\n"));
// Eject media,
// first select device 0 or 1.
- SelectDrive(chan, DeviceNumber);
- AtapiWritePort1(chan, IDX_IO1_o_Command,IDE_COMMAND_MEDIA_EJECT);
+ //SelectDrive(chan, DeviceNumber);
+ //AtapiWritePort1(chan, IDX_IO1_o_Command,IDE_COMMAND_MEDIA_EJECT);
+ command = IDE_COMMAND_MEDIA_EJECT;
+ } else
+ if (cdb->START_STOP.Start == 0) {
+ KdPrint2((PRINT_PREFIX "START_STOP standby\n"));
+ command = IDE_COMMAND_STANDBY_IMMED;
+ } else {
+ // TODO: we may need to perform hard reset (after sleep) or
+ // issue IDE_COMMAND_IDLE_IMMED in order to activate device
+ KdPrint2((PRINT_PREFIX "START_STOP activate\n"));
+
+ if(LunExt->PowerState == StartStop_Power_Sleep) {
+ UniataUserDeviceReset(deviceExtension, LunExt, lChannel);
+ status = SRB_STATUS_SUCCESS;
+ break;
+ } else
+ if(LunExt->PowerState > StartStop_Power_Idle) {
+ KdPrint2((PRINT_PREFIX " issue IDLE\n"));
+ command = IDE_COMMAND_IDLE_IMMED;
+ } else {
+ KdPrint2((PRINT_PREFIX " do nothing\n"));
+ status = SRB_STATUS_SUCCESS;
+ break;
+ }
+ }
+ if(command) {
+ statusByte = WaitOnBaseBusy(chan);
+ statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel, command, 0, 0, 0, 0, 0,
+ cdb->START_STOP.Immediate ? ATA_IMMEDIATE : ATA_WAIT_READY);
+ status = (statusByte & IDE_STATUS_ERROR) ? SRB_STATUS_ERROR : SRB_STATUS_SUCCESS;
+ //UniataExpectChannelInterrupt(chan, TRUE); // device may interrupt
+
+ } else {
+invalid_cdb:
+ KdPrint2((PRINT_PREFIX "START_STOP invalid\n"));
+ if (Srb->SenseInfoBuffer) {
+
+ PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer;
+
+ senseBuffer->ErrorCode = 0x70;
+ senseBuffer->Valid = 1;
+ senseBuffer->AdditionalSenseLength = 0xb;
+ senseBuffer->SenseKey = SCSI_SENSE_ILLEGAL_REQUEST;
+ senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_INVALID_CDB;
+ senseBuffer->AdditionalSenseCodeQualifier = 0;
+
+ Srb->SrbStatus = SRB_STATUS_AUTOSENSE_VALID;
+ Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
+ }
+ status = SRB_STATUS_ERROR;
}
- status = SRB_STATUS_SUCCESS;
break;
case SCSIOP_MEDIUM_REMOVAL:
- cdb = (PCDB)Srb->Cdb;
+ cdb = (PCDB)Srb->Cdb;
- statusByte = WaitOnBaseBusy(chan);
+ if(LunExt->IdentifyData.Removable) {
+ statusByte = WaitOnBaseBusy(chan);
- SelectDrive(chan, DeviceNumber);
- if (cdb->MEDIA_REMOVAL.Prevent == TRUE) {
- AtapiWritePort1(chan, IDX_IO1_o_Command,IDE_COMMAND_DOOR_LOCK);
- } else {
- AtapiWritePort1(chan, IDX_IO1_o_Command,IDE_COMMAND_DOOR_UNLOCK);
- }
- status = SRB_STATUS_SUCCESS;
- break;
+ //SelectDrive(chan, DeviceNumber);
+ if (cdb->MEDIA_REMOVAL.Prevent == TRUE) {
+ //AtapiWritePort1(chan, IDX_IO1_o_Command,IDE_COMMAND_DOOR_LOCK);
+ statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel, IDE_COMMAND_DOOR_LOCK, 0, 0, 0, 0, 0, ATA_IMMEDIATE);
+ } else {
+ //AtapiWritePort1(chan, IDX_IO1_o_Command,IDE_COMMAND_DOOR_UNLOCK);
+ statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel, IDE_COMMAND_DOOR_UNLOCK, 0, 0, 0, 0, 0, ATA_IMMEDIATE);
+ }
+ status = SRB_STATUS_SUCCESS;
+ } else {
+ status = SRB_STATUS_INVALID_REQUEST;
+ }
+ break;
+#if 0
// Note: I don't implement this, because NTFS driver too often issues this command
// It causes awful performance degrade. However, if somebody wants, I will implement
// SCSIOP_FLUSH_BUFFER/SCSIOP_SYNCHRONIZE_CACHE optionally.
-
-#if 0
case SCSIOP_FLUSH_BUFFER:
case SCSIOP_SYNCHRONIZE_CACHE:
KdPrint2((PRINT_PREFIX
"IdeSendCommand: SCSIOP_REQUEST_SENSE PATH:LUN:TID = %#x:%#x:%#x\n",
Srb->PathId, Srb->Lun, Srb->TargetId));
- if (chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED) {
+ if (LunExt->DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED) {
status = IdeBuildSenseBuffer(HwDeviceExtension,Srb);
break;
}
regs = (PIDEREGS_EX) &(Srb->Cdb[2]);
- lChannel = Srb->TargetId >> 1;
-
- regs->bDriveHeadReg &= 0x0f;
- regs->bDriveHeadReg |= (UCHAR) (((Srb->TargetId & 0x1) << 4) | 0xA0);
+ if(chan->DeviceExtension->HwFlags & UNIATA_SATA) {
+ //lChannel = Srb->TargetId >> 1;
+ } else {
+ DeviceNumber = max(DeviceNumber, 1);
+ regs->bDriveHeadReg &= 0x0f;
+ regs->bDriveHeadReg |= (UCHAR) (((DeviceNumber & 0x1) << 4) | 0xA0);
+ }
if((regs->bOpFlags & 1) == 0) { // execute ATA command
KdPrint2((PRINT_PREFIX
- "IdeSendCommand: SCSIOP_START_STOP_UNIT PATH:LUN:TID = %#x:%#x:%#x\n",
+ "IdeSendCommand: SCSIOP_ATA_PASSTHROUGH (exec) PATH:LUN:TID = %#x:%#x:%#x\n",
Srb->PathId, Srb->Lun, Srb->TargetId));
+ if((regs->bOpFlags & UNIATA_SPTI_EX_SPEC_TO) == UNIATA_SPTI_EX_SPEC_TO) {
+ to_lim = Srb->TimeOutValue;
+ } else {
+ if(Srb->TimeOutValue <= 2) {
+ to_lim = Srb->TimeOutValue*900;
+ } else {
+ to_lim = (Srb->TimeOutValue*999) - 500;
+ }
+ }
AtapiDisableInterrupts(deviceExtension, lChannel);
+ if(chan->DeviceExtension->HwFlags & UNIATA_AHCI) {
+ // AHCI
+ statusByte = UniataAhciSendPIOCommandDirect(
+ deviceExtension,
+ lChannel,
+ DeviceNumber,
+ Srb,
+ regs,
+ ATA_WAIT_INTR,
+ to_lim
+ );
+ if(statusByte == IDE_STATUS_WRONG) {
+ goto passthrough_err;
+ }
+ if(statusByte & (IDE_STATUS_BUSY | IDE_STATUS_ERROR)) {
+ UniataAhciAbortOperation(chan);
+ goto passthrough_err;
+ }
+ goto passthrough_done;
+ }
+
+ // SATA/PATA
if((AtaCommandFlags[regs->bCommandReg] & ATA_CMD_FLAG_DMA) || (regs->bOpFlags & UNIATA_SPTI_EX_USE_DMA)) {
- if((chan->lun[Srb->TargetId & 0x1]->LimitedTransferMode >= ATA_DMA)) {
+ if((chan->lun[DeviceNumber]->LimitedTransferMode >= ATA_DMA)) {
use_dma = TRUE;
// this will set REQ_FLAG_DMA_OPERATION in AtaReq->Flags on success
- if(!AtapiDmaSetup(HwDeviceExtension, Srb->TargetId & 0x1, lChannel, Srb,
+ if(!AtapiDmaSetup(HwDeviceExtension, DeviceNumber, lChannel, Srb,
(PUCHAR)(Srb->DataBuffer),
((Srb->DataTransferLength + DEV_BSIZE-1) & ~(DEV_BSIZE-1)))) {
use_dma = FALSE;
}
}
- AtapiWritePort1(chan, IDX_IO1_o_DriveSelect, regs->bDriveHeadReg);
+ 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);
if(statusByte & IDE_STATUS_ERROR) {
goto passthrough_err;
}
- AtapiDmaStart(HwDeviceExtension, (Srb->TargetId & 0x1), lChannel, Srb);
+ AtapiDmaStart(HwDeviceExtension, DeviceNumber, lChannel, Srb);
}
ScsiPortStallExecution(1); // wait for busy to be set
- if(regs->bOpFlags & UNIATA_SPTI_EX_SPEC_TO) {
- to_lim = Srb->TimeOutValue;
- } else {
- if(Srb->TimeOutValue <= 2) {
- to_lim = Srb->TimeOutValue*900;
- } else {
- to_lim = (Srb->TimeOutValue*999) - 500;
- }
- }
for(i=0; i<to_lim;i+=2) { // 2 msec from WaitOnBaseBusy()
statusByte = WaitOnBaseBusy(chan); // wait for busy to be clear, up to 2 msec
GetBaseStatus(chan, statusByte);
if(use_dma) {
AtapiCheckInterrupt__(deviceExtension, (UCHAR)lChannel);
}
- AtapiDmaDone(deviceExtension, (Srb->TargetId & 0x1), lChannel, NULL);
+ AtapiDmaDone(deviceExtension, DeviceNumber, lChannel, NULL);
GetBaseStatus(chan, statusByte);
if(statusByte & (IDE_STATUS_BUSY | IDE_STATUS_ERROR)) {
}
status = SRB_STATUS_SUCCESS;
}
-
+passthrough_done:;
AtapiEnableInterrupts(deviceExtension, lChannel);
} else { // read task register
+ BOOLEAN use48;
regs = (PIDEREGS_EX) Srb->DataBuffer;
- regs->bDriveHeadReg = AtapiReadPort1(chan, IDX_IO1_i_DriveSelect);
+ KdPrint2((PRINT_PREFIX
+ "IdeSendCommand: SCSIOP_ATA_PASSTHROUGH (snap) PATH:LUN:TID = %#x:%#x:%#x\n",
+ Srb->PathId, Srb->Lun, Srb->TargetId));
- if((regs->bOpFlags & ATA_FLAGS_48BIT_COMMAND) == 0) { // execute ATA command
- regs->bFeaturesReg = AtapiReadPort1(chan, IDX_IO1_i_Error);
- regs->bSectorCountReg = AtapiReadPort1(chan, IDX_IO1_i_BlockCount);
- regs->bSectorNumberReg = AtapiReadPort1(chan, IDX_IO1_i_BlockNumber);
- regs->bCylLowReg = AtapiReadPort1(chan, IDX_IO1_i_CylinderLow);
- regs->bCylHighReg = AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh);
+ if((Srb->DataTransferLength >= sizeof(IDEREGS_EX)) &&
+ (regs->bOpFlags & ATA_FLAGS_48BIT_COMMAND)) {
+ use48 = TRUE;
+ } else
+ if(Srb->DataTransferLength >= sizeof(IDEREGS)) {
+ use48 = FALSE;
} else {
- regs->bFeaturesReg = AtapiReadPort1(chan, IDX_IO1_i_Error);
- regs->bFeaturesRegH = AtapiReadPort1(chan, IDX_IO1_i_Error);
- regs->bSectorCountReg = AtapiReadPort1(chan, IDX_IO1_i_BlockCount);
- regs->bSectorCountRegH = AtapiReadPort1(chan, IDX_IO1_i_BlockCount);
- regs->bSectorNumberReg = AtapiReadPort1(chan, IDX_IO1_i_BlockNumber);
- regs->bSectorNumberRegH= AtapiReadPort1(chan, IDX_IO1_i_BlockNumber);
- regs->bCylLowReg = AtapiReadPort1(chan, IDX_IO1_i_CylinderLow);
- regs->bCylLowRegH = AtapiReadPort1(chan, IDX_IO1_i_CylinderLow);
- regs->bCylHighReg = AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh);
- regs->bCylHighRegH = AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh);
+ KdPrint2((PRINT_PREFIX " buffer too small \n"));
+ status = SRB_STATUS_DATA_OVERRUN;
+ break;
}
- regs->bCommandReg = AtapiReadPort1(chan, IDX_IO1_i_Status);
+ RtlZeroMemory(regs, use48 ? sizeof(IDEREGS_EX) : sizeof(IDEREGS));
+ regs->bOpFlags = use48 ? ATA_FLAGS_48BIT_COMMAND : 0;
+ UniataSnapAtaRegs(chan, 0, regs);
+
status = SRB_STATUS_SUCCESS;
}
break;
}
default:
-
+default_abort:
KdPrint2((PRINT_PREFIX
"IdeSendCommand: Unsupported command %#x\n",
Srb->Cdb[0]));
UCHAR statusByte,errorByte;
chan = &(deviceExtension->chan[lChannel]);
+ SelectDrive(chan, DeviceNumber);
if (EnableMSN == TRUE){
UniataUserDeviceReset(
PHW_DEVICE_EXTENSION deviceExtension,
PHW_LU_EXTENSION LunExt,
- ULONG PathId
+ ULONG lChannel
)
{
ULONG i;
- AtapiDisableInterrupts(deviceExtension, PathId);
- if (LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) {
+ AtapiDisableInterrupts(deviceExtension, lChannel);
+ if ((LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) &&
+ (LunExt->PowerState != StartStop_Power_Sleep)) {
KdPrint2((PRINT_PREFIX "UniataUserDeviceReset: Reset ATAPI\n"));
- AtapiSoftReset(&(deviceExtension->chan[PathId]), LunExt->Lun);
+ AtapiSoftReset(&(deviceExtension->chan[lChannel]), LunExt->Lun);
} else {
KdPrint2((PRINT_PREFIX "UniataUserDeviceReset: Reset IDE -> reset entire channel\n"));
- AtapiResetController__(deviceExtension, PathId, RESET_COMPLETE_NONE);
+ AtapiResetController__(deviceExtension, lChannel, RESET_COMPLETE_NONE);
for(i=0; i<deviceExtension->NumberLuns; i++) {
- deviceExtension->chan[PathId].lun[i]->DeviceFlags |= DFLAGS_REINIT_DMA;
+ deviceExtension->chan[lChannel].lun[i]->DeviceFlags |= DFLAGS_REINIT_DMA;
}
}
LunExt->DeviceFlags |= DFLAGS_REINIT_DMA; // force PIO/DMA reinit
- AtapiEnableInterrupts(deviceExtension, PathId);
+ AtapiEnableInterrupts(deviceExtension, lChannel);
return;
} // end UniataUserDeviceReset()
This routine is called from the SCSI port driver synchronized
with the kernel to start an IO request.
+ ->HwStartIo
Arguments:
*/
if(TopLevel && Srb && Srb->SrbExtension) {
KdPrint2((PRINT_PREFIX "TopLevel\n"));
- RtlZeroMemory(Srb->SrbExtension, sizeof(ATA_REQ));
+ //RtlZeroMemory(Srb->SrbExtension, sizeof(ATA_REQ));
+ UniAtaClearAtaReq(Srb->SrbExtension);
}
- do {
+ do { // fetch all queued commands for the channel (if valid)
lChannel = GET_CHANNEL(Srb);
//ldev = GET_LDEV(Srb);
chan = NULL;
LunExt = NULL;
DeviceNumber = GET_CDEV(Srb);
+ commPort = FALSE;
//ASSERT(deviceExtension);
//ASSERT(chan);
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 &&
((Srb->Function == SRB_FUNCTION_IO_CONTROL) ||
(Srb->Function == SRB_FUNCTION_EXECUTE_SCSI && Srb->Cdb[0] == SCSIOP_INQUIRY))
) {
+ // This is our virtual device
KdPrint2((PRINT_PREFIX
"AtapiStartIo: Communication port\n"));
if(Srb->Function == SRB_FUNCTION_EXECUTE_SCSI) {
+ if(Srb->DataTransferLength < sizeof(PINQUIRYDATA)) {
+ KdPrint2((PRINT_PREFIX "AtapiStartIo: Buffer too small: %#x < %#x\n", Srb->DataTransferLength,
+ sizeof(PINQUIRYDATA) ));
+wrong_buffer_size:
+ status = SRB_STATUS_DATA_OVERRUN;
+ goto complete_req;
+ }
+
PINQUIRYDATA inquiryData = (PINQUIRYDATA)(Srb->DataBuffer);
KdPrint2((PRINT_PREFIX
/* Pass IOCTL request down */
} else
if(lChannel >= deviceExtension->NumberChannels ||
- Srb->TargetId /*DeviceNumber*/ >= deviceExtension->NumberLuns ||
- Srb->Lun) {
+ Srb->TargetId /*DeviceNumber*/ >= deviceExtension->NumberLuns ||
+ Srb->Lun) {
- if(lChannel >= deviceExtension->NumberChannels) {
- chan = NULL;
- }
+ if(lChannel >= deviceExtension->NumberChannels) {
+ chan = NULL;
+ }
reject_srb:
//if(!CheckDevice(HwDeviceExtension, lChannel, DeviceNumber, FALSE)) {
- KdPrint3((PRINT_PREFIX
+ KdPrint3((PRINT_PREFIX
"AtapiStartIo: SRB rejected\n"));
- // Indicate no device found at this address.
- KdPrint2((PRINT_PREFIX "SRB_STATUS_SELECTION_TIMEOUT\n"));
- status = SRB_STATUS_SELECTION_TIMEOUT;
- goto complete_req;
+ // Indicate no device found at this address.
+ KdPrint2((PRINT_PREFIX "SRB_STATUS_SELECTION_TIMEOUT\n"));
+ status = SRB_STATUS_SELECTION_TIMEOUT;
+ goto complete_req;
//}
+ } else
+ if((deviceExtension->HwFlags & UNIATA_AHCI) &&
+ !UniataAhciChanImplemented(deviceExtension, lChannel)) {
+ chan = NULL;
}
if(!commPort) {
break;
//}
}
+ } else {
+ KdPrint2((PRINT_PREFIX
+ " SRB %#x, CDB %#x, AtaReq %#x, SCmd %#x\n", Srb, &(Srb->Cdb), Srb->SrbExtension, Srb->Cdb[0]));
}
/*
__try {
KdPrint2((PRINT_PREFIX "AtapiStartIo: Already have %d request(s)!\n", chan->queue_depth));
} else {
+
// Send command to device.
- KdPrint2((PRINT_PREFIX "Send to device\n"));
+ KdPrint2((PRINT_PREFIX "Send to device %x\n", Srb->Cdb[0]));
if(TopLevel) {
KdPrint2((PRINT_PREFIX "TopLevel (2), srb %#x\n", Srb));
AtaReq = (PATA_REQ)(Srb->SrbExtension);
#endif //NAVO_TEST
if(atapiDev &&
- (Srb->Cdb[0] != SCSIOP_ATA_PASSTHROUGH)) {
- KdPrint3((PRINT_PREFIX "Try ATAPI send\n"));
+ (Srb->Cdb[0] != SCSIOP_ATA_PASSTHROUGH)/* &&
+ (Srb->Cdb[0] != SCSIOP_REPORT_LUNS)*/) {
+ KdPrint3((PRINT_PREFIX "Try ATAPI send %x\n", Srb->Cdb[0]));
status = AtapiSendCommand(HwDeviceExtension, Srb, CMD_ACTION_ALL);
} else {
KdPrint2((PRINT_PREFIX "Try IDE send\n"));
// For now we support only Lun=0
// Note: reset is immediate command, it cannot be queued since it is usually used to
- // revert not- responding device to operational state
+ // revert not-responding device to operational state
KdPrint2((PRINT_PREFIX "AtapiStartIo: Reset device request received\n"));
UniataUserDeviceReset(deviceExtension, LunExt, lChannel);
status = SRB_STATUS_SUCCESS;
break;
- case SRB_FUNCTION_FLUSH:
-
- KdPrint2((PRINT_PREFIX "AtapiStartIo: Flush (do nothing)\n"));
- status = SRB_STATUS_SUCCESS;
- break;
-
- /* case SRB_FUNCTION_SHUTDOWN:
- case SRB_FUNCTION_FLUSH:
-
- // Flush device's cache.
- KdPrint2((PRINT_PREFIX "AtapiStartIo: Device flush received\n"));
-
- if (chan->CurrentSrb) {
-
- KdPrint2((PRINT_PREFIX "AtapiStartIo (SRB_FUNCTION_FLUSH): Already have a request!\n"));
- Srb->SrbStatus = SRB_STATUS_BUSY;
- ScsiPortNotification(RequestComplete,
- deviceExtension,
- Srb);
- return FALSE;
- }
-
- if (LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) {
- status = SRB_STATUS_SUCCESS;
- } else {
- status = AtaCommand(deviceExtension, GET_CDEV(Srb), GET_CHANNEL(Srb),
- IDE_COMMAND_FLUSH_CACHE, 0, 0, 0, 0, 0, ATA_WAIT_INTR);
- if (status & IDE_STATUS_DRQ) {
- status = SRB_STATUS_SUCCESS;
- } else {
- status = SRB_STATUS_SELECTION_TIMEOUT;
- }
- }
- break;*/
+ case SRB_FUNCTION_FLUSH:
+
+ KdPrint2((PRINT_PREFIX "AtapiStartIo: Flush (do nothing)\n"));
+ status = SRB_STATUS_SUCCESS;
+ break;
case SRB_FUNCTION_IO_CONTROL: {
if(!AtapiStringCmp( (PCHAR)(((PSRB_IO_CONTROL)(Srb->DataBuffer))->Signature),"SCSIDISK",sizeof("SCSIDISK")-1)) {
+ ULONG targetId = (ULONG)(-1);
+
+ if(len < sizeof(SRB_IO_CONTROL)) {
+ goto wrong_buffer_size;
+ }
+
+ // extract bogus bus address
switch (((PSRB_IO_CONTROL)(Srb->DataBuffer))->ControlCode) {
case IOCTL_SCSI_MINIPORT_SMART_VERSION: {
-
PGETVERSIONINPARAMS versionParameters = (PGETVERSIONINPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
- UCHAR deviceNumber;
- KdPrint2((PRINT_PREFIX "AtapiStartIo: IOCTL_SCSI_MINIPORT_SMART_VERSION\n"));
+ if(len < sizeof(SRB_IO_CONTROL)+sizeof(GETVERSIONINPARAMS)) {
+ goto wrong_buffer_size;
+ }
- // Version and revision per SMART 1.03
+ targetId = versionParameters->bIDEDeviceMap;
+ KdPrint2((PRINT_PREFIX "targetId (smart ver) %d\n", targetId));
+ break; }
+ case IOCTL_SCSI_MINIPORT_IDENTIFY:
+ case IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS:
+ case IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS:
+ case IOCTL_SCSI_MINIPORT_ENABLE_SMART:
+ case IOCTL_SCSI_MINIPORT_DISABLE_SMART:
+ case IOCTL_SCSI_MINIPORT_RETURN_STATUS:
+ case IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE:
+ case IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES:
+ case IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS:
+ case IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTO_OFFLINE:
+ case IOCTL_SCSI_MINIPORT_READ_SMART_LOG:
+ case IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG:
+ {
+ PSENDCMDINPARAMS cmdInParameters = (PSENDCMDINPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
+
+ if(len < sizeof(SRB_IO_CONTROL)+sizeof(SENDCMDINPARAMS) - 1) {
+ goto wrong_buffer_size;
+ }
- versionParameters->bVersion = 1;
- versionParameters->bRevision = 1;
- versionParameters->bReserved = 0;
+ targetId = cmdInParameters->bDriveNumber;
+ KdPrint2((PRINT_PREFIX "targetId (smart/ident) %d\n", targetId));
+ break; }
+ default:
+invalid_request:
+ KdPrint2((PRINT_PREFIX "AtapiStartIo: invalid IoControl %#x for SCSIDISK signature\n",
+ ((PSRB_IO_CONTROL)(Srb->DataBuffer))->ControlCode ));
+ status = SRB_STATUS_INVALID_REQUEST;
+ goto complete_req;
+ } // end switch()
- // Indicate that support for IDE IDENTIFY, ATAPI IDENTIFY and SMART commands.
- versionParameters->fCapabilities = (CAP_ATA_ID_CMD | CAP_ATAPI_ID_CMD | CAP_SMART_CMD);
+ // adjust (if necessary) bus address
+ if(targetId != (ULONG)(-1)) {
// This is done because of how the IOCTL_SCSI_MINIPORT
// determines 'targetid's'. Disk.sys places the real target id value
// in the DeviceMap field. Once we do some parameter checking, the value passed
// back to the application will be determined.
- deviceNumber = versionParameters->bIDEDeviceMap;
-
+ if (deviceExtension->NumberChannels == 1) {
+ // do this for legacy controllers and legacy callers
+ KdPrint2((PRINT_PREFIX "AtapiStartIo: legacy call\n"));
+ DeviceNumber = (targetId & 0x01);
+ lChannel = 0;
+ } else
if(commPort) {
+ // do this for smartmontools, sending IOCTLs to PhysicalDrive%d
+ // due to DISK.SYS design bug, we have invalid SCSI address in SRB
+ KdPrint2((PRINT_PREFIX "AtapiStartIo: legacy call (2)\n"));
+ if(deviceExtension->HwFlags & UNIATA_AHCI) {
+ lChannel = (UCHAR)targetId / 2;
+ DeviceNumber = 0;
+ } else {
+ lChannel = (UCHAR)(targetId / 2);
+ DeviceNumber = targetId & 0x01;
+ }
+ } else {
+ // otherwise assume lChannel and DeviceNumber from Srb are ok
+ }
+ if(lChannel >= deviceExtension->NumberChannels ||
+ DeviceNumber >= deviceExtension->NumberLuns) {
KdPrint2((PRINT_PREFIX
- "AtapiStartIo: SCSIDISK IOCTL for commPort -> EXECUTE_SCSI rejected (2)\n"));
+ "AtapiStartIo: SCSIDISK IOCTL for non-exestent drive %d -> EXECUTE_SCSI rejected (2)\n",
+ targetId));
// Indicate no device found at this address.
- KdPrint2((PRINT_PREFIX "SRB_STATUS_SELECTION_TIMEOUT\n"));
- status = SRB_STATUS_SELECTION_TIMEOUT;
- break;
+ goto reject_srb;
+ }
+ targetId = lChannel*deviceExtension->NumberLuns+DeviceNumber;
+ chan = &(deviceExtension->chan[lChannel]);
+ LunExt = chan->lun[DeviceNumber];
+ if(!LunExt) {
+ goto reject_srb;
}
+ atapiDev = (LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) ? TRUE : FALSE;
- if (!(LunExt->DeviceFlags & DFLAGS_DEVICE_PRESENT) ||
- atapiDev) {
+ if (!(LunExt->DeviceFlags & DFLAGS_DEVICE_PRESENT)) {
+ goto reject_srb;
+ }
+ }
- status = SRB_STATUS_SELECTION_TIMEOUT;
- break;
+ switch (((PSRB_IO_CONTROL)(Srb->DataBuffer))->ControlCode) {
+ case IOCTL_SCSI_MINIPORT_SMART_VERSION: {
+
+ PGETVERSIONINPARAMS versionParameters = (PGETVERSIONINPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
+ UCHAR deviceNumberMap;
+
+ KdPrint2((PRINT_PREFIX "AtapiStartIo: IOCTL_SCSI_MINIPORT_SMART_VERSION\n"));
+
+ // Version and revision per SMART 1.03
+
+ versionParameters->bVersion = 1;
+ versionParameters->bRevision = 1;
+ versionParameters->bReserved = 0;
+
+ // Indicate that support for IDE IDENTIFY, ATAPI IDENTIFY and SMART commands.
+ versionParameters->fCapabilities = (CAP_ATA_ID_CMD | CAP_ATAPI_ID_CMD | CAP_SMART_CMD);
+
+ if (atapiDev) {
+ goto invalid_request;
}
// NOTE: This will only set the bit
// S M S M
// 3 2 1 0
+ if(chan->DeviceExtension->HwFlags & UNIATA_AHCI) {
+ deviceNumberMap = 1 << lChannel;
+ DeviceNumber = 0;
+ } else
if (deviceExtension->NumberChannels == 1) {
if (chan->PrimaryAddress) {
- deviceNumber = 1 << DeviceNumber;
+ deviceNumberMap = 1 << DeviceNumber;
} else {
- deviceNumber = 4 << DeviceNumber;
+ deviceNumberMap = 4 << DeviceNumber;
}
} else {
- deviceNumber = (1 << DeviceNumber) << lChannel;
+ deviceNumberMap = 1 << (DeviceNumber+lChannel*2);
}
- versionParameters->bIDEDeviceMap = deviceNumber;
+ versionParameters->bIDEDeviceMap = deviceNumberMap;
status = SRB_STATUS_SUCCESS;
break;
PSENDCMDOUTPARAMS cmdOutParameters = (PSENDCMDOUTPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
SENDCMDINPARAMS cmdInParameters = *(PSENDCMDINPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
- UCHAR targetId;
KdPrint2((PRINT_PREFIX "AtapiStartIo: IOCTL_SCSI_MINIPORT_IDENTIFY\n"));
// Extract the target.
- targetId = cmdInParameters.bDriveNumber;
KdPrint2((PRINT_PREFIX "targetId %d\n", targetId));
- if((targetId >= deviceExtension->NumberChannels*2) ||
- !(deviceExtension->lun[targetId].DeviceFlags & DFLAGS_DEVICE_PRESENT)) {
- KdPrint2((PRINT_PREFIX "Error: xxx_ID_CMD for non-existant device\n"));
- status = SRB_STATUS_SELECTION_TIMEOUT;
- break;
- }
switch(cmdInParameters.irDriveRegs.bCommandReg) {
case ID_CMD:
- if((deviceExtension->lun[targetId].DeviceFlags & DFLAGS_ATAPI_DEVICE)) {
+ if(atapiDev) {
KdPrint2((PRINT_PREFIX "Error: ID_CMD for ATAPI\n"));
- status = SRB_STATUS_INVALID_REQUEST;
- break;
+ goto invalid_request;
}
/* FALL THROUGH */
case ATAPI_ID_CMD:
- if(!(deviceExtension->lun[targetId].DeviceFlags & DFLAGS_ATAPI_DEVICE) &&
+ if(!atapiDev &&
(cmdInParameters.irDriveRegs.bCommandReg == ATAPI_ID_CMD)) {
KdPrint2((PRINT_PREFIX "Error: ATAPI_ID_CMD for non-ATAPI\n"));
- status = SRB_STATUS_INVALID_REQUEST;
- break;
+ goto invalid_request;
}
len = min(len, sizeof(SENDCMDOUTPARAMS) - 1 + IDENTIFY_BUFFER_SIZE);
cmdOutParameters->DriverStatus.bIDEError = 0;
// Extract the identify data from the device extension.
- ScsiPortMoveMemory (cmdOutParameters->bBuffer, &deviceExtension->lun[targetId].IdentifyData,
+ ScsiPortMoveMemory (cmdOutParameters->bBuffer, &(LunExt->IdentifyData),
cmdOutParameters->cBufferSize);
+ if((cmdOutParameters->cBufferSize == IDENTIFY_BUFFER_SIZE) &&
+ (LunExt->IdentifyData.ChecksumValid == ATA_ChecksumValid)) {
+ // adjust checksum if it is possible
+ CHAR csum = 0;
+ ULONG i;
+
+ for(i=0; i < IDENTIFY_BUFFER_SIZE-1; i++) {
+ csum += (CHAR)(cmdOutParameters->bBuffer[i]);
+ }
+ cmdOutParameters->bBuffer[i] = -csum;
+ KdPrint2((PRINT_PREFIX "AtapiStartIo: adjust checksum %d\n"));
+ }
KdPrint2((PRINT_PREFIX "AtapiStartIo: IOCTL_SCSI_MINIPORT_IDENTIFY Ok\n"));
status = SRB_STATUS_SUCCESS;
}
break;
}
-
+/*
case IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS:
case IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS:
case IOCTL_SCSI_MINIPORT_ENABLE_SMART:
case IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE:
case IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES:
case IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS:
-
+*/
+ default:
+ // *all* IOCTLs here are SMART
if(commPort) {
KdPrint2((PRINT_PREFIX
"AtapiStartIo: SCSIDISK Smart IOCTL for commPort -> EXECUTE_SCSI rejected (3)\n"));
- // Indicate no device found at this address.
- KdPrint2((PRINT_PREFIX "SRB_STATUS_SELECTION_TIMEOUT\n"));
- status = SRB_STATUS_SELECTION_TIMEOUT;
- break;
+ }
+ if (atapiDev) {
+ goto invalid_request;
}
PostReq = UniataNeedQueueing(deviceExtension, chan, TopLevel);
KdPrint2((PRINT_PREFIX "AtapiStartIo: Already have %d request(s)!\n", chan->queue_depth));
} else {
- status = IdeSendSmartCommand(HwDeviceExtension,Srb);
+ status = IdeSendSmartCommand(HwDeviceExtension, Srb, targetId);
}
break;
- default :
+ // we should not get here, checked above
+/* default :
KdPrint2((PRINT_PREFIX "AtapiStartIo: invalid IoControl %#x for SCSIDISK signature\n",
((PSRB_IO_CONTROL)(Srb->DataBuffer))->ControlCode ));
status = SRB_STATUS_INVALID_REQUEST;
break;
-
+*/
}
} else
if(!AtapiStringCmp( (PCHAR)(((PSRB_IO_CONTROL)(Srb->DataBuffer))->Signature),"-UNIATA-", sizeof("-UNIATA-")-1)) {
//ULONG ldev = GET_LDEV2(AtaCtl->addr.PathId, AtaCtl->addr.TargetId, 0);
ULONG DeviceNumber = AtaCtl->addr.TargetId;
BOOLEAN bad_ldev;
- ULONG i;
+ ULONG i, pos;
+
+ pos = FIELD_OFFSET(UNIATA_CTL, RawData);
//chan = &(deviceExtension->chan[lChannel]);
+ if(len < pos) {
+ KdPrint2((PRINT_PREFIX "AtapiStartIo: AtaCtl Buffer too small: %#x < %#x\n", len,
+ FIELD_OFFSET(UNIATA_CTL, RawData) ));
+ goto wrong_buffer_size;
+ }
if(AtaCtl->addr.Lun ||
AtaCtl->addr.TargetId >= deviceExtension->NumberLuns ||
}
goto uata_ctl_queue;
case IOCTL_SCSI_MINIPORT_UNIATA_SET_MAX_MODE:
+ if(len < pos+sizeof(AtaCtl->SetMode)) {
+ KdPrint2((PRINT_PREFIX "AtapiStartIo: AtaCtl Buffer too small: %#x < %#x\n", len,
+ pos+sizeof(AtaCtl->SetMode) ));
+ goto wrong_buffer_size;
+ }
if(!AtaCtl->SetMode.ApplyImmediately) {
break;
}
KdPrint2((PRINT_PREFIX "AtapiStartIo: rescan bus\n"));
+ if(len < pos+sizeof(AtaCtl->FindDelDev)) {
+ KdPrint2((PRINT_PREFIX "AtapiStartIo: AtaCtl Buffer too small: %#x < %#x\n", len,
+ pos+sizeof(AtaCtl->FindDelDev) ));
+ goto wrong_buffer_size;
+ }
if(AtaCtl->FindDelDev.Flags & UNIATA_ADD_FLAGS_UNHIDE) {
KdPrint2((PRINT_PREFIX "AtapiStartIo: unhide from further detection\n"));
if(AtaCtl->addr.TargetId != 0xff) {
KdPrint2((PRINT_PREFIX "AtapiStartIo: remove %#x:%#x\n", AtaCtl->addr.PathId, AtaCtl->addr.TargetId));
+ if(len < pos+sizeof(AtaCtl->FindDelDev)) {
+ KdPrint2((PRINT_PREFIX "AtapiStartIo: AtaCtl Buffer too small: %#x < %#x\n", len,
+ pos+sizeof(AtaCtl->FindDelDev) ));
+ goto wrong_buffer_size;
+ }
LunExt->DeviceFlags = 0;
if(AtaCtl->FindDelDev.Flags & UNIATA_REMOVE_FLAGS_HIDE) {
KdPrint2((PRINT_PREFIX "AtapiStartIo: hide from further detection\n"));
- LunExt->DeviceFlags |= DFLAGS_HIDDEN;
+ //LunExt->DeviceFlags |= DFLAGS_HIDDEN;
+ UniataForgetDevice(LunExt);
}
for(i=0; i<AtaCtl->FindDelDev.WaitForPhysicalLink && i<30; i++) {
KdPrint2((PRINT_PREFIX "AtapiStartIo: Set transfer mode\n"));
+ if(len < pos+sizeof(AtaCtl->SetMode)) {
+ KdPrint2((PRINT_PREFIX "AtapiStartIo: AtaCtl Buffer too small: %#x < %#x\n", len,
+ pos+sizeof(AtaCtl->SetMode) ));
+ goto wrong_buffer_size;
+ }
if(AtaCtl->SetMode.OrigMode != IOMODE_NOT_SPECIFIED) {
LunExt->OrigTransferMode = (UCHAR)(AtaCtl->SetMode.OrigMode);
}
KdPrint2((PRINT_PREFIX "AtapiStartIo: Get transfer mode\n"));
+ if(len < pos+sizeof(AtaCtl->GetMode)) {
+ KdPrint2((PRINT_PREFIX "AtapiStartIo: AtaCtl Buffer too small: %#x < %#x\n", len,
+ pos+sizeof(AtaCtl->GetMode) ));
+ goto wrong_buffer_size;
+ }
AtaCtl->GetMode.OrigMode = LunExt->OrigTransferMode;
AtaCtl->GetMode.MaxMode = LunExt->LimitedTransferMode;
AtaCtl->GetMode.CurrentMode = LunExt->TransferMode;
+ AtaCtl->GetMode.PhyMode = LunExt->PhyTransferMode;
status = SRB_STATUS_SUCCESS;
break;
KdPrint2((PRINT_PREFIX "AtapiStartIo: Get version\n"));
+ if(len < pos+sizeof(AtaCtl->Version)) {
+ KdPrint2((PRINT_PREFIX "AtapiStartIo: AtaCtl Buffer too small: %#x < %#x\n", len,
+ pos+sizeof(AtaCtl->Version) ));
+ goto wrong_buffer_size;
+ }
AtaCtl->Version.Length = sizeof(GETDRVVERSION);
AtaCtl->Version.VersionMj = UNIATA_VER_MJ;
AtaCtl->Version.VersionMn = UNIATA_VER_MN;
KdPrint2((PRINT_PREFIX "AtapiStartIo: Get adapter info\n"));
- AtaCtl->AdapterInfo.HeaderLength = FIELD_OFFSET(ADAPTERINFO, Chan);
-
- if(len < AtaCtl->AdapterInfo.HeaderLength + sizeof(AtaCtl->AdapterInfo.Chan)) {
- KdPrint2((PRINT_PREFIX "AtapiStartIo: Buffer too small: %#x < %#x\n", len,
- AtaCtl->AdapterInfo.HeaderLength + sizeof(AtaCtl->AdapterInfo.Chan)));
- status = SRB_STATUS_DATA_OVERRUN;
- break;
+ if(len < pos+sizeof(AtaCtl->AdapterInfo)) {
+ KdPrint2((PRINT_PREFIX "AtapiStartIo: AtaCtl Buffer too small: %#x < %#x\n", len,
+ pos+sizeof(AtaCtl->AdapterInfo) ));
+ goto wrong_buffer_size;
}
+ AtaCtl->AdapterInfo.HeaderLength = sizeof(ADAPTERINFO);
AtaCtl->AdapterInfo.DevID = deviceExtension->DevID;
AtaCtl->AdapterInfo.RevID = deviceExtension->RevID;
}
AtaCtl->AdapterInfo.ChanInfoValid = FALSE;
AtaCtl->AdapterInfo.LunInfoValid = FALSE;
-
- RtlZeroMemory(&AtaCtl->AdapterInfo.Chan, sizeof(AtaCtl->AdapterInfo.Chan));
+ AtaCtl->AdapterInfo.ChanHeaderLengthValid = TRUE;
+
+ pos += AtaCtl->AdapterInfo.HeaderLength;
+
+ // zero tail
+ RtlZeroMemory(((PCHAR)AtaCtl)+pos,
+ len-pos);
+
+ if(len >= pos+AtaCtl->AdapterInfo.NumberChannels*sizeof(CHANINFO)) {
+ PCHANINFO ChanInfo = (PCHANINFO)( ((PCHAR)AtaCtl)+pos );
+ PHW_CHANNEL cur_chan;
+ KdPrint2((PRINT_PREFIX "AtapiStartIo: Fill channel info\n"));
+ for(i=0;i<AtaCtl->AdapterInfo.NumberChannels;i++) {
+ KdPrint2((PRINT_PREFIX "chan[%d] %x\n", i, cur_chan));
+ cur_chan = &(deviceExtension->chan[i]);
+ ChanInfo->MaxTransferMode = cur_chan->MaxTransferMode;
+ ChanInfo->ChannelCtrlFlags = cur_chan->ChannelCtrlFlags;
+ RtlCopyMemory(&(ChanInfo->QueueStat), &(cur_chan->QueueStat), sizeof(ChanInfo->QueueStat));
+ ChanInfo->ReorderCount = cur_chan->ReorderCount;
+ ChanInfo->IntersectCount = cur_chan->IntersectCount;
+ ChanInfo->TryReorderCount = cur_chan->TryReorderCount;
+ ChanInfo->TryReorderHeadCount = cur_chan->TryReorderHeadCount;
+ ChanInfo->TryReorderTailCount = cur_chan->TryReorderTailCount;
+ //ChanInfo->opt_MaxTransferMode = cur_chan->opt_MaxTransferMode;
+ ChanInfo++;
+ }
+ AtaCtl->AdapterInfo.ChanInfoValid = TRUE;
+ AtaCtl->AdapterInfo.ChanHeaderLength = sizeof(*ChanInfo);
+ }
status = SRB_STATUS_SUCCESS;
break;
// Set status in SRB.
Srb->SrbStatus = (UCHAR)status;
- AtapiDmaDBSync(chan, Srb);
+ if(chan && Srb) {
+ KdPrint2((PRINT_PREFIX "AtapiStartIo: AtapiDmaDBSync(%x, %x)\n", chan, Srb));
+ AtapiDmaDBSync(chan, Srb);
+ }
+ KdPrint2((PRINT_PREFIX "AtapiStartIo: UniataRemoveRequest(%x, %x)\n", chan, Srb));
UniataRemoveRequest(chan, Srb);
// Indicate command complete.
+ KdPrint2((PRINT_PREFIX "AtapiStartIo: ScsiPortNotification\n"));
ScsiPortNotification(RequestComplete,
deviceExtension,
Srb);
+ KdPrint2((PRINT_PREFIX "AtapiStartIo: UniataGetCurRequest\n"));
// Remove current Srb & get next one
if((Srb = UniataGetCurRequest(chan))) {
AtaReq = (PATA_REQ)(Srb->SrbExtension);
Srb = NULL;
}
}
+ KdPrint2((PRINT_PREFIX "AtapiStartIo: chan %x, Src %x\n", chan, Srb));
if(!chan) {
//ASSERT(TopLevel);
}
} // end AtapiStartIo__()
-
+#if 0
void
NTAPI
UniataInitAtaCommands()
flags = 0;
command = i;
- KdPrint2((PRINT_PREFIX "cmd %2.2x: ", command));
+ //KdPrint2((PRINT_PREFIX "cmd %2.2x: ", command));
switch(command) {
case IDE_COMMAND_READ_DMA48:
case IDE_COMMAND_WRITE_LOG_DMA48:
case IDE_COMMAND_TRUSTED_RCV_DMA:
case IDE_COMMAND_TRUSTED_SEND_DMA:
- KdPrint2((PRINT_PREFIX "DMA "));
+ case IDE_COMMAND_DATA_SET_MGMT: // TRIM
+ //KdPrint2((PRINT_PREFIX "DMA "));
flags |= ATA_CMD_FLAG_DMA;
}
switch(command) {
+ case IDE_COMMAND_WRITE_FUA_DMA48:
+ case IDE_COMMAND_WRITE_FUA_DMA_Q48:
+ case IDE_COMMAND_WRITE_MUL_FUA48:
+
+ flags |= ATA_CMD_FLAG_FUA;
+ /* FALL THROUGH */
+
case IDE_COMMAND_READ48:
case IDE_COMMAND_READ_DMA48:
case IDE_COMMAND_READ_DMA_Q48:
case IDE_COMMAND_WRITE_MUL48:
case IDE_COMMAND_WRITE_STREAM_DMA48:
case IDE_COMMAND_WRITE_STREAM48:
- case IDE_COMMAND_WRITE_FUA_DMA48:
- case IDE_COMMAND_WRITE_FUA_DMA_Q48:
- case IDE_COMMAND_WRITE_MUL_FUA48:
case IDE_COMMAND_FLUSH_CACHE48:
case IDE_COMMAND_VERIFY48:
- KdPrint2((PRINT_PREFIX "48 "));
+ //KdPrint2((PRINT_PREFIX "48 "));
flags |= ATA_CMD_FLAG_48;
/* FALL THROUGH */
case IDE_COMMAND_FLUSH_CACHE:
case IDE_COMMAND_VERIFY:
- KdPrint2((PRINT_PREFIX "LBA "));
+ //KdPrint2((PRINT_PREFIX "LBA "));
flags |= ATA_CMD_FLAG_LBAIOsupp;
}
+ switch(command) {
+ case IDE_COMMAND_READ_NATIVE_SIZE48:
+ case IDE_COMMAND_SET_NATIVE_SIZE48:
+ // we cannot set LBA flag for these commands to avoid BadBlock handling
+ //flags |= ATA_CMD_FLAG_LBAIOsupp;
+ flags |= ATA_CMD_FLAG_48;
+
+ case IDE_COMMAND_READ_NATIVE_SIZE:
+ case IDE_COMMAND_SET_NATIVE_SIZE:
+
+ flags |= ATA_CMD_FLAG_LBAIOsupp | ATA_CMD_FLAG_FUA;
+ }
+
flags |= ATA_CMD_FLAG_48supp;
switch (command) {
case IDE_COMMAND_VERIFY:
command = IDE_COMMAND_VERIFY48; break;
default:
- KdPrint2((PRINT_PREFIX "!28->48 "));
+ //KdPrint2((PRINT_PREFIX "!28->48 "));
flags &= ~ATA_CMD_FLAG_48supp;
}
- KdPrint2((PRINT_PREFIX "\t -> %2.2x (%2.2x)\n", command, flags));
+ switch (command) {
+ case IDE_COMMAND_READ:
+ case IDE_COMMAND_READ_MULTIPLE:
+ case IDE_COMMAND_READ_DMA48:
+ case IDE_COMMAND_READ_DMA_Q48:
+ case IDE_COMMAND_READ_STREAM_DMA48:
+ case IDE_COMMAND_READ_STREAM48:
+ case IDE_COMMAND_READ_DMA_Q:
+ case IDE_COMMAND_READ_DMA:
+ case IDE_COMMAND_READ_LOG_DMA48:
+ case IDE_COMMAND_TRUSTED_RCV_DMA:
+ case IDE_COMMAND_IDENTIFY:
+ case IDE_COMMAND_ATAPI_IDENTIFY:
+ //KdPrint2((PRINT_PREFIX "RD "));
+ flags |= ATA_CMD_FLAG_In;
+ break;
+ case IDE_COMMAND_WRITE:
+ case IDE_COMMAND_WRITE_MULTIPLE:
+ case IDE_COMMAND_WRITE_DMA48:
+ case IDE_COMMAND_WRITE_DMA_Q48:
+ case IDE_COMMAND_WRITE_DMA:
+ case IDE_COMMAND_WRITE_DMA_Q:
+ case IDE_COMMAND_WRITE_STREAM_DMA48:
+ case IDE_COMMAND_WRITE_STREAM48:
+ case IDE_COMMAND_WRITE_FUA_DMA48:
+ case IDE_COMMAND_WRITE_FUA_DMA_Q48:
+ //KdPrint2((PRINT_PREFIX "WR "));
+ flags |= ATA_CMD_FLAG_Out;
+ break;
+ }
+
+ //KdPrint2((PRINT_PREFIX "\t -> %2.2x (%2.2x)\n", command, flags));
AtaCommands48[i] = command;
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;
- WCHAR a;
+// WCHAR a;
#ifndef USE_REACTOS_DDK
NTSTATUS status;
#endif
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);
+ //a = (WCHAR)strlen(ver_string);
+
+ 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;
- 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");
+ // 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)\n", MajorVersion, MinorVersion, BuildNumber));
+ 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:
+ KdPrint2((PRINT_PREFIX "adjust options for VirtualBox\n"));
// adjust options for VirtualBox
g_opt_WaitBusyCount = 20000;
g_opt_WaitBusyDelay = 150;
g_opt_WaitDrqDelay = 100;
- g_opt_AtapiSendDisableIntr = 0;
+ g_opt_WaitBusyLongCount = 20000;
+ g_opt_MaxIsrWait = 200;
+ 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 (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_WaitBusyDelay = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"WaitBusyDelay", g_opt_WaitBusyDelay); // 10 vs 150
g_opt_WaitDrqDelay = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"WaitDrqDelay", g_opt_WaitDrqDelay); // 10 vs 100
- 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_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) ? 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) {
}
continue;
}
- BMList[i].AltInitMasterDev = (UCHAR)0xff;
+ //BMList[i].AltInitMasterDev = (UCHAR)0xff;
if(GlobalConfig->AtDiskPrimaryAddressClaimed)
PrimaryClaimed = TRUE;
if(GlobalConfig->AtDiskSecondaryAddressClaimed)
SecondaryClaimed = TRUE;
+ pref_alt = 0;
+
+ if(!WinVer_WDM_Model && !PrimaryClaimed && !SecondaryClaimed && !g_Dump &&
+ !(BMList[i].ChanInitOk & 0x80)) {
+
+ // 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;
+ }
+ }
if(g_opt_Verbose) {
_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;
}
if (newStatus == STATUS_SUCCESS) {
- BMList[i].ChanInitOk |= 0x01 << c;
+ if(WinVer_Id() < WinVer_2k) {
+ // This should be done in HwInitialize under w2k+ to ensure that
+ // channel is actually initialized
+ BMList[i].ChanInitOk |= 0x01 << c;
+ } else {
+ if(BMList[i].ChanInitOk & (0x01 << c)) {
+ KdPrint2((PRINT_PREFIX "HwInit passed\n"));
+ }
+ }
/*
if(BMList[i].MasterDev && (WinVer_Id() > WinVer_NT)) {
c = 1; // this will break our for()
*/
}
}
- if(WinVer_Id() >= WinVer_2k) {
- // the following doesn't work under higher OSes
+/* if(WinVer_Id() >= WinVer_2k) {
+ // the following didn't work under higher OSes,
+ // until we move setting of FLAGS to HwInit
KdPrint2((PRINT_PREFIX "make still one attempt\n"));
continue;
- }
+ }*/
if(BMList[i].ChanInitOk & 0x03) {
- // under NT we receive status immediately, so
- // we can omit alternative init method id STATUS_SUCCESS returned
+ // Under NT we receive status immediately, so
+ // we can omit alternative init method if STATUS_SUCCESS returned.
+ // Under w2k+ we relay on flags, set in HwInitialize.
KdPrint2((PRINT_PREFIX "Ok, no more retries required\n"));
break;
+ } else
+ if(WinVer_Id() >= WinVer_2k) {
+ // try AltInit if HwInit was not called immediately under w2k+
+ KdPrint2((PRINT_PREFIX "make still one attempt w2k+\n"));
+ } else {
+ // if (WinVer_Id() == WinVer_NT) and some error occured
+ // try alternative init method
+ KdPrint2((PRINT_PREFIX "make still one attempt w2k+\n"));
}
- // if (WinVer_Id() == WinVer_NT) and some error occured
- // try alternative init method
} // for(alt...)
-#if 0
- if(WinVer_WDM_Model) {
- hwInitializationData.comm.HwFindAdapter = UniataFindFakeBusMasterController;
- hwInitializationData.comm.NumberOfAccessRanges = 5;
- hwInitializationData.comm.AdapterInterfaceType = PCIBus;
-
- hwInitializationData.comm.VendorId = BMList[i].VendorId;
- hwInitializationData.comm.VendorIdLength = (USHORT) BMList[i].VendorIdLength;
- hwInitializationData.comm.DeviceId = BMList[i].DeviceId;
- hwInitializationData.comm.DeviceIdLength = (USHORT) BMList[i].DeviceIdLength;
-
- //BMList[i].channel = 0/*(UCHAR)c*/;
-
- KdPrint2((PRINT_PREFIX "Try init fake: %4.4s %4.4s \n",
- hwInitializationData.comm.VendorId,
- hwInitializationData.comm.DeviceId));
- newStatus = ScsiPortInitialize(DriverObject,
- Argument2,
- &hwInitializationData.comm,
- (PVOID)i);
- KdPrint2((PRINT_PREFIX "ScsiPortInitialize Status %#x\n", newStatus));
- }
-#endif //0
if(g_opt_Verbose) {
if(BMList[i].ChanInitOk & 0x03) {
_PrintNtConsole(" OK\n");
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)
hwInitializationData.comm.NumberOfAccessRanges = 6;
hwInitializationData.comm.AdapterInterfaceType = PCIBus;
- hwInitializationData.comm.VendorId = BMList[i].VendorId;
+ hwInitializationData.comm.VendorId = (PVOID)BMList[i].VendorId;
hwInitializationData.comm.VendorIdLength = (USHORT) BMList[i].VendorIdLength;
- hwInitializationData.comm.DeviceId = BMList[i].DeviceId;
+ hwInitializationData.comm.DeviceId = (PVOID)BMList[i].DeviceId;
hwInitializationData.comm.DeviceIdLength = (USHORT) BMList[i].DeviceIdLength;
BMList[i].channel = 0/*(UCHAR)c*/;
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)
hwInitializationData.comm.DeviceId = 0;
hwInitializationData.comm.DeviceIdLength = 0;
+ if(!BMListLen) {
+ hwInitializationData.comm.SrbExtensionSize = //FIELD_OFFSET(ATA_REQ, ata);
+ sizeof(ATA_REQ);
+ KdPrint2((PRINT_PREFIX "using AtaReq sz %x\n", hwInitializationData.comm.SrbExtensionSize));
+ }
+
// The adapter count is used by the find adapter routine to track how
// which adapter addresses have been tested.
// 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.
cdb->MECH_STATUS.OperationCode = SCSIOP_MECHANISM_STATUS;
cdb->MECH_STATUS.AllocationLength[1] = sizeof(MECHANICAL_STATUS_INFORMATION_HEADER);
+ KdPrint2((PRINT_PREFIX " MechanismStatusSrb %#x\n", srb));
+
return srb;
} // end BuildMechanismStatusSrb()
cdb->CDB6INQUIRY.OperationCode = SCSIOP_REQUEST_SENSE;
cdb->CDB6INQUIRY.AllocationLength = sizeof(SENSE_DATA);
+ KdPrint2((PRINT_PREFIX " RequestSenseSrb %#x\n", srb));
+
return srb;
} // end BuildRequestSenseSrb()
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));
status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE /*| RTL_REGISTRY_OPTIONAL*/,
paramPath.Buffer, parameters, NULL, NULL);
- KdPrint(( "AtapiCheckRegValue: %ws -> %ws is %#x\n", PathSuffix, Name, doRun));
+ if(NT_SUCCESS(status)) {
+ KdPrint(( "AtapiCheckRegValue: %ws -> %ws is %#x\n", PathSuffix, Name, doRun));
+ }
ExFreePool(paramPath.Buffer);
if(!NT_SUCCESS(status)) {
+failed:
doRun = Default;
}
}
if(deviceExtension->AdapterInterfaceType == PCIBus) {
// we must never get here for non-PCI
- status = UniataDisconnectIntr2(HwDeviceExtension);
+ /*status =*/ UniataDisconnectIntr2(HwDeviceExtension);
BMList[deviceExtension->DevIndex].Isr2Enable = FALSE;
}
break;
AtapiChipInit(HwDeviceExtension, DEVNUM_NOT_SPECIFIED, CHAN_NOT_SPECIFIED);
status = UniataConnectIntr2(HwDeviceExtension);
- for (c = 0; c < numberChannels; c++) {
- AtapiChipInit(HwDeviceExtension, DEVNUM_NOT_SPECIFIED, c);
- FindDevices(HwDeviceExtension, 0, c);
- AtapiEnableInterrupts(deviceExtension, c);
- AtapiHwInitialize__(deviceExtension, c);
- }
- if(deviceExtension->Isr2DevObj) {
- // we must never get here for non-PCI
- BMList[deviceExtension->DevIndex].Isr2Enable = TRUE;
+ if(NT_SUCCESS(status)) {
+ for (c = 0; c < numberChannels; c++) {
+ AtapiChipInit(HwDeviceExtension, DEVNUM_NOT_SPECIFIED, c);
+ FindDevices(HwDeviceExtension, 0, c);
+ AtapiEnableInterrupts(deviceExtension, c);
+ AtapiHwInitialize__(deviceExtension, c);
+ }
+ if(deviceExtension->Isr2DevObj) {
+ // we must never get here for non-PCI
+ BMList[deviceExtension->DevIndex].Isr2Enable = TRUE;
+ }
}
break;
PUCHAR String
);
+#define DEBUG_MSG_BUFFER_SIZE 512
+
extern "C"
VOID
_cdecl
...
)
{
- int len;
- UCHAR dbg_print_tmp_buff[512];
+ //int len;
+ UCHAR dbg_print_tmp_buff[DEBUG_MSG_BUFFER_SIZE];
// UNICODE_STRING msgBuff;
va_list ap;
va_start(ap, DebugMessage);
- len = _vsnprintf((PCHAR)&dbg_print_tmp_buff[0], 511, DebugMessage, ap);
+ /*len =*/ _vsnprintf((PCHAR)&dbg_print_tmp_buff[0], DEBUG_MSG_BUFFER_SIZE-1, DebugMessage, ap);
- dbg_print_tmp_buff[511] = 0;
+ dbg_print_tmp_buff[DEBUG_MSG_BUFFER_SIZE-1] = 0;
- KdPrint(((PCHAR)&(dbg_print_tmp_buff[0])));
+ //DbgPrint(((PCHAR)&(dbg_print_tmp_buff[0]))); // already done in KdPrint macro
HalDisplayString(dbg_print_tmp_buff);
+#ifdef _DEBUG
+ if(g_LogToDisplay > 1) {
+ AtapiStallExecution(g_LogToDisplay*1000);
+ }
+#endif // _DEBUG
+
va_end(ap);
} // end PrintNtConsole()