Reading From Void

Recently I came across the following question: What happens when software reads the registers of a non-existent IDE controller? That is, what happens when software reads for example ports in the 1F0h-1F7h/3F6h range (primary IDE channel) when there is no device on that channel?

For the vast majority of devices, the answer is simple, reads return with all bits set (0FFh). That’s when no device decodes the given address, i.e. no one claims the bus cycle/transaction. But IDE is different, because there often is a device which decodes those addresses, namely the IDE controller, usually on the motherboard within the southbridge chip.

The answer then might be buried somewhere deep in the Intel ICH datasheets or similar documentation. But it’s not.

There is only one curious piece of information in the Intel ICH6 and similar datasheets. These devices are compatible with earlier Intel chipsets which supported two IDE channels; the ICH6 still has all the primary and secondary channel registers, but physically there is no secondary channel. The ICH6 chipset was commonly used in PCs built around 2005, when it was common to have a SATA hard disk and a PATA CD/DVD-ROM (since SATA variants were rare if not unavailable).

The ICH6 IDE_TIMS register contains an enable bit documented as follows: “Enables the ICH6 to decode the associated Command Blocks (170–177h) and Control Block (376h). Accesses to these ranges return 00h, as the secondary channel is not implemented.”

The register reads clearly behave in an unusual way–rather than returning all bits set, they return all bits clear. But this is a very special case of a controller which does not even allow IDE devices to be attached, not the general case of a controller with no cable plugged in.

The Problem

Why would anyone care at all? The trouble is with software detection of IDE drives, more specifically detecting that they’re not present. The Intel ICH PRM for example suggests sending the IDENTIFY DEVICE or IDENTIFY PACKET DEVICE command. But that’s not so simple, and here’s why.

The IDE “task file” registers are only valid when the device is not busy, i.e. when the BSY bit (bit 7), in the status register (typically port 1F7h for the primary IDE channel) is clear. When BSY=1, writing commands generally produces undefined results, other bits in the status register are not valid, and other registers cannot be reliably accessed. The BSY bit will be set after drives power up and cleared once the device initialization completed.

The upshot is that software needs to wait for BSY=0 before doing anything further. But if there were no drive and register reads always returned with all bits set, it would look like the device was busy, and software would have to wait potentially a long time (about 30 seconds) before it could be certain that no device is attached, because it can take drives a while to initialize after power-up.

When the ICH6 always returns zeros on the secondary IDE controller ports, it looks to software like the drive is not busy, and it can access the other task file registers or write commands. And it will quickly establish that there’s no IDE device present. That’s clearly why the ICH6 behaves that way.

But what happens on a real IDE channel which may or may not have a drive or two attached?

Before considering that question, let’s complicate matters further by considering two cases of IDE device detection. There is the firmware (BIOS or EFI) which generally knows whether an IDE controller is present, but not whether a device is attached. An operating system on the other hand may not be able to determine whether an IDE interface is present at all, especially for secondary/tertiary/quaternary interfaces which often have no firmware support.

In the former case (firmware), drive detection generally “knows” its hardware and must rely on the BSY bit. Because the firmware runs very early, it must also expect that the BSY bit could take a few seconds to clear. The key is that the firmware normally knows whether given registers are IDE task file registers or not.

Operating systems may need to detect whether an IDE interface is present at all (i.e. if anything is decoding the registers). Such detection cannot rely on the BSY bit precisely because if there is no IDE interface, the registers will return 0FFh when read and it will look as if a drive were constantly busy. However, operating systems can typically safely assume that the drives are not busy when the detection starts, and if IDE registers return 0FFh (or zeros), there is certainly no IDE drive attached and most likely no IDE interface either.

The Answer

Looking for the answer in the ATA standards may seem pointless, because the case under consideration occurs when there is no ATA device. But it turns out the answer is there, in plain sight, just not in a place where one would probably look for it.

