/*++
-Copyright (c) 2002-2012 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
if(ChipFlags & UNIATA_AHCI) {
KdPrint2((PRINT_PREFIX " AHCI path\n"));
if(UniataAhciChanImplemented(deviceExtension, j)) {
-#if DBG
+#ifdef _DEBUG
UniataDumpAhciPortRegs(chan);
#endif
AtapiDisableInterrupts(deviceExtension, j);
return INTERRUPT_REASON_IGNORE;
}
break;
- case PRMIO:
- status = AtapiReadPortEx4(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressBM_0),0x0040);
- if(ChipFlags & PRSATA) {
- pr_status = AtapiReadPortEx4(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressBM_0),0x006c);
- AtapiWritePortEx4(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressBM_0),0x006c, pr_status & 0x000000ff);
+ case PRMIO: {
+ ULONG stat_reg = (ChipFlags & PRG2) ? 0x60 : 0x6c;
+ status = AtapiReadPortEx4(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressBM_0),0x40);
+ AtapiWritePortEx4(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressBM_0),0x40, status);
+
+ if(status & (1 << (Channel+1))) {
+ // our
+ } else {
+ KdPrint2((PRINT_PREFIX " Promise mio unexpected\n"));
+ return INTERRUPT_REASON_IGNORE;
}
+
+ if(!(ChipFlags & UNIATA_SATA))
+ break;
+
+ pr_status = AtapiReadPortEx4(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressBM_0),stat_reg);
+ AtapiWritePortEx4(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressBM_0),stat_reg, (pr_status & (0x11 << Channel)));
if(pr_status & (0x11 << Channel)) {
// TODO: reset channel
KdPrint2((PRINT_PREFIX " Promise mio unexpected + reset req\n"));
- return INTERRUPT_REASON_IGNORE;
+ UniataSataEvent(deviceExtension, lChannel, UNIATA_SATA_EVENT_DETACH, 0);
}
if(!(status & (0x01 << Channel))) {
- KdPrint2((PRINT_PREFIX " Promise mio unexpected\n"));
+ // Connect event
+ KdPrint2((PRINT_PREFIX " Promise mio unexpected attach\n"));
+ UniataSataEvent(deviceExtension, lChannel, UNIATA_SATA_EVENT_ATTACH, 0);
+ }
+ if(UniataSataClearErr(HwDeviceExtension, c, UNIATA_SATA_DO_CONNECT, 0)) {
+ OurInterrupt = INTERRUPT_REASON_UNEXPECTED;
+ } else {
return INTERRUPT_REASON_IGNORE;
}
+
AtapiWritePort4(chan, IDX_BM_DeviceSpecific0, 0x00000001);
- break;
+ break; }
}
break; }
case ATA_NVIDIA_ID: {
// BOOLEAN RestoreUseDpc = FALSE;
BOOLEAN DataOverrun = FALSE;
BOOLEAN NoStartIo = TRUE;
+ BOOLEAN NoRetry = FALSE;
KdPrint2((PRINT_PREFIX "AtapiInterrupt:\n"));
if(InDpc) {
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)\n", 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
-#if DBG
+#ifdef _DEBUG
UniataDumpAhciPortRegs(chan);
#endif
if(!UniataAhciAbortOperation(chan)) {
KdPrint2((PRINT_PREFIX "need UniataAhciReset\n"));
}
-#if DBG
+#ifdef _DEBUG
UniataDumpAhciPortRegs(chan);
#endif
UniataAhciWaitCommandReady(chan, 10);
if(deviceExtension->HwFlags & UNIATA_AHCI) {
error = AtaReq->ahci.in_error;
// wait ready
-#if DBG
+#ifdef _DEBUG
UniataDumpAhciPortRegs(chan);
#endif
if(!UniataAhciAbortOperation(chan)) {
}
// clear interrupts again
UniataAhciWaitCommandReady(chan, 10);
-#if DBG
+#ifdef _DEBUG
UniataDumpAhciPortRegs(chan);
#endif
UniataAhciStatus(HwDeviceExtension, lChannel, DEVNUM_NOT_SPECIFIED);
-#if DBG
+ 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 {
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);
#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;
}