Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

On IRQ14 how to identify an ATA drive causing the interrupt

369 views
Skip to first unread message

James Harris

unread,
Dec 19, 2013, 12:40:13 PM12/19/13
to
Say IRQ14 is set up to service an IDE/ATA controller but other devices could
also be sharing the same interrupt line. When IRQ14 fires what are the best
steps the interrupt handler should take in order to find out whether the
interrupt was caused by the disk controller? I cannot see anything
definitive in the ATA register specifications. Does the answer depend on
whether the transfer is via PIO or via DMA?

Similarly but separate, given that an ATA controller can have two drives
attached (DEV = 0, the "master" and DEV = 1, the "slave") how can we tell
which of the two drives require(s) attention?

As a slight aside but it may be of interest to others and may be relevant to
the latter of the above questions, I knew that ATA commands were issued by
setting up registers and then writing a command code. From what I have found
recently, however, it seems that the drive selector bit (DEV) - which is
part of the drive+head byte - does not wait for a command. Apparently, of
all the addressing bits just that one DEV bit takes effect without requiring
a command to be issued.

Some "interesting" subtleties of the ATA standards aren't there!

James


Marven Lee

unread,
Dec 19, 2013, 3:47:01 PM12/19/13
to
James Harris wrote:
> Say IRQ14 is set up to service an IDE/ATA controller but other devices
> could also be sharing the same interrupt line. When IRQ14 fires what are
> the best steps the interrupt handler should take in order to find out
> whether the interrupt was caused by the disk controller? I cannot see
> anything definitive in the ATA register specifications. Does the answer
> depend on whether the transfer is via PIO or via DMA?

This information is provided by the bus master status register on
controllers
that support it.

There are 2 documents you might want to check out regarding bus master DMA
and interrupts:
"Programming interface for Bus Master IDE Controller" and
"Ata/Atapi Host Adapters Standard (ATA - Adapter)"

--
Marv


Rod Pemberton

unread,
Dec 20, 2013, 2:32:47 AM12/20/13
to
On Thu, 19 Dec 2013 12:40:13 -0500, James Harris
<james.h...@gmail.com> wrote:

> As a slight aside but it may be of interest to others and may be
> relevant to the latter of the above questions, I knew that ATA commands
> were issued by setting up registers and then writing a command code. From
> what I have found recently, however, it seems that the drive selector bit
> (DEV) - which is part of the drive+head byte - does not wait for a
> command.
> Apparently, of all the addressing bits just that one DEV bit takes effect
> without requiring a command to be issued.
>

Are you using an emulator? Or, were you using real hardware? ...

This code piece may be of use to you and maybe Danish M. also:
https://groups.google.com/d/msg/comp.sys.ibm.pc.hardware.storage/KR1VGxyWUjQ/BXibIwktxlQJ


Rod Pemberton

James Harris

unread,
Dec 20, 2013, 9:36:19 AM12/20/13
to
"Marven Lee" <marv...@gmail.com> wrote in message
news:bhh49d...@mid.individual.net...
> James Harris wrote:
>> Say IRQ14 is set up to service an IDE/ATA controller but other devices
>> could also be sharing the same interrupt line. When IRQ14 fires what are
>> the best steps the interrupt handler should take in order to find out
>> whether the interrupt was caused by the disk controller? I cannot see
>> anything definitive in the ATA register specifications. Does the answer
>> depend on whether the transfer is via PIO or via DMA?
>
> This information is provided by the bus master status register on
> controllers
> that support it.

I might be wrong but I think that applies to DMA only. Also, isn't there a
way to distinguish interrupt sources that doesn't involve PCI? I was
thinking that this had to be done on ATA on its own as ATA used to exist
(and presumably allowed interrupt sharing?) before the presence of PCI.

> There are 2 documents you might want to check out regarding bus master DMA
> and interrupts:
> "Programming interface for Bus Master IDE Controller" and
> "Ata/Atapi Host Adapters Standard (ATA - Adapter)"

Thanks. That second one is the normal T13 standards doc series isn't it? For
anyone else who is looking for the early but complete ones see

http://www.t10.org/t13/#Wthdrawn

By the way, in the original post I mentioned the use of the DEV bit to
select master or slave drive. I was thinking of switching between the drives
so that normal operations could be used in parallel but from what I have
read since it seems that this requires what the standards call the
Overlapped feature set which was not available at least in ATA1 to ATA3 and
does not apply to PIO. That simplifies the requirement a bit.

There is apparently no visible bit to reflect the state of the interrupt
request value INTRQ. Maybe to detect that a drive is expecting service there
are different ways for PIO and for DMA. Maybe PCI for DMA and the DRQ bit
for PIO...? As above, only one drive can be accessed by PIO at a time which
may make this possible even if the standards are cumbersome.

James


James Harris

unread,
Dec 20, 2013, 3:55:22 PM12/20/13
to
"Rod Pemberton" <dont_us...@xnohavenotit.cnm> wrote in message
news:op.w8dq8xfl5zc71u@localhost...
> On Thu, 19 Dec 2013 12:40:13 -0500, James Harris
> <james.h...@gmail.com> wrote:
>
>> As a slight aside but it may be of interest to others and may be
>> relevant to the latter of the above questions, I knew that ATA commands
>> were issued by setting up registers and then writing a command code. From
>> what I have found recently, however, it seems that the drive selector bit
>> (DEV) - which is part of the drive+head byte - does not wait for a
>> command.
>> Apparently, of all the addressing bits just that one DEV bit takes effect
>> without requiring a command to be issued.
>>
>
> Are you using an emulator? Or, were you using real hardware? ...

Does it make a difference? I was just going by the specs.

> This code piece may be of use to you and maybe Danish M. also:
> https://groups.google.com/d/msg/comp.sys.ibm.pc.hardware.storage/KR1VGxyWUjQ/BXibIwktxlQJ

I cannot currently see its relevance but it may come in handy later so
thanks for posting it.

James


wolfgang kern

unread,
Dec 20, 2013, 5:07:09 PM12/20/13
to

James Harris wrote:
[about IRQ from HD(s)]

Yeah,
there once were a standard for
master/slave IDE_0 use IRQ_0E and
master/slave IDE_1 use IRQ_0F. (or opposite ? either way...)

But now when I look at my old present PC then I find already
connected five HDs plus one DVD which all can be programmed
and be used in native SATA (IDE-mode) regardless is they show
advanced featurs like NativeJobCollections ...
And I really give a fart to all these interrupt-signals,
I just ignore them by INT_ACK+IRET.

Of course we can define each device an IRQ-line within the APIC
(apart from legacy or PCI-told numbering), but why would someone
want an HW-interrupt for timing things we know in advance anyway?
__
wolfgang


James Harris

unread,
Dec 20, 2013, 7:59:10 PM12/20/13
to
"wolfgang kern" <now...@never.at> wrote in message
news:l92fia$8r1$1...@newsreader2.utanet.at...
>
> James Harris wrote:
> [about IRQ from HD(s)]
>
> Yeah,
> there once were a standard for
> master/slave IDE_0 use IRQ_0E and
> master/slave IDE_1 use IRQ_0F. (or opposite ? either way...)
>
> But now when I look at my old present PC then I find already
> connected five HDs plus one DVD which all can be programmed
> and be used in native SATA (IDE-mode) regardless is they show
> advanced featurs like NativeJobCollections ...

I remember one PC which had quite a high number of devices on each of the
sharable interrupts - at least the BIOS set it up that way when it was set
for a non-PnP OS. There are many permutations but it is possible that an OS
may have to run on a machine which has many devices sharing a disk
interrupt - disks and other things.

...

> I just ignore them by INT_ACK+IRET.

