Compaq EXTDISK.SYS

This is a follow-up to a previous post about the curious driver in Microsoft OS/2 1.21. After initially writing the article, additional information came to light, explaining why the code was there.

EXTDISK.SYS loaded in Compaq DOS 3.31 rev D (1988)

In summer 1988, Compaq released the Deskpro 386/25, the most powerful PC available at the time with a price tag over $10,000. At the time, Compaq did not offer dedicated server systems, but the Deskpro 386/25 was clearly meant to be usable as a file server. To that end, Compaq offered an expansion unit that could house up to two 300MB ESDI drives. The expansion unit was effectively an ESDI expander, attached to a disk controller in the main unit through a custom cable. The Deskpro 386/25 plus expansion unit could utilize two plus two 300MB drives, for a total of 1.2GB of storage (this was mid-1988).

Now comes the interesting part. Because Compaq used Western Digital ESDI controllers that looked like a regular PC/AT disk (or an IDE drive) to the system, Compaq made it possible to have one or two drives in the main unit with a disk controller responding at the 1F0h I/O port range, while the expansion unit responded at the “alternate” 170h address range long supported by PC/AT compatible disk controllers. To software, the ESDI controllers looked the same as old PC/AT controllers for ST-506 drives, and the same as newer IDE drives (which were already used by Compaq in 1988).

The initial support for four drives had two key components. The Compaq SETUP utility stored the drive type of the 3rd/4th drive in CMOS locations 1Bh/1Ch (conveniently right after 19h/1Ah used for the 1st/2nd drive). And for DOS, Compaq supplied a custom driver called EXTDISK.SYS.

Continue reading
Posted in Bugs, Compaq, DOS, PC history, Storage | 17 Comments

The Strange MS OS/2 1.21 Disk Driver

Attempting to install Microsoft OS/2 1.21 will fail on many systems with the following scary looking error:

FDISK failed, which makes installation difficult.

Pressing Enter as directed shows the following more detailed error message:

There is no hard disk; that is a problem!

The initial boot phase, as well as the installation stage immediately before the FDISK error is shown, takes much longer than it normally should.

Some, but not all, OEM versions of MS OS/2 1.21 are also affected. Tandon and Compaq have the same problem, but Intel MS OS/2 1.21 does not. IBM’s OS/2 1.2 SE or EE likewise does not have this trouble.

The problem is usually caused by having a CD-ROM on a secondary disk controller (IDE or otherwise). But it’s rather more complicated than that, and any device on a secondary disk controller is more likely than not going to cause problems. The failure is triggered by a subtle bug in the MS OS/2 1.21 disk driver.

Continue reading
Posted in Bugs, Microsoft, OS/2, PC history | 43 Comments

ESDI Adventures

At long last, I got hold of a decently well functioning ESDI drive. From my earlier adventures, I had a WD1007V-SE2 controller, as well as an older WD1007A. The WD1007A (Compaq branded) used to live in a Hyundai 286 machine together with a Microscience ESDI drive. But the Microscience drive tragically died some years ago.

I also have a somewhat working ST4182E drive (152MB), but its heads have an unfortunate tendency to stick when the drive is not use and then require manual intervention, so the drive isn’t very usable.

Now I got a CDC/Imprimis/Seagate Wren VI drive, CDC model number 94196-766 or Seagate model ST4766E. It has a formatted capacity of about 664MB and it was about the biggest ESDI drive in Seagate’s product lineup.

A 1991 ST4766E ESDI drive

The drive was sold as untested and I didn’t expect much of it. Visual inspection revealed mild corrosion in one area of the PCB, but there was no obvious cause for it (no leaky capacitors or some such). It may have been a result of sub-optimal storage conditions.

Before powering up the drive for the first time, I was rather apprehensive. But the drive spun up just fine and made the right kind of noises—heads unlatching followed by a seek test; by now I have a very good idea what a Seagate drive of CDC lineage should sound like. There were no suspicions noises and for a full-height 5.25″ drive with 8 disks inside the ST4766E is fairly quiet.

Continue reading
Posted in ESDI, PC hardware, PC history, Seagate | 32 Comments

Time Trouble

