CS-220, Sec. 90, Week 12C
R. Eckert

DISK I/O

Both hard and floppy disks store information magnetically. They are non-
volatile storage devices since the information remains on the disk after
the computer is turned off. They are also writable in the sense that the
information on a disk can be changed by writing new information--which
replaces the information that was stored previously. Floppy diskettes are
also highly portable, as it is easy to transport a diskette from one
computer to another.

As shown in the diagram below, a disk or diskette rotates under a
"read/write head" that can be moved in or out over the disk's surface. The
surface of the disk can be magnetized by causing a current to flow in a
tiny coil inside the read/write head. In the case of a floppy diskette, the
read/write head is in contact with the surface of the disk; in the case of
a hard disk, it floats over the surface. In either case information is
stored by changing the magnetism of the disk surface underneith the
read/write head. In the simplest systems a change of magnetic flux can
represent a one, and the absence of a change in magnetic flux  a zero. When
in write mode, the read/write head acts like an electromagnet that, depending
on the direction of electric current flowing in its coil, magnetizes the disk
surface in one direction or another as it goes by. In read mode the coil
senses changes in magnetic flux. As should be evident by this very brief
description, disk storage is serial (one bit at a time) in nature.



The surface of a disk is organized into concentric tracks, each of which is
divided into sections of an arc called sectors. In the case of floppy
disks, a very common organization (Double sided, high density, DSHD) is to
have 80 tracks on each side of the floppy, each of which is divided into 18
sectors. In this scheme each sector can hold 512 bytes of information
stored serially. In order to read data from or write data to a floppy disk,
the read/write head must be moved over the correct track, and we must wait
until the correct sector comes around and is under it. Then, when writing,
the system must extract each bit of each byte to be stored and send signals
to the hardware that will either change or not change the magnetic flux in
the coil. All of the bits must be sent while the sector is still under the
read/write head. In reading, the process is similar, but the coil detects
changes (or no changes) in magnetism on the surface which must be
interpretted as ones or zeroes, assembled into bytes, and stored in the
computer's memory. In either case timing is critical.

To facilitate the process of reading or writing disk data, the floppy disk
drive is controlled by an integrated circuit called a floppy disk
controller (FDC). This device can send signals to the drive mechanism that
make the read/write head move in or out and can detect when a given sector
is under the read/write head. It can also send signals to the floppy disk
drive to read or write a bit. Since this level of control is very low-level
and very difficult to achieve, the FDC is organized so that certain signals
it receives from the microprocessor can cause it to send the necessary
signals to the disk drive to do things like read or write an entire sector.
It can also tell the processor when a new byte has been assembled (reading)
and is ready to be stored in memory or when it is ready to receive a new
byte (writing) for serialization and output to the disk. In many
microcomputer systems, communication between the microprocessor and the FDC
is through I/O ports, in a way reminiscent of the printer (although much
more complex).

DIRECT TRACK/SECTOR DISK I/O

One way of doing disk I/O would be to use the FDC directly by monitoring
FDC status ports, sending appropriate commands to FDC command ports, and
reading or writing data from or to appropriate data ports. An easier way
would be to use operating system services to perform the same tasks. For
example, on a PC, BIOS int 25h can be used to perform an "absolute disk
read", and BIOS int 26h an "absolute disk write." In either case, CX must
be loaded with the number of sectors to read or written, AL the disk
drive to be used (A=0, B=1, C=2, etc.), DX the "starting logical sector
number", which for a double sided high density diskette would be:

  logical sector # = (sector - 1) + (head * 18) + (track * 36), where
  1<=sector<=18    0<=head<=1     0<=track<=79 

DS:BX must also be loaded with the start address of a block of
memory (buffer) that will be used to hold the incoming data in the case of
a disk read and which must contain the data to be stored in the case of a
disk write. For either of these two BIOS services, the carry flag indicates
whether (0) or not (1) the the operation was successful. If it failed
(CF=1), and AH register will indicate what the problem was as follows:

AH=1 ==> bad command
Ah=2 ==> bad address mark
AH=3 ==> write protected disk
AH=4 ==> sector not found
AH=8 ==> Direct Memory Access failure
AH=10h ==> Cyclic Redundancy Check error
AH=20h ==> disk controller error
AH=40h ==> seek error
AH=80h ==> device not responding (time out)

There is one other consideration in using int 25h and int 26h. Both of
them use the stack to preserve the flags--and do not restore the stack
pointer to its original value. Consequently you must do a pop (or add 2
to the stack pointer) to re-align the stack after invoking either 
interrupt.

USING BIOS INT 13H TO DO DIRECT TRACK/SECTOR DISK I/O

Int 13h in many ways combines the services of int 25h and int 26h to read 
or write one or more sectors of informaton. To read disk sectors, load AH 
with a 2; to write, load AH with a 3. The other registers should be set 
up as follows:

AL = number of sectors to transfer
ES:BX must point to the memory buffer providing or receiving the data
CH = track number (0-79 for a DS/HD floppy disk)
CL = sector number (0-17 for DS/HD floppy disk)
DH = head or side number (0 or 1 for DS/HD floppy disk)
DL = drive number (0=A, 1=B, 2=C, 3=D, etc.)

After invoking int 13h, if the carry flag is 0, the disk transfer was 
done successfully and AL will contain the actual number of sectors read 
or written. If the carry flag is 1, AH will conatain a status code that 
indicates what the problem was. The same codes are used as for int 25h 
and int 26h.

USING DOS (INT 21H) SERVICES FOR HIGH-LEVEL DISK I/O

Accessing the FDC directly or using BIOS services that write to specified
disk tracks and sectors can be very dangerous if the disk contains other
information that is important. Most operating systems have some sort of
file system for saving and reading information using named files. In the
case of the PC, DOS maintains something called a File Allocation Table
(FAT), which, in simplest terms, maps file names to the tracks and sectors
of the disk where the data in the file is actually stored.

Again on a PC, there are DOS services (accessed with int 21h, as usual)
that allow us to do disk I/O using named files. Some of these services are:
3Ch (create a file), 3Dh (open--make accessible for reading or writing--an
existing file), 3Eh (close an open file), 3F (read from a file, 40h (write
to a file), and 42h (seek--move a file position pointer to a given position
in the file). In all but the first two of these, the file is specified by
providing a 16-bit number called a file handle. This number is obtained
when the file is first created or opened. A brief description of these DOS
disk services is now given.

CREATE FILE:
AH=3Ch
CX=file attibute (00h==>normal file, 01h==>read only, 02==>hidden,
   04==>DOS system file, 08==>volume label, 10h==>subdirectory,
   20h==>archive file
DS:DX=address of the zero-terminated string that specifies the file name.
If successful, CF=0 and AX will contain the file handle that will be used
for subsequent accesses to the file.

OPEN EXISTING FILE:
AH=3Dh
AL=Mode flags (00==>read only, 01==>write only, 02==>read/write
DS:DX=address of the zero-terminated string that specifies the file name.
If successful, CF=0 and AX will contain the file handle that will be used
for subsequent accesses to the file.

CLOSE FILE:
AH=3Eh
BX=file handle specifying file to be closed.
If successful, CF=0.

READ FROM FILE:
AH=3Fh
BX=file handle specifying file to be read
CX=number of bytes to be read
DS:DX=start address of memory block (buffer) where the incoming data will
      be stored.
If successful, CF=0 and AX will contain the number of bytes actually read.


WRITE TO FILE:
AH=40h
BX=file handle specifying file to be written
CX=number of bytes to be written
DS:DX=start address of memory block (buffer) containing the data to be
      written.
If successful, CF=0 and AX will contain the number of bytes actually
written.

SEEK:
AH=42h
BX=file handle specifying file to be written
CX:DX=byte offset (how far to move file position pointer)
AL=origin of move (00==>from start of file, 01==>from current location,.
   03==>from end of file
If successful, CF=0 and DX/AX will contain the new file position pointer
location from the start of the file.