Back online ...
I've been pushing my tests with ATA further and here are the (possible) useful hints i can provide you:
1. When unmasking hardware interrupt for ATA device (IRQ 14 and 15), don't forget to unmask the cascade IRQ aswell (IRQ2).
2. Some commands (and among them ATA_IDENTIFY 0xEC) respond very quickly, especially under BOCHS. So most of the other stuff (like preparing memory structure, or installing time-outs) should be performed either *before* the command is set or in a code section where interrupts are disable (yes, even if what you wanna do is receiving an interrupt
)
For instance,
Code: Select all
kSemWait(ctrl->lock);
// warning: prototype is outb(<value>, <port>) in Clicker !
outb(ATA_IDENTIFY,ctrl->base+REG_COMMAND);
ctrl->command=ATA_IDENTIFY;
ctrl->status=STATUS_BSY;
ctrl->requestor=getSysGlocals()->thread;
kSemSignal(ctrl->lock);
log(KLOG_DEBUG,0,"sent ATA_IDENTIFY command to %s %s(%i)",ctrl->pname, drive_name[drive],drive);
notifier=ti_setAfter(5000,ataTimeOutEvent);
sign("waiting for event");
e=eWait(ataTimeOutEvent,ataCtrlCompleteEvent,NULL);
// code for analysis of the event received come here
didn't work:
- if the disk is very fast (and BOCHS disk *is*), an IRQ signalling the end of the IDENTIFY command could be received before ctrl->requestor and ctrl->command are set, which will make the Interrupt Service Routine behave very weirdly.
- nothing prevents ataCtrlCompleteEvent (generated by the ISR) to be sent before a receiver is planned with eWait( ... ), so the success of the command is likely to be lost.
The working code looks more like
Code: Select all
kSysLock(&(ctrl->lock));
ctrl->command=ATA_IDENTIFY;
ctrl->status=STATUS_BSY;
ctrl->requestor=getSysGlocals()->thread;
outb(ATA_IDENTIFY,ctrl->base+REG_COMMAND);
log(KLOG_DEBUG,0,"sent ATA_IDENTIFY command to %s %s(%i)",ctrl->pname,
drive_name[drive],drive);
notifier=ti_setAfter(5000,ataTimeOutEvent);
sign("waiting for event");
e=eWait(ataTimeOutEvent,ataCtrlCompleteEvent,NULL);
kSysUnlock(&(ctrl->lock));
Note that the semaphore has been replaced by a mutex that disables interrupts while locked. This guarantees us we will not receive IRQ14 before we told the handler how it should understand it.
The call to eWait() will setup handler for both ataTimeOut and ataCtrlComplete events and then schedule to another thread (the current thread is put asleep). Once we enter one of those thread that will have its IF flag set, we can receive the interrupt from the drive.
This makes me wondering whether a busy-waiting loop would have been better ...