

                        Ŀ
                                          
                            CHAPTER IV    
                                          
                        


              Ŀ
                                                    
                   THE LDC READ TRACK OPERATION     
                                                    
              



1. GENERALITIES

   We shall devote this chapter to the LDC operation known as 'read
track'. It is a very interesting operation mainly because playing
tricks with it is rather easy; in some cases, that is the only way to
read strange sectors and sometimes even organizational bytes.
Details will be given in section 4.
For the time being, let us mention that this operation can be used to
read all the data bytes on a track.

The read track operation can be implemented as a new INT 13h service,
say function FEh. About half of the hard work is already done : we
shall make use of several procedures that come with INT 13h / function
FFh  (see Chapter III).

The disk controller has no internal buffer. Therefore when it comes to
read or write data bytes, we shall make use of the Direct Memory
Access capability of the system (DMA). That is what section 2 is all
about.



2. DIRECT MEMORY ACCESS (DMA)

    The DMA provides several services. We already know about one : the
memory refresh function (see Chapter III - section 6).
Let us now examine another one.

With some devices, particularly disk drives, it is more sensible to
transfer a whole block of data at a time, rather than to transfer it
byte by byte.
The hardware is designed in such a way that the disk drive controller
transfers data to or from memory without the intervention of IN or OUT
instructions.
The IN and/or OUT instructions are still needed to initiate the
transfer, to specify things like the number of bytes to transfer and
the memory address for the transfer.
After the transfer is initiated, the disk drive controller handles all
the details and does not send the ready bit until the entire transfer
is complete.
This type of transfer is called 'Direct Memory Access Transfer'.

WHILE a DMA transfer is in progress, the processor can continue
executing other instructions. This is simply wonderful!
The instructions could be something like 'abort the transfer
immediately after 25 bytes are written to the disk'.
Although aborted operations require precise timings and are often
rather difficult to monitor, there are first-class rewards such as
writing bad CRC words and formatting only a part of a track.
More about aborted operations later on.

Here are the parameters required by the DMA :

          Ŀ
                                                           
                           DMA  PARAMETERS                 
                                                           
          Ĵ
                                                          
           thru                                           
           port                description                
                                                          
          Ĵ
                                                          
            0Bh    DMA command code :                     
                                       46h = read         
                                       42h = verify       
                                       4Ah = write        
                                                          
          Ĵ
                                                          
            0Ch    DMA command code just as above         
                   (one way to make DMA happy is to pass  
                   the command code through ports         
                          0Bh  and  0Ch           )       
                                                          
          Ĵ
                                                          
            05h    Number of bytes to transfer MINUS 1    
                                                          
          Ĵ
                                                          
            04h    Low 16 bits of transfer ABSOLUTE       
                   address                                
                                                          
          Ĵ
                                                          
            81h    High 4 bits of transfer ABSOLUTE       
                   address                                
                                                          
          Ĵ
                                                          
            0Ah    Enable DMA channel 2 by writing 2 to   
                   port 0Ah (channel 2 is reserved for    
                   disk operations)                       
                                                          
          




            Remember  Ŀ
                                                           
                         No page crossing !                
                                                           
          




The following procedure initializes the DMA for disk operations :



init_dma         proc    near
                 mov     al,dma_cmd_code
                 out     0ch,al
                 out     0bh,al
                 mov     ax,buffer_segment
                 mov     cl,4
                 rol     ax,cl
                 mov     ch,al
                 and     al,0f0h
                 add     ax,buffer_offset
                 jnc     no_carry
                 inc     ch
no_carry:        push    ax
                 out     4,al
                 mov     al,ah
                 out     4,al
                 mov     al,ch
                 and     al,0fh
                 out     81h,al
                 mov     ax,number_bytes
                 dec     ax
                 push    ax
                 out     5,al
                 mov     al,ah
                 out     5,al
                 pop     cx
                 pop     ax
                 add     ax,cx
                 mov     al,2
                 out     0ah,al
                 jnc     dma_end
                 jmp     dma_error
