/*++
-Copyright (c) 2002-2008 Alexandr A. Telyatnikov (Alter)
+Copyright (c) 2002-2014 Alexandr A. Telyatnikov (Alter)
Module Name:
id_ata.cpp
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)
etc. (See todo.txt)
ULONG g_WaitBusyInISR = 1;
+ULONG g_opt_WaitBusyCount = 200; // 20000
+ULONG g_opt_WaitBusyDelay = 10; // 150
+ULONG g_opt_WaitDrqDelay = 10; // 100
+ULONG g_opt_WaitBusyLongCount = 2000; // 2000
+ULONG g_opt_WaitBusyLongDelay = 250; // 250
+ULONG g_opt_MaxIsrWait = 40; //
+BOOLEAN g_opt_AtapiSendDisableIntr = 0; // 0
+BOOLEAN g_opt_AtapiDmaRawRead = 1; // 0
+BOOLEAN hasPCI = FALSE;
+
+ULONG g_opt_VirtualMachine = 0; // Auto
+
BOOLEAN InDriverEntry = TRUE;
BOOLEAN g_opt_Verbose = 0;
BOOLEAN WinVer_WDM_Model = FALSE;
+
//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
#endif //UNIATA_CORE
-BOOLEAN
-NTAPI
-AtapiCheckInterrupt__(
- IN PVOID HwDeviceExtension,
- IN UCHAR c
- );
-
-
#ifndef UNIATA_CORE
BOOLEAN
} while(t);
} // end UniataNanoSleep()
-
#define AtapiWritePortN_template(_type, _Type, sz) \
VOID \
DDKFASTAPI \
AtapiWritePort##sz( \
IN PHW_CHANNEL chan, \
- IN ULONG_PTR _port, \
+ IN ULONGIO_PTR _port, \
IN _type data \
) \
{ \
KdPrint(("invalid io write request @ ch %x, res* %x\n", chan, _port)); \
return; \
} \
+ if(res->Proc) { \
+ } else \
if(!res->MemIo) { \
ScsiPortWritePort##_Type((_type*)(res->Addr), data); \
} else { \
DDKFASTAPI \
AtapiWritePortEx##sz( \
IN PHW_CHANNEL chan, \
- IN ULONG_PTR _port, \
+ IN ULONGIO_PTR _port, \
IN ULONG offs, \
IN _type data \
) \
KdPrint(("invalid io write request @ ch %x, res* %x, offs %x\n", chan, _port, offs)); \
return; \
} \
+ if(res->Proc) { \
+ } else \
if(!res->MemIo) { \
ScsiPortWritePort##_Type((_type*)(res->Addr+offs), data); \
} else { \
DDKFASTAPI \
AtapiReadPort##sz( \
IN PHW_CHANNEL chan, \
- IN ULONG_PTR _port \
+ IN ULONGIO_PTR _port \
) \
{ \
PIORES res; \
KdPrint(("invalid io read request @ ch %x, res* %x\n", chan, _port)); \
return (_type)(-1); \
} \
+ if(res->Proc) { \
+ return 0; \
+ } else \
if(!res->MemIo) { \
/*KdPrint(("r_io @ (%x) %x\n", _port, res->Addr));*/ \
return ScsiPortReadPort##_Type((_type*)(res->Addr)); \
DDKFASTAPI \
AtapiReadPortEx##sz( \
IN PHW_CHANNEL chan, \
- IN ULONG_PTR _port, \
+ IN ULONGIO_PTR _port, \
IN ULONG offs \
) \
{ \
KdPrint(("invalid io read request @ ch %x, res* %x, offs %x\n", chan, _port, offs)); \
return (_type)(-1); \
} \
+ if(res->Proc) { \
+ return 0; \
+ } else \
if(!res->MemIo) { \
return ScsiPortReadPort##_Type((_type*)(res->Addr+offs)); \
} else { \
DDKFASTAPI \
AtapiReadBuffer##sz( \
IN PHW_CHANNEL chan, \
- IN ULONG_PTR _port, \
+ IN ULONGIO_PTR _port, \
IN PVOID Buffer, \
IN ULONG Count, \
IN ULONG Timing \
DDKFASTAPI \
AtapiWriteBuffer##sz( \
IN PHW_CHANNEL chan, \
- IN ULONG_PTR _port, \
+ IN ULONGIO_PTR _port, \
IN PVOID Buffer, \
IN ULONG Count, \
IN ULONG Timing \
UCHAR statusByte;
ULONG i;
+ // Assume, proper drive is already seleted
WaitOnBusyLong(chan);
for (i = 0; i < 0x10000; i++) {
{
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;
- for (i=0; i<20000; i++) {
+ UCHAR Status = IDE_STATUS_WRONG;
+ for (i=0; i<g_opt_WaitBusyCount; i++) {
GetBaseStatus(chan, Status);
if (Status & IDE_STATUS_BUSY) {
- AtapiStallExecution(150);
+ AtapiStallExecution(g_opt_WaitBusyDelay);
continue;
} else {
break;
{
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
for (i=0; i<1000; i++) {
GetStatus(chan, Status);
if (Status & IDE_STATUS_BUSY) {
- AtapiStallExecution(100);
+ AtapiStallExecution(g_opt_WaitDrqDelay);
} else if (Status & IDE_STATUS_DRQ) {
break;
} else {
- AtapiStallExecution(200);
+ AtapiStallExecution(g_opt_WaitDrqDelay*2);
}
}
return Status;
for (i=0; i<2; i++) {
GetStatus(chan, Status);
if (Status & IDE_STATUS_BUSY) {
- AtapiStallExecution(100);
+ AtapiStallExecution(g_opt_WaitDrqDelay);
} else if (Status & IDE_STATUS_DRQ) {
break;
} else {
- AtapiStallExecution(100);
+ AtapiStallExecution(g_opt_WaitDrqDelay);
}
}
return Status;
KdPrint2((PRINT_PREFIX "AtapiSoftReset:\n"));
UCHAR statusByte2;
+ if(chan->DeviceExtension->HwFlags & UNIATA_AHCI) {
+ UniataAhciSoftReset(chan->DeviceExtension, chan->lChannel, DeviceNumber);
+ return;
+ }
+
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
+ AtapiStallExecution(10000);
+ for (i = 0; i < 1000; i++) {
+ AtapiStallExecution(999);
+ }
+ } else {
+ AtapiStallExecution(500);
+ GetBaseStatus(chan, statusByte2);
+ AtapiWritePort1(chan, IDX_IO1_o_Command, IDE_COMMAND_ATAPI_RESET);
+
+ // Do not wait for BUSY assertion if it was initially set, jump to
+ // BUSY release wait loop
+ if(!(statusByte2 & IDE_STATUS_BUSY)) {
+ // Wait for BUSY assertion, in some cases delay may occure
+ // 100ms should be enough
+ i = 10*1000;
+ while (!(AtapiReadPort1(chan, IDX_IO1_i_Status) & IDE_STATUS_BUSY) &&
+ i--)
+ {
+ 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);
+ }
}
SelectDrive(chan, DeviceNumber);
GetBaseStatus(chan, statusByte2);
}
if(chan->DeviceExtension->HwFlags & UNIATA_SATA) {
- UniataSataClearErr(chan->DeviceExtension, chan->lChannel, UNIATA_SATA_IGNORE_CONNECT);
+ UniataSataClearErr(chan->DeviceExtension, chan->lChannel, UNIATA_SATA_IGNORE_CONNECT, DeviceNumber);
+/* if(!(chan->ChannelCtrlFlags & CTRFLAGS_NO_SLAVE)) {
+ UniataSataClearErr(chan->DeviceExtension, chan->lChannel, UNIATA_SATA_IGNORE_CONNECT, 1);
+ }*/
}
return;
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 ldev = lChannel*2 + DeviceNumber;
ULONG i;
PUCHAR plba;
- KdPrint2((PRINT_PREFIX "AtaCommand48: cntrlr %#x:%#x ldev %#x, cmd %#x, lba %#I64x count %#x feature %#x\n",
- deviceExtension->DevIndex, deviceExtension->Channel, ldev, command, lba, count, feature ));
+ KdPrint2((PRINT_PREFIX "AtaCommand48: cntrlr %#x:%#x dev %#x, cmd %#x, lba %#I64x count %#x feature %#x\n",
+ deviceExtension->DevIndex, deviceExtension->Channel, DeviceNumber, command, lba, count, feature ));
- //if(!(deviceExtension->HwFlags & UNIATA_SATA)) {
- SelectDrive(chan, DeviceNumber);
+ if(deviceExtension->HwFlags & UNIATA_AHCI) {
+ //PIDE_AHCI_CMD AHCI_CMD = &(chan->AhciCtlBlock->cmd);
- statusByte = WaitOnBusy(chan);
+ KdPrint3((" (ahci)\n"));
- /* ready to issue command ? */
- if (statusByte & IDE_STATUS_BUSY) {
- KdPrint2((PRINT_PREFIX " Returning BUSY status\n"));
- return statusByte;
- }
- //}
+ statusByte = UniataAhciSendPIOCommand(deviceExtension, lChannel, DeviceNumber,
+ (PSCSI_REQUEST_BLOCK)NULL,
+ NULL,
+ 0,
+ command,
+ lba, count,
+ feature,
+ 0 /* ahci flags */ ,
+ wait_flags,
+ 1000 /* timeout 1 sec */
+ );
+
+ return statusByte;
+ }
+
+ SelectDrive(chan, DeviceNumber);
+
+ statusByte = WaitOnBusy(chan);
+
+ /* ready to issue command ? */
+ if (statusByte & IDE_STATUS_BUSY) {
+ KdPrint2((PRINT_PREFIX " Returning BUSY status\n"));
+ return statusByte;
+ }
// !!! We should not check ERROR condition here
// ERROR bit may be asserted durring previous operation
// and not cleared after SELECT
//>>>>>> NV: 2006/08/03
- if((AtaCommandFlags[command] & ATA_CMD_FLAG_LBAIOsupp) &&
- CheckIfBadBlock(&(deviceExtension->lun[ldev]), lba, count)) {
+ 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;
//return SRB_STATUS_ERROR;
//<<<<<< NV: 2006/08/03
/* only use 48bit addressing if needed because of the overhead */
- if ((lba >= ATA_MAX_LBA28 || count > 256) &&
- deviceExtension->lun[ldev].IdentifyData.FeaturesSupport.Address48) {
+ if (UniAta_need_lba48(command, lba, count,
+ chan->lun[DeviceNumber]->IdentifyData.FeaturesSupport.Address48)) {
- KdPrint2((PRINT_PREFIX " ldev %#x USE_LBA_48\n", ldev ));
+ KdPrint2((PRINT_PREFIX " dev %#x USE_LBA_48\n", DeviceNumber ));
/* translate command into 48bit version */
if(AtaCommandFlags[command] & ATA_CMD_FLAG_48supp) {
command = AtaCommands48[command];
AtapiWritePort1(chan, IDX_IO1_o_CylinderHigh, (UCHAR)(plba[5]));
AtapiWritePort1(chan, IDX_IO1_o_CylinderHigh, (UCHAR)(plba[2]));
- //KdPrint2((PRINT_PREFIX "AtaCommand48: ldev %#x USE_LBA48 (2)\n", ldev ));
+ //KdPrint2((PRINT_PREFIX "AtaCommand48: dev %#x USE_LBA48 (2)\n", DeviceNumber ));
AtapiWritePort1(chan, IDX_IO1_o_DriveSelect, IDE_USE_LBA | (DeviceNumber ? IDE_DRIVE_2 : IDE_DRIVE_1) );
} else {
chan->ChannelCtrlFlags &= ~CTRFLAGS_LBA48;
//if(feature ||
- // (deviceExtension->lun[ldev].DeviceFlags & (DFLAGS_ATAPI_DEVICE | DFLAGS_TAPE_DEVICE | DFLAGS_LBA_ENABLED))) {
+ // (chan->lun[DeviceNumber]->DeviceFlags & (DFLAGS_ATAPI_DEVICE | DFLAGS_TAPE_DEVICE | DFLAGS_LBA_ENABLED))) {
AtapiWritePort1(chan, IDX_IO1_o_Feature, (UCHAR)feature);
//}
AtapiWritePort1(chan, IDX_IO1_o_BlockCount, (UCHAR)count);
AtapiWritePort1(chan, IDX_IO1_o_BlockNumber, (UCHAR)plba[0]);
AtapiWritePort1(chan, IDX_IO1_o_CylinderLow, (UCHAR)plba[1]);
AtapiWritePort1(chan, IDX_IO1_o_CylinderHigh, (UCHAR)plba[2]);
- if(deviceExtension->lun[ldev].DeviceFlags & DFLAGS_LBA_ENABLED) {
- //KdPrint2((PRINT_PREFIX "AtaCommand28: ldev %#x USE_LBA\n", ldev ));
+ if(chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_LBA_ENABLED) {
+ //KdPrint2((PRINT_PREFIX "AtaCommand28: dev %#x USE_LBA\n", DeviceNumber ));
AtapiWritePort1(chan, IDX_IO1_o_DriveSelect, (UCHAR)(plba[3] & 0xf) | IDE_USE_LBA | (DeviceNumber ? IDE_DRIVE_SELECT_2 : IDE_DRIVE_SELECT_1) );
} else {
- //KdPrint2((PRINT_PREFIX "AtaCommand28: ldev %#x USE_CHS\n", ldev ));
+ //KdPrint2((PRINT_PREFIX "AtaCommand28: dev %#x USE_CHS\n", DeviceNumber ));
AtapiWritePort1(chan, IDX_IO1_o_DriveSelect, (UCHAR)(plba[3] & 0xf) | (DeviceNumber ? IDE_DRIVE_SELECT_2 : IDE_DRIVE_SELECT_1) );
}
}
// 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
KdPrint2((PRINT_PREFIX " try to continue\n"));
statusByte &= ~IDE_STATUS_ERROR;
}
- chan->ExpectingInterrupt = TRUE;
+ UniataExpectChannelInterrupt(chan, TRUE);
// !!!!!
InterlockedExchange(&(chan->CheckIntr),
CHECK_INTR_IDLE);
IN UCHAR sector,
IN UCHAR count,
IN UCHAR feature,
- IN ULONG flags
+ IN ULONG wait_flags
)
{
- return AtaCommand48(deviceExtension, DeviceNumber, lChannel,
- command,
- (ULONG)sector | ((ULONG)cylinder << 8) | ((ULONG)(head & 0x0f) << 24),
- count, feature, flags);
+ if(!(deviceExtension->HwFlags & UNIATA_AHCI)) {
+ return AtaCommand48(deviceExtension, DeviceNumber, lChannel,
+ command,
+ (ULONG)sector | ((ULONG)cylinder << 8) | ((ULONG)(head & 0x0f) << 24),
+ count, feature, wait_flags);
+ } else {
+ 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 */
+ );
+
+ }
} // end AtaCommand()
LONG
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) {
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
+#if DBG
VOID
NTAPI
UniataDumpATARegs(
}
return;
} // end UniataDumpATARegs()
+#endif
+
+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;
- ULONG ldev = (lChannel * 2) + DeviceNumber;
- PHW_LU_EXTENSION LunExt = &(deviceExtension->lun[ldev]);
+ 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
+ } else {
+ KdPrint2((PRINT_PREFIX "IssueIdentify: PM empty port\n"));
+ return FALSE;
+ }
+ } else
if(DeviceNumber && (chan->ChannelCtrlFlags & CTRFLAGS_NO_SLAVE)) {
KdPrint2((PRINT_PREFIX "IssueIdentify: NO SLAVE\n"));
return FALSE;
return FALSE;
}
- SelectDrive(chan, DeviceNumber);
- AtapiStallExecution(10);
- statusByte = WaitOnBusyLong(chan);
- // Check that the status register makes sense.
- GetBaseStatus(chan, statusByte2);
-
- UniataDumpATARegs(chan);
+ if(use_ahci) {
+ statusByte = WaitOnBusyLong(chan);
+#if DBG
+ 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, statusByte);
+ }
if (Command == IDE_COMMAND_IDENTIFY) {
// Mask status byte ERROR bits.
if (signatureLow == ATAPI_MAGIC_LSB &&
signatureHigh == ATAPI_MAGIC_MSB) {
// Device is Atapi.
- KdPrint2((PRINT_PREFIX "IssueIdentify: this is ATAPI (ldev %d)\n", ldev));
+ KdPrint2((PRINT_PREFIX "IssueIdentify: this is ATAPI (dev %d)\n", DeviceNumber));
return FALSE;
}
// 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.
if (signatureLow == ATAPI_MAGIC_LSB &&
signatureHigh == ATAPI_MAGIC_MSB) {
- KdPrint2((PRINT_PREFIX "IssueIdentify: this is ATAPI (2) (ldev %d)\n", ldev));
+ KdPrint2((PRINT_PREFIX "IssueIdentify: this is ATAPI (2) (dev %d)\n", DeviceNumber));
// Device is Atapi.
return FALSE;
}
statusByte = UniataIsIdle(deviceExtension, statusByte) & ~IDE_STATUS_INDEX;
if (statusByte != IDE_STATUS_IDLE) {
// Give up on this.
- KdPrint2((PRINT_PREFIX "IssueIdentify: no dev (ldev %d)\n", ldev));
+ KdPrint2((PRINT_PREFIX "IssueIdentify: no dev (dev %d)\n", DeviceNumber));
return FALSE;
}
}
} 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;
+ j = 4; // skip old-style checks
} else {
j = 0;
}
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 & IDE_STATUS_DRQ) {
KdPrint2((PRINT_PREFIX "IssueIdentify: IDE_STATUS_DRQ (%#x)\n", statusByte));
GetBaseStatus(chan, statusByte);
// One last check for Atapi.
- signatureLow = AtapiReadPort1(chan, IDX_IO1_i_CylinderLow);
- signatureHigh = AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh);
+ if (Command == IDE_COMMAND_IDENTIFY) {
+ signatureLow = AtapiReadPort1(chan, IDX_IO1_i_CylinderLow);
+ signatureHigh = AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh);
- if (signatureLow == ATAPI_MAGIC_LSB &&
- signatureHigh == ATAPI_MAGIC_MSB) {
- KdPrint2((PRINT_PREFIX "IssueIdentify: this is ATAPI (3) (ldev %d)\n", ldev));
- // Device is Atapi.
- return FALSE;
+ if (signatureLow == ATAPI_MAGIC_LSB &&
+ signatureHigh == ATAPI_MAGIC_MSB) {
+ KdPrint2((PRINT_PREFIX "IssueIdentify: this is ATAPI (3) (dev %d)\n", DeviceNumber));
+ // Device is Atapi.
+ return FALSE;
+ }
}
break;
} else {
if (signatureLow == ATAPI_MAGIC_LSB &&
signatureHigh == ATAPI_MAGIC_MSB) {
// Device is Atapi.
- KdPrint2((PRINT_PREFIX "IssueIdentify: this is ATAPI (4) (ldev %d)\n", ldev));
+ KdPrint2((PRINT_PREFIX "IssueIdentify: this is ATAPI (4) (dev %d)\n", DeviceNumber));
return FALSE;
}
+ } else {
+ if(!(statusByte & IDE_STATUS_ERROR) && (statusByte & IDE_STATUS_BUSY)) {
+ KdPrint2((PRINT_PREFIX "IssueIdentify: DRQ not asserted immediately, BUSY -> WaitForDrq\n"));
+ 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 (!(statusByte & IDE_STATUS_DRQ)) {
- KdPrint2((PRINT_PREFIX "IssueIdentify: !IDE_STATUS_DRQ (2) (%#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);
- return FALSE;
- }
- GetBaseStatus(chan, statusByte);
- KdPrint2((PRINT_PREFIX "IssueIdentify: BASE statusByte %#x\n", statusByte));
+ } else {
- if (atapiDev || !(LunExt->DeviceFlags & DFLAGS_DWORDIO_ENABLED) /*!deviceExtension->DWordIO*/) {
+ 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));
- 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;
+ if (!(statusByte & IDE_STATUS_DRQ)) {
+ KdPrint2((PRINT_PREFIX "IssueIdentify: !IDE_STATUS_DRQ (2) (%#x)\n", statusByte));
+ GetBaseStatus(chan, statusByte);
+ return FALSE;
}
-#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);
- }
+ GetBaseStatus(chan, statusByte);
+ KdPrint2((PRINT_PREFIX "IssueIdentify: BASE statusByte %#x\n", statusByte));
- 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 "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, cur %d\n",
+ deviceExtension->FullIdentifyData.CfAdvPowerMode
+ ));
// Check out a few capabilities / limitations of the device.
if (deviceExtension->FullIdentifyData.RemovableStatus & 1) {
// Determine if this drive supports the MSN functions.
KdPrint2((PRINT_PREFIX "IssueIdentify: Marking drive %d as removable. SFE = %d\n",
- ldev,
+ DeviceNumber,
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 cylinders=0;
ULONGLONG tmp_cylinders=0;
// Read very-old-style drive geometry
- KdPrint2((PRINT_PREFIX "CHS %#x:%#x:%#x\n",
+ KdPrint2((PRINT_PREFIX "CHS %#x:%#x:%#x\n",
deviceExtension->FullIdentifyData.NumberOfCylinders,
deviceExtension->FullIdentifyData.NumberOfHeads,
deviceExtension->FullIdentifyData.SectorsPerTrack
/* (deviceExtension->FullIdentifyData.TranslationFieldsValid) &&*/
(NumOfSectors < deviceExtension->FullIdentifyData.UserAddressableSectors)) {
KdPrint2((PRINT_PREFIX "NumberOfCylinders == 0x3fff\n"));
- cylinders =
+ cylinders =
(deviceExtension->FullIdentifyData.UserAddressableSectors /
(deviceExtension->FullIdentifyData.NumberOfHeads *
deviceExtension->FullIdentifyData.SectorsPerTrack));
(deviceExtension->FullIdentifyData.UserAddressableSectors48 > NumOfSectors)
) {
KdPrint2((PRINT_PREFIX "LBA48\n"));
- cylinders =
+ cylinders =
(deviceExtension->FullIdentifyData.UserAddressableSectors48 /
(deviceExtension->FullIdentifyData.NumberOfHeads *
deviceExtension->FullIdentifyData.SectorsPerTrack));
KdPrint2((PRINT_PREFIX "cylinders %#I64x\n", cylinders));
-
+
NativeNumOfSectors = cylinders *
deviceExtension->FullIdentifyData.NumberOfHeads *
deviceExtension->FullIdentifyData.SectorsPerTrack;
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)
+ ((ULONGLONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh) << 40)
;
+ }
}
if((NativeNumOfSectors & 0xffffff) == ((NativeNumOfSectors >> 24) & 0xffffff)) {
NumOfSectors = NativeNumOfSectors;
}
}
- }
+ } // !error
}
-
+
if(NumOfSectors < 0x2100000 /*&& NumOfSectors > 31*1000*1000*/) {
// check for native LBA size
// some drives report ~32Gb in Identify Block
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) {
}
}
}
- KdPrint2((PRINT_PREFIX "final LunExt->opt_GeomType=%x\n", LunExt->opt_GeomType));
if(LunExt->opt_GeomType == GEOM_STD) {
deviceExtension->FullIdentifyData.CurrentSectorsPerTrack =
)
{
PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
- PIDENTIFY_DATA2 identifyData = &deviceExtension->lun[(lChannel * 2) + DeviceNumber].IdentifyData;
+ PIDENTIFY_DATA2 identifyData;
+ PHW_LU_EXTENSION LunExt;
// ULONG i;
UCHAR statusByte;
UCHAR errorByte;
- if(deviceExtension->lun[(lChannel * 2) + DeviceNumber].DeviceFlags &
+ LunExt = deviceExtension->chan[lChannel].lun[DeviceNumber];
+ identifyData = &(LunExt->IdentifyData);
+
+ if(LunExt->DeviceFlags &
(DFLAGS_LBA_ENABLED | DFLAGS_ORIG_GEOMETRY))
return TRUE;
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 numberChannels = deviceExtension->NumberChannels;
PHW_CHANNEL chan = NULL;
ULONG i,j;
- ULONG max_ldev;
+ ULONG MaxLuns;
UCHAR statusByte;
PSCSI_REQUEST_BLOCK CurSrb;
ULONG ChannelCtrlFlags;
#endif
//ULONG RevID = deviceExtension->RevID;
ULONG ChipFlags = deviceExtension->HwFlags & CHIPFLAG_MASK;
- UCHAR tmp8;
+ //UCHAR tmp8;
UCHAR tmp16;
KdPrint2((PRINT_PREFIX "AtapiResetController: Reset IDE %#x/%#x @ %#x\n", VendorID, DeviceID, slotNumber));
+ KdPrint2((PRINT_PREFIX "simplexOnly %d\n", deviceExtension->simplexOnly));
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));
- max_ldev = (chan->ChannelCtrlFlags & CTRFLAGS_NO_SLAVE) ? 1 : 2;
+ chan = &(deviceExtension->chan[j]);
+ MaxLuns = chan->NumberLuns;
+ KdPrint2((PRINT_PREFIX " CompleteType %#x, Luns %d, chan %#x, sptr %#x\n", CompleteType, MaxLuns, chan, &chan));
+ //MaxLuns = (chan->ChannelCtrlFlags & CTRFLAGS_NO_SLAVE) ? 1 : 2;
if(CompleteType != RESET_COMPLETE_NONE) {
#ifndef UNIATA_CORE
while((CurSrb = UniataGetCurRequest(chan))) {
PATA_REQ AtaReq = (PATA_REQ)(CurSrb->SrbExtension);
- KdPrint2((PRINT_PREFIX "AtapiResetController: pending SRB %#x\n", CurSrb));
+ KdPrint2((PRINT_PREFIX "AtapiResetController: pending SRB %#x, chan %#x\n", CurSrb, chan));
// 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;
if (CurSrb->SenseInfoBuffer) {
PSENSE_DATA senseBuffer = (PSENSE_DATA)CurSrb->SenseInfoBuffer;
+ KdPrint2((PRINT_PREFIX " senseBuffer %#x, chan %#x\n", senseBuffer, chan));
senseBuffer->ErrorCode = 0x70;
senseBuffer->Valid = 1;
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,
+ deviceExtension,
PathId,
TargetId,
Lun);
// Save control flags
ChannelCtrlFlags = chan->ChannelCtrlFlags;
// Clear expecting interrupt flag.
- chan->ExpectingInterrupt = FALSE;
+ UniataExpectChannelInterrupt(chan, FALSE);
chan->RDP = FALSE;
chan->ChannelCtrlFlags = 0;
InterlockedExchange(&(chan->CheckIntr),
CHECK_INTR_IDLE);
-
+
+ for (i = 0; i < MaxLuns; i++) {
+ chan->lun[i]->PowerState = 0;
+ }
// Reset controller
- KdPrint2((PRINT_PREFIX " disable intr (0)\n"));
- AtapiDisableInterrupts(deviceExtension, j);
- KdPrint2((PRINT_PREFIX " done\n"));
- switch(VendorID) {
- case ATA_INTEL_ID: {
- ULONG mask;
- ULONG timeout;
- if(!(ChipFlags & UNIATA_SATA))
- goto default_reset;
- if(!UniataIsSATARangeAvailable(deviceExtension, j)) {
- goto default_reset;
+ if(ChipFlags & UNIATA_AHCI) {
+ KdPrint2((PRINT_PREFIX " AHCI path\n"));
+ if(UniataAhciChanImplemented(deviceExtension, j)) {
+#ifdef _DEBUG
+ UniataDumpAhciPortRegs(chan);
+#endif
+ AtapiDisableInterrupts(deviceExtension, j);
+ UniataAhciReset(HwDeviceExtension, j);
+ } else {
+ KdPrint2((PRINT_PREFIX " skip not implemented\n"));
}
+ } else {
+ 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)) {
+ goto default_reset;
+ }
+ if(!UniataIsSATARangeAvailable(deviceExtension, j)) {
+ goto default_reset;
+ }
- /* ICH6 & ICH7 in compat mode has 4 SATA ports as master/slave on 2 ch's */
- if(ChipFlags & UNIATA_AHCI) {
- mask = 0x0005 << j;
- } else {
- /* ICH5 in compat mode has SATA ports as master/slave on 1 channel */
- GetPciConfig1(0x90, tmp8);
- if(tmp8 & 0x04) {
- mask = 0x0003;
+#if 0
+ /* ICH6 & ICH7 in compat mode has 4 SATA ports as master/slave on 2 ch's */
+ if(ChipFlags & UNIATA_AHCI) {
+ mask = 0x0005 << j;
} else {
- mask = 0x0001 << j;
+ /* ICH5 in compat mode has SATA ports as master/slave on 1 channel */
+ GetPciConfig1(0x90, tmp8);
+ if(tmp8 & 0x04) {
+ mask = 0x0003;
+ } else {
+ mask = 0x0001 << j;
+ }
}
- }
- ChangePciConfig2(0x92, a & ~mask);
- AtapiStallExecution(10);
- ChangePciConfig2(0x92, a | mask);
- timeout = 100;
- while (timeout--) {
- AtapiStallExecution(10000);
- GetPciConfig2(0x92, tmp16);
- if ((tmp16 & (mask << 4)) == (mask << 4)) {
- AtapiStallExecution(10000);
- break;
+#else
+ mask = 1 << chan->lun[0]->SATA_lun_map;
+ if (MaxLuns > 1) {
+ mask |= (1 << chan->lun[1]->SATA_lun_map);
}
- }
- break; }
- case ATA_SIS_ID:
- case ATA_NVIDIA_ID: {
- KdPrint2((PRINT_PREFIX " SIS/nVidia\n"));
- if(!(ChipFlags & UNIATA_SATA))
- goto default_reset;
- break; }
- case ATA_SILICON_IMAGE_ID: {
- ULONG offset;
- ULONG Channel = deviceExtension->Channel + j;
- if(!(ChipFlags & UNIATA_SATA))
- goto default_reset;
- offset = ((Channel & 1) << 7) + ((Channel & 2) << 8);
- /* disable PHY state change interrupt */
- AtapiWritePortEx4(NULL, (ULONG_PTR)&deviceExtension->BaseIoAddressSATA_0, 0x148 + offset, 0);
-
- UniataSataClearErr(HwDeviceExtension, j, UNIATA_SATA_IGNORE_CONNECT);
-
- /* reset controller part for this channel */
- AtapiWritePortEx4(NULL, (ULONG_PTR)&deviceExtension->BaseIoAddressSATA_0, 0x48,
- AtapiReadPortEx4(NULL, (ULONG_PTR)&deviceExtension->BaseIoAddressSATA_0, 0x48) | (0xc0 >> Channel));
- AtapiStallExecution(1000);
- AtapiWritePortEx4(NULL, (ULONG_PTR)&deviceExtension->BaseIoAddressSATA_0, 0x48,
- AtapiReadPortEx4(NULL, (ULONG_PTR)&deviceExtension->BaseIoAddressSATA_0, 0x48) & ~(0xc0 >> Channel));
-
+#endif
+ ChangePciConfig2(0x92, a & ~mask);
+ AtapiStallExecution(10);
+ ChangePciConfig2(0x92, a | mask);
+ timeout = 100;
- break; }
- case ATA_PROMISE_ID: {
- break; }
- default:
- if(ChipFlags & UNIATA_SATA) {
- KdPrint2((PRINT_PREFIX " SATA generic reset\n"));
- UniataSataClearErr(HwDeviceExtension, j, UNIATA_SATA_IGNORE_CONNECT);
- }
+ /* Wait up to 1 sec for "connect well". */
+ if (ChipFlags & (I6CH | I6CH2)) {
+ pshift = 8;
+ } else {
+ pshift = 4;
+ }
+ while (timeout--) {
+ GetPciConfig2(0x92, tmp16);
+ if (((tmp16 >> pshift) & mask) == mask) {
+ GetBaseStatus(chan, statusByte);
+ if(statusByte != IDE_STATUS_WRONG) {
+ break;
+ }
+ }
+ AtapiStallExecution(10000);
+ }
+ break; }
+ case ATA_SIS_ID:
+ case ATA_NVIDIA_ID: {
+ KdPrint2((PRINT_PREFIX " SIS/nVidia\n"));
+ if(!(ChipFlags & UNIATA_SATA))
+ goto default_reset;
+ break; }
+ case ATA_SILICON_IMAGE_ID: {
+ ULONG offset;
+ ULONG Channel = deviceExtension->Channel + j;
+ if(!(ChipFlags & UNIATA_SATA))
+ goto default_reset;
+ offset = ((Channel & 1) << 7) + ((Channel & 2) << 8);
+ /* disable PHY state change interrupt */
+ AtapiWritePortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0), 0x148 + offset, 0);
+
+ UniataSataClearErr(HwDeviceExtension, j, UNIATA_SATA_IGNORE_CONNECT, 0);
+
+ /* reset controller part for this channel */
+ AtapiWritePortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0), 0x48,
+ AtapiReadPortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0), 0x48) | (0xc0 >> Channel));
+ AtapiStallExecution(1000);
+ AtapiWritePortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0), 0x48,
+ AtapiReadPortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0), 0x48) & ~(0xc0 >> Channel));
+
+
+ break; }
+ case ATA_PROMISE_ID: {
+ break; }
+ default:
+ if(ChipFlags & UNIATA_SATA) {
+ KdPrint2((PRINT_PREFIX " SATA generic reset\n"));
+ 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 );
- KdPrint2((PRINT_PREFIX " wait a little\n"));
- AtapiStallExecution(10000);
- // Disable interrupts
- KdPrint2((PRINT_PREFIX " disable intr\n"));
- AtapiDisableInterrupts(deviceExtension, j);
- AtapiStallExecution(100);
- KdPrint2((PRINT_PREFIX " re-enable intr\n"));
- AtapiEnableInterrupts(deviceExtension, j);
- KdPrint2((PRINT_PREFIX " wait a little (2)\n"));
- AtapiStallExecution(100000);
- KdPrint2((PRINT_PREFIX " done\n"));
+ KdPrint2((PRINT_PREFIX " send reset\n"));
+ AtapiWritePort1(chan, IDX_IO2_o_Control, IDE_DC_DISABLE_INTERRUPTS |
+ IDE_DC_RESET_CONTROLLER );
+ KdPrint2((PRINT_PREFIX " wait a little\n"));
+ AtapiStallExecution(10000);
+ // Disable interrupts
+ KdPrint2((PRINT_PREFIX " disable intr\n"));
+ AtapiDisableInterrupts(deviceExtension, j);
+ AtapiStallExecution(100);
+ KdPrint2((PRINT_PREFIX " re-enable intr\n"));
+ AtapiEnableInterrupts(deviceExtension, j);
+ KdPrint2((PRINT_PREFIX " wait a little (2)\n"));
+ AtapiStallExecution(100000);
+ KdPrint2((PRINT_PREFIX " done\n"));
- break;
- }
+ break;
+ } // end switch()
- //if(!(ChipFlags & UNIATA_SATA)) {
- if(!UniataIsSATARangeAvailable(deviceExtension, j)) {
- // Reset DMA engine if active
- KdPrint2((PRINT_PREFIX " check DMA engine\n"));
- dma_status = GetDmaStatus(chan->DeviceExtension, chan->lChannel);
- KdPrint2((PRINT_PREFIX " DMA status %#x\n", dma_status));
- if((ChannelCtrlFlags & CTRFLAGS_DMA_ACTIVE) ||
- (dma_status & BM_STATUS_INTR)) {
- AtapiDmaDone(HwDeviceExtension, 0, j, NULL);
+ //if(!(ChipFlags & UNIATA_SATA)) {}
+ if(!UniataIsSATARangeAvailable(deviceExtension, j)) {
+ // Reset DMA engine if active
+ KdPrint2((PRINT_PREFIX " check DMA engine\n"));
+ dma_status = GetDmaStatus(chan->DeviceExtension, chan->lChannel);
+ KdPrint2((PRINT_PREFIX " DMA status %#x\n", dma_status));
+ if((ChannelCtrlFlags & CTRFLAGS_DMA_ACTIVE) ||
+ (dma_status & BM_STATUS_INTR)) {
+ AtapiDmaDone(HwDeviceExtension, 0, j, NULL);
+ }
}
- }
+ } // ATA vs AHCI
// 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 < max_ldev; i++) {
+ for (i = 0; i < MaxLuns; i++) {
// Check if device present.
- if (!(deviceExtension->lun[i + (j * 2)].DeviceFlags & DFLAGS_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()
+ KdPrint2((PRINT_PREFIX " device have gone\n"));
+ continue;
+ }
#ifdef NAVO_TEST
continue;
#else //NAVO_TEST
continue;
}
} else {
- if(!UniataAnybodyHome(HwDeviceExtension, j, i)) {
- KdPrint2((PRINT_PREFIX " device have gone\n"));
- UniataForgetDevice(&(deviceExtension->lun[i + (j * 2)]));
+ if(ChipFlags & UNIATA_AHCI) {
+ // everything is done in UniataAhciReset()
+ KdPrint2((PRINT_PREFIX " found some device\n"));
+
+ if(!IssueIdentify(HwDeviceExtension,
+ i, j,
+ ATAPI_DEVICE(chan, i) ?
+ IDE_COMMAND_ATAPI_IDENTIFY : IDE_COMMAND_IDENTIFY,
+ FALSE)) {
+ KdPrint2((PRINT_PREFIX " identify failed !\n"));
+ UniataForgetDevice(chan->lun[i]);
+ }
+ continue;
+ }
+ if(!UniataAnybodyHome(HwDeviceExtension, j, i)) {
+ KdPrint2((PRINT_PREFIX " device have gone\n"));
+ UniataForgetDevice(chan->lun[i]);
}
#endif //NAVO_TEST
}
AtapiStallExecution(10);
statusByte = WaitOnBusyLong(chan);
statusByte = UniataIsIdle(deviceExtension, statusByte);
- if(statusByte == 0xff) {
- KdPrint2((PRINT_PREFIX
+ if(statusByte == IDE_STATUS_WRONG) {
+ KdPrint2((PRINT_PREFIX
"no drive, status %#x\n",
statusByte));
- UniataForgetDevice(&(deviceExtension->lun[i + (j * 2)]));
+ UniataForgetDevice(chan->lun[i]);
} else
// Check for ATAPI disk.
- if (deviceExtension->lun[i + (j * 2)].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",
IDE_COMMAND_ATAPI_IDENTIFY, FALSE);
} else {
- KdPrint2((PRINT_PREFIX
+ KdPrint2((PRINT_PREFIX
"AtapiResetController: Status after soft reset %#x\n",
statusByte));
}
GetBaseStatus(chan, statusByte);
}
// force DMA mode reinit
- deviceExtension->lun[i + (j * 2)].DeviceFlags |= DFLAGS_REINIT_DMA;
+ 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,
// Call the HwInitialize routine to setup multi-block.
AtapiHwInitialize__(deviceExtension, j);
- }
+ } // for(channel)
ScsiPortNotification(NextRequest, deviceExtension, NULL);
return TRUE;
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 ldev = GET_LDEV(Srb);
+ ULONG DeviceNumber = GET_CDEV(Srb);
+ PHW_LU_EXTENSION LunExt = chan->lun[DeviceNumber];
// Read the error register.
- errorByte = AtapiReadPort1(chan, IDX_IO1_i_Error);
- KdPrint2((PRINT_PREFIX
+ 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));
- if (deviceExtension->lun[ldev].DeviceFlags & DFLAGS_ATAPI_DEVICE) {
+ if (LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) {
switch (errorByte >> 4) {
case SCSI_SENSE_NO_SENSE:
- KdPrint2((PRINT_PREFIX
+ KdPrint2((PRINT_PREFIX
"ATAPI: No sense information\n"));
scsiStatus = SCSISTAT_CHECK_CONDITION;
srbStatus = SRB_STATUS_ERROR;
case SCSI_SENSE_RECOVERED_ERROR:
- KdPrint2((PRINT_PREFIX
+ KdPrint2((PRINT_PREFIX
"ATAPI: Recovered error\n"));
scsiStatus = 0;
srbStatus = SRB_STATUS_SUCCESS;
case SCSI_SENSE_NOT_READY:
- KdPrint2((PRINT_PREFIX
+ KdPrint2((PRINT_PREFIX
"ATAPI: Device not ready\n"));
scsiStatus = SCSISTAT_CHECK_CONDITION;
srbStatus = SRB_STATUS_ERROR;
case SCSI_SENSE_MEDIUM_ERROR:
- KdPrint2((PRINT_PREFIX
+ KdPrint2((PRINT_PREFIX
"ATAPI: Media error\n"));
scsiStatus = SCSISTAT_CHECK_CONDITION;
srbStatus = SRB_STATUS_ERROR;
case SCSI_SENSE_HARDWARE_ERROR:
- KdPrint2((PRINT_PREFIX
+ KdPrint2((PRINT_PREFIX
"ATAPI: Hardware error\n"));
scsiStatus = SCSISTAT_CHECK_CONDITION;
srbStatus = SRB_STATUS_ERROR;
case SCSI_SENSE_ILLEGAL_REQUEST:
- KdPrint2((PRINT_PREFIX
+ KdPrint2((PRINT_PREFIX
"ATAPI: Illegal request\n"));
scsiStatus = SCSISTAT_CHECK_CONDITION;
srbStatus = SRB_STATUS_ERROR;
case SCSI_SENSE_UNIT_ATTENTION:
- KdPrint2((PRINT_PREFIX
+ KdPrint2((PRINT_PREFIX
"ATAPI: Unit attention\n"));
scsiStatus = SCSISTAT_CHECK_CONDITION;
srbStatus = SRB_STATUS_ERROR;
case SCSI_SENSE_DATA_PROTECT:
- KdPrint2((PRINT_PREFIX
+ KdPrint2((PRINT_PREFIX
"ATAPI: Data protect\n"));
scsiStatus = SCSISTAT_CHECK_CONDITION;
srbStatus = SRB_STATUS_ERROR;
case SCSI_SENSE_BLANK_CHECK:
- KdPrint2((PRINT_PREFIX
+ KdPrint2((PRINT_PREFIX
"ATAPI: Blank check\n"));
scsiStatus = SCSISTAT_CHECK_CONDITION;
srbStatus = SRB_STATUS_ERROR;
break;
case SCSI_SENSE_ABORTED_COMMAND:
- KdPrint2((PRINT_PREFIX
+ KdPrint2((PRINT_PREFIX
"Atapi: Command Aborted\n"));
scsiStatus = SCSISTAT_CHECK_CONDITION;
srbStatus = SRB_STATUS_ERROR;
default:
- KdPrint2((PRINT_PREFIX
+ KdPrint2((PRINT_PREFIX
"ATAPI: Invalid sense information\n"));
scsiStatus = 0;
srbStatus = SRB_STATUS_ERROR;
chan->ReturningMediaStatus = errorByte;
if (errorByte & IDE_ERROR_MEDIA_CHANGE_REQ) {
- KdPrint2((PRINT_PREFIX
+ KdPrint2((PRINT_PREFIX
"IDE: Media change\n"));
scsiStatus = SCSISTAT_CHECK_CONDITION;
srbStatus = SRB_STATUS_ERROR;
}
} else if (errorByte & IDE_ERROR_COMMAND_ABORTED) {
- KdPrint2((PRINT_PREFIX
+ KdPrint2((PRINT_PREFIX
"IDE: Command abort\n"));
srbStatus = SRB_STATUS_ABORTED;
scsiStatus = SCSISTAT_CHECK_CONDITION;
srbStatus |= SRB_STATUS_AUTOSENSE_VALID;
}
- deviceExtension->lun[ldev].ErrorCount++;
+ LunExt->ErrorCount++;
} else if (errorByte & IDE_ERROR_END_OF_MEDIA) {
- KdPrint2((PRINT_PREFIX
+ KdPrint2((PRINT_PREFIX
"IDE: End of media\n"));
scsiStatus = SCSISTAT_CHECK_CONDITION;
srbStatus = SRB_STATUS_ERROR;
srbStatus |= SRB_STATUS_AUTOSENSE_VALID;
}
- if (!(deviceExtension->lun[ldev].DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED)){
- deviceExtension->lun[ldev].ErrorCount++;
+ if (!(LunExt->DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED)){
+ LunExt->ErrorCount++;
}
} else if (errorByte & IDE_ERROR_ILLEGAL_LENGTH) {
- KdPrint2((PRINT_PREFIX
+ KdPrint2((PRINT_PREFIX
"IDE: Illegal length\n"));
srbStatus = SRB_STATUS_INVALID_REQUEST;
} else if (errorByte & IDE_ERROR_BAD_BLOCK) {
- KdPrint2((PRINT_PREFIX
+ KdPrint2((PRINT_PREFIX
"IDE: Bad block\n"));
srbStatus = SRB_STATUS_ERROR;
scsiStatus = SCSISTAT_CHECK_CONDITION;
} else if (errorByte & IDE_ERROR_ID_NOT_FOUND) {
- KdPrint2((PRINT_PREFIX
+ KdPrint2((PRINT_PREFIX
"IDE: Id not found\n"));
srbStatus = SRB_STATUS_ERROR;
scsiStatus = SCSISTAT_CHECK_CONDITION;
srbStatus |= SRB_STATUS_AUTOSENSE_VALID;
}
- deviceExtension->lun[ldev].ErrorCount++;
+ LunExt->ErrorCount++;
} else if (errorByte & IDE_ERROR_MEDIA_CHANGE) {
- KdPrint2((PRINT_PREFIX
+ KdPrint2((PRINT_PREFIX
"IDE: Media change\n"));
scsiStatus = SCSISTAT_CHECK_CONDITION;
srbStatus = SRB_STATUS_ERROR;
} else if (errorByte & IDE_ERROR_DATA_ERROR) {
- KdPrint2((PRINT_PREFIX
+ KdPrint2((PRINT_PREFIX
"IDE: Data error\n"));
scsiStatus = SCSISTAT_CHECK_CONDITION;
srbStatus = SRB_STATUS_ERROR;
- if (!(deviceExtension->lun[ldev].DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED)){
- deviceExtension->lun[ldev].ErrorCount++;
+ if (!(LunExt->DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED)){
+ LunExt->ErrorCount++;
}
// Build sense buffer
}
}
- if (deviceExtension->lun[ldev].ErrorCount >= MAX_ERRORS) {
+ if (LunExt->ErrorCount >= MAX_ERRORS) {
// deviceExtension->DWordIO = FALSE;
- KdPrint2((PRINT_PREFIX
+ KdPrint2((PRINT_PREFIX
"MapError: ErrorCount >= MAX_ERRORS\n"));
- deviceExtension->lun[ldev].DeviceFlags &= ~DFLAGS_DWORDIO_ENABLED;
- deviceExtension->lun[ldev].MaximumBlockXfer = 0;
+ LunExt->DeviceFlags &= ~DFLAGS_DWORDIO_ENABLED;
+ LunExt->MaximumBlockXfer = 0;
BrutePoint();
- KdPrint2((PRINT_PREFIX
+ KdPrint2((PRINT_PREFIX
"MapError: Disabling 32-bit PIO and Multi-sector IOs\n"));
// Log the error.
- KdPrint2((PRINT_PREFIX
+ KdPrint2((PRINT_PREFIX
"ScsiPortLogError: devExt %#x, Srb %#x, P:T:D=%d:%d:%d, MsgId %#x (%d)\n",
HwDeviceExtension,
Srb,
// Reprogram to not use Multi-sector.
UCHAR statusByte;
- if (deviceExtension->lun[ldev].DeviceFlags & DFLAGS_DEVICE_PRESENT &&
- !(deviceExtension->lun[ldev].DeviceFlags & DFLAGS_ATAPI_DEVICE)) {
+ if (LunExt->DeviceFlags & DFLAGS_DEVICE_PRESENT &&
+ !(LunExt->DeviceFlags & (DFLAGS_ATAPI_DEVICE | DFLAGS_MANUAL_CHS))) {
- statusByte = AtaCommand(deviceExtension, ldev & 0x1, lChannel, IDE_COMMAND_SET_MULTIPLE, 0, 0, 0, 0, 0, ATA_WAIT_BASE_READY);
+ statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel, IDE_COMMAND_SET_MULTIPLE, 0, 0, 0, 0, 0, ATA_WAIT_BASE_READY);
// Check for errors. Reset the value to 0 (disable MultiBlock) if the
// command was aborted.
errorByte));
// Adjust the devExt. value, if necessary.
- deviceExtension->lun[ldev].MaximumBlockXfer = 0;
+ LunExt->MaximumBlockXfer = 0;
BrutePoint();
}
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);
- for (i = lChannel*2; i < (lChannel+1)*2; i++) {
+ for (i = 0; i < chan->NumberLuns; i++) {
KdPrint3((PRINT_PREFIX "AtapiHwInitialize: lChannel %#x, dev %x\n", lChannel, i));
- LunExt = &(deviceExtension->lun[i]);
+ LunExt = chan->lun[i];
// skip empty slots
if (!(LunExt->DeviceFlags & DFLAGS_DEVICE_PRESENT)) {
continue;
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
- IdeMediaStatus(TRUE,deviceExtension,(UCHAR)i);
+ IdeMediaStatus(TRUE,deviceExtension,lChannel,(UCHAR)i);
// If supported, setup Multi-block transfers.
- statusByte = AtaCommand(deviceExtension, i & 1, lChannel,
+ statusByte = AtaCommand(deviceExtension, i, lChannel,
IDE_COMMAND_SET_MULTIPLE, 0, 0, 0,
LunExt->MaximumBlockXfer, 0, ATA_WAIT_BASE_READY);
statusByte,
errorByte));
- statusByte = AtaCommand(deviceExtension, i & 1, lChannel,
+ 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.
}
if(LunExt->IdentifyData.MajorRevision) {
-
+
if(LunExt->opt_ReadCacheEnable) {
KdPrint2((PRINT_PREFIX " Try Enable Read Cache\n"));
// If supported, setup read/write cacheing
- statusByte = AtaCommand(deviceExtension, i & 1, lChannel,
+ statusByte = AtaCommand(deviceExtension, i, lChannel,
IDE_COMMAND_SET_FEATURES, 0, 0, 0,
0, ATA_C_F_ENAB_RCACHE, ATA_WAIT_BASE_READY);
// Check for errors.
if (statusByte & IDE_STATUS_ERROR) {
- KdPrint2((PRINT_PREFIX
+ KdPrint2((PRINT_PREFIX
"AtapiHwInitialize: Enable read/write cacheing on Device %d failed\n",
i));
LunExt->DeviceFlags &= ~DFLAGS_RCACHE_ENABLED;
}
} else {
KdPrint2((PRINT_PREFIX " Disable Read Cache\n"));
- statusByte = AtaCommand(deviceExtension, i & 1, lChannel,
+ statusByte = AtaCommand(deviceExtension, i, lChannel,
IDE_COMMAND_SET_FEATURES, 0, 0, 0,
0, ATA_C_F_DIS_RCACHE, ATA_WAIT_BASE_READY);
LunExt->DeviceFlags &= ~DFLAGS_RCACHE_ENABLED;
if(LunExt->opt_WriteCacheEnable) {
KdPrint2((PRINT_PREFIX " Try Enable Write Cache\n"));
// If supported & allowed, setup write cacheing
- statusByte = AtaCommand(deviceExtension, i & 1, lChannel,
+ 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
+ KdPrint2((PRINT_PREFIX
"AtapiHwInitialize: Enable write cacheing on Device %d failed\n",
i));
LunExt->DeviceFlags &= ~DFLAGS_WCACHE_ENABLED;
}
} else {
KdPrint2((PRINT_PREFIX " Disable Write Cache\n"));
- statusByte = AtaCommand(deviceExtension, i & 1, lChannel,
+ statusByte = AtaCommand(deviceExtension, i, lChannel,
IDE_COMMAND_SET_FEATURES, 0, 0, 0,
- 0, ATA_C_F_ENAB_WCACHE, ATA_WAIT_BASE_READY);
+ 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_IDLE, 0, 0, 0,
+ LunExt->opt_StandbyTimer, 0, ATA_WAIT_BASE_READY);
+ // Check for errors.
+ if (statusByte & IDE_STATUS_ERROR) {
+ KdPrint2((PRINT_PREFIX
+ "AtapiHwInitialize: standby timer on Device %d failed\n",
+ i));
+ }
+ }
}
} 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, i);
+ 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
IN PMECHANICAL_STATUS_INFORMATION_HEADER MechanismStatus)
{
PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
- ULONG ldev = GET_LDEV(Srb);
+ ULONG lChannel = GET_CHANNEL(Srb);
+ PHW_CHANNEL chan = &(deviceExtension->chan[lChannel]);
+ ULONG DeviceNumber = GET_CDEV(Srb);
+ PHW_LU_EXTENSION LunExt = chan->lun[DeviceNumber];
if (MechanismStatus) {
- deviceExtension->lun[ldev].DiscsPresent = MechanismStatus->NumberAvailableSlots;
- if (deviceExtension->lun[ldev].DiscsPresent > 1) {
- deviceExtension->lun[ldev].DeviceFlags |= DFLAGS_ATAPI_CHANGER;
+ LunExt->DiscsPresent = MechanismStatus->NumberAvailableSlots;
+ if (LunExt->DiscsPresent > 1) {
+ LunExt->DeviceFlags |= DFLAGS_ATAPI_CHANGER;
}
}
return;
return 0;
}
- // Calculate the string length.
+ // Calculate the string length and lower case all characters.
cptr = String;
while (*cptr++) {
stringLength++;
kptr = KeyWord;
while ((*cptr == *kptr) ||
- (*cptr <= 'Z' && *cptr + ('a' - 'A') == *kptr) ||
- (*cptr >= 'a' && *cptr - ('a' - 'A') == *kptr)) {
+ (*cptr >= 'A' && *cptr <= 'Z' && *cptr + ('a' - 'A') == *kptr) ||
+ (*cptr >= 'a' && *cptr <= 'z' && *cptr - ('a' - 'A') == *kptr)) {
cptr++;
kptr++;
goto ReturnCallback;
}
-#if DBG
+#ifdef DBG
if (!IS_RDP((srb->Cdb[0]))) {
KdPrint2((PRINT_PREFIX "AtapiCallBack: Invalid CDB marked as RDP - %#x\n", srb->Cdb[0]));
}
// Ask for next request.
ScsiPortNotification(NextLuRequest,
- deviceExtension,
+ deviceExtension,
PathId,
TargetId,
Lun);
// 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)InterlockedCompareExchange(&chan->CheckIntr,
- CHECK_INTR_ACTIVE,
- CHECK_INTR_DETECTED) == CHECK_INTR_DETECTED) {
+ if((ULONG)CrNtInterlockedCompareExchange(CRNT_ILK_PTYPE &(chan->CheckIntr),
+ CRNT_ILK_TYPE CHECK_INTR_ACTIVE,
+ CRNT_ILK_TYPE CHECK_INTR_DETECTED) == CHECK_INTR_DETECTED)
+ {
//ASSERT(!deviceExtension->simplexOnly);
chan->DpcState = DPC_STATE_ISR;
if(!AtapiInterrupt__(HwDeviceExtension, (UCHAR)c)) {
)
{
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];
-
- KdPrint2((PRINT_PREFIX "Intr: VendorID+DeviceID/Rev %#x/%#x\n", deviceExtension->DevID, deviceExtension->RevID));
+ //BOOLEAN checked[AHCI_MAX_PORT];
+ ULONG hIS;
+ ULONG checked;
+
+ KdPrint2((PRINT_PREFIX "Intr: VendorID+DeviceID/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 "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;
}
-// fc =
-// atapiDev = (deviceExtension->lun[ldev].DeviceFlags & DFLAGS_ATAPI_DEVICE) ? TRUE : 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;
- //non_empty_chan = (deviceExtension->lun[c*2].DeviceFlags | deviceExtension->lun[c*2+1].DeviceFlags)
- // & DFLAGS_DEVICE_PRESENT;
- 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 (deviceExtension->chan[c].CheckIntr == CHECK_INTR_DETECTED) {
// deviceExtension->chan[c].CheckIntr = CHECK_INTR_ACTIVE;
// }
- c_state = (ULONG)InterlockedCompareExchange(&(deviceExtension->chan[c].CheckIntr),
- CHECK_INTR_ACTIVE,
- CHECK_INTR_DETECTED);
+ c_state =
+ (ULONG)CrNtInterlockedCompareExchange(CRNT_ILK_PTYPE &(deviceExtension->chan[c].CheckIntr),
+ CRNT_ILK_TYPE CHECK_INTR_ACTIVE,
+ CRNT_ILK_TYPE CHECK_INTR_DETECTED);
if(c_state == CHECK_INTR_IDLE) {
// c_state = deviceExtension->chan[c].CheckIntr;
// if (deviceExtension->chan[c].CheckIntr == CHECK_INTR_IDLE) {
// deviceExtension->chan[c].CheckIntr = CHECK_INTR_ACTIVE
// }
- c_state = (ULONG)InterlockedCompareExchange(&(deviceExtension->chan[c].CheckIntr),
- CHECK_INTR_ACTIVE,
- CHECK_INTR_IDLE);
+ c_state =
+ (ULONG)CrNtInterlockedCompareExchange(CRNT_ILK_PTYPE &(deviceExtension->chan[c].CheckIntr),
+ CRNT_ILK_TYPE CHECK_INTR_ACTIVE,
+ CRNT_ILK_TYPE CHECK_INTR_IDLE);
}
} while(c_state == CHECK_INTR_CHECK);
KdPrint2((PRINT_PREFIX "AtapiInterrupt(base): locked\n"));
if((c_state == CHECK_INTR_DETECTED) ||
(i_res = AtapiCheckInterrupt__(deviceExtension, (UCHAR)c))) {
- if(i_res == 2) {
+ 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;
BOOLEAN status = FALSE;
ULONG c_count = 0;
ULONG i_res;
+ ULONG hIS;
+ ULONG checked;
// we should never get here for ISA/MCA
if(!BMList[deviceExtension->DevIndex].Isr2Enable) {
return FALSE;
}
+ 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;
}
- if((ULONG)CrNtInterlockedCompareExchange(&(deviceExtension->chan[c].CheckIntr),
- CHECK_INTR_CHECK,
- CHECK_INTR_IDLE) != CHECK_INTR_IDLE) {
+ if((ULONG)CrNtInterlockedCompareExchange(CRNT_ILK_PTYPE &(deviceExtension->chan[c].CheckIntr),
+ CRNT_ILK_TYPE CHECK_INTR_CHECK,
+ CRNT_ILK_TYPE CHECK_INTR_IDLE) != CHECK_INTR_IDLE)
+ {
KdPrint2((PRINT_PREFIX "AtapiInterrupt2: !CHECK_INTR_IDLE\n"));
// hunt on unexpected intr (Some devices generate double interrupts,
// some controllers (at least CMD649) interrupt twice with small delay.
if((i_res = AtapiCheckInterrupt__(deviceExtension, (UCHAR)c))) {
KdPrint2((PRINT_PREFIX "AtapiInterrupt2: intr\n"));
- if(i_res == 2) {
+ if(i_res == INTERRUPT_REASON_UNEXPECTED) {
KdPrint2((PRINT_PREFIX "AtapiInterrupt2: Catch unexpected\n"));
InterlockedExchange(&(deviceExtension->chan[c].CheckIntr), CHECK_INTR_IDLE);
return TRUE;
}
KdPrint2((PRINT_PREFIX "AtapiInterrupt2: return %d\n", status));
return status;
-
+
} // end AtapiInterrupt2()
RETTYPE_XXableInterrupts
if(!(deviceExtension->chan[c].ChannelCtrlFlags & CTRFLAGS_DPC_REQ)) {
- if((ULONG)InterlockedCompareExchange(&(deviceExtension->chan[c].CheckIntr),
- CHECK_INTR_ACTIVE,
- CHECK_INTR_DETECTED) != CHECK_INTR_DETECTED) {
+ if((ULONG)CrNtInterlockedCompareExchange(CRNT_ILK_PTYPE &(deviceExtension->chan[c].CheckIntr),
+ CRNT_ILK_TYPE CHECK_INTR_ACTIVE,
+ CRNT_ILK_TYPE CHECK_INTR_DETECTED) != CHECK_INTR_DETECTED)
+ {
continue;
}
-
+
} else {
deviceExtension->chan[c].ChannelCtrlFlags &= ~CTRFLAGS_DPC_REQ;
}
} else {
// check if other channel(s) interrupted
// must do nothing in simplex mode
- if((ULONG)CrNtInterlockedCompareExchange(&(chan->CheckIntr),
- CHECK_INTR_ACTIVE,
- CHECK_INTR_DETECTED) != CHECK_INTR_DETECTED) {
+ if((ULONG)CrNtInterlockedCompareExchange(CRNT_ILK_PTYPE &(chan->CheckIntr),
+ CRNT_ILK_TYPE CHECK_INTR_ACTIVE,
+ CRNT_ILK_TYPE CHECK_INTR_DETECTED) != CHECK_INTR_DETECTED) {
continue;
}
//ASSERT(!deviceExtension->simplexOnly);
)
{
PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
- KdPrint2((PRINT_PREFIX "AtapiEnableInterrupts_%d: %d\n",c, deviceExtension->chan[c].DisableIntr));
+ PHW_CHANNEL chan;
+ //UCHAR statusByte;
+
if(c >= deviceExtension->NumberChannels) {
+ KdPrint2((PRINT_PREFIX "AtapiEnableInterrupts_%d: WRONG CHANNEL\n",c));
return;
}
- if(!InterlockedDecrement(&deviceExtension->chan[c].DisableIntr)) {
- AtapiWritePort1(&deviceExtension->chan[c], IDX_IO2_o_Control,
- IDE_DC_A_4BIT );
- deviceExtension->chan[c].ChannelCtrlFlags &= ~CTRFLAGS_INTR_DISABLED;
+ 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,
+ (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 );
+ //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(&deviceExtension->chan[c], IDX_IO2_o_Control,
+ AtapiWritePort1(chan, IDX_IO2_o_Control,
IDE_DC_DISABLE_INTERRUPTS /*| IDE_DC_A_4BIT*/ );
}
return;
)
{
PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
- KdPrint2((PRINT_PREFIX "AtapiDisableInterrupts_%d: %d\n",c, deviceExtension->chan[c].DisableIntr));
- // mark channel as busy
+ PHW_CHANNEL chan;
if(c >= deviceExtension->NumberChannels) {
+ KdPrint2((PRINT_PREFIX "AtapiDisableInterrupts_%d: WRONG CHANNEL\n",c));
return;
}
- if(InterlockedIncrement(&deviceExtension->chan[c].DisableIntr)) {
- AtapiWritePort1(&deviceExtension->chan[c], IDX_IO2_o_Control,
- IDE_DC_DISABLE_INTERRUPTS /*| IDE_DC_A_4BIT*/ );
- deviceExtension->chan[c].ChannelCtrlFlags |= CTRFLAGS_INTR_DISABLED;
+ chan = &(deviceExtension->chan[c]);
+ KdPrint2((PRINT_PREFIX "AtapiDisableInterrupts_%d: %d\n",c, chan->DisableIntr));
+ // mark channel as busy
+ if(InterlockedIncrement(&chan->DisableIntr)) {
+ if(deviceExtension->HwFlags & UNIATA_AHCI) {
+ 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)) {
+
+ 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;
+ }
if(chan->ChannelCtrlFlags & CTRFLAGS_DMA_ACTIVE) {
DmaTransfer = TRUE;
goto check_unknown;
}
- if((ChipFlags & UNIATA_AHCI) &&
- UniataIsSATARangeAvailable(deviceExtension, lChannel)) {
- OurInterrupt = UniataAhciStatus(HwDeviceExtension, lChannel);
- return OurInterrupt;
- }
-
// Attention !
// We can catch (BM_STATUS_ACTIVE + BM_STATUS_INTR) when operation is actually completed
// Such behavior was observed with Intel ICH-xxx chips
switch(ChipType) {
case PROLD:
case PRNEW:
- status = AtapiReadPortEx4(chan, (ULONG_PTR)&deviceExtension->BaseIoAddressBM_0,0x1c);
+ status = AtapiReadPortEx4(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressBM_0),0x1c);
if (!DmaTransfer)
break;
- if (!(status &
+ if (!(status &
((Channel) ? 0x00004000 : 0x00000400))) {
KdPrint2((PRINT_PREFIX " Promise old/new unexpected\n"));
- return FALSE;
+ return INTERRUPT_REASON_IGNORE;
}
break;
case PRTX:
break;
if(!(status & 0x20)) {
KdPrint2((PRINT_PREFIX " Promise tx unexpected\n"));
- return FALSE;
+ return INTERRUPT_REASON_IGNORE;
}
break;
- case PRMIO:
- status = AtapiReadPortEx4(chan, (ULONG_PTR)&deviceExtension->BaseIoAddressBM_0,0x0040);
- if(ChipFlags & PRSATA) {
- pr_status = AtapiReadPortEx4(chan, (ULONG_PTR)&deviceExtension->BaseIoAddressBM_0,0x006c);
- AtapiWritePortEx4(chan, (ULONG_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 FALSE;
+ UniataSataEvent(deviceExtension, lChannel, UNIATA_SATA_EVENT_DETACH, 0);
}
if(!(status & (0x01 << Channel))) {
- KdPrint2((PRINT_PREFIX " Promise mio unexpected\n"));
- return FALSE;
+ // 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: {
/* get and clear interrupt status */
if(ChipFlags & NVQ) {
- pr_status = AtapiReadPortEx4(chan, (ULONG_PTR)&deviceExtension->BaseIoAddressSATA_0,offs);
- AtapiWritePortEx4(chan, (ULONG_PTR)&deviceExtension->BaseIoAddressSATA_0,offs, (0x0fUL << shift) | 0x00f000f0);
+ pr_status = AtapiReadPortEx4(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),offs);
+ AtapiWritePortEx4(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),offs, (0x0fUL << shift) | 0x00f000f0);
} else {
- pr_status = AtapiReadPortEx1(chan,(ULONG_PTR)&deviceExtension->BaseIoAddressSATA_0,offs);
- AtapiWritePortEx1(chan, (ULONG_PTR)&deviceExtension->BaseIoAddressSATA_0,offs, (0x0f << shift));
+ 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));
/* check for and handle connect events */
if(((pr_status & (0x0cUL << shift)) == (0x04UL << shift)) ) {
- UniataSataEvent(deviceExtension, lChannel, UNIATA_SATA_EVENT_ATTACH);
+ UniataSataEvent(deviceExtension, lChannel, UNIATA_SATA_EVENT_ATTACH, 0);
}
/* check for and handle disconnect events */
if((pr_status & (0x08UL << shift)) &&
!((pr_status & (0x04UL << shift) &&
- AtapiReadPort4(chan, IDX_SATA_SStatus))) ) {
- UniataSataEvent(deviceExtension, lChannel, UNIATA_SATA_EVENT_DETACH);
+ UniataSataReadPort4(chan, IDX_SATA_SStatus, 0))) ) {
+ UniataSataEvent(deviceExtension, lChannel, UNIATA_SATA_EVENT_DETACH, 0);
}
/* do we have any device action ? */
if(!(pr_status & (0x01UL << shift))) {
KdPrint2((PRINT_PREFIX " nVidia unexpected\n"));
- if(UniataSataClearErr(HwDeviceExtension, c, UNIATA_SATA_DO_CONNECT)) {
- OurInterrupt = 2;
+ if(UniataSataClearErr(HwDeviceExtension, c, UNIATA_SATA_DO_CONNECT, 0)) {
+ OurInterrupt = INTERRUPT_REASON_UNEXPECTED;
} else {
- return FALSE;
+ return INTERRUPT_REASON_IGNORE;
}
}
KdPrint2((PRINT_PREFIX " Sii DS0 %x\n", reg32));
if(reg32 == 0xffffffff) {
KdPrint2((PRINT_PREFIX " Sii mio unexpected\n"));
- return FALSE;
+ return INTERRUPT_REASON_IGNORE;
}
if(!(reg32 & (BM_DS0_SII_DMA_SATA_IRQ | BM_DS0_SII_DMA_COMPLETE | BM_DS0_SII_IRQ | BM_DS0_SII_DMA_ENABLE | BM_DS0_SII_DMA_ERROR))) {
KdPrint2((PRINT_PREFIX " Sii mio unexpected (2)\n"));
- return FALSE;
+ return INTERRUPT_REASON_IGNORE;
}
if(ChipFlags & UNIATA_SATA) {
* controllers continue to assert IRQ as long as
* SError bits are pending. Clear SError immediately.
*/
- if(UniataSataClearErr(HwDeviceExtension, c, UNIATA_SATA_DO_CONNECT)) {
- OurInterrupt = 2;
+ if(UniataSataClearErr(HwDeviceExtension, c, UNIATA_SATA_DO_CONNECT, 0)) {
+ OurInterrupt = INTERRUPT_REASON_UNEXPECTED;
}
}
}
KdPrint2((PRINT_PREFIX " 0x71 = %#x\n", reg8));
if (!(reg8 &
(Channel ? 0x08 : 0x04))) {
- return FALSE;
+ return INTERRUPT_REASON_IGNORE;
}
if (!DmaTransfer) {
KdPrint2((PRINT_PREFIX " cmd our\n"));
- OurInterrupt = 2;
+ OurInterrupt = INTERRUPT_REASON_UNEXPECTED;
}
SetPciConfig1(0x71, (Channel ? 0x08 : 0x04));
}
//dma_status = GetDmaStatus(deviceExtension, lChannel);
if (!((dma_status = GetDmaStatus(deviceExtension, lChannel)) & BM_STATUS_INTR)) {
KdPrint2((PRINT_PREFIX " Acard unexpected\n"));
- return FALSE;
+ return INTERRUPT_REASON_IGNORE;
}
AtapiWritePort1(chan, IDX_BM_Status, dma_status | BM_STATUS_INTR);
AtapiStallExecution(1);
AtapiWritePort1(chan, IDX_BM_Command,
AtapiReadPort1(chan, IDX_BM_Command) & ~BM_COMMAND_START_STOP);
goto skip_dma_stat_check;
+ case ATA_INTEL_ID:
+ if(UniataIsSATARangeAvailable(deviceExtension, lChannel)) {
+ if(ChipFlags & UNIATA_AHCI) {
+ // Do nothing here
+ } else
+ if(ChipFlags & UNIATA_SATA) {
+ if(UniataSataClearErr(HwDeviceExtension, c, UNIATA_SATA_DO_CONNECT, 0)) {
+ OurInterrupt = INTERRUPT_REASON_UNEXPECTED;
+ }
+ if(!(chan->ChannelCtrlFlags & CTRFLAGS_NO_SLAVE)) {
+ if(UniataSataClearErr(chan->DeviceExtension, chan->lChannel, UNIATA_SATA_IGNORE_CONNECT, 1)) {
+ OurInterrupt = INTERRUPT_REASON_UNEXPECTED;
+ }
+ }
+ }
+ }
+ break;
default:
if(UniataIsSATARangeAvailable(deviceExtension, lChannel)) {
if(ChipFlags & UNIATA_AHCI) {
// Do nothing here
} else
if(ChipFlags & UNIATA_SATA) {
- if(UniataSataClearErr(HwDeviceExtension, c, UNIATA_SATA_DO_CONNECT)) {
- OurInterrupt = 2;
+ if(UniataSataClearErr(HwDeviceExtension, c, UNIATA_SATA_DO_CONNECT, 0)) {
+ OurInterrupt = INTERRUPT_REASON_UNEXPECTED;
}
}
}
KdPrint2((PRINT_PREFIX " DmaTransfer + !BM_STATUS_INTR (%x)\n", dma_status));
if(dma_status & BM_STATUS_ERR) {
KdPrint2((PRINT_PREFIX " DmaTransfer + BM_STATUS_ERR -> our\n"));
- OurInterrupt = 2;
+ OurInterrupt = INTERRUPT_REASON_UNEXPECTED;
} 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 = 2;
+ 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 FALSE;
+ return INTERRUPT_REASON_IGNORE;
}
}
}
KdPrint2((PRINT_PREFIX " clear unexpected DMA intr\n"));
AtapiDmaDone(deviceExtension, DEVNUM_NOT_SPECIFIED ,lChannel, NULL);
// catch it !
- OurInterrupt = 2;
+ OurInterrupt = INTERRUPT_REASON_UNEXPECTED;
}
}
skip_dma_stat_check:
- if(!(ChipFlags & UNIATA_SATA)) {
+ if(!(ChipFlags & UNIATA_SATA) && chan->ExpectingInterrupt) {
AtapiStallExecution(1);
}
- LunExt = &(deviceExtension->lun[c*2 + 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 " ATAPI additional check\n"));
} else {
KdPrint2((PRINT_PREFIX " expecting intr + BUSY (3), non ATAPI\n"));
- return FALSE;
+ return INTERRUPT_REASON_IGNORE;
}
if((statusByte & ~IDE_STATUS_DRQ) != (IDE_STATUS_BUSY | IDE_STATUS_DRDY | IDE_STATUS_DSC)) {
KdPrint3((PRINT_PREFIX " unexpected status, seems it is not our\n"));
- return FALSE;
+ return INTERRUPT_REASON_IGNORE;
}
if(!(LunExt->DeviceFlags & DFLAGS_INT_DRQ) && (statusByte & IDE_STATUS_DRQ)) {
KdPrint3((PRINT_PREFIX " unexpected DRQ, seems it is not our\n"));
- return FALSE;
+ return INTERRUPT_REASON_IGNORE;
}
EarlyIntr = TRUE;
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 TRUE;
+ return INTERRUPT_REASON_OUR;
}
if(g_WaitBusyInISR) {
}
if (statusByte & IDE_STATUS_BUSY) {
KdPrint2((PRINT_PREFIX " still BUSY, seems it is not our\n"));
- return FALSE;
+ return INTERRUPT_REASON_IGNORE;
}
}
/* 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
+ } else
if(!(statusByte & (IDE_STATUS_DRQ | IDE_STATUS_DRDY))) {
KdPrint2((PRINT_PREFIX " no DRQ/DRDY set\n"));
return OurInterrupt;
#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;
}
//ASSERT(!chan->queue_depth || chan->cur_req);
KdPrint2((PRINT_PREFIX "AtapiCheckInterrupt__: exit with TRUE\n"));
- return TRUE;
+ return INTERRUPT_REASON_OUR;
} // end AtapiCheckInterrupt__()
BOOLEAN atapiDev = FALSE;
+#ifdef DBG
UCHAR Channel;
+#endif //DBG
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) {
UCHAR TargetId;
UCHAR Lun;
UCHAR OldReqState = REQ_STATE_NONE;
- ULONG ldev;
+ //ULONG ldev;
PHW_LU_EXTENSION LunExt;
lChannel = c;
+
+#ifdef DBG
Channel = (UCHAR)(deviceExtension->Channel + lChannel);
KdPrint2((PRINT_PREFIX " cntrlr %#x:%d, irql %#x, c %d\n", deviceExtension->DevIndex, Channel, KeGetCurrentIrql(), c));
+#endif //DBG
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"));
}
if (srb) {
- PathId = srb->PathId;
+ PathId = srb->PathId;
TargetId = srb->TargetId;
- Lun = srb->Lun;
+ Lun = srb->Lun;
} else {
PathId = (UCHAR)c;
TargetId =
goto enqueue_next_req;
}
- ldev = GET_LDEV2(PathId, TargetId, Lun);
- DeviceNumber = (UCHAR)(ldev & 1);
- LunExt = &(deviceExtension->lun[ldev]);
+ //ldev = GET_LDEV2(PathId, TargetId, Lun);
+ DeviceNumber = (UCHAR)(TargetId);
+ LunExt = chan->lun[DeviceNumber];
atapiDev = (LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) ? TRUE : FALSE;
KdPrint2((PRINT_PREFIX " dev_type %s\n", atapiDev ? "ATAPI" : "IDE"));
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"));
// 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 */
- GetBaseStatus(chan, statusByte);
+ if(deviceExtension->HwFlags & UNIATA_AHCI) {
+ UniataAhciEndTransaction(HwDeviceExtension, lChannel, DeviceNumber, srb);
+ 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) {
+ //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);
+ }
if(atapiDev) {
KdPrint3((PRINT_PREFIX "AtapiInterrupt: ATAPI Entered with status (%#x)\n", statusByte));
} else {
KdPrint2((PRINT_PREFIX " operate like in DPC\n"));
InDpc = TRUE;
}
-
+
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.
AtapiStallExecution(TimerValue);
goto ServiceInterrupt;
#endif //UNIATA_CORE
- } else
+ } else
if (InDpc && i == k) {
// reset the controller.
- KdPrint2((PRINT_PREFIX
+ KdPrint2((PRINT_PREFIX
" Resetting due to BUSY on entry - %#x.\n",
statusByte));
goto IntrPrepareResetController;
// 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"));
+ //if(chan->ChannelCtrlFlags & CTRFLAGS_DSC_BSY) {}
+/*
+#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"));
}
}
- if(AtaReq && DmaTransfer) {
+ if(AtaReq && DmaTransfer && !(deviceExtension->HwFlags & UNIATA_AHCI)) {
switch(OldReqState) {
case REQ_STATE_EARLY_INTR:
case REQ_STATE_DPC_WAIT_BUSY0:
if ((statusByte & IDE_STATUS_ERROR) ||
(dma_status & BM_STATUS_ERR)) {
- error = AtapiReadPort1(chan, IDX_IO1_i_Error);
+ if(deviceExtension->HwFlags & UNIATA_AHCI) {
+ 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 "AtapiInterrupt: Error %#x\n", error));
/*
if(error & IDE_STATUS_CORRECTED_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(100);
+ AtapiStallExecution(50);
} else {
break;
}
#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;
+ if(!(deviceExtension->HwFlags & UNIATA_AHCI)) {
+ AtaReq->Flags &= ~REQ_FLAG_DMA_OPERATION;
+ AtaReq->Flags |= REQ_FLAG_FORCE_DOWNRATE;
// LunExt->DeviceFlags |= DFLAGS_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(DmaTransfer && (chan->lun[DeviceNumber]->TransferMode > ATA_UDMA2) &&
deviceExtension->HbaCtrlFlags |= HBAFLAGS_DMA_DISABLED_LBA48;
} else
if(AtaReq->Flags & REQ_FLAG_FORCE_DOWNRATE) {
- KdPrint2((PRINT_PREFIX "Some higher mode doesn't work right :((\n"));
#ifdef IO_STATISTICS
- chan->lun[DeviceNumber]->RecoverCount[AtaReq->retry]++;
- if(chan->lun[DeviceNumber]->RecoverCount[AtaReq->retry] >= chan->lun[DeviceNumber]->IoCount/3 ||
+ KdPrint2((PRINT_PREFIX "Some higher mode doesn't work right :((\n"));
+ KdPrint2((PRINT_PREFIX "Recovery stats[%d]: %d vs %d\n",
+ AtaReq->retry,
+ LunExt->RecoverCount[AtaReq->retry],
+ LunExt->BlockIoCount
+ ));
+ LunExt->RecoverCount[AtaReq->retry]++;
+ if(LunExt->RecoverCount[AtaReq->retry] >= chan->lun[DeviceNumber]->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
- chan->lun[DeviceNumber]->IoCount++;
+ if(AtaReq->bcount) {
+ // we need stats for Read/Write operations
+ LunExt->BlockIoCount++;
+ }
+ 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;
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 (interruptReason == 0x1 && (statusByte & IDE_STATUS_DRQ)) {
+ if(deviceExtension->HwFlags & UNIATA_AHCI) {
+ 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 == ATAPI_IR_COD_Cmd && (statusByte & IDE_STATUS_DRQ)) {
// 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);
AtaReq->ReqState = REQ_STATE_ATAPI_EXPECTING_DATA_INTR;
if(chan->ChannelCtrlFlags & CTRFLAGS_DMA_OPERATION) {
KdPrint2((PRINT_PREFIX "AtapiInterrupt: AtapiDmaStart().\n"));
- AtapiDmaStart(HwDeviceExtension, ldev & 1, lChannel, srb);
+ AtapiDmaStart(HwDeviceExtension, DeviceNumber, lChannel, srb);
}
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;
KdPrint2((PRINT_PREFIX "AtapiInterrupt: get W wordCount %#x\n", wordCount));
if (wordCount != AtaReq->WordsLeft) {
- KdPrint2((PRINT_PREFIX
+ KdPrint2((PRINT_PREFIX
"AtapiInterrupt: %d words requested; %d words xferred\n",
AtaReq->WordsLeft,
wordCount));
// Verify this makes sense.
if (wordCount > AtaReq->WordsLeft) {
wordCount = AtaReq->WordsLeft;
- KdPrint2((PRINT_PREFIX
+ KdPrint2((PRINT_PREFIX
"AtapiInterrupt: Write underrun\n"));
DataOverrun = TRUE;
}
// IDE path. Check if words left is at least DEV_BSIZE/2 = 256.
if (AtaReq->WordsLeft < wordsThisInterrupt) {
-
// Transfer only words requested.
wordCount = AtaReq->WordsLeft;
-
} else {
-
// Transfer next block.
wordCount = wordsThisInterrupt;
}
}
- 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) {
- KdPrint2((PRINT_PREFIX
+ KdPrint2((PRINT_PREFIX
"AtapiInterrupt: Write interrupt\n"));
statusByte = WaitOnBusy(chan);
}
} else {
- KdPrint3((PRINT_PREFIX
- "AtapiInterrupt: Int reason %#x, but srb is for a write %#x.\n",
+ KdPrint3((PRINT_PREFIX
+ "AtapiInterrupt: Int reason %#x, but srb is for a read %#x.\n",
interruptReason,
srb));
status = SRB_STATUS_ERROR;
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)) {
if (atapiDev) {
AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountLow) |
(AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountHigh) << 8);
- // Covert bytes to words.
- wordCount /= 2;
+ // Convert bytes to words.
+ wordCount >>= 1;
KdPrint2((PRINT_PREFIX "AtapiInterrupt: get R wordCount %#x\n", wordCount));
if (wordCount != AtaReq->WordsLeft) {
- KdPrint2((PRINT_PREFIX
+ KdPrint2((PRINT_PREFIX
"AtapiInterrupt: %d words requested; %d words xferred\n",
AtaReq->WordsLeft,
wordCount));
// Check if words left is at least 256.
if (AtaReq->WordsLeft < wordsThisInterrupt) {
-
// Transfer only words requested.
wordCount = AtaReq->WordsLeft;
-
} else {
-
// Transfer next block.
wordCount = wordsThisInterrupt;
}
}
- 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*/) {
- KdPrint2((PRINT_PREFIX
+ KdPrint2((PRINT_PREFIX
"IdeIntr: Read %#x words\n", wordCount));
ReadBuffer(chan,
KdDump(AtaReq->DataBuffer, wordCount*2);
}
- GetStatus(chan, statusByte);
+ GetBaseStatus(chan, statusByte);
KdPrint2((PRINT_PREFIX " status re-check %#x\n", statusByte));
if(DataOverrun) {
KdPrint2((PRINT_PREFIX " DataOverrun\n"));
AtapiSuckPort2(chan);
+ GetBaseStatus(chan, statusByte);
+ }
+
+ if(statusByte & IDE_STATUS_BUSY) {
+ for (i = 0; i < 2; i++) {
+ AtapiStallExecution(10);
+ GetBaseStatus(chan, statusByte);
+ if (!(statusByte & IDE_STATUS_BUSY)) {
+ break;
+ }
+ }
}
} else {
- KdPrint2((PRINT_PREFIX
+ KdPrint2((PRINT_PREFIX
"IdeIntr: Read %#x Dwords\n", wordCount/2));
ReadBuffer2(chan,
// 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) {
*((ULONG *) &(AtaReq->DataBuffer[2])) = 0x00080000;
AtaReq->DataBuffer += wordCount;
}
+
+ 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));
+
+ 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;
+ }
}
}
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 os 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;
}
+ //if (AtaReq->WordsLeft) {
+ // status = SRB_STATUS_DATA_OVERRUN;
+ //} else {
+ status = SRB_STATUS_SUCCESS;
+ //}
#ifdef UNIATA_DUMP_ATAPI
if(srb &&
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;
if (status == SRB_STATUS_DATA_OVERRUN) {
// Check to see if we at least get mininum number of bytes
if ((srb->DataTransferLength - AtaReq->WordsLeft) >
- (offsetof (SENSE_DATA, AdditionalSenseLength) + sizeof(senseData->AdditionalSenseLength))) {
+ (FIELD_OFFSET (SENSE_DATA, AdditionalSenseLength) + sizeof(senseData->AdditionalSenseLength))) {
status = SRB_STATUS_SUCCESS;
}
}
if ((senseData->SenseKey != SCSI_SENSE_ILLEGAL_REQUEST) &&
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 (
AtaReq->OriginalSrb);
} else {
- // last request was illegal. No point trying again
+ // last request was illegal. No point trying again.
+ // Do-nothing call ?
AtapiHwInitializeChanger (HwDeviceExtension,
srb,
(PMECHANICAL_STATUS_INFORMATION_HEADER) NULL);
if (AtaReq->OriginalSrb) {
KdPrint2((PRINT_PREFIX "AtapiInterrupt: call AtapiHwInitializeChanger()\n"));
+ // Do-nothing call ?
AtapiHwInitializeChanger (HwDeviceExtension,
srb,
(PMECHANICAL_STATUS_INFORMATION_HEADER) 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;
}
if (i == 5*30) {
// reset the controller.
- KdPrint2((PRINT_PREFIX
+ KdPrint2((PRINT_PREFIX
"AtapiInterrupt: Resetting due to BSY still up - %#x.\n",
statusByte));
goto IntrPrepareResetController;
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;
KdPrint2((PRINT_PREFIX "AtapiInterrupt: Clear RDP\n"));
chan->RDP = FALSE;
goto CompleteRDP;
- }
+ }
AtapiStallExecution(50);
}
}
NULL);
} else {
ScsiPortNotification(NextLuRequest,
- deviceExtension,
+ deviceExtension,
PathId,
TargetId,
Lun);
interruptReason,
statusByte));
+ 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
+ KdPrint2((PRINT_PREFIX
"IdeSendSmartCommand: bCommandReg != SMART_CMD\n"));
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);
if (statusByte & IDE_STATUS_BUSY) {
- KdPrint2((PRINT_PREFIX
+ KdPrint2((PRINT_PREFIX
"IdeSendSmartCommand: Returning BUSY status\n"));
return SRB_STATUS_BUSY;
}
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);
if (statusByte & IDE_STATUS_BUSY) {
- KdPrint2((PRINT_PREFIX
+ KdPrint2((PRINT_PREFIX
"IdeSendSmartCommand: Returning BUSY status\n"));
return SRB_STATUS_BUSY;
}
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
)
{
USHORT cylinder;
ULONG tmp;
- (*max_bcount) = 0;
-
if(LunExt->DeviceFlags & DFLAGS_LBA_ENABLED) {
if(LunExt->LimitedTransferMode >= ATA_DMA) {
if(LunExt->DeviceExtension) {
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()
PHW_CHANNEL chan = &(deviceExtension->chan[lChannel]);
PHW_LU_EXTENSION LunExt;
PATA_REQ AtaReq = (PATA_REQ)(Srb->SrbExtension);
- ULONG ldev = GET_LDEV(Srb);
- UCHAR DeviceNumber = (UCHAR)(ldev & 1);
- ULONG startingSector;
+ //ULONG ldev = GET_LDEV(Srb);
+ UCHAR DeviceNumber = GET_CDEV(Srb);;
+ ULONGLONG startingSector=0;
ULONG max_bcount;
ULONG wordCount = 0;
UCHAR statusByte,statusByte2;
UCHAR cmd;
ULONGLONG lba;
BOOLEAN use_dma = FALSE;
+ ULONG fis_size;
AtaReq->Flags |= REQ_FLAG_REORDERABLE_CMD;
- LunExt = &deviceExtension->lun[ldev];
+ LunExt = chan->lun[DeviceNumber];
if((CmdAction & CMD_ACTION_PREPARE) &&
(AtaReq->ReqState != REQ_STATE_READY_TO_TRANSFER)) {
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_READ:
+ case SCSIOP_WRITE:
+ MOV_DD_SWP(startingSector, ((PCDB)Srb->Cdb)->CDB10.LBA);
+ MOV_SWP_DW2DD(AtaReq->bcount, ((PCDB)Srb->Cdb)->CDB10.TransferBlocks);
+ break;
+ case SCSIOP_READ12:
+ case SCSIOP_WRITE12:
+ 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));
// 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
use_dma = FALSE;
}
}
+
+ 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,
+ lba,
+ (USHORT)(AtaReq->bcount),
+ 0
+ /*,(AtaReq->Flags & REQ_FLAG_READ) ? 0 : ATA_AHCI_CMD_WRITE*/
+ );
+
+ if(!fis_size) {
+ KdPrint3((PRINT_PREFIX "IdeReadWrite: AHCI !FIS\n"));
+ return SRB_STATUS_ERROR;
+ }
+
+ 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));
+ }
+
AtaReq->ReqState = REQ_STATE_READY_TO_TRANSFER;
+
} else { // exec_only
KdPrint2((PRINT_PREFIX "IdeReadWrite (ExecOnly): \n"));
lba = AtaReq->lba;
}
}
if(!(CmdAction & CMD_ACTION_EXEC)) {
+
return SRB_STATUS_PENDING;
}
// if this is queued request, reinit DMA and check
// if DMA mode is still available
- AtapiDmaReinit(deviceExtension, ldev, AtaReq);
+ AtapiDmaReinit(deviceExtension, LunExt, AtaReq);
if (/*EnableDma &&*/
(LunExt->TransferMode >= ATA_DMA)) {
use_dma = TRUE;
}
}
+ // Send IO command.
+ KdPrint2((PRINT_PREFIX "IdeReadWrite: Lba %#I64x, Count %#x(%#x)\n", lba, ((Srb->DataTransferLength + 0x1FF) / 0x200),
+ ((wordCount*2 + DEV_BSIZE-1) / DEV_BSIZE)));
if(use_dma) {
chan->ChannelCtrlFlags |= CTRFLAGS_DMA_OPERATION;
} else {
chan->ChannelCtrlFlags &= ~CTRFLAGS_DMA_OPERATION;
}
- // Send IO command.
- KdPrint2((PRINT_PREFIX "IdeReadWrite: Lba %#I64x, Count %#x(%#x)\n", lba, ((Srb->DataTransferLength + 0x1FF) / 0x200),
- ((wordCount*2 + DEV_BSIZE-1) / DEV_BSIZE)));
+ if(deviceExtension->HwFlags & UNIATA_AHCI) {
+ // AHCI doesn't distinguish DMA and PIO
+ //AtapiDmaStart(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) {
(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) {
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)) {
- KdPrint2((PRINT_PREFIX
+ KdPrint2((PRINT_PREFIX
"IdeReadWrite: Write %#x words\n", wordCount));
WriteBuffer(chan,
} else {
- KdPrint2((PRINT_PREFIX
+ KdPrint2((PRINT_PREFIX
"IdeReadWrite: Write %#x Dwords\n", wordCount/2));
WriteBuffer2(chan,
PHW_CHANNEL chan = &(deviceExtension->chan[lChannel]);
PATA_REQ AtaReq = (PATA_REQ)(Srb->SrbExtension);
PHW_LU_EXTENSION LunExt;
- ULONG ldev = GET_LDEV(Srb);
+ //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 = &deviceExtension->lun[ldev];
+ LunExt = chan->lun[DeviceNumber];
// Drive has these number sectors.
if(!(sectors = (ULONG)(LunExt->NumOfSectors))) {
sectors = LunExt->IdentifyData.SectorsPerTrack *
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 {
lba = UniAtaCalculateLBARegs(LunExt, startingSector, &max_bcount);
- statusByte = AtaCommand48(deviceExtension, ldev & 0x01, GET_CHANNEL(Srb),
+ statusByte = AtaCommand48(deviceExtension, LunExt->Lun, GET_CHANNEL(Srb),
IDE_COMMAND_VERIFY, lba,
- sectorCount,
+ (USHORT)sectorCount,
0, ATA_IMMEDIATE);
if(!(statusByte & IDE_STATUS_ERROR)) {
UCHAR lChannel = GET_CHANNEL(Srb);
PHW_CHANNEL chan = &(deviceExtension->chan[lChannel]);
PATA_REQ AtaReq = (PATA_REQ)(Srb->SrbExtension);
- ULONG ldev = GET_LDEV(Srb);
- ULONG i;
+ PHW_LU_EXTENSION LunExt;
+ //ULONG ldev = GET_LDEV(Srb);
+ ULONG DeviceNumber = GET_CDEV(Srb);
ULONG flags;
- UCHAR statusByte,byteCountLow,byteCountHigh;
+ UCHAR statusByte,statusByte0,byteCountLow,byteCountHigh;
BOOLEAN use_dma = FALSE;
BOOLEAN dma_reinited = FALSE;
BOOLEAN retried = FALSE;
+ ULONG fis_size;
+ UCHAR FeatureReg=0;
+
+ LunExt = chan->lun[DeviceNumber];
KdPrint3((PRINT_PREFIX "AtapiSendCommand: req state %#x, Action %x\n", AtaReq->ReqState, CmdAction));
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;
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;
default:
return SRB_STATUS_BUSY;
}
//
- if (!(deviceExtension->lun[ldev].DeviceFlags & DFLAGS_CHANGER_INITED) &&
+ if (!(LunExt->DeviceFlags & DFLAGS_CHANGER_INITED) &&
!AtaReq->OriginalSrb) {
KdPrint2((PRINT_PREFIX "AtapiSendCommand: SRB_STATUS_BUSY (2)\n"));
return SRB_STATUS_BUSY;
}
}
+#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 {
+
+ // 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;
+
+ KdPrint2((PRINT_PREFIX "AtapiSendCommand: AtapiHwInitializeChanger()\n"));
+ // Do-nothing call ?
+ AtapiHwInitializeChanger (HwDeviceExtension, Srb,
+ (PMECHANICAL_STATUS_INFORMATION_HEADER) NULL);
+ // fall out
+ }
+ }
+#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(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
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(AtapiDmaSetup(HwDeviceExtension, ldev & 1, lChannel, Srb,
+ 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
/*((Srb->DataTransferLength + DEV_BSIZE-1) & ~(DEV_BSIZE-1))*/
break;
}
// try setup DMA
+setup_dma:
if(use_dma) {
- if(!AtapiDmaSetup(HwDeviceExtension, ldev & 1, lChannel, Srb,
+ 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)) {
KdPrint2((PRINT_PREFIX "AtapiSendCommand: no dma\n"));
KdPrint2((PRINT_PREFIX "AtapiSendCommand: zero transfer, no DMA setup\n"));
}
+
+ if(deviceExtension->HwFlags & UNIATA_AHCI) {
+
+ UniataAhciSetupCmdPtr(AtaReq);
+
+ 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 &&
+ (Srb->SrbFlags & SRB_FLAGS_DATA_IN)) {
+ 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);
+
+ KdPrint2((PRINT_PREFIX "AtapiSendCommand ahci io flags %x: \n", AtaReq->ahci.io_cmd_flags));
+ }
+
} else {
if(AtaReq->Flags & REQ_FLAG_DMA_OPERATION) {
// if this is queued request, reinit DMA and check
// if DMA mode is still available
KdPrint2((PRINT_PREFIX "AtapiSendCommand: AtapiDmaReinit() (1)\n"));
- AtapiDmaReinit(deviceExtension, ldev, AtaReq);
+ AtapiDmaReinit(deviceExtension, LunExt, AtaReq);
if (/*EnableDma &&*/
- (deviceExtension->lun[ldev].TransferMode >= ATA_DMA)) {
+ (LunExt->TransferMode >= ATA_DMA)) {
KdPrint2((PRINT_PREFIX "AtapiSendCommand: use dma (2)\n"));
use_dma = TRUE;
} else {
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, ldev, AtaReq);
+ AtapiDmaReinit(deviceExtension, LunExt, AtaReq);
} if(AtaReq->TransferLength) {
if(!dma_reinited) {
KdPrint2((PRINT_PREFIX "AtapiSendCommand: AtapiDmaReinit()\n"));
- AtapiDmaReinit(deviceExtension, ldev, AtaReq);
+ AtapiDmaReinit(deviceExtension, LunExt, AtaReq);
if (/*EnableDma &&*/
- (deviceExtension->lun[ldev].TransferMode >= ATA_DMA)) {
+ (LunExt->TransferMode >= ATA_DMA)) {
use_dma = TRUE;
} else {
AtaReq->Flags &= ~REQ_FLAG_DMA_OPERATION;
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, ldev, AtaReq);
+ AtapiDmaReinit(deviceExtension, LunExt, AtaReq);
}
}
KdPrint2((PRINT_PREFIX "AtapiSendCommand: use_dma=%d\n", use_dma));
if(AtaReq->Flags & REQ_FLAG_DMA_OPERATION) {
KdPrint2((PRINT_PREFIX " REQ_FLAG_DMA_OPERATION\n"));
}
-
+
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 (!(deviceExtension->lun[ldev].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.
- deviceExtension->lun[ldev].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 = deviceExtension->lun[ldev].DeviceFlags;
+ flags = LunExt->DeviceFlags;
if(flags & (DFLAGS_SANYO_ATAPI_CHANGER | DFLAGS_ATAPI_CHANGER)) {
- if((Srb->Lun) > (deviceExtension->lun[ldev].DiscsPresent - 1)) {
+ if((Srb->Lun) > (LunExt->DiscsPresent - 1)) {
// Indicate no device found at this address.
AtaReq->ReqState = REQ_STATE_TRANSFER_COMPLETE;
return SRB_STATUS_SELECTION_TIMEOUT;
}
retry:
- // Select device 0 or 1.
- SelectDrive(chan, ldev & 0x1);
+ // 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) {
make_reset:
KdPrint3((PRINT_PREFIX "AtapiSendCommand: DRQ still asserted.Status (%#x)\n", statusByte));
AtapiDisableInterrupts(deviceExtension, lChannel);
- AtapiSoftReset(chan, ldev & 1);
+ AtapiSoftReset(chan, DeviceNumber);
KdPrint2((PRINT_PREFIX "AtapiSendCommand: Issued soft reset to Atapi device. \n"));
// Re-initialize Atapi device.
- CheckDevice(HwDeviceExtension, GET_CHANNEL(Srb), ldev & 1, TRUE);
+ CheckDevice(HwDeviceExtension, GET_CHANNEL(Srb), DeviceNumber, TRUE);
/*
- IssueIdentify(HwDeviceExtension, ldev & 1, GET_CHANNEL(Srb),
+ IssueIdentify(HwDeviceExtension, DeviceNumber, GET_CHANNEL(Srb),
IDE_COMMAND_ATAPI_IDENTIFY, FALSE);
*/
// 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 &&
+ (Srb->SrbFlags & SRB_FLAGS_DATA_IN)) {
+ FeatureReg |= ATA_F_DMAREAD;
+ }
+ }
+
+ AtapiWritePort1(chan, IDX_IO1_o_Feature, FeatureReg);
// Write transfer byte count to registers.
byteCountLow = (UCHAR)(Srb->DataTransferLength & 0xFF);
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);
KdPrint3((PRINT_PREFIX "AtapiSendCommand: return SRB_STATUS_PENDING (DRQ)\n"));
return SRB_STATUS_PENDING;
- } else {
+ }
- // This device quickly sets DRQ when ready to receive the packet.
+ // 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));
+ 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);
+ UniataExpectChannelInterrupt(chan, TRUE);
+ AtaReq->ReqState = REQ_STATE_ATAPI_DO_NOTHING_INTR;
+ InterlockedExchange(&(chan->CheckIntr),
+ CHECK_INTR_IDLE);
- //AtapiDisableInterrupts(deviceExtension, lChannel);
+ if(g_opt_AtapiSendDisableIntr) {
+ AtapiDisableInterrupts(deviceExtension, lChannel);
+ }
+ // remember status. Later we may check if error appeared after cmd packet
+ statusByte0 = statusByte;
- // Write ATAPI packet command.
- AtapiWritePort1(chan, IDX_IO1_o_Command, IDE_COMMAND_ATAPI_PACKET);
+ // Write ATAPI packet command.
+ AtapiWritePort1(chan, IDX_IO1_o_Command, IDE_COMMAND_ATAPI_PACKET);
- // Wait for DRQ.
- WaitOnBusy(chan);
- statusByte = WaitForDrq(chan);
+ // Wait for DRQ.
+ WaitOnBusy(chan);
+ statusByte = WaitForDrq(chan);
- // Need to read status register and clear interrupt (if any)
- GetBaseStatus(chan, statusByte);
+ // Need to read status register and clear interrupt (if any)
+ GetBaseStatus(chan, statusByte);
- if (!(statusByte & IDE_STATUS_DRQ)) {
+ if (!(statusByte & IDE_STATUS_DRQ)) {
+ if(g_opt_AtapiSendDisableIntr) {
AtapiEnableInterrupts(deviceExtension, lChannel);
- KdPrint3((PRINT_PREFIX "AtapiSendCommand: DRQ never asserted (%#x)\n", statusByte));
- AtaReq->ReqState = REQ_STATE_TRANSFER_COMPLETE;
- return SRB_STATUS_ERROR;
}
+ KdPrint3((PRINT_PREFIX "AtapiSendCommand: DRQ never asserted (%#x)\n", statusByte));
+ AtaReq->ReqState = REQ_STATE_TRANSFER_COMPLETE;
+ return SRB_STATUS_ERROR;
}
GetStatus(chan, statusByte);
statusByte = WaitOnBaseBusy(chan);
// Indicate expecting an interrupt and wait for it.
- chan->ExpectingInterrupt = TRUE;
+ UniataExpectChannelInterrupt(chan, TRUE);
InterlockedExchange(&(chan->CheckIntr),
CHECK_INTR_IDLE);
AtaReq->ReqState = REQ_STATE_ATAPI_EXPECTING_DATA_INTR;
GetBaseStatus(chan, statusByte);
- //AtapiEnableInterrupts(deviceExtension, lChannel);
+ if(g_opt_AtapiSendDisableIntr) {
+ AtapiEnableInterrupts(deviceExtension, lChannel);
+ }
WriteBuffer(chan,
(PUSHORT)Srb->Cdb,
- 6,
+ LunExt->IdentifyData.AtapiCmdSize ? 8 : 6,
0);
+ GetStatus(chan, statusByte);
+ KdPrint3((PRINT_PREFIX "AtapiSendCommand: cmd status (%#x)\n", statusByte));
+
+ // When we operate in DMA mode, we should not start transfer when there is an error on entry
+ // Interrupt may never come in such case.
+ if(statusByte & IDE_STATUS_ERROR) {
+ UCHAR interruptReason;
+
+ GetBaseStatus(chan, statusByte);
+ KdPrint3((PRINT_PREFIX "AtapiSendCommand: Error on cmd: (%#x)\n", statusByte));
+
+ 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_DSC) {
+ KdPrint3((PRINT_PREFIX "AtapiSendCommand: DSC 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, ldev & 1, lChannel, Srb);
+ AtapiDmaStart(HwDeviceExtension, DeviceNumber, lChannel, Srb);
}
KdPrint3((PRINT_PREFIX "AtapiSendCommand: ExpectingInterrupt (%#x)\n", chan->ExpectingInterrupt));
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 ldev;
+ ULONG DeviceNumber;
PATA_REQ AtaReq;
+ UCHAR command;
+
SetCheckPoint(5);
//ULONG __ebp__ = 0;
lChannel = GET_CHANNEL(Srb);
chan = &(deviceExtension->chan[lChannel]);
- ldev = GET_LDEV(Srb);
+ //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 > 2) /*||
- (!deviceExtension->lun[ldev].DeviceFlags & DFLAGS_DEVICE_PRESENT)*/) {
+ (Srb->TargetId >= deviceExtension->NumberLuns)) {
- KdPrint2((PRINT_PREFIX
+ KdPrint2((PRINT_PREFIX
"IdeSendCommand: SCSIOP_INQUIRY rejected\n"));
// Indicate no device found at this address.
status = SRB_STATUS_SELECTION_TIMEOUT;
} else {
- KdPrint2((PRINT_PREFIX
+ KdPrint2((PRINT_PREFIX
"IdeSendCommand: SCSIOP_INQUIRY ok\n"));
PINQUIRYDATA inquiryData = (PINQUIRYDATA)(Srb->DataBuffer);
- PIDENTIFY_DATA2 identifyData = &(deviceExtension->lun[ldev].IdentifyData);
-
- if (!(deviceExtension->lun[ldev].DeviceFlags & DFLAGS_DEVICE_PRESENT)) {
+ PIDENTIFY_DATA2 identifyData = &(LunExt->IdentifyData);
- if(!CheckDevice(HwDeviceExtension, lChannel, ldev & 1, FALSE)) {
- KdPrint2((PRINT_PREFIX
+ if (!(chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_DEVICE_PRESENT)) {
+
+ if(!CheckDevice(HwDeviceExtension, lChannel, DeviceNumber, FALSE)) {
+ KdPrint2((PRINT_PREFIX
"IdeSendCommand: SCSIOP_INQUIRY rejected (2)\n"));
// Indicate no device found at this address.
#ifndef NAVO_TEST
break;
}
} else {
- if(!UniataAnybodyHome(HwDeviceExtension, lChannel, ldev & 1)) {
- KdPrint2((PRINT_PREFIX
+ if(!UniataAnybodyHome(HwDeviceExtension, lChannel, DeviceNumber)) {
+ KdPrint2((PRINT_PREFIX
"IdeSendCommand: SCSIOP_INQUIRY device have gone\n"));
// Indicate no device found at this address.
- UniataForgetDevice(&(deviceExtension->lun[ldev]));
+ UniataForgetDevice(chan->lun[DeviceNumber]);
#endif //NAVO_TEST
status = SRB_STATUS_SELECTION_TIMEOUT;
break;
inquiryData->DeviceType = DIRECT_ACCESS_DEVICE;
// Set the removable bit, if applicable.
- if (deviceExtension->lun[ldev].DeviceFlags & DFLAGS_REMOVABLE_DRIVE) {
- KdPrint2((PRINT_PREFIX
+ if (LunExt->DeviceFlags & DFLAGS_REMOVABLE_DRIVE) {
+ KdPrint2((PRINT_PREFIX
"RemovableMedia\n"));
inquiryData->RemovableMedia = 1;
}
// Set the Relative Addressing (LBA) bit, if applicable.
- if (deviceExtension->lun[ldev].DeviceFlags & DFLAGS_LBA_ENABLED) {
+ if (LunExt->DeviceFlags & DFLAGS_LBA_ENABLED) {
inquiryData->RelativeAddressing = 1;
- KdPrint2((PRINT_PREFIX
+ KdPrint2((PRINT_PREFIX
"RelativeAddressing\n"));
}
// Set the CommandQueue bit
// 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 (deviceExtension->lun[ldev].DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED) {
+
+ if(cdb->MODE_SENSE.PageCode == MODE_PAGE_POWER_CONDITION) {
+ PMODE_POWER_CONDITION_PAGE modeData;
- SelectDrive(chan, ldev & 0x1);
- 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;
+ modeData->PageLength = sizeof(MODE_PAGE_POWER_CONDITION)-sizeof(MODE_PARAMETER_HEADER);
+ 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;
case SCSIOP_TEST_UNIT_READY:
- KdPrint2((PRINT_PREFIX
+ KdPrint2((PRINT_PREFIX
"IdeSendCommand: SCSIOP_TEST_UNIT_READY PATH:LUN:TID = %#x:%#x:%#x\n",
Srb->PathId, Srb->Lun, Srb->TargetId));
- if (deviceExtension->lun[ldev].DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED) {
+ if (chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED) {
// Select device 0 or 1.
- SelectDrive(chan, ldev & 0x1);
- 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;
case SCSIOP_READ_CAPACITY:
- KdPrint2((PRINT_PREFIX
+ 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_CAPACITY_DATA));
MOV_DD_SWP( ((PREAD_CAPACITY_DATA)Srb->DataBuffer)->BytesPerBlock, i );
// Calculate last sector.
- if(!(i = (ULONG)deviceExtension->lun[ldev].NumOfSectors)) {
- i = deviceExtension->lun[ldev].IdentifyData.SectorsPerTrack *
- deviceExtension->lun[ldev].IdentifyData.NumberOfHeads *
- deviceExtension->lun[ldev].IdentifyData.NumberOfCylinders;
+ if(!(i = (ULONG)LunExt->NumOfSectors)) {
+ i = LunExt->IdentifyData.SectorsPerTrack *
+ LunExt->IdentifyData.NumberOfHeads *
+ LunExt->IdentifyData.NumberOfCylinders;
}
i--;
MOV_DD_SWP( ((PREAD_CAPACITY_DATA)Srb->DataBuffer)->LogicalBlockAddress, i );
- KdPrint2((PRINT_PREFIX
+ KdPrint2((PRINT_PREFIX
"** IDE disk %#x - #sectors %#x, #heads %#x, #cylinders %#x\n",
Srb->TargetId,
- deviceExtension->lun[ldev].IdentifyData.SectorsPerTrack,
- deviceExtension->lun[ldev].IdentifyData.NumberOfHeads,
- deviceExtension->lun[ldev].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
+ KdPrint2((PRINT_PREFIX
"IdeSendCommand: SCSIOP_VERIFY PATH:LUN:TID = %#x:%#x:%#x\n",
Srb->PathId, Srb->Lun, Srb->TargetId));
status = IdeVerify(HwDeviceExtension,Srb);
case SCSIOP_READ:
case SCSIOP_WRITE:
+ case SCSIOP_READ12:
+ case SCSIOP_WRITE12:
+ case SCSIOP_READ16:
+ case SCSIOP_WRITE16:
- KdPrint2((PRINT_PREFIX
+ 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));
+ KdPrint2((PRINT_PREFIX
+ "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, ldev & 0x1);
- 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, ldev & 0x1);
- 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:
- SelectDrive(chan, ldev & 0x1);
+ SelectDrive(chan, DeviceNumber);
AtapiWritePort1(chan, IDX_IO1_o_Command,IDE_COMMAND_FLUSH_CACHE);
status = SRB_STATUS_SUCCESS;
// status = SRB_STATUS_PENDING;
// this function makes sense buffers to report the results
// of the original GET_MEDIA_STATUS command
- KdPrint2((PRINT_PREFIX
+ KdPrint2((PRINT_PREFIX
"IdeSendCommand: SCSIOP_REQUEST_SENSE PATH:LUN:TID = %#x:%#x:%#x\n",
Srb->PathId, Srb->Lun, Srb->TargetId));
- if (deviceExtension->lun[ldev].DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED) {
+ if (LunExt->DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED) {
status = IdeBuildSenseBuffer(HwDeviceExtension,Srb);
break;
}
PIDEREGS_EX regs;
BOOLEAN use_dma = FALSE;
ULONG to_lim;
-
+
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",
+ KdPrint2((PRINT_PREFIX
+ "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((regs->bOpFlags & ATA_FLAGS_48BIT_COMMAND) == 0) { // execute ATA command
AtapiWritePort1(chan, IDX_IO1_o_CylinderHigh, regs->bCylHighReg);
}
AtapiWritePort1(chan, IDX_IO1_o_Command, regs->bCommandReg);
-
+
if(use_dma) {
GetBaseStatus(chan, statusByte);
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:
-
- KdPrint2((PRINT_PREFIX
+default_abort:
+ KdPrint2((PRINT_PREFIX
"IdeSendCommand: Unsupported command %#x\n",
Srb->Cdb[0]));
IdeMediaStatus(
BOOLEAN EnableMSN,
IN PVOID HwDeviceExtension,
- UCHAR ldev
+ IN ULONG lChannel,
+ IN ULONG DeviceNumber
)
{
PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
PHW_CHANNEL chan;
- UCHAR lChannel = ldev >> 1;
UCHAR statusByte,errorByte;
chan = &(deviceExtension->chan[lChannel]);
+ SelectDrive(chan, DeviceNumber);
if (EnableMSN == TRUE){
// If supported enable Media Status Notification support
- if ((deviceExtension->lun[ldev].DeviceFlags & DFLAGS_REMOVABLE_DRIVE)) {
+ if ((chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_REMOVABLE_DRIVE)) {
// enable
- statusByte = AtaCommand(deviceExtension, ldev & 1, lChannel,
+ statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel,
IDE_COMMAND_SET_FEATURES, 0, 0, 0,
0, ATA_C_F_ENAB_MEDIASTAT, ATA_WAIT_BASE_READY);
// Read the error register.
errorByte = AtapiReadPort1(chan, IDX_IO1_i_Error);
- KdPrint2((PRINT_PREFIX
+ KdPrint2((PRINT_PREFIX
"IdeMediaStatus: Error enabling media status. Status %#x, error byte %#x\n",
statusByte,
errorByte));
} else {
- deviceExtension->lun[ldev].DeviceFlags |= DFLAGS_MEDIA_STATUS_ENABLED;
+ chan->lun[DeviceNumber]->DeviceFlags |= DFLAGS_MEDIA_STATUS_ENABLED;
KdPrint2((PRINT_PREFIX "IdeMediaStatus: Media Status Notification Supported\n"));
chan->ReturningMediaStatus = 0;
} else { // end if EnableMSN == TRUE
// disable if previously enabled
- if ((deviceExtension->lun[ldev].DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED)) {
+ if ((chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED)) {
- statusByte = AtaCommand(deviceExtension, ldev & 1, lChannel,
+ statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel,
IDE_COMMAND_SET_FEATURES, 0, 0, 0,
0, ATA_C_F_DIS_MEDIASTAT, ATA_WAIT_BASE_READY);
- deviceExtension->lun[ldev].DeviceFlags &= ~DFLAGS_MEDIA_STATUS_ENABLED;
+ chan->lun[DeviceNumber]->DeviceFlags &= ~DFLAGS_MEDIA_STATUS_ENABLED;
}
UniataUserDeviceReset(
PHW_DEVICE_EXTENSION deviceExtension,
PHW_LU_EXTENSION LunExt,
- ULONG PathId,
- ULONG ldev
+ ULONG lChannel
)
{
- AtapiDisableInterrupts(deviceExtension, PathId);
- if (LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) {
+ ULONG i;
+ 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]), ldev & 1);
+ AtapiSoftReset(&(deviceExtension->chan[lChannel]), LunExt->Lun);
} else {
KdPrint2((PRINT_PREFIX "UniataUserDeviceReset: Reset IDE -> reset entire channel\n"));
- AtapiResetController__(deviceExtension, PathId, RESET_COMPLETE_NONE);
- deviceExtension->chan[PathId].lun[0]->DeviceFlags |= DFLAGS_REINIT_DMA;
- deviceExtension->chan[PathId].lun[1]->DeviceFlags |= DFLAGS_REINIT_DMA;
+ AtapiResetController__(deviceExtension, lChannel, RESET_COMPLETE_NONE);
+ for(i=0; i<deviceExtension->NumberLuns; i++) {
+ 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:
PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
UCHAR lChannel;
PHW_CHANNEL chan;
+ PHW_LU_EXTENSION LunExt;
ULONG status;
- ULONG ldev;
+ //ULONG ldev;
+ ULONG DeviceNumber;
UCHAR PathId;
UCHAR TargetId;
UCHAR Lun;
/* KeBugCheckEx(0xc000000e,
(Srb->PathId<<16) | (Srb->TargetId<<8) | (Srb->Lun),
- Srb->Function,
+ Srb->Function,
TopLevel, 0x80000001);
*/
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);
- chan = &(deviceExtension->chan[lChannel]);
- ldev = GET_LDEV(Srb);
+ //ldev = GET_LDEV(Srb);
+ chan = NULL;
+ LunExt = NULL;
+ DeviceNumber = GET_CDEV(Srb);
+ commPort = FALSE;
//ASSERT(deviceExtension);
//ASSERT(chan);
- KdPrint2((PRINT_PREFIX
+ 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));
((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
commPort = TRUE;
/* Pass IOCTL request down */
} else
- if(GET_CDEV(Srb) >= 2 ||
- ldev >= deviceExtension->NumberChannels*2 ||
- lChannel >= deviceExtension->NumberChannels ||
- Srb->Lun) {
+ if(lChannel >= deviceExtension->NumberChannels ||
+ 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, ldev & 1, FALSE)) {
- KdPrint3((PRINT_PREFIX
+ //if(!CheckDevice(HwDeviceExtension, lChannel, DeviceNumber, FALSE)) {
+ 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;
}
- atapiDev = (deviceExtension->lun[ldev].DeviceFlags & DFLAGS_ATAPI_DEVICE) ? TRUE : FALSE;
+ if(!commPort) {
+ chan = &(deviceExtension->chan[lChannel]);
+ LunExt = chan->lun[DeviceNumber];
+ if(!LunExt) {
+ goto reject_srb;
+ }
+ atapiDev = (LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) ? TRUE : FALSE;
+ } else {
+ atapiDev = FALSE;
+ }
#ifdef _DEBUG
- if(!commPort && !(chan->lun[ldev & 1])) {
+ if(!commPort && !LunExt) {
#if 0
PrintNtConsole("de = %#x, chan = %#x , dev %#x, nchan %#x\n",
deviceExtension,
- chan, ldev & 1,
+ chan, DeviceNumber,
deviceExtension->NumberChannels);
- PrintNtConsole("lchan = %#x, ldev %#x, cdev %#x, lun0 %#x\n",
- lChannel, ldev, GET_CDEV(Srb), deviceExtension->chan[0].lun[0]);
+ PrintNtConsole("lchan = %#x, cdev %#x, lun0 %#x\n",
+ lChannel, GET_CDEV(Srb), deviceExtension->chan[0].lun[0]);
PrintNtConsole("Function %#x, PATH:LUN:TID = %#x:%#x:%#x\n",
Srb->Function, Srb->PathId, Srb->Lun, Srb->TargetId);
#endif //0
case SRB_FUNCTION_EXECUTE_SCSI:
- if(!(deviceExtension->lun[ldev].DeviceFlags & DFLAGS_DEVICE_PRESENT)) {
+ if(!LunExt || !(LunExt->DeviceFlags & DFLAGS_DEVICE_PRESENT)) {
if(Srb->Cdb[0] == SCSIOP_ATA_PASSTHROUGH) {
// let passthrough go
} else
// let INQUIRY go
} else {
- //if(!CheckDevice(HwDeviceExtension, lChannel, ldev & 1, FALSE)) {
- KdPrint2((PRINT_PREFIX
+ //if(!CheckDevice(HwDeviceExtension, lChannel, DeviceNumber, FALSE)) {
+ KdPrint2((PRINT_PREFIX
"AtapiStartIo: EXECUTE_SCSI rejected (2)\n"));
// Indicate no device found at this address.
KdPrint2((PRINT_PREFIX "SRB_STATUS_SELECTION_TIMEOUT\n"));
break;
//}
}
+ } else {
+ KdPrint2((PRINT_PREFIX
+ " SRB %#x, CDB %#x, AtaReq %#x, SCmd %#x\n", Srb, &(Srb->Cdb), Srb->SrbExtension, Srb->Cdb[0]));
}
/*
__try {
}
/*KeBugCheckEx(0xc000000e,
(Srb->PathId<<16) | (Srb->TargetId<<8) | (Srb->Lun),
- Srb->Function,
+ Srb->Function,
status, 0x80000001);*/
if(status == SRB_STATUS_BUSY)
status = SRB_STATUS_PENDING;
// Insert requests AFTER they have been initialized on
// CMD_ACTION_PREPARE stage
// we should not check TopLevel here (it is always TRUE)
- //ASSERT(chan->lun[GET_LDEV(Srb) & 1]);
+ //ASSERT(chan->lun[GET_CDEV(Srb)]);
UniataQueueRequest(chan, Srb);
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);
KdPrint2((PRINT_PREFIX "TopLevel (3), AtaReq %#x\n", AtaReq));
//ASSERT(!AtaReq->Flags);
- //ASSERT(chan->lun[GET_LDEV(Srb) & 1]);
+ //ASSERT(chan->lun[GET_CDEV(Srb)]);
UniataQueueRequest(chan, Srb);
// AtaReq = (PATA_REQ)(Srb->SrbExtension);
//ASSERT(!AtaReq->Flags);
}
#ifndef NAVO_TEST
- if(!(deviceExtension->lun[ldev].DeviceFlags & DFLAGS_DEVICE_PRESENT)) {
+ if(!LunExt || !(LunExt->DeviceFlags & DFLAGS_DEVICE_PRESENT)) {
+ if(!LunExt) {
+ goto reject_srb;
+ }
if(Srb->Cdb[0] == SCSIOP_INQUIRY) {
- if(UniataAnybodyHome(deviceExtension, chan->lChannel, ldev & 1)) {
- if(!CheckDevice(HwDeviceExtension, chan->lChannel, ldev & 1, TRUE)) {
+ if(UniataAnybodyHome(deviceExtension, chan->lChannel, DeviceNumber)) {
+ if(!CheckDevice(HwDeviceExtension, chan->lChannel, DeviceNumber, TRUE)) {
goto reject_srb;
}
}
- if(!(deviceExtension->lun[ldev].DeviceFlags & DFLAGS_DEVICE_PRESENT)) {
+ if(!(LunExt->DeviceFlags & DFLAGS_DEVICE_PRESENT)) {
goto reject_srb;
}
} else
#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"));
}
/* KeBugCheckEx(0xc000000e,
(Srb->PathId<<16) | (Srb->TargetId<<8) | (Srb->Lun),
- Srb->Function,
+ Srb->Function,
status, 0x80000002);*/
}
// 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, &(deviceExtension->lun[ldev]), lChannel, ldev);
+ UniataUserDeviceReset(deviceExtension, LunExt, lChannel);
status = SRB_STATUS_SUCCESS;
break;
case SRB_FUNCTION_SHUTDOWN:
KdPrint2((PRINT_PREFIX "AtapiStartIo: Shutdown\n"));
- if(!(deviceExtension->lun[ldev].DeviceFlags & DFLAGS_DEVICE_PRESENT)) {
+ if(!LunExt || !(LunExt->DeviceFlags & DFLAGS_DEVICE_PRESENT)) {
KdPrint2((PRINT_PREFIX "AtapiStartIo: Shutdown - no such device\n"));
- }
+ } else
if(atapiDev) {
// FLUSH ATAPI device - do nothing
KdPrint2((PRINT_PREFIX "AtapiStartIo: Shutdown - ATAPI device\n"));
// FLUSH IDE/ATA device
KdPrint2((PRINT_PREFIX "AtapiStartIo: Shutdown - IDE device\n"));
AtapiDisableInterrupts(deviceExtension, lChannel);
- status = AtaCommand(deviceExtension, ldev & 1, GET_CHANNEL(Srb),
+ status = AtaCommand(deviceExtension, DeviceNumber, GET_CHANNEL(Srb),
IDE_COMMAND_FLUSH_CACHE, 0, 0, 0, 0, 0, ATA_WAIT_IDLE);
// If supported & allowed, reset write cacheing
- if(deviceExtension->lun[ldev].DeviceFlags & DFLAGS_WCACHE_ENABLED) {
+ if(LunExt->DeviceFlags & DFLAGS_WCACHE_ENABLED) {
// Disable write cache
- status = AtaCommand(deviceExtension, ldev & 1, lChannel,
+ status = AtaCommand(deviceExtension, DeviceNumber, lChannel,
IDE_COMMAND_SET_FEATURES, 0, 0, 0,
0, ATA_C_F_DIS_WCACHE, ATA_WAIT_BASE_READY);
// Check for errors.
if (status & IDE_STATUS_ERROR) {
- KdPrint2((PRINT_PREFIX
+ KdPrint2((PRINT_PREFIX
"AtapiHwInitialize: Disable write cacheing on Device %d failed\n",
- ldev));
+ DeviceNumber));
}
- deviceExtension->lun[ldev].DeviceFlags &= ~DFLAGS_WCACHE_ENABLED;
+ LunExt->DeviceFlags &= ~DFLAGS_WCACHE_ENABLED;
// Re-enable write cache
- status = AtaCommand(deviceExtension, ldev & 1, lChannel,
+ status = AtaCommand(deviceExtension, DeviceNumber, lChannel,
IDE_COMMAND_SET_FEATURES, 0, 0, 0,
0, ATA_C_F_ENAB_WCACHE, ATA_WAIT_BASE_READY);
// Check for errors.
if (status & IDE_STATUS_ERROR) {
- KdPrint2((PRINT_PREFIX
+ KdPrint2((PRINT_PREFIX
"AtapiHwInitialize: Enable write cacheing on Device %d failed\n",
- ldev));
- deviceExtension->lun[ldev].DeviceFlags &= ~DFLAGS_WCACHE_ENABLED;
+ DeviceNumber));
+ LunExt->DeviceFlags &= ~DFLAGS_WCACHE_ENABLED;
} else {
- deviceExtension->lun[ldev].DeviceFlags |= DFLAGS_WCACHE_ENABLED;
+ LunExt->DeviceFlags |= DFLAGS_WCACHE_ENABLED;
}
}
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 (deviceExtension->lun[ldev].DeviceFlags & DFLAGS_ATAPI_DEVICE) {
- status = SRB_STATUS_SUCCESS;
- } else {
- status = AtaCommand(deviceExtension, ldev & 1, 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_IO_CONTROL: {
ULONG len;
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 (!(deviceExtension->lun[ldev].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 << ldev;
+ deviceNumberMap = 1 << DeviceNumber;
} else {
- deviceNumber = 4 << ldev;
+ deviceNumberMap = 4 << DeviceNumber;
}
} else {
- deviceNumber = 1 << ldev;
+ 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)) {
PUNIATA_CTL AtaCtl = (PUNIATA_CTL)(Srb->DataBuffer);
- ULONG ldev = GET_LDEV2(AtaCtl->addr.PathId, AtaCtl->addr.TargetId, 0);
- PHW_LU_EXTENSION LunExt;
+ //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 ||
- ldev >= deviceExtension->NumberChannels*2 ||
+ AtaCtl->addr.TargetId >= deviceExtension->NumberLuns ||
AtaCtl->addr.PathId >= deviceExtension->NumberChannels) {
+ chan = NULL;
bad_ldev = TRUE;
LunExt = NULL;
} else {
bad_ldev = FALSE;
- LunExt = &(deviceExtension->lun[ldev]);
lChannel = AtaCtl->addr.PathId;
chan = &(deviceExtension->chan[lChannel]);
+ LunExt = chan->lun[DeviceNumber];
}
- KdPrint2((PRINT_PREFIX "AtapiStartIo: -UNIATA- %#x, ldev %#x\n", AtaCtl->hdr.ControlCode, ldev));
+ KdPrint2((PRINT_PREFIX "AtapiStartIo: -UNIATA- %#x, dev %#x\n", AtaCtl->hdr.ControlCode, DeviceNumber));
/* check for valid LUN */
switch (AtaCtl->hdr.ControlCode) {
case IOCTL_SCSI_MINIPORT_UNIATA_FIND_DEVICES:
case IOCTL_SCSI_MINIPORT_UNIATA_RESET_DEVICE:
+ // this would be BUS reset
if(bad_ldev &&
(AtaCtl->addr.PathId >= deviceExtension->NumberChannels ||
AtaCtl->addr.TargetId != 0xff ||
AtaCtl->addr.Lun != 0
)) {
if(AtaCtl->hdr.ControlCode == IOCTL_SCSI_MINIPORT_UNIATA_FIND_DEVICES &&
- ldev < deviceExtension->NumberChannels*2) { // AtaCtl->addr.TargetId != 0xff
- LunExt = &(deviceExtension->lun[ldev]);
+ DeviceNumber < deviceExtension->NumberLuns) { // AtaCtl->addr.TargetId != 0xff
+ lChannel = AtaCtl->addr.PathId;
+ chan = &(deviceExtension->chan[lChannel]);
+ LunExt = chan->lun[DeviceNumber];
// OK
} else {
goto handle_bad_ldev;
}
+ } else {
+ lChannel = AtaCtl->addr.PathId;
+ chan = &(deviceExtension->chan[lChannel]);
}
- // this would be BUS reset
- lChannel = AtaCtl->addr.PathId;
- chan = &(deviceExtension->chan[lChannel]);
break;
case IOCTL_SCSI_MINIPORT_UNIATA_DELETE_DEVICE:
case IOCTL_SCSI_MINIPORT_UNIATA_SET_MAX_MODE:
}
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) {
- deviceExtension->lun[ldev].DeviceFlags &= ~DFLAGS_HIDDEN;
+ LunExt->DeviceFlags &= ~DFLAGS_HIDDEN;
} else {
}
}
KdPrint2((PRINT_PREFIX "AtapiStartIo: remove %#x:%#x\n", AtaCtl->addr.PathId, AtaCtl->addr.TargetId));
- deviceExtension->lun[ldev].DeviceFlags = 0;
+ 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"));
- deviceExtension->lun[ldev].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);
}
LunExt->DeviceFlags |= DFLAGS_REINIT_DMA; // force PIO/DMA reinit
if(AtaCtl->SetMode.ApplyImmediately) {
- AtapiDmaInit__(deviceExtension, ldev);
+ AtapiDmaInit__(deviceExtension, LunExt);
}
-/* deviceExtension->lun[ldev].TransferMode =
- deviceExtension->lun[ldev].LimitedTransferMode = (UCHAR)(setTransferMode->Mode);*/
+/* LunExt->TransferMode =
+ LunExt->LimitedTransferMode = (UCHAR)(setTransferMode->Mode);*/
status = SRB_STATUS_SUCCESS;
break;
}
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;
+ }
+ case IOCTL_SCSI_MINIPORT_UNIATA_GET_VERSION: {
+
+ 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;
+ AtaCtl->Version.SubVerMj = UNIATA_VER_SUB_MJ;
+ AtaCtl->Version.SubVerMn = UNIATA_VER_SUB_MN;
status = SRB_STATUS_SUCCESS;
break;
KdPrint2((PRINT_PREFIX "AtapiStartIo: Get adapter info\n"));
- AtaCtl->AdapterInfo.HeaderLength = offsetof(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.InterruptMode = deviceExtension->InterruptMode;
AtaCtl->AdapterInfo.BusInterruptVector = deviceExtension->BusInterruptVector;
AtaCtl->AdapterInfo.NumberChannels = deviceExtension->NumberChannels;
+ AtaCtl->AdapterInfo.NumberLuns = (UCHAR)deviceExtension->NumberLuns;
AtaCtl->AdapterInfo.AdapterInterfaceType = deviceExtension->AdapterInterfaceType;
if(deviceExtension->FullDevName) {
strncpy(AtaCtl->AdapterInfo.DeviceName, deviceExtension->FullDevName, 64);
}
AtaCtl->AdapterInfo.ChanInfoValid = FALSE;
-
- RtlZeroMemory(&AtaCtl->AdapterInfo.Chan, sizeof(AtaCtl->AdapterInfo.Chan));
+ AtaCtl->AdapterInfo.LunInfoValid = FALSE;
+ 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;
}
case IOCTL_SCSI_MINIPORT_UNIATA_RESETBB: {
-
+
KdPrint2((PRINT_PREFIX "AtapiStartIo: Forget BB list\n"));
ForgetBadBlocks(LunExt);
if(bad_ldev) {
goto do_bus_reset;
} else {
- UniataUserDeviceReset(deviceExtension, LunExt, AtaCtl->addr.PathId, ldev);
+ UniataUserDeviceReset(deviceExtension, LunExt, AtaCtl->addr.PathId);
}
status = SRB_STATUS_SUCCESS;
if (status != SRB_STATUS_PENDING) {
- KdPrint2((PRINT_PREFIX
+ KdPrint2((PRINT_PREFIX
"AtapiStartIo: Srb %#x complete with status %#x\n",
Srb,
status));
// 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);
}
NULL);
ScsiPortNotification(NextLuRequest,
- deviceExtension,
+ deviceExtension,
PathId,
TargetId,
Lun);
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:
+ //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;
}
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;
Connect_DbgPrint();
KdPrint2((PRINT_PREFIX "%s", (PCCHAR)ver_string));
- a = (WCHAR)strlen(ver_string);
+ //a = (WCHAR)strlen(ver_string);
g_opt_Verbose = (BOOLEAN)AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"PrintLogo", 0);
if(g_opt_Verbose) {
if(!SavedDriverObject) {
SavedDriverObject = (PDRIVER_OBJECT)DriverObject;
+#ifdef USE_REACTOS_DDK
KdPrint(("UniATA Init: OS should be ReactOS\n"));
+ MajorVersion=0x04;
+ MinorVersion=0x01;
+ BuildNumber=1;
+#else
+ // we are here for the 1st time
+ // init CrossNT and get OS version
+ if(!NT_SUCCESS(status = CrNtInit(SavedDriverObject, RegistryPath))) {
+ KdPrint(("UniATA Init: CrNtInit failed with status %#x\n", status));
+ //HalDisplayString((PUCHAR)"DbgPrnHkInitialize: CrNtInit failed\n");
+ return status;
+ }
+#endif // USE_REACTOS_DDK
+ KdPrint(("UniATA Init: OS ver %x.%x (%d), %d CPU(s)\n", MajorVersion, MinorVersion, BuildNumber, KeNumberProcessors));
KeQuerySystemTime(&t0);
do {
} while(t0.QuadPart == t1.QuadPart);
g_PerfDt = (ULONG)((t1.QuadPart - t0.QuadPart)/10);
KdPrint(("Performance calibration: dt=%d, counter=%I64d\n", g_PerfDt, g_Perf ));
-
} else {
KdPrint(("UniATA Init: ReEnter\n"));
ReEnter = TRUE;
KdPrint2((PRINT_PREFIX "\n\nATAPI IDE enum supported BusMaster Devices\n"));
if(!ReEnter) {
+
+ g_opt_VirtualMachine = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"VirtualMachineType", g_opt_VirtualMachine);
+ if(g_opt_VirtualMachine > VM_MAX_KNOWN) {
+ g_opt_VirtualMachine = 0;
+ }
+ if(AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"VirtualBox", (g_opt_VirtualMachine == VM_VBOX))) {
+ g_opt_VirtualMachine = VM_VBOX;
+ }
+ // Pre-scan PCI bus, also check if we are under VM
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_WaitBusyLongCount = 20000;
+ g_opt_MaxIsrWait = 200;
+ g_opt_AtapiSendDisableIntr = 0;
+ g_opt_AtapiDmaRawRead = FALSE;
+ break;
+ }
+
+ if(!hasPCI) {
+ KdPrint2((PRINT_PREFIX "old slow machine, adjust timings\n"));
+ // old slow machine, adjust timings
+ g_opt_WaitBusyCount = 20000;
+ g_opt_WaitBusyDelay = 150;
+ g_opt_WaitDrqDelay = 100;
+ g_opt_WaitBusyLongCount = 20000;
+ g_opt_MaxIsrWait = 200;
+ }
+
+ 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_WaitBusyLongCount = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"WaitBusyLongCount", g_opt_WaitBusyLongCount); // 2000 vs 20000
+ g_opt_WaitBusyLongDelay = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"WaitBusyLongDelay", g_opt_WaitBusyLongDelay); // 250 vs 250
+ g_opt_AtapiSendDisableIntr = (BOOLEAN)AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"AtapiSendDisableIntr", g_opt_AtapiSendDisableIntr); // 1 vs 0
+ g_opt_AtapiDmaRawRead = (BOOLEAN)AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"AtapiDmaRawRead", g_opt_AtapiDmaRawRead); // 1 vs 0
+ g_opt_MaxIsrWait = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"MaxIsrWait", g_opt_MaxIsrWait); // 40 vs xxx
}
// Look for legacy ISA-bridged PCI IDE controller (onboard)
}
continue;
}
- BMList[i].AltInitMasterDev = (UCHAR)0xff;
+ //BMList[i].AltInitMasterDev = (UCHAR)0xff;
if(GlobalConfig->AtDiskPrimaryAddressClaimed)
PrimaryClaimed = TRUE;
if(GlobalConfig->AtDiskSecondaryAddressClaimed)
SecondaryClaimed = TRUE;
+ if(!WinVer_WDM_Model && !PrimaryClaimed && !SecondaryClaimed &&
+ !(BMList[i].ChanInitOk & 0x80)) {
+ newStatus = UniataClaimLegacyPCIIDE(i);
+ 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++) {
Argument2,
&hwInitializationData.comm,
(PVOID)(i | (alt ? 0x80000000 : 0)));
- KdPrint2((PRINT_PREFIX "Status %#x\n", newStatus));
+ 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 "Status %#x\n", newStatus));
- }
-#endif //0
if(g_opt_Verbose) {
if(BMList[i].ChanInitOk & 0x03) {
_PrintNtConsole(" OK\n");
/* KeBugCheckEx(0xc000000e,
(i << 16) | BMList[0].ChanInitOk,
- c,
+ c,
newStatus, statusToReturn);*/
// Look for PCI IDE controller
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*/;
Argument2,
&hwInitializationData.comm,
(PVOID)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
+ // It stops scanning PCI bus when reaches empty PCI Function inside Slot
+ // However, this PCI Slot may have higher non-empty Functions
+ // UniATA will perform all staff instead of ScsiPort under NT,
+ // but for ReactOS it is better to patch ScsiPort.
+ KdPrint2((PRINT_PREFIX "STATUS_DEVICE_DOES_NOT_EXIST, try workaround\n"));
+ hwInitializationData.comm.AdapterInterfaceType = Isa;
+ newStatus = ScsiPortInitialize(DriverObject,
+ Argument2,
+ &hwInitializationData.comm,
+ (PVOID)(i | 0x80000000));
+ KdPrint2((PRINT_PREFIX "ScsiPortInitialize Status %#x (2)\n", newStatus));
+ }
if (newStatus < statusToReturn)
statusToReturn = newStatus;
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.
Argument2,
&hwInitializationData.comm,
&adapterCount);
+ KdPrint2((PRINT_PREFIX "ScsiPortInitialize Status %#x\n", newStatus));
if (newStatus < statusToReturn)
statusToReturn = newStatus;
}
Argument2,
&hwInitializationData.comm,
&adapterCount);
+ KdPrint2((PRINT_PREFIX "ScsiPortInitialize Status %#x\n", newStatus));
if (newStatus < statusToReturn)
statusToReturn = newStatus;
}
InDriverEntry = FALSE;
- KdPrint2((PRINT_PREFIX "\n\nLeave ATAPI IDE MiniPort DriverEntry with status %#x\n", statusToReturn));
+ KdPrint2((PRINT_PREFIX "\n\nLeave UNIATA MiniPort DriverEntry with status %#x\n", statusToReturn));
return statusToReturn;
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()
RtlZeroMemory(paramPath.Buffer, paramPath.MaximumLength);
RtlAppendUnicodeToString(¶mPath, RegistryPath->Buffer);
RtlAppendUnicodeToString(¶mPath, L"\\");
- RtlAppendUnicodeToString(¶mPath, PathSuffix);
+ RtlAppendUnicodeToString(¶mPath, REGRTL_STR_PTYPE PathSuffix);
// Check for the Xxx value.
RtlZeroMemory(parameters, (sizeof(RTL_QUERY_REGISTRY_TABLE)*ITEMS_TO_QUERY));
parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
- parameters[0].Name = Name;
+ parameters[0].Name = REGRTL_STR_PTYPE Name;
parameters[0].EntryContext = &doRun;
parameters[0].DefaultType = REG_DWORD;
parameters[0].DefaultData = &zero;
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(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;
+ //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()
-