The early ATA standards (ATA-1 and ATA-2) have very little to say on the subject. In the ATA-3 draft standard (January 1997), clause 3.3 “Electrical characteristics” is the part which software engineers invariably skip. Said clause contains a table called “Driver types and required termination”, which certainly does not sound like it could possibly be relevant to software. It includes the following somewhat cryptic note: “Devices shall not have a pull-up resistor on DD7. It is recommended that a host have a 10 kΩ pull-down resistor and not a pull-up resistor on DD7 to allow a host to recognize the absence of a device at power-up. It is intended that this recommendation become mandatory in a future revision of this standard.”

Okay, that’s probably clear as mud to most software people. Are the newer ATA standards any easier to understand? The ATA-4 draft standard (August 1998) is not: “Devices shall not have a pull-up resistor on DD7. The host shall have a 10 kΩ pull-down resistor and not a pull-up resistor on DD7 to allow a host to recognize the absence of a device at power-up.” The only thing that changed is that the pull-down resistor on the host side is mandatory, as the ATA-3 specification forewarned.

Luckily, the ATA-5 draft standard (Feb 2000) finally provides a clear answer. The relevant text now reads: “Devices shall not have a pull-up resistor on DD7. The host shall have a 10 kΩ pull-down resistor and not a pull-up resistor on DD7 to allow a host to recognize the absence of a device at power-up so that a host shall detect BSY as being cleared when attempting to read the Status register of a device that is not present.”

In other words, a pull-down resistor is required on the host side, so that bit 7 always reads as clear when accessing registers on an IDE channel with no devices attached. This arrangement will allow software to see BSY=0 and make other register accesses valid. Software will then quickly notice that registers don’t retain values written to them and commands do not produce expected results.

So what happens with the other bits (DD0-DD6)? The ATA standard does not specify how the other signals should be terminated. Most likely they will then behave as usual and return as bits set.

Reality Check

Does real hardware follow the ATA specification? Quite unsurprisingly, at least some does. A test was performed on a ThinkPad T61p, which uses the ICH8M-E chipset.

The laptop’s CD-ROM was removed after power-up, so that there would be no device on the parallel ATA channel but everything was configured normally. DOS DEBUG was used to read from the corresponding ports. Sure enough, ports in the range 1F0h-1F7h and port 3F6h all returned the value 7Fh when read, suggesting that the host indeed has a pull-down resistor for the DD7 signal but not for the DD0-DD6 signals. Therefore, firmware may rely on the fact that if no device is present, the BSY bit will not be set.

What have we learned from this exercise? Perhaps “PCs are stupidly complicated, but all the complications are there for a reason”.

This entry was posted in BIOS, IDE, PC hardware. Bookmark the permalink.