dma_end:         ret

dma_error:

;                PAGE   CROSSING
;                tell calling program
;                the requested operation
;                cannot be performed


init_dma         endp





3. THE READ TRACK PHASES

   The command phase 9-byte sequence is as follows :


          Ŀ
                                                           
                  read track command phase sequence        
                                                           
          Ĵ
                                                          
           byte                                           
            no                 description                
                                                          
          Ĵ
                                                          
            01     MUST be  42h                           
                                                          
          Ĵ
                                                          
            02     (4 * head) + drive                     
                                                          
          Ĵ
                                                          
            03     track number                           
                                                          
          Ĵ
                                                          
            04     head number                            
                                                          
          Ĵ
                                                          
            05     sector number; does not seem to be of  
                   any use                                
                   may be set to  01                      
                                                          
          Ĵ
                                                          
            06     data size code                         
                   code n means  128 * 2^n bytes/sector   
                                                          
          Ĵ
                                                          
            07     number of sectors/track                
                   if in doubt it should be set to  FFh   
                                                          
          Ĵ
                                                          
            08     read/write gap length                  
                   it tells the disk controller how       
                   many bytes to skip before looking for  
                   the next sector so that it can avoid   
                   reading some of the nonsense bytes of  
                   4Eh in the gap between sectors         
                                                          
          Ĵ
                                                          
            09     known as the DTL byte; does not seem   
                   to be of any real use : see            
                   Appendix C                             
                                                          
          




The result phase provides 7 bytes. Details are given in Hogan's
Sourcebook (8.19). The result bytes MUST be read (see Chapter III
- section 4) after the entire transfer is complete. That leaves us
with the question :
           How does one know that the operation is complete?
When it is complete the disk controller invokes a diskette interrupt
which sets bit 7 of a status byte located at  0000:043Eh .
So one has to keep polling this byte until bit 7 is set then reset
the bit to 0 and continue on the next step.
The following procedure demonstrates how things can be worked out :


wait_int        proc    near
                mov     dh,2
                xor     ax,ax
                mov     es,ax
                mov     bx,43eh
                mov     cx,ax
wi1:            mov     dl,es:[bx]
                test    dl,80h
                jnz     wi2
                loop    wi1
                dec     dh
                jnz     wi1
                jmp     time_out
wi2:            and     byte ptr es:[bx],7fh
                ret

time_out:

;               time out error
;               tell the calling program

wait_int        endp




We conclude this section by recalling the steps involved in a read
track operation :

         (A) Turn the disk drive motor on     (if necessary)
         (B) Recalibrate the read/write head  (if necessary)
         (C) Position the read/write head over the desired track
                                              (if necessary)
         (D) Initialize the DMA
         (E) Command phase
         (F) Wait for the transfer to be complete
         (G) Read the result phase bytes




4. EXPERIMENTING WITH THE READ TRACK OPERATION

   Let us denote

   the number of bytes to be read (DMA parameter)         by  NB
   the number of sectors/track (command phase parameter)  by  EOT
   the sector size code (command phase parameter)         by  NN
   the read/write gap (command phase parameter)           by  GL
   the minimum of   NB  and  EOT * 128 * 2^NN             by  NR

Starting from the  * beginning *  of a track, the read track operation
reads what it thinks are  NR data bytes. It assumes that all sectors
are of size  128 * 2^NN (whether this is true or not). After reading
bytes from a sector, it looks for the next sector and reads from that
sector until NR bytes are read.

The best way of making things clear is to carry out a few experiments.

Let us start by (re)formatting a disk using the standard  FORMAT
program (the one on the System Disk).
NO files should be written to the experimentation disk!


EXPERIMENT 1

Call read track with   NB  = 1200h       track = 0
                       EOT = 9           head  = 0
                       NN  = 2
                       GL  = 2Ah

The result phase bytes do not show any error and the buffer contains
the actual 200h * 9 = 1200h data bytes on track 0/head 0.


EXPERIMENT 2

