Hi fzabkar,
I had time to spend on this project over the last month. I spent a lot of time doing various experiments and analyzing the bootloader of that thing. I did a lot of work so I'll try to keep things brief and simple.
As you suggested in your last post, it is necessary to edit the CHS values in the BPB to match the newly-installed drive. Once this is done, the error message is no longer displayed. We get a neat "Executing Code Loaded From Disk" and I even get a nice Tektronix copyright string. However, it takes a couple of minutes to get there and the boot process stalls before reaching the OS (or rather while initializing the OS). Which gets me to the following point.
I took a lot of captures of the ATA bus with a 16-channel logic analyzer (DSLogic). At first, it was difficult to make sense of it (spec isn't crystal-clear about edge polarity to say the least and timings are rather short for 20MHz-analysis). But now that all is clear, I found one thing that stands out.
First, a note on how I'll decode ATA addresses in this text. I find it easier to use one hex digit for CS0- and CS1-, and another for DA2, DA1, DA0. Here is how I set the decoder in DSLogic to illustrate:
Attachment:
addr_decoding.png [ 22.89 KiB | Viewed 10083 times ]
Also note that I only capture the data bus LSB (DD0 to DD7) and ignore the MSB (DD15 to DD8) as my analyzer does not have enough inputs. This is not really a limitation as most register transfers are 8-bit wide (aside from the Data register which is 16-bit wide).
To get data from the hard drive, the bootloader initiates a PIO read of one or more sectors by setting up the Sector Count (0x12), Sector Number (0x13), Cylinder Low (0x14), Cylinder High (0x15) and Device Drive/Head (0x16) registers and then writing 0x20 "Read sector(s) (w/retry)" to the ATA command register. It then waits for the INTRQ pin to be asserted by the drive while polling the Alternate Status (0x26) register.
Attachment:
seagate_read_start.png [ 100.33 KiB | Viewed 10083 times ]
Once the interrupt is asserted by the drive (meaning that one or more 512-byte sector is ready to be fetched), the bootloader reads the Alternate Status (0x26) register once more, reads the regular Status (0x17) register to clear the interrupt, reads the Error (0x11) register to make sure that everything is fine, then the Sector Count (0x12) register to get how many sectors are to be fetched (important, more on that below) and finally the Alternate Status (0x26) register one last time. It then proceeds to read one full 512-byte sector by polling the Data (0x10) register 256 times. Once the entire sector has been read, the bootloader waits for the drive to raise INTRQ, then it starts over: read Alternate Status, Status, Error, Sector Count (which is now decremented by one), Alternate Status, fetches data... Until it fetches the last sector, where Sector Count now reads 0 (more on that below). Once the last sector has been read, it reads the Status (0x17) register one last time.
Attachment:
seagate_read_mid.png [ 101.82 KiB | Viewed 10083 times ]
Attachment:
seagate_read_end.png [ 68.56 KiB | Viewed 10083 times ]
When I put a newer hard drive (I tried both a 128MB Transcend CF300 CF and a 40GB Toshiba MK4026GAX 2.5" HDD, both share the same behavior), all sectors are correctly retrieved. However, there is a huge 7.5-second delay between each read attempt (the following capture is hugely zoomed out, each spike represents a lot of register reads/writes).
Attachment:
transcend_7.5s.png [ 41.17 KiB | Viewed 10083 times ]
Upon closer inspection, we notice that the last read of the Status (0x17) register (after all data has been read) is missing. It is only performed 7.5 seconds later.
Attachment:
transcend_read_end.png [ 54.67 KiB | Viewed 10083 times ]
Going deeper, we can observe that the Seagate returns an incorrect Sector Count (0x12). It is decremented by one compared to the newer Transcend and Toshiba drives. For example, when reading one sector, the Toshiba or Transcend drive will return a Sector Count of 0x01 while the Seagate will return 0x00. When fetching 16 sectors, the Toshiba and Transcend report a Sector Count of 0x10 while the Seagate reports 0x0f.
Attachment:
transcend_read_mid.png [ 110.26 KiB | Viewed 10083 times ]
I suspect that the Seagate drive doesn't follow the ATA specification correctly and reports the Sector Count register with an off-by-one. As the bootloader was written with the Seagate behavior in mind, with newer drives it will think that a sector remains to be read and wait for an interrupt, only to time out after 7.5 seconds. It proceeds to slowly load the OS which likes it even less and crashes.
Looking into the ATA-1 spec, it says:
Quote:
If this register is zero at command completion, the command was successful.
If not successfully completed, the register contains the number of sectors
which need to be transferred in order to complete the request.
The Transcend datasheet says:
Quote:
Sector Count Register (Address - 1F2h[172h]; Offset 2)
This register contains the numbers of sectors of data requested to be transferred on a read or write
operation between the host and the CompactFlash Storage Card. If the value in this register is zero, a count
of 256 sectors is specified. If the command was successful, this register is zero at command completion. If
not successfully completed, the register contains the number of sectors that need to be transferred in order
to complete the request.
Now my question: is anyone aware of a "quirk" on Seagate devices from 1994 that would explain this? Or could this be explained through the ATA standard in some way? I had no luck with Google. I limited search results to the 90s but nothing mentions this behavior. Maybe an old-timer remembers something like this?