10 Responses to Reading From Void

  1. Michal Necasek says:

    Indirectly mentioned. It just refers to “platform design recommendations”.

  2. Stu says:

    It’s a shame that there’s no way to read the Device Control register (as it shares its address with the Alternate Status register). Since its lowest bit is always 0, that would be an easy way to detect the presence/absence of a controller at least. These old interfaces with write-only registers do have a tendency to make things unnecessarily difficult in the longer term.

  3. Chris M. says:

    Amiga users have an alternative way to dealing with the “no drives connected” delay. They use an IDE terminator.

    https://www.amigawiki.org/doku.php?id=de:signals:ide_termination

    The built in Kickstart driver takes FOREVER to scan for drives that aren’t there and time out.

  4. Jack says:

    I wonder why the Kickstart does that? I’d assume the hardware would work the same way on an Amiga, but it’s possible it doesn’t…

  5. MiaM says:

    Did the earliest ISA IDE interfaces have bus buffers at all? If not, the interface was basically just an address decoder and it would be totally impossible to detect it’s precense unless a device was connected.

    Chris: Never seen any of those!

    Btw, Amiga uses a pull-down resistor on the IRQ line from the IDE/ATA interface, to get rid of the requirement to have some enable/disable logic.

    Jack: On at least the Amiga 600 and Amiga 1200, there aren’t any small ram or eeprom to write configuration data on, and there are no jumpers, so there is no way for Kickstart to know if there is a super slow disk connected or no disk at all.

    Also for those computers most users would want a hard disk connected anyways.

    For the Amiga 600 they actually shipped some computers with an older Kickstart (2.04) without the IDE/ATA support (which started to appear in Kickstart 2.05).

  6. Chris M. says:

    The Amiga 4000 has a battery, but it really just runs the clock, no PRAM on the machine that I know of. The target audience for the terminator are folks running strictly SCSI or other add-on storage devices (all usually faster thanks to using DMA).

    The onboard interface is just a bog standard PIO0 IDE controller, which can be upgraded to PIO1 with aftermarket logic upgrades. All in all, it was impressive for 1992. It could run and boot off of multi-gig hard drives with ease (4GB limit with ROM drivers, mostly because of the file system) and supported ATAPI devices with the correct device drivers without a problem.

  7. Michal Necasek says:

    That’s more like exactly the same thing. Pins 3 and 5 correspond to DD7 and DD6 signals, and the terminator forces those bits to be low when read. I assume those Amigas were built with the expectation the drive would always be present, so the host side did not have the pull-downs.

  8. Michal Necasek says:

    Early ISA IDE (or “AT Bus” as they used to be called) interfaces were not standardized at all, so you’d have to examine historic drives and interfaces to find out. As far as I know the “paddleboards” (ISA cards with 40-pin IDE connector) were trivial, all they did was decode the address ranges and pass the chip select signals to the drive. You can try figuring out from the ATA-1 spec how it was done (it’s very vague).

    I am almost certain that there we no buffers and no pull-downs, and it was not possible to detect drive presence; or rather it was not possible to quickly detect drive absence. But, there was a big but: If you had no (AT/IDE) drive configured in the BIOS setup, then the BIOS would not even try to probe for drives!

    From experience I know that if an old (circa 1990) PC/AT compatible is configured with a C: drive (more accurately BIOS drive 80h) and there is no drive plugged in, there will be a long timeout and the BIOS will complain that the HDD controller is broken. To get around that, you simply disable the C: drive and you can boot from SCSI or whatever. Keep in mind that those boards could be run not just with no drives but also no IDE interface at all (i.e. no one even decoding the addresses).

    As I mentioned in the article, operating systems had different assumptions and expected that drive registers would be accessible, and often first checked if the task file registers could be read and written to tell if there was anything at all. Firmware is in a more difficult position because it may well run before the drive completed powering up, and it might initially not respond.

    I’m guessing that the requirement for the host-side pull-down was added in the mid to late 1990s when the landscape changed a bit, and a) pretty much every board had an IDE controller on it (bus mastering etc.), b) BIOSes defaulted to auto-detection for IDE drives, and c) two IDE channels were standard, meaning it was far from unusual to have no devices on the secondary channel. That is what required the ability to quickly tell if an IDE channel was unpopulated. In those days, the BIOS had to set up a PCI IDE controller (or VLB…) and didn’t have to guess whether there’s any IDE interface at all.

  9. Michal Necasek says:

    Yes, write-only registers are crazy. No end of headaches because there are too many legitimate situations where the register state needs to be saved and restored.

    The trouble with using the Device Control register (if it were readable) for early detection is the same as with all the rest, you just can’t. When BSY=1, there’s not a lot software can safely do. Most register writes have “indeterminate” results. Reading most command registers returns the Status register, where only the BSY bit is valid if BSY=1.

    I don’t know this but I speculate that some old drives did not truly respond to register accesses early in their power-up sequence, and the status register (probably all registers) did return 0FFh for a while. That sort of behavior, as rude as it would be, would in fact be consistent with the ATA specification.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.