summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaszlo Ersek <lersek@redhat.com>2016-01-19 10:46:39 +0000
committerlersek <lersek@Edk2>2016-01-19 10:46:39 +0000
commit036849752427ff8615cfc492a6daf4c06cb203d6 (patch)
tree27aea84be6a8c1aaf1b4a73af6e4dd72cf0d45b0
parentdfc229f6a67b03e3c47b67b92982a100cfef738a (diff)
downloadedk2-036849752427ff8615cfc492a6daf4c06cb203d6.tar.gz
edk2-036849752427ff8615cfc492a6daf4c06cb203d6.tar.bz2
edk2-036849752427ff8615cfc492a6daf4c06cb203d6.zip
MdeModulePkg/.../IdeMode: report early finish of packet read as success
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.tian@intel.com> Cc: Star Zeng <star.zeng@intel.com> Cc: John Snow <jsnow@redhat.com> Reference: https://github.com/tianocore/edk2/issues/43 Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Laszlo Ersek <lersek@redhat.com> Reviewed-by: Feng Tian <feng.tian@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@19685 6f19259b-4bc3-4df7-8a09-765794883524
-rw-r--r--MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.c6
1 files changed, 6 insertions, 0 deletions
diff --git a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.c b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.c
index b06f9889ed..320ee90828 100644
--- a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.c
+++ b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.c
@@ -1967,6 +1967,12 @@ AtaPacketReadWrite (
// 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;
}