[comp.os.msdos.programmer] Formatting diskettes

jml@stekt.oulu.fi (Lepp{j{rvi Jouni) (04/19/91)

I've been writing a kind of diskette copying utility, which should also
format the target disk if so needed. The copying goes fine already, but
the formatting seems to be the really hard part. 

I've tried to use the BIOS services via int 13h for this. First, I set 
format parameters with ah = 18h, ch = n of tracks - 1, cl = n of sectors, 
dl = drive, then the actual formatting should go track by track with 
ah = 05h, al = n of tracks, es:bx = address field table, ch = track, 
cl = sector (0, actually this seems to have no effect ?), dh = head, 
dl = disk. My address field table consists of one entry / sector each 
4 bytes containing track,head,sector + 1,2 (=512 bytes / sector).

Actually I copied this procedure from the DOS's format command by setting 
an interrupt handler to monitor its actions. (format.com itself does not
make these calls, instead it appears to use DOS iocntl (int 21h,AH=44h) 
functions (0dh, 0fh ?)(BTW :-)). 

I can't get this work, however : When I try to format a track on a 1.2 M
disk, only nine of the fifteen sectors appear on the disk. It seems that
the bios somehow has the idea of the disk being 360 k, no matter that setting
the right parameters for formatting via int 13h, ah = 18h seems to succeed
(ah = 0 upon return). 

I've used Borlands turbo C to write these making use of the pseudo-variables
to access registers etc. (I looked the compiler's .asm output file through and
it seems to be doing just what intented, that is, the registers being set
up do not get overwritten before the int instruction. The trap routine written
for format.com also confirms this.)

I could use the dos iocntl's too, but my documentation claims that these are
valid from DOS v. 3.2 and later only. Despites it might be that these are
not 'officially' defined by Microsoft and might therefore be modified.

So, how do I do this right ?

Please reply with email. I'll summarize here later (if I get any replies 
in the first place .. :-) Thanks (even) in advance ?


-- 
- Jouni Lepp{j{rvi / jml@stekt.oulu.fi   -
- '.. but only maybe, life is a joy .. ' -

jml@stekt.oulu.fi (Lepp{j{rvi Jouni) (04/25/91)

The solution for my problem with diskette formatting is in the following  :

..
>From: ale@jvd.msk.su (Aleksey Odinokov)
..
>BIOS int 13h function 18h which is called Set Parameters ... doesn't
>really set parameters needed for diskette formating. But only verifies
>that BIOS support for asked combination of tracks, sectors and heads
>exists. Upon return this function give in es:di pointer to diskette
>parameter block for asked configuration. And you have manually point
>diskette parameter vector (int 1eh) to parameter block, pointer to which
>you got from function 18h. And if you ask formatting after that diskette
>should formated as you asked.
..

After realizing this to be the solution, I even managed to find a point
in the DOS's disk driver in which just the procedure described above is
used.

I have composed a summary about the issue, which should include the neccessary
information to get diskettes of various kinds formatted, provided that the
programmer already is familiar with the use of interrupt services, interrupt 
vectors, the general structure of disk(ettes) and such things. I hope that
it would be complete and in other ways useful enough so that it could be dug
up the next time this problem arises.

I decided not to include my source code, since the present code fragments 
are far from complete. Also, the use of turbo C's pseudo variables to 
access registers makes the whole thing a bit shaky : the order of operations
is often essential to produce code that actually does what one intends.
So, I think, these would not make a great example.

I'll post the summary as a separate article following this one.

My English is far from perfect and so the style and grammar in the document
may be somewhat odd and erratic, but there is not much I can do about that
right now .. :-)

Once again : Thanks to all of you who replied !
-- 
- Jouni Lepp{j{rvi / jml@stekt.oulu.fi   -
- '.. but only maybe, life is a joy .. ' -

jml@stekt.oulu.fi (Lepp{j{rvi Jouni) (04/25/91)

Formatting diskettes on IBM PC/XT/AT and compatibles using BIOS calls
---------------------------------------------------------------------
   
   Disclaimer :
   
   My intention is, of course, provide correct data. I don't, however,
   take any responsibility for any damage or loss caused by incorrectness 
   on incompleteness of this document.
   
   This document has been written with floppy disk formatting in mind.
   Parameters and procedures for hard disk formatting are likely to
   differ. 
   
   Trademarks and the like may appear in this document, which are, 
   by definition, the property of their holders.
   
   Any information in this document derived from degugging DOS applies 
   to MS-DOS v. 3.3.
   
   
   
BIOS functions used with disk formatting
----------------------------------------   

   The bios function used is int 13h (disk services). 
   
   The subfunctions used are :

   
   ah = 00h, reset disk system
   ---------------------------
   
   This should be called before anything else to force the disk system
   into a known state. (Usually this does not make a difference, however.)
   
   on entry :
   
   ah = 00h                
   
   upon return :
   
   ah = status, 0 = ok, any other means error
   carry flag set on error (ah != 0)
                          
   The status codes (also HD codes are included for completeness) :
                           
   00h : ok
   01h : bad command (or missing support for a subfunction)
   02h : address mark not found
   03h : attempted write protect violation (floppy)
   04h : sector not found
   05h : reset failed (HD)
   06h : disk changed (floppy)
   07h : bad parameter table (HD)
   08h : DMA overrun (floppy)
   09h : attempted DMA over 64k boundary
   0ah : bad sector flag (HD)
   0bh : bad cylinder detected (HD) *
   0ch : media type not found (floppy) *
   0dh : invalid number of sectors in format (HD) *
   0eh : control data address mark detected (HD) *
   0fh : DMA arbitration level out of allowable range (HD) *
   10h : CRC or ECC error on read
   11h : ECC corrected data error (HD) 
   20h : controller failed
   40h : seek failed
   80h : timeout, drive not ready
   aah : drive not ready (HD)
   bbh : undefined error (HD)
   cch : write fault (HD)
   e0h : status error (HD)
   ffh : sense operation failed (HD) *
   
   (floppy) applies only to floppy drives
   (HD)     applies only to hard disks
   *        applies to PS/2 and extented bios only
   
   Calling this function prior to actually starting to format also takes
   care of the likely 'disk changed' (status = 06h) situation, in which
   the disk system has sensed a disk change since the last disk operation.
   
   
   
   ah = 04h, verify sectors
   ------------------------
   
   This function is used to verify (the formatted) sectors.
   
   on entry :
   
   ah = 04h
   al = # of sectors
   ch = track # (0 - (n-1))
   cl = sector # (1 - n)
   dh = head # (0,1)
   dl = drive # (0 = A, 1 = B)
   [es:bx = buffer, see below]
   
   upon return :
   
   ah = status, 0 = ok, any other means error
   carry flag set on error (ah != 0)
                           
   See ah = 0 (reset disk system) above for status codes.
   
   
   While single sectors can be verified with this function, it is
   recommented that entrire tracks are verified at once to achieve
   better performance.
   
   The Programmers PC sourcebook (and Commodore PC's technical handbook)
   mention that es:bx should contain a buffer address. The sourcebook
   mentions that this is not required for AT bios after 11/15/85, but
   it does not mention PC's or XT's at all. Advanced MS-DOS programming, 
   however, does not mention this setting, instead it explictly states 
   that 'no data is transferred to of from memory by this operation'.
   Debugging DOS's disk driver's behavior reveals that it assumes that
   no buffer is needed since it has bx:es = 0000:0000 upon entry to
   int 13h with this subfunction. So, I figure that the value in es:bx
   can be quite safely ignored. It can't hurt, however, to set es:bx
   to some buffer in which bios could safely write the verified sectors.
   (I assume that this is about the only use for the buffer.)
   

   
   ah = 05h, format track
   ----------------------
   
   This function is used to format a complete track (or 'cylinder').
   I've the impression that signle sectors cannot be formatted, since
   this operation actually sets the sector marks on the disk that are
   later used to locate the sectors.
   
   on entry :
   
   ah = 05h                         
   al = # of sectors
   es:bx pointer sector header table
   ch = track # (0 .. (n-1))
   cl = sector # (appears to have no effect, I use 0 always)
   dh = head # (0,1)
   dl = drive # (0 = A, 1 = B)
   
   upon return :
   
   ah = status, 0 = ok, any other means error
   carry flag set on error (ah != 0)
   
   See ah = 0 (reset disk system) above for status codes.
   
   
   The sector header table is an array of four byte entries, one
   entry for each sector in a track. Single entry layout is as follows :
   
   offset   contents
   
     0      track number (0 - (n-1))
     1      head number  (0 - (n-1))
     2      sector number (1 - n) (note the range, 1 = first sector !)
     3      bytes / sector, 0 = 128, 1 = 256, 2 = 512, 3 = 1024
     
   From studying the bios listing I have the impression that the
   sector header table is passed to the floppy controller using
   DMA controller. The DMA controller has an address space of only 
   64 k which is extented to 1 M with a page register which can 
   be set to one of the 16 64k chunks of the entire 1 M space.
   Therefore the entrire sector header table should be fully inside
   of one these pages or formatting fails. The same applies to any
   disk buffer in this context : they all should be within one DMA
   page.
   

   
   ah = 18h, set media type for format
   -----------------------------------
   
   This function is used to get (it doesn't actually set anything) the
   pointer to the media descriptor table for a specific kind of disk.
   Int 1eh vector is then replaced with this pointer to actually set
   the media type.
   
   This function is available in IBM bioses after 11/15/85 (AT) and
   1/10/86 (XT).
   
   on entry:
   
   ah = 18h
   ch = highest track #, that is, # of tracks - 1
   cl = # of sectors
   dl = drive #, (0 = A, 1 = B)
   
   upon return:
   
   ah = status, 0 = ok, any other means error
   carry flag set on error (ah != 0)
   
   See ah = 0 (reset disk system) above for a list of status codes.
   
   The error (if any) is most likely due to lack of support
   for the media type being 'set'.  Older bioses may also
   lack the entire function. On PC/XT bioses this should be
   no problem, since their drives can handle only one major
   flavor of disks anyway and the bios defaults to this.
   
   Parameters for the usual disk types :
   
   capasity    tracks   sectors 
   
   360k        40       9
   1.2M        80       15
   720k        80       9
   1.44M       80       18
   
   (The numbers above are decimal.)
   
   Although setting the vector 1eh to the value returned by this 
   subfunction might seem like an unclean hack, this is the way
   it works. My debugging of DOS's disk driver in io.sys revealed
   that it does just this.

   
   

The formatting procedure
------------------------
   
   1. Reset the controller with subfunction 00h.
   
   2. Get the parameter table pointer for the
      disk type to be formatted with subfunc 18h.
      Set the interrupt vector 1eh to this value.
      (I think it is a good idea to store the old
      value of this vector and restore it when
      the formatting is done. I'm not sure, however, 
      if this is actually required.)
      
   3. Format the disk, track by track, with subfunction 05h.
      (Though not required it would be a good idea to verify
      the formatted tracks with subfunction 04h as they are
      formatted to detect defects on the disk.)
   
   Note that the disk formatted is not the same as produced by DOS's
   format-command. The formatting actually only sets the disk up, so
   that its sectors can be written and read. At this point, you could
   e.g. copy a similar disk's contents on it track by track, and so create
   a copy comparable to one made by DOS's diskcopy. To make the disk 
   appear as one created by DOS's format-command you would need to write
   a bootblock, FAT(s) and a root directory on it. (The bootblock is vital
   even if the disk is not meant to be bootable, since DOS stores the
   disk parameters in it.) A complete discussion about all this is beyond
   the scope of this document. The information needed can be found e.g.
   from the book 'Advanced MS-DOS Programming'.
   
   Another way to format a disk would be to use DOS int 21h function
   44h (ioctl). DOS's format appears to do this. However, I couln't
   find complete documentation for the subfunctions (0dh,0fh) used for
   this. (PC sourcebook was about the only of my references to even
   mention these functions.) Despites these calls are valid only from 
   DOS 3.2 (PC sourcebook). DOS's disk driver appears to use the bios
   calls for regular diskettes anyway, so there is not much use to do
   this via the DOS ioctl's, other than that one might be able to 
   write a formatter that might handle also excotic disks.


Bibliography
------------

Thom Hogan, The programmers PC sourcebook
Microsoft press, ISBN 1-55615-118-7

Ray Duncan, Advanced MS-DOS programming
Microsoft press, ISBN 0-914845-77-2

Ralf Brown's interrupt list

IBM PC/XT/AT Technical reference


-----------------------------------------------------------------------------
This document was written by Jouni Leppjrvi, jml@stekt.oulu.fi.
It may be freely distributed on a non-commercial basis. Comments 
corrections, clarifications and additions are wellcome.
-----------------------------------------------------------------------------
-- 
- Jouni Lepp{j{rvi / jml@stekt.oulu.fi   -
- '.. but only maybe, life is a joy .. ' -