Last Friday I had a moment of panic. While investigating why different run-time libraries might interpret file timestamps differently, I noticed that even Windows doesn’t always agree with itself. When was dos4gw.exe last modified, at 10:14 PM or 9:14 PM?

Which is it, 9:14 PM or 10:14 PM?

For some (but not all) files, the dir command in cmd shows timestamps that are off by an hour compared to timestamps shown by Explorer or PowerShell. How is this possible? And is either of those timestamps even correct?

Continue reading
Posted in Bugs, Development, Microsoft | 19 Comments

Learn Something Old Every Day, Part XIV: read() Return Value May Surprise

Last week I amused myself by porting some source code from Watcom C to Microsoft C. In general that is not difficult, because Watcom C was intended to achieve a high degree of compatibility with Microsoft’s C dialect.

Yet one small-ish program kept crashing when built with Microsoft C. It didn’t seem to be doing anything suspicious and didn’t produce any noteworthy warnings when built with either compiler.

After some head scratching and debugging, I traced the difference to a piece of code like this:

  if( read( hdl, buf, BUF_SIZE ) != BUF_SIZE )
// Last file block read, deal with EOF
else
// Not near end of file

To my surprise, the return value from read() is rather different between the two compilers’ run-time libraries when the file is open with the O_TEXT flag (and therefore meant to translate line endings from CR/LF to LF when reading).

Continue reading
Posted in C, Development | 11 Comments

Learn Something Old Every Day, Part XIII: InDOS Is Not Enough

The other day I spent a while trying to understand the purpose of a rather strange looking piece of code inside Borland’s THELP.COM utility shipped with Turbo Pascal 6.0 (THELP.COM was misbehaving under emulated DOS).

The THELP utility performs the following actions:

  • Use INT 21h/34h to get the address of the InDOS flag
  • Starting from the beginning of the InDOS segment, search for word 3E80h using the SCASW instruction
  • If found, check if the location in memory six bytes past the 3E80h word holds the value BCh
  • If so, store the word just past 3E80h for later use

This logic is applied to DOS version 4 and below (effectively 2.0 to 4.x), not newer versions. But what could it possibly be good for?

Continue reading
Posted in DOS, PC history, Undocumented | 13 Comments

Minor 387 Documentation Mystery

So here I am, writing a bit of test code to figure out the behavior of x87 FPUs with regard to saving and loading the FPU state (FSTENV/FLDENV and FSAVE/FRSTOR instructions in different modes and formats).

The original real-mode only 8087 state format included the instruction and operand pointers as 20-bit linear addresses (because $REASONS) and also stored 11 bits of the floating-point (FP) opcode; the remaining five were always the ESC instruction.

The 287 also needed to be able to save the state in protected mode, with full segment and offset addresses. For whatever reason, Intel decided to keep the size of the saved FP environment (7 words); because the saved code and data pointer addresses used 32 bits each instead of 20, there was no longer room for the floating-point opcode. That wasn’t a huge deal because the opcode could be fished out of memory.

When the 387 came out, it naturally needed to support 32-bit state, with 16-bit segments and 32-bit offsets. Instead of 7 words, the 32-bit state was extended to 7 dwords, with extra padding in reserved fields.

I was pretty sure the floating-point opcode is there somewhere in the 32-bit protected-mode state, but needed a reminder as to where exactly. I happened to have Agarwal’s 80×86 Architecture & Programming, Volume II (1991) open on a nearby page, so I looked there first. On page 240, there’s a diagram of the 32-bit protected-mode FPU state format. But no FP opcode. Odd.

The next closest book was Hummel’s PC Magazine Programmer’s Technical Reference: The Processor and Coprocessor (1992). On page 696, documenting the FSTENV/FNSTENV instruction, there’s the saved state diagram. But again, no floating-point opcode! Is my memory that bad? (Rhetorical question, don’t answer!)

Continue reading
Posted in Documentation, Intel, x87 | 9 Comments

The Other Three

A previous blog post explored the semi-mysterious yet sometimes highly useful DOS APPEND command. Now it’s time to look at its relatives: ASSIGN, JOIN, and SUBST.

ASSIGN