You mean you ignore those interrupts and so ignore the devices? Or do you
poll those devices separately outside the interrupt mechanism?

> Of course we can define each device an IRQ-line within the APIC
> (apart from legacy or PCI-told numbering), but why would someone
> want an HW-interrupt for timing things we know in advance anyway?

Once we get to APIC handling and, even worse, PCI interrupt routing things
can become a lot more complex. At the moment I am just thinking of how to
handle the earliest machines which predate PCI and use only the ATA system.
The idea is that that should work on any AT or later compatible.

Current thought:

1. For PIO (which seems to be the only option on machines which predate PCI)
check the status register's DRQ bit. This bit apparently indicates that the
current drive wants to read or write via its data port. Timing could be an
issue in that something else may have triggered the interrupt but by the
time the ISR starts running the disk has also asserted its INTRQ state.
However, even if that happened I think it would still be OK to service the
drive and clear its interrupt state just as if the drive had been the first
to trigger the interrupt condition. The originally-asserting device could
also be serviced before returning to the interrupted task.

2. For DMA disk access, AIUI, PCI has to be present to provide the DMA
facilities needed so in this case the driver code would be sure to have PCI
available and so could work with its indicators (as Marven Lee mentioned) to
recognise that disk activity was the cause of an interrupt.

Bottom line is that the most basic and most universal approach seems to be
to read and write using PIO, to handle one request to a disk controller at a
time, and to examine the DRQ bit to find out whether a drive needs service.
Does that sound about right?

I don't like the idea of carrying out a 256-word PIO transfer in an ISR (and
that's just for one sector) but it seems to be unavoidable. Leaving the
sector to be transferred after the interrupt has been acknowledged and the
ISR has returned might be possible but seems dangerous. On the other hand,
not acknowledging the interrupt in the ISR (and relying on the fact that AT
IRQs are edge triggered) seems that it would be unreliable.

So I am left with carrying out the 256-word transfer in the ISR. Best I can
think of in order to avoid impacting the response time of other interrupts
is to make the normal disk interrupts (14 and 15) the lowest priority. Then
at least devices on other IRQs will be able to interrupt the PIO transfers
... I think.

AIUI this should be possible as long as higher priority devices can
interrupt the CPU. For that, ISTM that I would have to avoid sending EOI to
the PICs and yet would have to reenable CPU interrupts. So the service
routine would have the following outline.

service routine:
;save registers etc
...
sti ;enable CPU interrupts while we handle this ISR
...
;If needed carry out PIO transfer
...
;End of service routine
cli
mov al, 0x20
out 0x00a0, al
out 0x0020, al
... ;restore registers
iret

The idea is that the CPUs interrupts will be enabled and that the PICs will
allow higher priority interrupts for most of the ISR. The CPU's interrupts
will be disabled only where needed. Disabling them just prior to sending the
EOIs is so that at that point we can be sure the ISR will continue to
completion.

Incidentally, normal interrupt prioritisation would not make it possible to
have IRQs 14 and 15 as lowest priority. The normal sequence is, from memory,
highest to lowest,

0 1 8 9 10 11 12 13 14 15 3 4 5 6 7

However, I prefer starting the interrupt priorities with IRQ 3 so that the
low speed devices especially serial ports get handled first. They may be the
most sensitive to interrupt latency so should have highest priority. With
the above thoughts on IRQs 14 and 15 that would make my preferred sequence,
highest to lowest,

3 4 5 6 7 0 1 8 9 10 11 12 13 14 15

It has been quiet in aod recently hasn't it!

James


Rod Pemberton

unread,
Dec 21, 2013, 1:37:08 AM12/21/13
to
On Fri, 20 Dec 2013 09:36:19 -0500, James Harris
<james.h...@gmail.com> wrote:

> Also, isn't there a way to distinguish interrupt sources that
> doesn't involve PCI?

You can distinquish which interrupt is active using the
in-service register of the PIC. Of course, you should
already know which interrupt is executing ...

That won't resolve your shared interrupt issue.

I don't know if in-service register is available for
the APIC or LAPIC. It could have something similar.

From what I've read here, it seems that you can assign a
device an interrupt for APIC or LAPIC, so why would you
share interrupts for hard drives?


Rod Pemberton

Rod Pemberton

unread,
Dec 21, 2013, 1:38:12 AM12/21/13
to
On Fri, 20 Dec 2013 15:55:22 -0500, James Harris
<james.h...@gmail.com> wrote:
> "Rod Pemberton" <dont_us...@xnohavenotit.cnm> wrote in message
> news:op.w8dq8xfl5zc71u@localhost...
>> On Thu, 19 Dec 2013 12:40:13 -0500, James Harris
>> <james.h...@gmail.com> wrote:

>>> As a slight aside but it may be of interest to others and may be
>>> relevant to the latter of the above questions, I knew that ATA commands
>>> were issued by setting up registers and then writing a command code.
>>> From what I have found recently, however, it seems that the drive
>>> selector
>>> bit (DEV) - which is part of the drive+head byte - does not wait for a
>>> command. Apparently, of all the addressing bits just that one DEV bit
>>> takes effect without requiring a command to be issued.
>>>
>>
>> Are you using an emulator? Or, were you using real hardware? ...
>
> Does it make a difference? I was just going by the specs.
>

It might.

Personally, I wouldn't trust any emulator for testing any low-level
hardware code. I believe that real world hardware is needed to ensure
proper timing, initialization, spin-up, acknowledgements, correctly
and fully implemented registers, etc.

In this case though, I don't know: insufficient information. In general,
yes. Benjamin Lunt has found a variety of errors in one major emulator
and Alexei Frounze has demonstrated that some emulators find some coding
errors that real world hardware accepts. Of course, IMO, it's debatable
as to whether it's an error if real world hardware accepts it... A clear
case can be made that the code is correct if hardware accepts it, but
the same is not true for emulators.

>> This code piece may be of use to you and maybe Danish M. also:
>> [link]
>
> I cannot currently see its relevance but it may come in handy later so
> thanks for posting it.
>

It's code which sends IDE commands. It's simple. It should be
easily extendable or modifiable. It's about the only other code I've
found besides Hale Landis' which is actually useable.


Rod Pemberton

James Harris

unread,
Dec 21, 2013, 6:47:39 AM12/21/13
to
"Rod Pemberton" <dont_us...@xnohavenotit.cnm> wrote in message
news:op.w8fjb6175zc71u@localhost...
> On Fri, 20 Dec 2013 09:36:19 -0500, James Harris
> <james.h...@gmail.com> wrote:
>
>> Also, isn't there a way to distinguish interrupt sources that
>> doesn't involve PCI?
>
> You can distinquish which interrupt is active using the
> in-service register of the PIC. Of course, you should
> already know which interrupt is executing ...

Yes, reading the PIC's ISR would not help or be necessary.

> That won't resolve your shared interrupt issue.

Right.

> I don't know if in-service register is available for
> the APIC or LAPIC. It could have something similar.

Even if it would help in principle the APIC architecture is not present on
all PCs.

> From what I've read here, it seems that you can assign a
> device an interrupt for APIC or LAPIC, so why would you
> share interrupts for hard drives?

I have not looked at APICs in much detail simply because they are not
universal; not all PCs have them. I have a vague recollection, though, and
this may be wrong, that there are still only 16 lines on the IO-APIC (the
part of the APIC architecture which listens for device interrupts). IIRC
inter-processor interrupts can be Message Signalled on some systems which
would allow far more vectors for notifications between processors but
hardware interrupts are still restricted to sixteen. (I have an uncomforable
feeling that that paragraph contains some errors. It has been a while since
I looked at that stuff and never had a need for it.)

