I'm in the process of writing a real deal (no cheap hacks, trying to do everything per spec) ATA(PI) DMA driver.
After fixing endless bugs, there are still 2 bugs left, that I can't seem to tackle on my own.
1."Bug": Issuing 0xEF (set features command) command seems to break VirtualBox:
0xC8 (read sectors DMA) succeeds , interrupt fires, no errors, RDY and SRV bits are set, as soon as the interrupt fires I print the transfer buffer and there is nothing in it -> then my code returns and waits for some time and I read it again and suddenly there is data in it, like whaaat??
If I completely remove the code from below, everything works, as soon as the interrupt fires the buffer gets printed and there is expected data in it, SRV and RDY bits are set.
Code: Select all
...
Select_Device(ATA_devices[i], 0, true);
Hardware::Outportb(ATA_devices[i].base_address + 1, 0x03);
uint8_t DMA_mode = 0;
if(ATA_devices[i].ultra_DMA_mode_supported == true)
{
DMA_mode = 0x08 << 3;
DMA_mode |= ATA_devices[i].ultra_DMA_mode;
}
else if(ATA_devices[i].multiword_DMA_mode_supported == true)
{
DMA_mode = 0x04 << 3;
DMA_mode |= ATA_devices[i].multiword_DMA_mode;
}
Hardware::Outportb(ATA_devices[i].base_address + 2, DMA_mode);
Hardware::Outportb(ATA_devices[i].base_address + 7, 0xEF);
if(Wait_Specific(ATA_devices[i], 6, 1500) == true)
{
uint8_t status_byte = Hardware::Inportb(ATA_devices[i].base_address + 1);
if((status_byte & (1 << 2)) != 0)
{
error msg...
}
}
else
{
error msg...
}
...
I've read every possible topic on this forum, but couldn't find a solution.
What I've tried:
nIEN -> check
PCI bus mastering bit -> check
PIC -> check
direction bit -> check
start DMA transfer bit -> check
waiting -> check
PRDT and transfer buffer alignment -> check
proper device select -> check
clearing error and interrupt bit -> check
zeroing out memory -> check
proper drive info detection -> check
proper dma info detection -> check
...
What did I miss?