Call read track with   NB  = 1210h       track = 0
                       EOT = 9           head  = 0
                       NN  = 2
                       GL  = 2Ah

The result phase bytes show an 'end of cylinder' error. That is
because   NB > EOT * 128 * 2^NN . In other words, the calling
parameters are inconsistent : because of the value of NB the disk
controller tries to access a tenth sector although  EOT = 9 !
The buffer contains the actual 1200h data bytes just as with
experiment 1.


EXPERIMENT 3

Call read track with   NB  = 11F0h       track = 0
                       EOT = 9           head  = 0
                       NN  = 2
                       GL  = 2Ah

The result phase bytes do not show any error and the buffer contains
11F0h data bytes (all the data bytes from sectors 1 to 8 and 1F0h
bytes from sector 9).
No CRC error is reported because although only 1F0h bytes from
sector 9 are sent to the data bus, the disk controller reads
* internally *  the complete sector and then performs a CRC check.


EXPERIMENT 4

Call read track with   NB  = 2400h       track = 14
                       EOT = 9           head  = 0
                       NN  = 3
                       GL  = 8

The result bytes show       a data field CRC error
                       and  a 'no data' error.

The 'no data' error means that during the execution of the command,
the starting sector could not be found. Such an error is reported
because read track is called with  NN = 3  so that the disk controller
expects the first CHRN field to be  14 00 01 03 .
As our experimentation disk is a standard one the first CHRN field is
in fact  14 00 01 02 !
The reason for the data field CRC error will become obvious quite
soon.

Let us look at the data buffer.

Bytes 0000 to 01FF are all of the same value (format fill byte).

As NN = 3 the disk controller assumes that sectors are of data length
1024 (= 400h). Therefore when dealing with sector 1 it reads the real
512 data bytes and the next 512 disk bytes (non real data bytes)
whether they are organizational bytes or bytes from sector 2.
Assuming that we are lucky (because some non real data bytes may be
bit shifted and in error) that is exactly what we can see when looking
at the data buffer :

        bytes                             are
  
   0200h and 0201h  the data field CRC bytes for sector 1
   0202h to  0251h  bytes of 4Eh (gap between sectors 1 and 2)
   0252h to  025Dh  bytes of OO
   025Eh to  0260h  bytes of A1h
   0261h            byte  of FEh
   0262h to  0265h  the CHRN field bytes for sector 2 (14 00 02 02)
   0266h and 0267h  the CHRN field CRC bytes for sector 2
   0268h to  027Dh  bytes of 4Eh
   027Eh to  0289h  bytes of 00
   028Ah to  028Ch  bytes of A1h
   028Dh            byte  of FBh
   028Eh to  03FFh  data bytes from sector 2

Now what is the next CHRN field found after reading the first
1024 bytes?  14 00 03 02 of course!

Some easy calculation show that :

      the real data     may be found (in the data buffer)
        for sector                  at offset
     
            1               0000h  to  01FFh
            2               1400h  to  15FFh
            3               0400h  to  05FFh
            4               1800h  to  19FFh
            5               0800h  to  09FFh
            6               1C00h  to  1DFFh
            7               0C00h  to  0DFFh
            8               2000h  to  21FFh
            9               1000h  to  11FFh

Remark : The bit shift condition mentioned above may occur on any
         track but it is much more likely to occur when a sector is
rewritten (the rotation rate may differ slightly from the last time we
wrote that sector so that the length of the sector will differ from
its previous length, possibly destroying a small part of the gap after
the sector or alternately allowing a few bits to survive). That is the
the reason why we make use of a newly (re)formatted disk without any
file written to it.

The reader should carry out the same experiment with track 0/head 0
(this one is rewritten by the FORMAT program as it reserves some
sectors for the operating system); more bit shifts will appear.

Sometimes things may even be worse : clock bits are read rather than
the 'real' bits.

Nevertheless, such conditions never occur when reading real data
bytes.

There is no cure when clock bits are read.
A data buffer shift procedure turns out to be very useful to deal with
bit shifts.