The sixteen-IRQ limit shouldn't be a big problem, though. It is easy enough
to share interrupt vectors at least at the software level. The service
routine can just call each potential handler in sequence. For example, if
IRQ14 is shared by an ATA controller and two other devices (A and B) the OS
service routine can include

fired = 0;
fired += device_A_handler(device_A_id);
fired += device_B_handler(device_B_id);
fired += ata_handler(ata_id);

In real code these would probably be executed in a loop which read the
handler routine and device id from a list. Then the code could support an
arbitrary number of handlers. (For level-triggered interrupts it might be
possible and faster to handle one at a time if the code was more complex and
handled rotating of priorities within a given IRQ but that's a bit off topic
just now.)

The idea of the "fired" variable is to document how many interrupts were
handled by the sequence. This is mainly for logging purposes but it might
also be handy to know if no interrupts were found to be ready in case that
indicated an error.

There is also the issue of assigning interrupts to devices. The BIOS can do
that to save the OS having to parse the PnP or PCI config info. (I think the
two are separate.) If it does then the BIOS will choose which to share. Even
if the OS allocates interrupts it might choose to share those for disks.

Either way, and to answer your question, interrupts may have to be shared
for hard disks. But as mentioned in a separate post it looks like this
should not be a problem even on the most universal (i.e. oldest) hardware.

James


James Harris

unread,
Dec 21, 2013, 8:15:42 AM12/21/13
to
"Rod Pemberton" <dont_us...@xnohavenotit.cnm> wrote in message
news:op.w8fjdyw55zc71u@localhost...

...

>>> Are you using an emulator? Or, were you using real hardware? ...
>>
>> Does it make a difference? I was just going by the specs.
>>
>
> It might.
>
> Personally, I wouldn't trust any emulator for testing any low-level
> hardware code. I believe that real world hardware is needed to ensure
> proper timing, initialization, spin-up, acknowledgements, correctly
> and fully implemented registers, etc.

Interesting point. My intention for now is just to write to the ATA specs.
You see, this is really about programming language design rather than OSes.
As my language design is gradually progressing I am looking for examples of
pieces of code, i.e. things I can use as tests to help develop the design of
the language. An ATA driver seemed like a good candidate for a number of
reasons: code has to compile to 16-bit, 32-bit and 64-bit modes; code has to
be able to run as part of an interrupt handler; code has to be fairly
detailed; and code has to make it easy to record unexpected conditions (see
below).

> In this case though, I don't know: insufficient information. In general,
> yes. Benjamin Lunt has found a variety of errors in one major emulator
> and Alexei Frounze has demonstrated that some emulators find some coding
> errors that real world hardware accepts. Of course, IMO, it's debatable
> as to whether it's an error if real world hardware accepts it... A clear
> case can be made that the code is correct if hardware accepts it, but
> the same is not true for emulators.

AIUI some real hardware varies from the specs (and some of the specs are
pretty awful, ISTM, so divergence is hardly surprising). An OS writer could
insist on writing to the specs and nothing else. But then even the specs are
not completely consistent. For example, some ATA standards document a delay
of 400ns and some do not. Some add new meanings to fields and, more
importantly, some remove old meanings. And some wordings could be understood
in more than one way.

If we want our OS code to run on real hardware we have to accept a certain
amount of variation and write to accommodate the differences. It is not too
big a step from considering writing to accommodate real hardware variation
to considering writing to accommodate emulators also.

From what I have seen I suspect that a lot of differences between hardware
and emulators (and between different pieces of hardware) could be dealt with
by writing defensively. I found that the well-known old Toshiba Tecra A20
hardware issue was purely down to timing of a few microseconds. A defensive
check at the end of the A20 enable routine would have dealt with it
properly.

There is no way we as OS developers can test on all hardware. Even if we get
a piece of code working on a few machines there is no guarantee that it will
work the same way on other machines (or emulators).

So as well as writing defensively, IMO it is essential that when something
does go wrong an OS module is able to record enough info to allow the
program writer to understand the issue and rectify it in the next release of
the code. That's probably fairly obvious but I've rarely, if ever, seen code
which adequately records such info.

For example, taking the current case in point, when carrying out a PIO read
of a sector we would expect DRQ to be set for all 256 words and to clear as
the last word is read at the end. We could check it before each word. Or we
could do something slightly less costly and: check that it is set, read 255
words, check that it is still set, read the last word and then check it
again to make sure it has cleared. That way we can be more confident that
the protocol is working as expected.

There are lots of opportunities for such checking - effectively confirming
that the hardware is behaving as expected. In reality this doesn't just
check the hardware but also serves to check that the software processing is
running in lock-step with the hardware, i.e. that our software is correct
not just under testing but each time it runs.

Going back to your comment on hardware/emulator differences, as you say
faults may be due to coding errors. I suspect many faults are due to very
small issues that could be resolved by defensive programming - especially
where timings are concerned - and by recording of anything unexpected.

James


s_dub...@yahoo.com

unread,
Dec 21, 2013, 11:53:06 AM12/21/13
to
On Friday, December 20, 2013 6:59:10 PM UTC-6, James Harris wrote:
> "wolfgang kern" <now...@never.at> wrote in message
>
> news:l92fia$8r1$1...@newsreader2.utanet.at...
>
> >
>
> > James Harris wrote:
>
> > [about IRQ from HD(s)]
>
[snip]
>
>
> > I just ignore them by INT_ACK+IRET.
>
> You mean you ignore those interrupts and so ignore the devices? Or do you
> poll those devices separately outside the interrupt mechanism?
>

Probably not OR, but AND. I know the subject is about HD access, but regarding the keyboard handler, when I wrote polling code to test the 8042 status register for scancodes I got occasional erratic results until I also replaced the Int 09h (IRQ 1) handler with just that: EOI, IRET. I went the polling route in order to test and gain confidence as to what the 8042 was doing before dropping the polling code and implementing an Int 09h handler. In hindsight, it is more obvious that there will be trouble with both the polling code and the interrupt handler code competing for data and status.

Steve

>
>
> James

Rod Pemberton

unread,
Dec 21, 2013, 6:25:42 PM12/21/13
to
On Sat, 21 Dec 2013 06:47:39 -0500, James Harris
<james.h...@gmail.com> wrote:
> "Rod Pemberton" <dont_us...@xnohavenotit.cnm> wrote in message
> news:op.w8fjb6175zc71u@localhost...
>> On Fri, 20 Dec 2013 09:36:19 -0500, James Harris
>> <james.h...@gmail.com> wrote:

>>> Also, isn't there a way to distinguish interrupt sources that
>>> doesn't involve PCI?
>>
>> [...]
>
>> From what I've read here, it seems that you can assign a
>> device an interrupt for APIC or LAPIC, so why would you
>> share interrupts for hard drives?
>
> [...]
>
> The sixteen-IRQ limit shouldn't be a big problem, though. It is easy
> enough to share interrupt vectors at least at the software level.
> The service routine can just call each potential handler in sequence.

Can it?

That would imply (to me at least...) that each service routine already
has a method to discriminate against incorrect devices to prevent
code which is not correct for that device from executing. I.e., no
need to distinguish.

> For example, if IRQ14 is shared by an ATA controller and two other
> devices (A and B) the OS service routine can include
>
> fired = 0;
> fired += device_A_handler(device_A_id);
> fired += device_B_handler(device_B_id);
> fired += ata_handler(ata_id);
>
> In real code these would probably be executed in a loop which read the
> handler routine and device id from a list. Then the code could support an
> arbitrary number of handlers. (For level-triggered interrupts it might be
> possible and faster to handle one at a time if the code was more complex
> and handled rotating of priorities within a given IRQ but that's a bit
> off
> topic just now.)

