LBA PIO reading not working

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
Revelation
Member
Member
Posts: 47
Joined: Sat Jun 21, 2008 8:15 am

LBA PIO reading not working

Post by Revelation »

When I try to read data from a hard drive with LBA28, I get only zeros as result.

Code: Select all

int waituntilbusy(unsigned int base)
{
    unsigned int maxtry = 300000;
	unsigned char r;

  while(((r = inb(base + 0x07)) &  0x80) || !(r & 0x40))
       {
        maxtry--;
        if (maxtry == 0)
        {
            puts("Error: read time-out.\n");
            return 0;
        }
    }

 return 1;
}

int GetSector(unsigned char ide, unsigned long drive, unsigned long sector)
{
    unsigned char buffer[512];
    unsigned int idx;
    unsigned short tmpword;
    unsigned short base;

    if (ide == 0)
        base = 0x1F0;
    else
        if (ide == 1)
            base = 0x170;
        else
            return 0;

    // first set the read parameters
    outb(base + 1, 0x0); // reset the error flag
    outb(base + 2, 0x1); // read 1 sector
    outb(base + 3, (unsigned char)sector); // first address byte
    outb(base + 4, (unsigned char)(sector >> 8)); // second address byte
    outb(base + 5, (unsigned char)(sector >> 16)); // third address byte

    outb(base + 6, 0xE0 | (drive << 4) | ((sector >> 24) & 0x0F)); // select drive
    outb(base + 7, 0x20); // read with retry

    if (!waituntilbusy(base))
        return 0;


    for (idx = 0; idx < 256; idx++)
    {
        tmpword = inw(base); // read a word
        buffer[idx * 2] = (unsigned char)tmpword;
        buffer[idx * 2 + 1] = (unsigned char)(tmpword >> 8);
    }

    for (idx = 0; idx < 512; idx++)
        putch(buffer[idx]);

    return 1;
}
Oddly, when I use 0xA0 instead of 0xE0, I get a good result, but only for the first sector. I haven't got a clue where to look for the error, I've tried so many things. Have you got an idea?
Now is the winter of my disk content.
Laksen
Member
Member
Posts: 140
Joined: Fri Nov 09, 2007 3:30 am
Location: Aalborg, Denmark

Re: LBA PIO reading not working

Post by Laksen »

try this instead: outb(base + 6, 0x40 | (drive << 4) | ((sector >> 24) & 0x0F)); // select drive

Oh and where's the 400ns delay? I don't see any wait for IRQ in your code

Edit: and what is your waituntilbusy function supposed to do? You are supposed to wait until bsy=0 and drq=1. not until bsy!=1 and drdy!=0
http://j-software.dk | JPasKernel - My Object Pascal kernel
User avatar
bewing
Member
Member
Posts: 1401
Joined: Wed Feb 07, 2007 1:45 pm
Location: Eugene, OR, US

Re: LBA PIO reading not working

Post by bewing »

Heh. Clearly Laksen has read ATA_PIO_Mode -- it would be wise for you to see it, too, Revelation.

The 0xE0 vs. 0x40 should not cause problems. The extra bits are for compatibility with legacy disks.

I am more likely to guess that you are calling this funtion with bad values for your LBA sector number. Do you understand that LBAs start at 0?
(And you should also test that "drive" is never anything other than 0 or 1.)
Laksen
Member
Member
Posts: 140
Joined: Fri Nov 09, 2007 3:30 am
Location: Aalborg, Denmark

Re: LBA PIO reading not working

Post by Laksen »

bewing wrote:Heh. Clearly Laksen has read ATA_PIO_Mode...
Negative. I read the specification, from one end to the other(both directions)
http://j-software.dk | JPasKernel - My Object Pascal kernel
User avatar
Revelation
Member
Member
Posts: 47
Joined: Sat Jun 21, 2008 8:15 am

Re: LBA PIO reading not working

Post by Revelation »

Edit: and what is your waituntilbusy function supposed to do? You are supposed to wait until bsy=0 and drq=1. not until bsy!=1 and drdy!=0
Are you sure the code is wrong? It looks fine to me.
Heh. Clearly Laksen has read ATA_PIO_Mode -- it would be wise for you to see it, too, Revelation.
I have read it.
I am more likely to guess that you are calling this funtion with bad values for your LBA sector number. Do you understand that LBAs start at 0?
(And you should also test that "drive" is never anything other than 0 or 1.)
I'm starting to wonder if my code is using LBA, because when I enter 1 as the sector, I get the first block, like with CHS. How can I make sure my code uses LBA?


edit: I just read the specs, and it says that the E0 should do the trick...
Now is the winter of my disk content.
Laksen
Member
Member
Posts: 140
Joined: Fri Nov 09, 2007 3:30 am
Location: Aalborg, Denmark

Re: LBA PIO reading not working

Post by Laksen »

Try this:

Code: Select all

void nanodelay(unsigned int ns)
{
   //Approx delay
   ns *= 4;
   while(ns > 0) ns--;
}

int waituntilbusy(unsigned int base)
{
   unsigned int maxtry = 300000;
   unsigned char r;
   
   nanodelay(400);

   r = inb(base + 0x07);
   while((r & 0x88) != 0x08)
   {
      maxtry--;
      if (maxtry <= 0)
      {
         puts("Error: read time-out.\n");
         return 0;
      }
      r = inb(base + 0x07);
   }
   return 1;
}
http://j-software.dk | JPasKernel - My Object Pascal kernel
User avatar
Revelation
Member
Member
Posts: 47
Joined: Sat Jun 21, 2008 8:15 am

Re: LBA PIO reading not working

Post by Revelation »

Thanks Laksen!

I've found the problem: once again it's bochs. My code works fine if I test it on my real computer. Now I have to figure out why bochs doesn't like LBA.

edit: I've got it working now :D
Now is the winter of my disk content.
Post Reply