Page 1 of 1

[SOLVED] ATA: DRQ not cleared after a multiple sectors read

Posted: Tue Dec 31, 2013 4:48 am
by wichtounet
Hi,

I've a problem making my ATA driver works in Qemu. The problem comes arises when I read multiple sectors at once, 8 in my case. After the 8 * 256 words have been read, the DRQ flag is still set. Normally that should indicate that there are still data, but I don't see how this is possibles since I have read the 8 blocks.

The reads of only 1 blocks succeeds without any problem. Moreover, if, instead of a read of 8 blocks, I read 8 times 1 block, it works perfectly.

In Bochs, everything is working perfectly.

Here is my function to read sectors:

Code: Select all

bool read_write_sectors(ata::drive_descriptor& drive, uint64_t start, uint8_t count, void* data){
    //Select the device
    if(!select_device(drive)){
        return false;
    }

    auto controller = drive.controller;

    uint8_t sc = start & 0xFF;
    uint8_t cl = (start >> 8) & 0xFF;
    uint8_t ch = (start >> 16) & 0xFF;
    uint8_t hd = (start >> 24) & 0x0F;

    //Process the command
    out_byte(controller + ATA_NSECTOR, count);
    out_byte(controller + ATA_SECTOR, sc);
    out_byte(controller + ATA_LCYL, cl);
    out_byte(controller + ATA_HCYL, ch);
    out_byte(controller + ATA_DRV_HEAD, (1 << 6) | (drive.slave << 4) | hd);
    out_byte(controller + ATA_COMMAND, ATA_READ_BLOCK);

    //Wait at least 400ns before reading status register
    sleep_ms(1);

    //Wait at most 30 seconds for BSY flag to be cleared
    if(!wait_for_controller(controller, ATA_STATUS_BSY, 0, 30000)){
        return false;
    }

    //Verify if there are errors
    if(in_byte(controller + ATA_STATUS) & ATA_STATUS_ERR){
        return false;
    }

    //Wait the IRQ to happen
    if(controller == ATA_PRIMARY){
        ata_wait_irq_primary();
    } else {
        ata_wait_irq_secondary();
    }

    //The device can report an error after the IRQ
    if(in_byte(controller + ATA_STATUS) & ATA_STATUS_ERR){
        return false;
    }

    uint16_t* buffer = reinterpret_cast<uint16_t*>(data);

        //Read the disk sectors
        for(uint8_t sector = 0; sector < count; ++sector){
            for(int i = 0; i < 256; ++i){
                *buffer++ = in_word(controller + ATA_DATA);
            }
        }

    return true;
}
(The complete ATA code is available here https://github.com/wichtounet/thor-os/b ... rc/ata.cpp)

Do you something wrong with my function ? Is this a bad idead to read multiple sectors at once ?

Thanks

Re: ATA: DRQ not cleared after a multiple sectors read in Qe

Posted: Tue Dec 31, 2013 7:24 am
by iansjack
I believe that you are supposed to poll, or wait for an interrupt, after each sector is read. That makes sense as it may take an appreciable time between sectors (for example if the heads have to move to a new cylinder).

Re: ATA: DRQ not cleared after a multiple sectors read in Qe

Posted: Thu Jan 02, 2014 6:33 am
by wichtounet
iansjack wrote:I believe that you are supposed to poll, or wait for an interrupt, after each sector is read. That makes sense as it may take an appreciable time between sectors (for example if the heads have to move to a new cylinder).
Oh gosh. I was sure than only one IRQ was fired for the whole block, but it is only the case with READ MULTIPLE and WRITE MULTIPLE commands.

I will review my driver to handle this.

Thanks ;)