So, an interrupt, say for 'device_A' is triggered and you plan on calling
handlers for 'device_A', 'device_B', and 'ata', i.e., all available
handlers.
Again, that seems to imply the 'device_B_handler' can identify and reject
'device_A', ditto 'ata_handler'. So, where exactly is the distinguish
issue?

> The idea of the "fired" variable is to document how many interrupts were
> handled by the sequence. This is mainly for logging purposes but it might
> also be handy to know if no interrupts were found to be ready in case
> that indicated an error.

It might also be useful to know which interrupt fired. From the code, it's
not possible to tell if the handler's are returning 0 or 1, so 'fired' is
just selectively incrementing by one. Alternately, the handler might be
returning a 0 or #define with a or'able/maskable bit value indicating
exactly
which interrupt fired. I would expect '+=' (arithmetic addition) if
returning
a 0 or 1 value, but '|=' (logical-or assign) if returning an
or'able/maskable
bit value, e.g. if returning zero or one of these for it's respective
handler:

#define DEVICE_A 1 /* 'fired' return value for device_A_handler */
#define DEVICE_B 2 /* 'fired' return value for device_B_handler */
#define DEVICE_ATA 4 /* 'fired' return value for ata_handler */
...


Rod Pemberton

James Harris

unread,
Dec 21, 2013, 7:08:38 PM12/21/13
to
"Rod Pemberton" <dont_us...@xnohavenotit.cnm> wrote in message

...

>> The sixteen-IRQ limit shouldn't be a big problem, though. It is easy
>> enough to share interrupt vectors at least at the software level.
>> The service routine can just call each potential handler in sequence.
>
> Can it?
>
> That would imply (to me at least...) that each service routine already
> has a method to discriminate against incorrect devices to prevent
> code which is not correct for that device from executing. I.e., no
> need to distinguish.

Each service routine would need to know if its device is requesting service.
As an example, the ATA handler would need a way to tell if the ATA
controller is requesting service. That is the point of this thread. (The ATA
controller doesn't make its INTRQ state visible but as discussed there seem
to be ways around it.)

>> For example, if IRQ14 is shared by an ATA controller and two other
>> devices (A and B) the OS service routine can include
>>
>> fired = 0;
>> fired += device_A_handler(device_A_id);
>> fired += device_B_handler(device_B_id);
>> fired += ata_handler(ata_id);
>>
>> In real code these would probably be executed in a loop which read the
>> handler routine and device id from a list. Then the code could support an
>> arbitrary number of handlers. (For level-triggered interrupts it might be
>> possible and faster to handle one at a time if the code was more complex
>> and handled rotating of priorities within a given IRQ but that's a bit
>> off
>> topic just now.)
>
> So, an interrupt, say for 'device_A' is triggered and you plan on calling
> handlers for 'device_A', 'device_B', and 'ata', i.e., all available
> handlers.

Not all available handlers but all those registered for the current
interrupt. In the example, devices A and B and the ATA disk are all sharing
the same IRQ, say IRQ14.

> Again, that seems to imply the 'device_B_handler' can identify and reject
> 'device_A', ditto 'ata_handler'. So, where exactly is the distinguish
> issue?

When IRQ14 fires we don't know whether device A or B or the hard drive
controller caused it. It is possible that two or even all three of them are
requesting service.

So each handler has to check whether its device has requested service or
not. The code for each device would be something like

if (my device has requested service) {
service the device;
return 1;
}
return 0;

In practice the code might be reorganised but you get the idea.

James


Rod Pemberton

unread,
Dec 22, 2013, 2:11:29 AM12/22/13
to
On Sat, 21 Dec 2013 08:15:42 -0500, James Harris
<james.h...@gmail.com> wrote:
> "Rod Pemberton" <dont_us...@xnohavenotit.cnm> wrote in message
> news:op.w8fjdyw55zc71u@localhost...
...

>>>> Are you using an emulator? Or, were you using real hardware? ...
>>>
>>> Does it make a difference? I was just going by the specs.
>>
>> It might.
>>
>
> Interesting point. My intention for now is just to write to the ATA
> specs.

A comment in this a.o.d. thread indicates Bochs had/has a problem with ATA:
https://groups.google.com/d/msg/alt.os.development/K73doPm4T3w/3L8KjHVt63EJ


Rod Pemberton

Rod Pemberton

unread,
Dec 22, 2013, 2:52:17 AM12/22/13
to
On Sat, 21 Dec 2013 19:08:38 -0500, James Harris
<james.h...@gmail.com> wrote:
> "Rod Pemberton" <dont_us...@xnohavenotit.cnm> wrote in message
...

> When IRQ14 fires we don't know whether device A or B or the hard
> drive controller caused it. It is possible that two or even all
> three of them are requesting service.
>

For my sanity, which ports are we talking about exactly?

...

My understanding is that these are the historical IDE ports
and interrupts:

IDE 0x1f0 thru 0x1f7, 0x3f6, 0x3f7, IRQ 14
IDE 0x170 thru 0x177, 0x376, 0x377, IRQ 15 (or alt. IRQ 10)
IDE 0x1e8 thru 0x1ef, 0x3ee, 0x3ef, IRQ 11 (or alt. IRQ 12)
IDE 0x168 thru 0x16f, 0x36e, 0x36f, IRQ 10 (or alt. IRQ 9)

The alternate (alt.) IRQs conflict with standard IRQs, but
might've been used on some machines or add-on cards.

Some versions of Linux support these:

IDE 0x1e0 thru 0x1e7, 0x3e6, 0x3e7, IRQ 8
IDE 0x160 thru 0x167, 0x366, 0x367, IRQ 12

I have no idea why... I could presume they are for an add-on
hard disk card, which PCs no longer use. I'm not sure if
they replace the others above or are in addition to them.

All sample code I have indicates you program the IDE through
the ports. E.g., it's a sequence something like (for base 0x1f0):

Wait 400ns, check 0x1f7 for not busy, send 0x1f2 through 0x1f5,
wait 440ns, check 0x1f7 for not busy, check 0x3f6 for not busy,
0x3f6 for device ready, send 0x1f7 command, repeat check 0x1f7
and 0x3f6 checks, wait, check again, and read/write 0x1f0.

None of the sample code waits for an IRQ.

IDE 0x1f0 seems to have a status register 0x1f7, alternate status
register 0x3f6, and an error register 0x1f1. So, maybe, a
combination of bits in those registers or equivalent appropriate
register, the base port, and the IRQ number, perhaps, could be enough
to distinquish the device. But, mostly, it seems that historically,
each disk device was on a different IRQ and *not* shared.

I'm not clear on how and when an IDE device generates an interrupt.
IIRC, installable cards could set the IRQ on hardware lines of the
card interface. I'd assume motherboard hardware could or does the
same, but I'm not sure under what conditions. I know that interrupts
are (un)maskable in the PIC, and IRQ 14 is the first AT hard disk while
IRQ 15 is the second AT hard disk. (BTW, IRQ 5 is the XT hard disk.)
This implies the hardware is tied to IRQ 14 and IRQ 15, at least for
the first two hard disks... IRQ 10 and IRQ 11 could be unmasked in
the PIC, if needed, but, officially, those IRQs are "reserved".


Rod Pemberton

wolfgang kern

unread,
Dec 22, 2013, 5:56:17 AM12/22/13
to

Rod Pemberton asked:
...
>> When IRQ14 fires we don't know whether device A or B or the hard
>> drive controller caused it. It is possible that two or even all
>> three of them are requesting service.

> For my sanity, which ports are we talking about exactly?

> My understanding is that these are the historical IDE ports
> and interrupts:
>
> IDE 0x1f0 thru 0x1f7, 0x3f6, 0x3f7, IRQ 14
> IDE 0x170 thru 0x177, 0x376, 0x377, IRQ 15 (or alt. IRQ 10)
> IDE 0x1e8 thru 0x1ef, 0x3ee, 0x3ef, IRQ 11 (or alt. IRQ 12)
> IDE 0x168 thru 0x16f, 0x36e, 0x36f, IRQ 10 (or alt. IRQ 9)

