From 43654b1cb92269a6d6374f33f729efe91ed9d788 Mon Sep 17 00:00:00 2001 From: Reza Jelveh Date: Wed, 22 Oct 2014 05:52:48 +0000 Subject: MdeModulePkg/AtaAtapiPassThru: When D2H FIS received at PIO DATA-IN transfer, check PxTFD.Error register to confirm if there is a real error for better device compatibilities with Qemu and Marvel9230 sata controllers. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Reza Jelveh Signed-off-by: Feng Tian Reviewed-by: A. Sava Reviewed-by: Star Zeng git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16225 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c | 33 +++++++++++++++++------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c index 7fc7a28..72b1e5c 100644 --- a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c +++ b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c @@ -704,6 +704,8 @@ AhciPioTransfer ( UINT32 PortTfd; UINT32 PrdCount; BOOLEAN InfiniteWait; + BOOLEAN PioFisReceived; + BOOLEAN D2hFisReceived; if (Timeout == 0) { InfiniteWait = TRUE; @@ -780,15 +782,31 @@ AhciPioTransfer ( Status = EFI_TIMEOUT; Delay = DivU64x32 (Timeout, 1000) + 1; do { + PioFisReceived = FALSE; + D2hFisReceived = FALSE; Offset = FisBaseAddr + EFI_AHCI_PIO_FIS_OFFSET; - Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, EFI_AHCI_FIS_PIO_SETUP, NULL); if (!EFI_ERROR (Status)) { + PioFisReceived = TRUE; + } + // + // According to SATA 2.6 spec section 11.7, D2h FIS means an error encountered. + // But Qemu and Marvel 9230 sata controller may just receive a D2h FIS from device + // after the transaction is finished successfully. + // To get better device compatibilities, we further check if the PxTFD's ERR bit is set. + // By this way, we can know if there is a real error happened. + // + Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET; + Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, EFI_AHCI_FIS_REGISTER_D2H, NULL); + if (!EFI_ERROR (Status)) { + D2hFisReceived = TRUE; + } + + if (PioFisReceived || D2hFisReceived) { Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD; PortTfd = AhciReadReg (PciIo, (UINT32) Offset); // // PxTFD will be updated if there is a D2H or SetupFIS received. - // For PIO IN transfer, D2H means a device error. Therefore we only need to check the TFD after receiving a SetupFIS. // if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) { Status = EFI_DEVICE_ERROR; @@ -797,23 +815,20 @@ AhciPioTransfer ( PrdCount = *(volatile UINT32 *) (&(AhciRegisters->AhciCmdList[0].AhciCmdPrdbc)); if (PrdCount == DataCount) { + Status = EFI_SUCCESS; break; } } - Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET; - Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, EFI_AHCI_FIS_REGISTER_D2H, NULL); - if (!EFI_ERROR (Status)) { - Status = EFI_DEVICE_ERROR; - break; - } - // // Stall for 100 microseconds. // MicroSecondDelay(100); Delay--; + if (Delay == 0) { + Status = EFI_TIMEOUT; + } } while (InfiniteWait || (Delay > 0)); } else { // -- cgit v1.1