EXPERIMENT 5

Call read track with   NB  = 2400h       track = 14
                       EOT = 9           head  = 0
                       NN  = 3
                       GL  = 255

The result bytes show       a data field CRC error
                       and  a 'no data' error       (of course).

The following CHRN fields may be found in the data buffer :

                offset    CHRN field
               
                0262h     14 00 02 02
                0662h     14 00 05 02
                0A62h     14 00 08 02
                0E62h     14 00 02 02
                1262h     14 00 05 02
                1662h     14 00 08 02
                1A62h     14 00 02 02
                1E62h     14 00 05 02
                2262h     14 00 08 02

and

      the real data     may be found (in the data buffer)
        for sector                  at offset
     
            1               0000h  to  01FFh
            1               0C00h  to  0DFFh
            1               1800h  to  19FFh
            4               0400h  to  05FFh
            4               1000h  to  11FFh
            4               1C00h  to  1DFFh
            7               0800h  to  09FFh
            7               1400h  to  15FFh
            7               2000h  to  21FFh

The reason for the repeats is that the disk controller is instructed
to skip 255 bytes after reading each 1024-byte block.


EXPERIMENT 6

Let us first reformat track 14/head 0 using INT 13h/function 05. The
format function calling parameters are standard except for the
order of the CHRN fields :

                  14 00 01 02
                  14 00 03 02
                  14 00 02 02
                  14 00 04 02
                  14 00 05 02
                  14 00 06 02
                  14 00 07 02
                  14 00 08 02
                  14 00 09 02

Next, using INT 13h/function 3 let us write a message, say
'This is sector R', in each sector R  (1 <= R <= 9).

Call read track with   NB  = 1200h       track = 14
                       EOT = 9           head  = 0
                       NN  = 2
                       GL  = 2Ah

The result phase bytes show a 'no data' error due to the non standard
order of sectors.
The data buffer shows :

           This is sector 1     at  offset  0000h
           This is sector 3     at  offset  0200h
           This is sector 2     at  offset  0400h
           ................     .................

This confirms that the read track operation reads sectors in the disk
physical order.


WARNING : Read track aborts if it does not find the data mark
          3 bytes of A1h + FBh  (Chapter I - section 7) when
attempting to read a sector.
An example is given in Chapter V - section 4.



5. POSITIONING THE READ/WRITE HEAD ON THE BEGINNING OF A TRACK

   In this section we shall answer question (b) raised in Chapter III-
section 6.

The trick is as follows :

We instruct the disk controller to perform a 'wrong' read track
operation; 'wrong' means that we make the disk controller to think the
recording method is an old one (not used any more). It tries to read
bytes starting at the beginning of the track. After one complete
revolution it will stop searching. That is the right time to take over
(as the read/write head is again at the beginning of the track).
As it would be a waste of time we must find a way around the necessity
to read the result phase bytes. The only reasonable way is to perform
a disk controller reset. That can be done by resetting bits of the DOR
register (Chapter III - section 3) :


reset         proc      near
              mov       dx,3f2h
              mov       cl,drive
              mov       al,10h
              shl       al,cl
              or        al,cl
              or        al,8
              out       dx,al
              or        al,4
              jmp       rs1
rs1:          out       dx,al
              ret
reset         endp


Now, the 'wrong' read track operation is quite similar to the standard
one. We only need to change the first byte in the command phase
sequence to  02   and set the number of bytes to be read (DMA
parameter) to  8 .

We conclude by putting things together :

      (A) Turn the disk motor on               (if necessary)
      (B) Recalibrate the read/write head      (if necessary)
      (C) Position the read/write head over the desired track
                                               (if necessary)
      (D) Initialize the DMA
      (E) Command phase
      (F) Wait for the transfer to be 'complete', i.e. allow the disk
               controller to realize nothing can be read
               (wait_int procedure in section 3)
      (G) Perform a disk controller reset
      (H) Carry on IMMEDIATELY
          e.g. read CHRN fields in a loop