[...]

I never saw any mainboard supporting any other than 01F0 and 0170
let aside the SATA native IDE yet (ie: ports 0x0A000+0x09002 ...).

But I have two harddisks connected to port 01F0 (master/slave),
and they of course share one IRQ-pin. Same for port 0170.
So I renounced to figure which one fired an IRQ and just remember
which device were ordered to do something within a certain time.
And my main idle loop can perform other things during 'while wait'
for completion or timout or error.
__
wolfgang


wolfgang kern

unread,
Dec 22, 2013, 8:01:45 AM12/22/13
to

James Harris wrote:

>> [about IRQ from HD(s)]
>>
>> Yeah,
>> there once were a standard for
>> master/slave IDE_0 use IRQ_0E and
>> master/slave IDE_1 use IRQ_0F. (or opposite ? either way...)
>>
>> But now when I look at my old present PC then I find already
>> connected five HDs plus one DVD which all can be programmed
>> and be used in native SATA (IDE-mode) regardless is they show
>> advanced featurs like NativeJobCollections ...

> I remember one PC which had quite a high number of devices on each of the
> sharable interrupts - at least the BIOS set it up that way when it was set
> for a non-PnP OS. There are many permutations but it is possible that an
> OS > may have to run on a machine which has many devices sharing a disk
> interrupt - disks and other things.

Yes, but I see too much overhead with shared IRQs.

>> I just ignore them by INT_ACK+IRET.

> You mean you ignore those interrupts and so ignore the devices?

:) I just ignore IRQ14/15, not the devices of course.

> Or do you poll those devices separately outside the interrupt mechanism?

I let my OS remember the last command sent to a HD and set a timeout
counter for every device. And then I see not much difference between
"wait for IRQ" and "wait for completion/timeout/error", except that
the latter saves me from 'WhoDidIt' and may already contain all info.

[...OK let aside APIC yet]
> The idea is that that should work on any AT or later compatible.

> Current thought:

> 1. For PIO (which seems to be the only option on machines which predate
> PCI) check the status register's DRQ bit. This bit apparently indicates
> that the > current drive wants to read or write via its data port. Timing
> could be an issue in that something else may have triggered the interrupt
> but by the time the ISR starts running the disk has also asserted its
> INTRQ state. However, even if that happened I think it would still be OK
> to service the drive and clear its interrupt state just as if the drive
> had been the first > to trigger the interrupt condition. The
> originally-asserting device could also be serviced before returning to the
> interrupted task.

The BIOS may see addon cards (IIRC they reside on ISA-slots) and assign
shared IRQ14/15 to it. But methink this is history from last century :)

AFAIK we cannot access master and slave on one port at the same time anyway.
So this shared IRQ14/15-issue might be just a theoretical one for old PCs ?
Mostly there are only four connectors for internal IDE-HDs.

[...DMA]

> Bottom line is that the most basic and most universal approach seems to be
> to read and write using PIO, to handle one request to a disk controller at
> a time, and to examine the DRQ bit to find out whether a drive needs
> service. Does that sound about right?

Yeah, even I see it in the opposite direction:
The Data-Request-Bit will only be active after a sent command and
may rare (defective HW) occure unexpected.

> I don't like the idea of carrying out a 256-word PIO transfer in an ISR
> (and that's just for one sector) but it seems to be unavoidable. Leaving
> the sector to be transferred after the interrupt has been acknowledged and
> the ISR has returned might be possible but seems dangerous. On the other
> hand, not acknowledging the interrupt in the ISR (and relying on the fact
> that AT > IRQs are edge triggered) seems that it would be unreliable.

The EOI affects the PIC only, while the int-Bit in the IDE-status register
remain active until port 01f7 read, but read from 03f6 doesn't clear it.

> So I am left with carrying out the 256-word transfer in the ISR. Best I
> can > think of in order to avoid impacting the response time of other
> interrupts is to make the normal disk interrupts (14 and 15) the lowest
> priority. Then > at least devices on other IRQs will be able to interrupt
> the PIO transfers ... I think.

> AIUI this should be possible as long as higher priority devices can
> interrupt the CPU. For that, ISTM that I would have to avoid sending EOI
> to > the PICs and yet would have to reenable CPU interrupts. So the
> service routine would have the following outline.
>
> service routine:
> ;save registers etc
> ...
> sti ;enable CPU interrupts while we handle this ISR
> ...
> ;If needed carry out PIO transfer
> ...
> ;End of service routine
> cli
> mov al, 0x20
> out 0x00a0, al
> out 0x0020, al
> ... ;restore registers
> iret

a possible solution, but it wont save you from polling for
'write successful', 'data-available', 'error' or 'timeout'.

if you mean to run older PCs be aware of interrupted REP issues.

[...]

> It has been quiet in aod recently hasn't it!

seems folks are busy with shopping for X-mas :)
__
wolfgang


James Harris

unread,
Dec 22, 2013, 6:33:06 PM12/22/13
to
"Rod Pemberton" <dont_us...@xnohavenotit.cnm> wrote in message
news:op.w8hhhfb45zc71u@localhost...
> On Sat, 21 Dec 2013 19:08:38 -0500, James Harris
> <james.h...@gmail.com> wrote:
>> "Rod Pemberton" <dont_us...@xnohavenotit.cnm> wrote in message
> ...
>
>> When IRQ14 fires we don't know whether device A or B or the hard
>> drive controller caused it. It is possible that two or even all
>> three of them are requesting service.
>>
>
> For my sanity, which ports are we talking about exactly?

I'm not sure I understand. I wasn't talking about ports!

Am happy to talk about ports but this was purely about interrupts - how to
recognise that a particular hard drive needs service if the controller that
the drive is connected to is using an interrupt which might be shared with
one or more other interrupt sources.

If you are asking about why I mentioned IRQ14 that was just an example. That
particular IRQ might relate to the controller which is programmed on ports
0x1f0 etc but the same interrupt sharing principles would apply to IRQ15 and
ports 0x170 etc or any other combination.

> My understanding is that these are the historical IDE ports
> and interrupts:
>
> IDE 0x1f0 thru 0x1f7, 0x3f6, 0x3f7, IRQ 14
> IDE 0x170 thru 0x177, 0x376, 0x377, IRQ 15 (or alt. IRQ 10)
> IDE 0x1e8 thru 0x1ef, 0x3ee, 0x3ef, IRQ 11 (or alt. IRQ 12)
> IDE 0x168 thru 0x16f, 0x36e, 0x36f, IRQ 10 (or alt. IRQ 9)
>
> The alternate (alt.) IRQs conflict with standard IRQs, but
> might've been used on some machines or add-on cards.
>
> Some versions of Linux support these:
>
> IDE 0x1e0 thru 0x1e7, 0x3e6, 0x3e7, IRQ 8
> IDE 0x160 thru 0x167, 0x366, 0x367, IRQ 12
>
> I have no idea why... I could presume they are for an add-on
> hard disk card, which PCs no longer use. I'm not sure if
> they replace the others above or are in addition to them.
>
> All sample code I have indicates you program the IDE through
> the ports. E.g., it's a sequence something like (for base 0x1f0):
>
> Wait 400ns, check 0x1f7 for not busy, send 0x1f2 through 0x1f5,
> wait 440ns, check 0x1f7 for not busy, check 0x3f6 for not busy,
> 0x3f6 for device ready, send 0x1f7 command, repeat check 0x1f7
> and 0x3f6 checks, wait, check again, and read/write 0x1f0.

