ATA PIO read only works one half the times

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
User avatar
DeezRamChips
Member
Member
Posts: 132
Joined: Fri Apr 08, 2016 5:03 am
Location: atapio.cpp - why won't you work :(
Contact:

ATA PIO read only works one half the times

Post by DeezRamChips »

Hi :D

I'm making a ext2fs driver and while I was debugging it, I noticed the extended superblock was not loading.
When I looked a little further into it, I noticed my drive_read function was returning only zeros the second time it was run.
But if I tried to run it a third time, then it would work... I tried a few thing and it appears like it works in the following pattern:
1 - Works
2 - Doesn't work
3 - Works
4 - Doesn't work
(and so on)

Code: Select all

int ATAPIO_Class::readBlock(int drive, int numblock, int count, char *buf) {
    uint16_t tmpword;
    int idx;

    if (count == 0) {
        kernel_panic(0x1234, "Null sector count read");
    }

	selectDrive(drive, numblock, count);
	outb(0x1F7, 0x20);

    // Wait for ready signal
    uint8_t status = (inb(0x1F7) & 0x08);
	while (!status) {
        status = (inb(0x1F7) & 0x08);
    }


	for (idx = 0; idx < 256 * count; idx++) {
		tmpword = inw(0x1F0);
		buf[idx * 2] = (uint8_t)tmpword;
		buf[idx * 2 + 1] = (uint8_t)(tmpword >> 8);
	}

	return count;
}
I've even tried adding a 1ms delay just to be sure, but it doesn't change anything
also, reading 5 times like it says on the wiki doesn't change anything either :/
I talked to someone who had also tried making a ATAPIO driver and he said he also had issues
so he switched to AHCI, but I don't want to get into AHCI just yet, seems too complicated just
to test my ext2fs driver...

I'm testing my code on QEMU btw.

Hope someone can figure out what's going on :P
User avatar
iansjack
Member
Member
Posts: 4706
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: ATA PIO read only works one half the times

Post by iansjack »

I may be wrong, but I think you should be checking the status register to see that the controller is not busy before starting the read.
User avatar
DeezRamChips
Member
Member
Posts: 132
Joined: Fri Apr 08, 2016 5:03 am
Location: atapio.cpp - why won't you work :(
Contact:

Re: ATA PIO read only works one half the times

Post by DeezRamChips »

Well, It's already what i'm doing :?
and if I check it before sending the read command, it hangs :/
User avatar
iansjack
Member
Member
Posts: 4706
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: ATA PIO read only works one half the times

Post by iansjack »

I don't think you are checking it. It's bit 7 in the status register.
User avatar
DeezRamChips
Member
Member
Posts: 132
Joined: Fri Apr 08, 2016 5:03 am
Location: atapio.cpp - why won't you work :(
Contact:

Re: ATA PIO read only works one half the times

Post by DeezRamChips »

Oh yeah sorry I thought you meant the DRQ bit ^^

changed it and it still gets zeros on second read :/

Code: Select all

Terminal.print("Waiting for drive ready... ");
inb(0x1F7);
inb(0x1F7);
inb(0x1F7);
inb(0x1F7);
uint8_t status = inb(0x1F7);
while ((status & 0x80) && !(status & 0x08)) {
	status = inb(0x1F7);
}
Terminal.println("READY");

selectDrive(drive, numblock, count);

outb(0x1F7, 0x20);

// Wait for ready signal
Terminal.print("Waiting for data... ");
inb(0x1F7);
inb(0x1F7);
inb(0x1F7);
inb(0x1F7);
status = inb(0x1F7);
while ((status & 0x80) && !(status & 0x08)) {
	status = inb(0x1F7);
}
Terminal.println("READING");

for (idx = 0; idx < 256 * count; idx++) {
	tmpword = inw(0x1F0);
	buf[idx * 2] = (uint8_t)tmpword;
	buf[idx * 2 + 1] = (uint8_t)(tmpword >> 8);
}
User avatar
BrightLight
Member
Member
Posts: 901
Joined: Sat Dec 27, 2014 9:11 am
Location: Maadi, Cairo, Egypt
Contact:

Re: ATA PIO read only works one half the times

Post by BrightLight »

You can't read the sectors all at once from the data port. You read 256 words (512 bytes, one sector) and then stop there, wait for the BSY bit to clear and the DRQ bit to set again, and then you continue. The actual drive fetches the sectors one by one, and there may be small delays between them, which is why you need to poll the status register in PIO mode.
DeezRamChips wrote:

Code: Select all

Terminal.print("Waiting for drive ready... ");
inb(0x1F7);
inb(0x1F7);
inb(0x1F7);
inb(0x1F7);
uint8_t status = inb(0x1F7);
while ((status & 0x80) && !(status & 0x08)) {
   status = inb(0x1F7);
}
Why is this loop here? Why are you waiting for the DRQ bit before even doing a drive select? It's possible that this code can loop forever, and as a matter of fact, I'm surprised it didn't. Do a drive select, send the LBA and sector count, send the read command, wait for the BSY bit to clear, and then for each sector, wait for the BSY bit and the DRQ bit.

Also if you ever intend on running on real HW, don't assume port numbers.
You know your OS is advanced when you stop using the Intel programming guide as a reference.
User avatar
DeezRamChips
Member
Member
Posts: 132
Joined: Fri Apr 08, 2016 5:03 am
Location: atapio.cpp - why won't you work :(
Contact:

Re: ATA PIO read only works one half the times

Post by DeezRamChips »

Thanks :D

I can confirm this fixed the issue. I must not have understood the wiki page for that ^^

I moved on to making an AHCI driver though, seems more professional then PIO.

Thanks again :)
Post Reply