Page 1 of 1

Hard drive question

Posted: Tue Mar 13, 2007 7:58 pm
by frank
The other day I decided to update my hard drive read and write functions. I decided to make them use interrupts instead of polling for data request. I have a question about when the ata controller fires an interrupt though. Right now my read hard drive function looks like this: ( I use PIO )

1. Write out sector number
2. Issue seek command
3. Wait for interrupt
4. Issue read command

5. Wait for interrupt
6. Read 1 sector
7. If we have not finished reading all sectors, go to 5

However, sometimes the int erupt for step 5 fails to come and my hard drive read function times out. I have 2 questions
1. Does the hard drive controller issue an interrupt for every sector read and
2. Does the above routine look okay, am I missing something.

Thanks,
Frank

Posted: Wed Mar 14, 2007 8:23 am
by Mikae
Do you check ERR and DF bit in status register after every interrupt? How do you poll your device, using status register or alternate status register? A read of status register clears interrupt pending state in a device, may be, it is a problem?

Re: Hard drive question

Posted: Wed Mar 14, 2007 11:19 am
by octavio
frank wrote:The other day I decided to update my hard drive read and write functions. I decided to make them use interrupts instead of polling for data request. I have a question about when the ata controller fires an interrupt though. Right now my read hard drive function looks like this: ( I use PIO )

1. Write out sector number
2. Issue seek command
3. Wait for interrupt
4. Issue read command

5. Wait for interrupt
6. Read 1 sector
7. If we have not finished reading all sectors, go to 5

However, sometimes the int erupt for step 5 fails to come and my hard drive read function times out. I have 2 questions
1. Does the hard drive controller issue an interrupt for every sector read and
2. Does the above routine look okay, am I missing something.

Thanks,
Frank
I think it only fires interrupt if the drive become busy, but if data is already available then the driver must start the transfer without waiting for the interrupt, note also that after the transfer is complete another interrupt is generated.
The seek command is not needed.

Posted: Wed Mar 14, 2007 3:12 pm
by frank
Here is the code from the problem portion of the function

Code: Select all

// send the read command
outportb( base_port + 7, 0x20 );

// get a pointer to the buffer
WORD *read_buffer = (WORD *)buffers[ buf ].Get_Whole_Buffer( );

// read the data in 1 sector at a time
for ( i = 0; i < 64; i++ )
{
    // wait for the interupt to fire
    if ( !Wait_For_Interupt( irq_number, 5000 ) )
    {
        // release the mutex
        Release_Mutex( mutex );

        return( DISK_TIMEOUT_ERROR );

    } // end if

    // wait 1 PIO cycle
    inportb( base_port + 0x206 );

    // read from the status register
    UINT status = inportb( base_port + 7 );

    // check for error
    if ( status & 1 )
    {
        // release the mutex
        Release_Mutex( mutex );

        // return the error
        return ( ( inportb( base_port + 1 ) << 8 ) | DISK_DRIVE_ERROR );

    } // end if

    for ( int offset = 0; offset < 512 / 2; offset++ )
    {
        (*read_buffer) = inportw( base_port );
        read_buffer++;

    } // end for

} // end for

// check for an error
if ( inportb( base_port + 7 ) & 0x1 )
{
    // an error occured
    int error = inportb( base_port + 1 );

    // release the mutex
    Release_Mutex( mutex );

    // return error
    return( (error << 8 ) | DISK_DRIVE_ERROR );

} // end if
Wait for interrupt has the following takes the interrupt number and the maximum number of milliseconds to wait for the interrupt. Are you sure that the seek command is not needed, even on older hardware. By the way I only support drives with LBA addressing. I know that interrupts are enabled because I get one are the seek command.

Posted: Wed Mar 14, 2007 6:54 pm
by bewing
The reply above seems to be correct. You are reading the regular status port (base + 7). You need to be reading the ALTERNATE status port. For the moment, I can't find the port number, but it's in the documentation -- especially if you can read that wacky CS, DS assertion/negation table.

But the point is that a read from the regular status port will pre-empt an impending interrupt and keep it from ever happening.

Beyond that, yes, a disk will send an interrupt for every single sector, when the data is ready to read.

I think interrupts are time-wasters, so I'd rather not receive them. So I always pre-empt mine on purpose in PIO mode.

Posted: Wed Mar 14, 2007 7:14 pm
by frank
bewing wrote:The reply above seems to be correct. You are reading the regular status port (base + 7). You need to be reading the ALTERNATE status port. For the moment, I can't find the port number, but it's in the documentation -- especially if you can read that wacky CS, DS assertion/negation table.
I thought that somewhere you had to read the main status register to clear the interrupt, and that if you did not clear the interrupt you would not be to receive any more interrupts from the drive controller.
ata reference wrote: The device shall exit the interrupt pending state when:
1) the device is selected, BSY is cleared to zero, and the Status register is read;
2) the device is selected, both BSY and DRQ are cleared to zero, and the Command register is
written;
3) the RESET- signal is asserted;
4) the SRST bit is set to one.

Posted: Wed Mar 14, 2007 9:43 pm
by octavio
I have done a HD driver for my OS and it do not uses the seek command,it works also on older disks using chs, i have tested disk from 1992.
Mi HD driver uses polling but the atapi driver uses interrupts, i do not use the
alternate status port, i send commands for reading multiple sectors ,then i wait for the first interrupt, read a sector and read the status byte , if busy then the driver waits for another interrupt, else it reads next sector.
did you send the ACK to the PIC ?

Posted: Thu Mar 15, 2007 10:09 am
by frank
octavio wrote: did you send the ACK to the PIC ?
yes thats handled by the isr.

So after I read a sector, i should check to see if the drive is busy. If it is busy, then i should wait for another interupt, if it is not I should just go ahead and read the next sector?