Yes, that's the kind of thing and as part of this discussion someone
(possibly me) came up with the idea of restricting interrupt-driven ATA IO
to single-threaded PIO only and reading the DRQ bit from the status register
to determine whether the drive needed service. I haven't tested it. So far
it is only theory.

> None of the sample code waits for an IRQ.

An ATA controller can be told not to generate interrupts by setting the nIEN
(not interrupt enable) bit but interrupts are desirable for all the usual
reasons.

Incicentally, the "n" in nIEN is there to negate the logic. I would have
thought it would be better to call the bit IDIS meaning interrupt disable.
Then a 1 means interrupt disable and a 0 means interrupt not disabled.
Exactly the same meaning and interpretation but just an easier-to-use name.

> IDE 0x1f0 seems to have a status register 0x1f7, alternate status
> register 0x3f6, and an error register 0x1f1. So, maybe, a
> combination of bits in those registers or equivalent appropriate
> register, the base port, and the IRQ number, perhaps, could be enough
> to distinquish the device. But, mostly, it seems that historically,
> each disk device was on a different IRQ and *not* shared.
>
> I'm not clear on how and when an IDE device generates an interrupt.
> IIRC, installable cards could set the IRQ on hardware lines of the
> card interface. I'd assume motherboard hardware could or does the
> same, but I'm not sure under what conditions. I know that interrupts
> are (un)maskable in the PIC, and IRQ 14 is the first AT hard disk while
> IRQ 15 is the second AT hard disk. (BTW, IRQ 5 is the XT hard disk.)
> This implies the hardware is tied to IRQ 14 and IRQ 15, at least for
> the first two hard disks... IRQ 10 and IRQ 11 could be unmasked in
> the PIC, if needed, but, officially, those IRQs are "reserved".

IIRC some IRQ lines such as 0 (timer) and 1 (keyboard) are dedicated and
others, including those used for hard disks, 14 and 15 are carried to the
bus and are shareable. Unless we can be sure that an ATA controller is the
only user of, say, IRQ14 then when IRQ14 fires we need to know how to find
out whether the disk is requesting service.

James


James Harris

unread,
Dec 22, 2013, 6:40:31 PM12/22/13
to
"Rod Pemberton" <dont_us...@xnohavenotit.cnm> wrote in message
news:op.w8hflfnk5zc71u@localhost...
Thanks. I took a look at it. It may be that Bochs had a fault but it seems
possible that Bochs of that era was working to ATA1 standards. I found that
ATA1 expects the drive/head register to be set as

1x1x_xxxx

Those 1 bits are, in ATA2, defined to be ignored.

Bochs now works to ATA6, IIRC.

James


Rod Pemberton

unread,
Dec 22, 2013, 8:06:59 PM12/22/13
to
On Sun, 22 Dec 2013 18:33:06 -0500, James Harris
<james.h...@gmail.com> wrote:
> "Rod Pemberton" <dont_us...@xnohavenotit.cnm> wrote in message
> news:op.w8hhhfb45zc71u@localhost...
>> On Sat, 21 Dec 2013 19:08:38 -0500, James Harris
>> <james.h...@gmail.com> wrote:
>>> "Rod Pemberton" <dont_us...@xnohavenotit.cnm> wrote in message
...

>> For my sanity, which ports are we talking about exactly?
>
> I'm not sure I understand. I wasn't talking about ports!
>

I know you weren't discussing ports, but the controller interfaces for
specific devices are either: 1) memory mapped or 2) port mapped.
ISTM there is a correlation between ports and IRQs. This necessitates
knowing which ports we're discussing.

> Am happy to talk about ports but this was purely about interrupts - how
> to recognise that a particular hard drive needs service if the controller
> that the drive is connected to is using an interrupt which might be
> shared
> with one or more other interrupt sources.

Well, I can't confirm it's purely about interrupts. Most likely you'll
need to read or read back some information from the device controller,
or perhaps cache/save it like Wolfgang.

> Unless we can be sure that an ATA controller is the only user of, say,
> IRQ14 then when IRQ14 fires we need to know how to find out whether
> the disk is requesting service.

For 0x1f0 or respective ports, one of the IDE interface registers has
the device, master or slave, that is written to or read from.

The notes I have indicate that when 0x3f7 (or 0x377 for 0x170) is used
for IDE instead of for a floppy, it's setup like so:

7 6 5 4 3 2 1 0
- nWTG nHS3 nHS2 nHS1 nHS0 nDS1 nDS0

(bit7 tri-state for IDE)
(bits 6 thru 0 tri-stated for floppy - bit7 is disk change)

That register decsription should probably be in the specifications...

nDS0 and nDS1 are drive select bits for master and slave. I.e., you
could read these during IRQ14. See, this is where the ports question
comes into play...

If there are multiple _different_ devices on IRQ14, say a mouse and
a hard disk, then you most likely would need to read respective
controllers or interfaces.


Rod Pemberton

James Harris

unread,
Dec 22, 2013, 8:05:55 PM12/22/13
to
"wolfgang kern" <now...@never.at> wrote in message
news:l96nta$24u$2...@newsreader2.utanet.at...
>
> James Harris wrote:
>
>>> [about IRQ from HD(s)]
>>>
>>> Yeah,
>>> there once were a standard for
>>> master/slave IDE_0 use IRQ_0E and
>>> master/slave IDE_1 use IRQ_0F. (or opposite ? either way...)
>>>
>>> But now when I look at my old present PC then I find already
>>> connected five HDs plus one DVD which all can be programmed
>>> and be used in native SATA (IDE-mode) regardless is they show
>>> advanced featurs like NativeJobCollections ...
>
>> I remember one PC which had quite a high number of devices on each of the
>> sharable interrupts - at least the BIOS set it up that way when it was
>> set for a non-PnP OS. There are many permutations but it is possible that
>> an OS > may have to run on a machine which has many devices sharing a
>> disk interrupt - disks and other things.
>
> Yes, but I see too much overhead with shared IRQs.

They may be hard to avoid. If there are more interrupting sources than IRQs
some have to be shared.

Just thinking about how they might be laid out:

0 timer
1 keyboard
2 cascade
3 serial
4 serial
5 parallel
6 floppy
7 parallel
8 rtc
9 available
10 available
11 available
12 mouse
13 copro or available
14 ata
15 ata

Things to add might include: audio, network card, graphics card, usb, modem,
firewire etc. Just checking the old laptop I am typing this on, XP has some
unused IRQs but IRQ9 is shared among no fewer than seven (7) devices! (Info
from Device Manager -> View -> Resources by either Type or Connection.) That
said, most are PCI interrupts which may work differently.

>>> I just ignore them by INT_ACK+IRET.
>
>> You mean you ignore those interrupts and so ignore the devices?
>
> :) I just ignore IRQ14/15, not the devices of course.
>
>> Or do you poll those devices separately outside the interrupt mechanism?
>
> I let my OS remember the last command sent to a HD and set a timeout
> counter for every device. And then I see not much difference between
> "wait for IRQ" and "wait for completion/timeout/error", except that
> the latter saves me from 'WhoDidIt' and may already contain all info.

You mean you check for completion after a certain amount of time? That's
novel! Isn't it relatively slow because it increases latency?

> [...OK let aside APIC yet]
>> The idea is that that should work on any AT or later compatible.
>
>> Current thought:
>
>> 1. For PIO (which seems to be the only option on machines which predate
>> PCI) check the status register's DRQ bit. This bit apparently indicates
>> that the > current drive wants to read or write via its data port. Timing
>> could be an issue in that something else may have triggered the interrupt
>> but by the time the ISR starts running the disk has also asserted its
>> INTRQ state. However, even if that happened I think it would still be OK
>> to service the drive and clear its interrupt state just as if the drive
>> had been the first > to trigger the interrupt condition. The
>> originally-asserting device could also be serviced before returning to
>> the interrupted task.
>
> The BIOS may see addon cards (IIRC they reside on ISA-slots) and assign
> shared IRQ14/15 to it. But methink this is history from last century :)
>
> AFAIK we cannot access master and slave on one port at the same time
> anyway.
> So this shared IRQ14/15-issue might be just a theoretical one for old PCs
> ?
> Mostly there are only four connectors for internal IDE-HDs.

