SVN r19611 (git commit 7cac240163), "MdeModulePkg/Ide: return correct
status when DRQ is not ready for ATAPI", changed the behavior of
AtaPacketReadWrite(), when DRQReady2() reported an error. The previous
logic had been to:

(a) terminate the transfer loop,
(b) check the status register with CheckStatusRegister(), and determine
    AtaPacketReadWrite()'s return code directly from that.

Action (a) had been correct, but action (b) had masked genuine errors.

For example, when DRQReady2() reported EFI_TIMEOUT -- because the BSY bit
had not been cleared within the allotted time --, CheckStatusRegister()
would report EFI_SUCCESS, simply *because* BSY was still set, and the rest
of the status bits could not be evaluated.

SVN r19611 (git commit 7cac240163) intended to fix action (b) by directly
propagating the error code of DRQReady2() from AtaPacketReadWrite(),
eliminating the CheckStatusRegister() call. This was the right thing for
most of the errors reported by DRQReady2() -- timeout, command abort,
other device error --, but there was one exception: the "read" sub-case of
EFI_NOT_READY, which stands for "'read' complete, with less data available
than the requested amount".

Regarding the "write" sub-case of EFI_NOT_READY: the
AtaPacketCommandExecute() function programs the full transfer length into
the IDE device before it calls AtaPacketReadWrite(), and
AtaPacketReadWrite() only uses CylinderLsb and CylinderMsb for "chunking"
(as requested by the device). Therefore the device cannot justifiedly
clear DRQ earlier than seeing the entire data, when writing.

However, when reading from the device, a "short read" is a successful
operation. (The actual read length will be decoded by the higher level
protocols.) And "short reads" had been handled correctly by the logic
before git 7cac240163. Namely, when DRQReady2() returns EFI_NOT_READY, the
BSY bit is already clear, and we can call CheckStatusRegister() to
investigate all the other bits it cares about.

Therefore restore the logic from before git 7cac240163, but only for the
"read" sub-case of EFI_NOT_READY.

This problem was encountered with OVMF running on QEMU's i440fx IDE
emulation. Many thanks to John Snow for analyzing QEMU's behavior, and
pointing out that it adhered to the relevant specs.

Cc: Feng Tian <feng.t...@intel.com>
Cc: Star Zeng <star.z...@intel.com>
Cc: John Snow <js...@redhat.com>
Reference: https://github.com/tianocore/edk2/issues/43
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Laszlo Ersek <ler...@redhat.com>
---
 MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.c 
b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.c
index b06f988..320ee90 100644
--- a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.c
+++ b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.c
@@ -1963,14 +1963,20 @@ AtaPacketReadWrite (
 
   while (ActualWordCount < RequiredWordCount) {
     //
     // before each data transfer stream, the host should poll DRQ bit ready,
     // to see whether indicates device is ready to transfer data.
     //
     Status = DRQReady2 (PciIo, IdeRegisters, Timeout);
+    if ((Status == EFI_NOT_READY) && Read) {
+      //
+      // Device provided less data than we intended to read -- exit early.
+      //
+      return CheckStatusRegister (PciIo, IdeRegisters);
+    }
     if (EFI_ERROR (Status)) {
       return Status;
     }
 
     //
     // get current data transfer size from Cylinder Registers.
     //
-- 
1.8.3.1

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to