summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorConrad Pankoff <deoxxa@fknsrs.biz>2019-08-11 14:55:53 +1000
committerAndreas Kling <awesomekling@gmail.com>2019-08-11 08:25:11 +0200
commitf6dd76b9159245943ccca8a35305140ecd7f63d1 (patch)
tree2c7b85b9a5951f1023cf376213332232003b1c31
parentd1a7316799d9f49ed42ccc57514c06e464f2ceeb (diff)
downloadserenity-f6dd76b9159245943ccca8a35305140ecd7f63d1.zip
Kernel: Fix PATA reads without DMA
Apparently we need to poll the drive for its status after each sector we read if we're not doing DMA. Previously we only did it at the start, which resulted in every sector after the first in a batch having 12 bytes of garbage on the end. This manifested as silent read corruption.
-rw-r--r--Kernel/Devices/PATAChannel.cpp16
1 files changed, 12 insertions, 4 deletions
diff --git a/Kernel/Devices/PATAChannel.cpp b/Kernel/Devices/PATAChannel.cpp
index ece7e0619a..db3d025c53 100644
--- a/Kernel/Devices/PATAChannel.cpp
+++ b/Kernel/Devices/PATAChannel.cpp
@@ -443,13 +443,21 @@ bool PATAChannel::ata_read_sectors(u32 start_sector, u16 count, u8* outbuf, bool
if (m_device_error)
return false;
- u8 status = IO::in8(m_io_base + ATA_REG_STATUS);
- ASSERT(status & ATA_SR_DRQ);
+ for (int i = 0; i < count; i++) {
+ wait_400ns(m_io_base);
+
+ while (IO::in8(m_io_base + ATA_REG_STATUS) & ATA_SR_BSY)
+ ;
+
+ u8 status = IO::in8(m_io_base + ATA_REG_STATUS);
+ ASSERT(status & ATA_SR_DRQ);
#ifdef PATA_DEBUG
- kprintf("Retrieving %u bytes (status=%b), outbuf=%p...\n", count * 512, status, outbuf);
+ kprintf("PATAChannel: Retrieving 512 bytes (part %d) (status=%b), outbuf=%p...\n", i, status, outbuf + (512 * i));
#endif
- IO::repeated_in16(m_io_base + ATA_REG_DATA, outbuf, count * 256);
+ IO::repeated_in16(m_io_base + ATA_REG_DATA, outbuf + (512 * i), 256);
+ }
+
return true;
}