An ATA controller can support two ATA drives, master and slave. It has to be
unusual for a PC to access both at the same time but it is possible such as
when copying from one drive to the other. And a server might do so more
often. From what I have seen recently it seems that the Overlapped command
set is there to allow concurrent IOs to master and slave (ATA4 and later).
IIRC it requires use of DMA and won't work with PIO.
Good point about timeout etc.

Write DMA generates an interrupt on completion. I think Write Sectors (the
PIO version) does too. Not certain though.

> if you mean to run older PCs be aware of interrupted REP issues.

Good reminder. Thanks.

James


James Harris

unread,
Dec 22, 2013, 8:56:11 PM12/22/13
to
"Rod Pemberton" <dont_us...@xnohavenotit.cnm> wrote in message

...

> The notes I have indicate that when 0x3f7 (or 0x377 for 0x170) is used
> for IDE instead of for a floppy, it's setup like so:
>
> 7 6 5 4 3 2 1 0
> - nWTG nHS3 nHS2 nHS1 nHS0 nDS1 nDS0
>
> (bit7 tri-state for IDE)
> (bits 6 thru 0 tri-stated for floppy - bit7 is disk change)
>
> That register decsription should probably be in the specifications...
>
> nDS0 and nDS1 are drive select bits for master and slave. I.e., you
> could read these during IRQ14. See, this is where the ports question
> comes into play...

OK, I understand your point about ports. I think the port you are referring
to is the Drive Address Register. It was present in ATA1. I'm not sure that
it survived into later standards. However, as long as we wait for an
operation to complete to one of the two drives at a time - i.e. we
single-thread the disk controller driver - we can remember which drive we
are waiting for so the interrupt handler will always know which drive is
current. The DRV bit in the drive/head register 0x1f6 might also do the job
but simply remembering the current drive id would be faster.

> If there are multiple _different_ devices on IRQ14, say a mouse and
> a hard disk, then you most likely would need to read respective
> controllers or interfaces.

Yes, that is exactly the point. Some devices present their interrupt request
state in a bit that a program can read but ATA controllers do not. They have
an internal INTRQ state but it is hidden from programmers. It is therefore a
challenge for software to find out whether a given ATA controller is making
an interrupt request or not. Am thinking it might be possible to read the
Status Register (0x1f7) and check the DRQ bit (PIO transfers only).

It should be said that I was looking for an ATA-only solution. PCI is
available on all machines apart from the very old ones. With ATA and PCI
programming done together a lot of the above would not be necessary.

James


James Harris

unread,
Dec 23, 2013, 7:52:43 AM12/23/13
to
"wolfgang kern" <now...@never.at> wrote in message
news:l96nta$24u$2...@newsreader2.utanet.at...

...

>> I remember one PC which had quite a high number of devices on each of the
>> sharable interrupts - at least the BIOS set it up that way when it was
>> set for a non-PnP OS. There are many permutations but it is possible that
>> an OS > may have to run on a machine which has many devices sharing a
>> disk interrupt - disks and other things.
>
> Yes, but I see too much overhead with shared IRQs.

I have been thinking about that comment. I assume you mean the cost of
checking devices to see if they had generated an interrupt. For each shared
interrupt the cost might be one port read per device (to see if that device
is requesting service).

Thinking about it, though, that doesn't seem too bad especially when a
machine with lots of devices is likely to be a more recent one with faster
IO.

If a certain IRQ had four devices then sharing it it would require a max of
three extra checks. As long as that interrupt did not fire very often the
cost would be very small.

...


> if you mean to run older PCs be aware of interrupted REP issues.

I have been trying to find/recall what these were. Best I have come up with
is a bug on certain CPUs that when an instruction with more than one prefix
is interrupted the return from the interrupt service routine fails to go
back to the first prefix. About right?

I found a comment that this bug was fixed in 80386 CPUs onward so all 386s
and later should be OK. Is that too simplistic?

Some refs in case anyone else is interested.

http://computer-programming-forum.com/46-asm/b067286619bbafa2.htm
https://groups.google.com/forum/#!topic/comp.lang.asm.x86/1HS_V0bp-iE

If it is a problem it would apply to all code that can be interrupted, even
user code, so hopefully it is not an issue on any processor we might use.

James


wolfgang kern

unread,
Dec 23, 2013, 8:49:54 AM12/23/13
to

James Harris wrote:

[about ...]
>> Yes, but I see too much overhead with shared IRQs.

> I have been thinking about that comment. I assume you mean the cost of
> checking devices to see if they had generated an interrupt. For each
> shared > interrupt the cost might be one port read per device (to see if
> that device > is requesting service).

> Thinking about it, though, that doesn't seem too bad especially when a
> machine with lots of devices is likely to be a more recent one with faster
> IO.

> If a certain IRQ had four devices then sharing it it would require a max
> of > three extra checks. As long as that interrupt did not fire very often
> the cost would be very small.

I/O-ports are still today the main bottleneck for performance.
For me also the IRQ-mechanics eats too many clock-cycles, and
because an IRQ from any HD doesn't tell me the reason for it,
I try to disable and ignore IRQ14/15.

Sure, if I'd send commands to four HDs in one sequence then this
needs also four checks for completion.

> ...

>> if you mean to run older PCs be aware of interrupted REP issues.
> I have been trying to find/recall what these were. Best I have come up
> with > is a bug on certain CPUs that when an instruction with more than
> one prefix is interrupted the return from the interrupt service routine
> fails to go back to the first prefix. About right?

yes,

> I found a comment that this bug was fixed in 80386 CPUs onward so all 386s
> and later should be OK. Is that too simplistic?

IIRC this bug was also found on early 386.

> Some refs in case anyone else is interested.
>
> http://computer-programming-forum.com/46-asm/b067286619bbafa2.htm
> https://groups.google.com/forum/#!topic/comp.lang.asm.x86/1HS_V0bp-iE

> If it is a problem it would apply to all code that can be interrupted,
> even > user code, so hopefully it is not an issue on any processor we
> might use.

I hope so for all who use older machines, in my area, inclusive all my
customers, 386,486, Pentium and Athlon are already out and just history.

__
wolfgang


James Harris

unread,
Dec 23, 2013, 3:13:38 PM12/23/13
to
"James Harris" <james.h...@gmail.com> wrote in message
news:l982ar$oak$1...@dont-email.me...

...

> ... Just checking the old laptop I am typing this on, XP has some unused
> IRQs but IRQ9 is shared among no fewer than seven (7) devices! (Info from
> Device Manager -> View -> Resources by either Type or Connection.) That
> said, most are PCI interrupts which may work differently.

A minor follow up on that. I found a relevant Microsoft knowledgebase
article. It doesn't really have enough detail to be useful but it does talk
about XP's IRQ9 sharing.

http://support.microsoft.com/kb/314068

James


Rod Pemberton

unread,
Dec 23, 2013, 4:27:20 PM12/23/13
to
On Sun, 22 Dec 2013 20:56:11 -0500, James Harris
<james.h...@gmail.com> wrote:

> Yes, that is exactly the point. Some devices present their interrupt
> request state in a bit that a program can read but ATA controllers
> do not. They have an internal INTRQ state but it is hidden from
> programmers. It is therefore a challenge for software to find out
> whether a given ATA controller is making an interrupt request or not.

