I am currently working on a hobby OS, specifically the ATA driver. I am having some issues with PIO data-in commands with interrupts. I am trying to execute the READ MULTIPLE command to read multiple sectors from the drive, block by block, with an interrupt firing for each block.
If I request a read of 4 blocks (1 sector per block). I expect to get 4 interrupts, one for each data block. Upon receiving the 4th interrupt I can identify that I've transferred all data and update my request structure accordingly. However, in VirtualBox I've found that after the last data block has been transferred I received yet another interrupt (STATUS = 0x50, READY, OVERLAPPED MODE SERVER REQ). I can simply read the STATUS register then to clear it, but I don't think I should ever receive the 5th interrupt according to the specs.
So what is the proper way acknowledge an interrupt issued by an ATA device?
In this example I issue a READ MULTIPLE command, and then my ISR does the following:
The ATA specs for the PIO data-in command protocol don't indicate that you need to read the status register. From that I assumed that when I receive an interrupt all I have to do is follow the protocol and finish by sending the EOIs to the PICs. As for the setting/clearing of nIEN, in dealing with VirtualBox I've found that if I don't do this I don't receive any interrupts past the first one. So I set nIEN when entering the ISR, then clear it before I leave. I'd think that wouldn't have any effect, but it must be related to reading/writing that specific register.
This always happens to me, I post a question I've been struggling with, only to find the answer myself shortly after.
The ATA-6 spec I've been referencing has this one line in the PIO data-in section (9.5):
When in this state, the host shall read the device Status register.
With ATA the Status register has a side-effect: it clears a pending interrupt. I knew this, but I didn't correctly read this part before. It doesn't mention why you should read the register, it just states it exactly as above.
The important part is how this works with the interrupt handler. After issuing a PIO data-in command, once the INTRQ is asserted, you simply read the Status register once to clear the interrupt, then continue to processes the interrupt and return as normal (just sending EOIs to the PICs.) What had me confused is that none of the documentation I read mentioned exactly how this should work with interrupts (receive an INTRQ, read Status, processes interrupt.) Most online guides only deal with polled IO.
This is one of the difficulties with low-level programming, key details, such as needing to read the Status register in the ISR, are often glanced over. This one was left as a single line in the protocol description. Call me picky but I just would have expected more emphasis on this point.