Page 1 of 1

LBA PIO reading not working

Posted: Thu Aug 07, 2008 10:55 am
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?

Re: LBA PIO reading not working

Posted: Thu Aug 07, 2008 12:32 pm
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

Re: LBA PIO reading not working

Posted: Thu Aug 07, 2008 1:41 pm
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.)

Re: LBA PIO reading not working

Posted: Thu Aug 07, 2008 2:28 pm
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)

Re: LBA PIO reading not working

Posted: Fri Aug 08, 2008 3:16 am
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...

Re: LBA PIO reading not working

Posted: Fri Aug 08, 2008 4:06 am
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;
}

Re: LBA PIO reading not working

Posted: Fri Aug 08, 2008 4:09 am
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