Does the BIOS "know" how to do this?

If so, then a v86 emulator that traps and displays ports could reveal
some of what the BIOS does.

Otherwise, I'd have to restart my OS project and get up to date on
ATA, ATAPI, IDE, SATA, etc to come to any further conclusions.


Rod Pemberton

Rod Pemberton

unread,
Dec 23, 2013, 4:53:27 PM12/23/13
to
On Mon, 23 Dec 2013 07:52:43 -0500, James Harris
<james.h...@gmail.com> wrote:
> "wolfgang kern" <now...@never.at> wrote in message
> news:l96nta$24u$2...@newsreader2.utanet.at...

>> if you mean to run older PCs be aware of interrupted REP issues.
>
> I have been trying to find/recall what these were. Best I have come up
> with is a bug on certain CPUs that when an instruction with more than one
> prefix is interrupted the return from the interrupt service routine fails
> to go back to the first prefix. About right?
>
> I found a comment that this bug was fixed in 80386 CPUs onward so all
> 386s and later should be OK. Is that too simplistic?
>
> Some refs in case anyone else is interested.
>
> http://computer-programming-forum.com/46-asm/b067286619bbafa2.htm
> https://groups.google.com/forum/#!topic/comp.lang.asm.x86/1HS_V0bp-iE
>

I have these listed in my personal notes on the various x86 bugs and
undocumented opcodes:

1) 386 DX had a problem with REP INSB, if CX was one, CX was not
decremented
2) 386 DX had a problem with REP MOVS when used with a size prefix, then
the
next intruction needed a size prefix also

Unfortunately, I didn't keep a list of references or sources. I know
there is a big text file in RBIL called 86BUGS.LST by Harald Feldmann.
(IIRC, you're familiar with it.)


Rod Pemberton

Rod Pemberton

unread,
Dec 23, 2013, 4:53:34 PM12/23/13
to
On Sun, 22 Dec 2013 20:05:55 -0500, James Harris
<james.h...@gmail.com> wrote:

> Just checking the old laptop I am typing this on, XP has
> some unused IRQs but IRQ9 is shared among no fewer than
> seven (7) devices! [...] That said, most are PCI interrupts
> which may work differently.

Is that for APIC or LAPIC?

I really wouldn't expect more than a couple shared devices with
the old PICs. Although, I guess the machine could support at least
as many devices on one IRQ as you have slots for cards ... and
maybe another one or two for the motherboard devices.


Rod Pemberton

James Harris

unread,
Dec 23, 2013, 5:28:17 PM12/23/13
to
"Rod Pemberton" <dont_us...@xnohavenotit.cnm> wrote in message
news:op.w8kdvubj5zc71u@localhost...
> On Sun, 22 Dec 2013 20:56:11 -0500, James Harris
> <james.h...@gmail.com> wrote:
>
>> Yes, that is exactly the point. Some devices present their interrupt
>> request state in a bit that a program can read but ATA controllers
>> do not. They have an internal INTRQ state but it is hidden from
>> programmers. It is therefore a challenge for software to find out
>> whether a given ATA controller is making an interrupt request or not.
>
> Does the BIOS "know" how to do this?
>
> If so, then a v86 emulator that traps and displays ports could reveal
> some of what the BIOS does.

Sounds like a lot of work when I already have an easy possible solution
based on the specs!

James


James Harris

unread,
Dec 23, 2013, 5:45:19 PM12/23/13
to
"Rod Pemberton" <dont_us...@xnohavenotit.cnm> wrote in message
news:op.w8ke3krq5zc71u@localhost...
> On Sun, 22 Dec 2013 20:05:55 -0500, James Harris
> <james.h...@gmail.com> wrote:
>
>> Just checking the old laptop I am typing this on, XP has
>> some unused IRQs but IRQ9 is shared among no fewer than
>> seven (7) devices! [...] That said, most are PCI interrupts
>> which may work differently.
>
> Is that for APIC or LAPIC?

Sorry, I don't know. Neither seems to be mentioned.

James


wolfgang kern

unread,
Dec 24, 2013, 4:43:26 PM12/24/13
to

James Harris wrote:

>>> Yes, that is exactly the point. Some devices present their interrupt
>>> request state in a bit that a program can read but ATA controllers
>>> do not. They have an internal INTRQ state but it is hidden from
>>> programmers. It is therefore a challenge for software to find out
>>> whether a given ATA controller is making an interrupt request or not.

it's not hidden.
But if the BIOS handles it 'before you' then you may not see it.

>> Does the BIOS "know" how to do this?

I'd say yes of course!

>> If so, then a v86 emulator that traps and displays ports could reveal
>> some of what the BIOS does.

now this depends on ...

> Sounds like a lot of work when I already have an easy possible solution
> based on the specs!

I think we can trust all specs about IDE-HD and all RBIL-stuff for this.
Emulators might not be aware of all features, I never used such, so I
cant tell about their behaviour.
And if we let the BIOS handle the ports before we read them, then
we see almost nothing ...[a status-port read clears the IRQ-bit]

I still think you (to James yet) try to support something not present
anymore in the field. 386 and 486 are already dead and just history even
in low income areas like Africa and former Eastern-Europe counties.

__
wolfgang
MERRY CHRISTMAS TO EVERYONE


James Harris

unread,
Jan 15, 2014, 5:25:41 PM1/15/14
to
"James Harris" <james.h...@gmail.com> wrote in message
news:l92p4v$40e$1...@dont-email.me...

...

> Current thought:
>
> 1. For PIO (which seems to be the only option on machines which predate
> PCI) check the status register's DRQ bit. This bit apparently indicates
> that the current drive wants to read or write via its data port.

For reasons which it is not necessary to go in to the above technique for
interrupt sharing got a bit complicated with PIO writes. Fortunately, there
seems to be a much better way that will work for both reads and writes that
is simpler and more in keeping with the standards. The idea is to keep a
record of which drives the ISR is waiting for and then, in the ISR, check
whether the drive is still busy or not. Once it is no longer busy the
command it was executing has finished. Simple and logical!

The detailed justification is as follows. These comments are from the ATA2
draft standard d0948r4c-ATA-2.

For PIO reads:

---
Section 8.3
g) When the block of data is available, the device sets the DRQ bit (setting
the DRQ bit is optional if an error
condition exists). If there is an error condition, the device sets the
appropriate status and error bits as
required by that error condition. Finally, the device clears the BSY bit and
then asserts INTRQ;
---

Note that whether an error occurs or not the device clears BSY *and then*
asserts INTRQ. So if an interrupt handler waiting for a device sees BSY
cleared then it knows INTRQ is asserted.

For PIO writes the situation is more complex but amounts to the same thing:

---
Section 8.4
k) The device processes the data block just received from the host. When
this processing is completed, one
of the following actions is taken:
- If no error occurred while processing the data block and if no additional
blocks are to be transferred,
the device clears the BSY bit and then asserts INTRQ. Command execution is
complete;
- If an error occurred while processing the data block the device sets the
appropriate status and error
bits as required by that error condition. The device clears the BSY bit and
then asserts INTRQ.
Command execution is complete;
- If no error occurred while processing the data block and if transfer of
another block is required,
processing continues with the next step;
l) When ready to receive the next data block from the host, the device sets
the DRQ bit, clears the BSY bit
and then asserts INTRQ;
---

The bottom line is that in each possible PIO write outcome the device
"clears the BSY bit and then asserts INTRQ" so, again, in the interrupt
handler if we are waiting for a device and that device has BSY cleared then
we know that the device has asserted its interrupt request line.

This seems to be an ideal answer to the original question about how to share
hard disk IRQs using only the ATA system.

James


0 new messages