ASSIGN is the oldest of the bunch. It was written by IBM and first appeared in PC DOS 2.0 in March 1983 (it wasn’t part of MS-DOS 2.x). It is very simple and rather limited.

ASSIGN re-routes requests to an existing drive to another drive. If the user runs

ASSIGN A=C

then requests to drive A: end up addressing drive C: instead.

Note “existing” — the drive letter that is being reassigned must exist. On a machine that has drives A:, B:, C:, and D:, an attempt to run

ASSIGN F=D

will fail with “Invalid parameter”.

Like APPEND, the ASSIGN command is a TSR, and it is one of the earliest DOS TSRs, together with the PRINT command.

ASSIGN works by intercepting INT 25h and 26h vectors (direct disk I/O) and re-routes all accesses according to its internal drive map.

There are no provisions to unload ASSIGN, but running ASSIGN without any arguments will clear its drive mapping table and undo any effects of previous ASSIGN commands.

In later DOS versions,

ASSIGN /STATUS

will show the current drive mappings, if any.

Continue reading
Posted in DOS, IBM, PC history | 13 Comments

I Thought I Found a Bug…

So I was working on improving a DOS emulator, when I found that something seemingly trivial wasn’t working right when COMMAND.COM was asked to do the following:

echo AB> foo.txt
echo CD>> foo.txt

Instead of ABCD, foo.txt contained ABBC.

I verified that yes, the right data was being passed to fwrite(), with the big caveat that what COMMAND.COM was doing wasn’t quite as straightforward as one might think:

  • Open foo.txt
  • Write ‘AB’
  • Close foo.txt
  • Open foo.txt
  • Seek one byte backward from the end of the file
  • Read one byte
  • Write ‘CD’
  • Close foo.txt

The reason for the complexity is that COMMAND.COM tries to deal with a case that the file ends with a Ctrl-Z character (which wasn’t the case for me), and if so, the Ctrl-Z needs to be deleted. Somehow the seek/read/write sequence was confusing things. But why?

Continue reading
Posted in Bugs, C, Development, Watcom | 25 Comments

DOS APPEND

For a long time, I couldn’t quite grasp what the DOS APPEND command could possibly be good for. Until I came across a situation which APPEND was made for.

When I worked on organizing and building the DOS 2.11 source code, I tried to place the source files in a tree structure similar to that used by DOS 3.x (this is known from DOS 3.x OAKs):

C:.
└───src
├───bios
├───cmd
│ ├───chkdsk
│ ├───command
│ ├───debug
│ ├───diskcopy
│ ├───edlin
│ ├───exe2bin
│ ├───fc
│ ├───find
│ ├───format
│ ├───more
│ ├───print
│ ├───recover
│ ├───sort
│ └───sys
├───dos
├───inc
└───msdos

The inc subdirectory unsurprisingly contains shared include files such as DOSSYM.ASM, which are included just about from everywhere. No problem, right?

Except… to get output that most closely matches existing DOS 2.x binaries, it is necessary to use an old version of MASM (version 1.25 seems to do the trick). But MASM 1.25 is designed to run on top of DOS 1.x, and knows nothing whatsoever about directories.

It is possible that back in the day, DOS 2.x was built from a single huge directory on a hard disk. In fact it is known that DOS 2.0 could not be built on PCs at all, and was built on DEC mainframes. Yet DOS 2.11 was also clearly modified such that it could be build on PCs using Microsoft’s development tools.

However it was done back in 1983, lumping 150+ assembler source files into a single directory, and then adding hundreds of object and executable files, did not sound at all appealing. Cloning DOSSYM.ASM to every directory where it was needed seemed even worse.

That’s when I somehow remembered that APPEND exists, and realized that it’s the perfect solution to the problem. Before building, one can run

APPEND ..\..\INC;..\INC

and the inc directory becomes accessible from all of its sibling subdirectories and from subdirectories one level deeper. It would have been possible to use an absolute path as well, but this way the build batch file does not need to know where it lives.

With APPEND in place, the old MASM 1.25 which uses FCB I/O will find the centrally located include files, and the source code can be organized into a neat hierarchical structure that’s far easier to work with than one giant blob.

Continue reading
Posted in DOS, IBM | 46 Comments