From: kircher@saruman.neuro.tuwien.ac.at (Gerhard R. Kircher)
Subject: How to make a bad blocks list for mk(e)fs
Organization: Technical University of Vienna
X-Newsreader: TIN [version 1.1 PL6]
Date: Fri, 13 Nov 1992 11:00:44 GMT


Generating a bad block list for mk(e)fs
=======================================

Nov 11, 1992  Gerhard Kircher   (kircher@neuro.tuwien.ac.at)


Introduction
------------

First of all: the -c option (check bad blocks) of mk(e)fs
does not work (the code used cannot detect any bad blocks).
Fortunately there is another option -l <file> to tell
mk(e)fs where the bad blocks are.
SCSI and IDE drive users do not need any bad block management
- the drive logic does it for them. However, users of old
MFM or RLL drives do need it. 


1 Where are my bad blocks ?
---------------------------

Every MFM or RLL drive is tested by the manufacturer and the
locations of bad blocks are usually printed directly
on the drive case.
If you cannot find any bad block information on your
drive, you can use the common disk test software (Norton,...)
to check your drive and obtain a defect list.

Locations of bad blocks are given in terms of
cylinder and head coordinates. Cylinder and head
together specify a certain track. Some manufacturers
are more specific about the location of the bad spot
within the track but if you know how to use this information
you probably do not need to read this guide.
So if we know the track where the bad spot sits, we
declare the entire track as bad (even experts do this).

What we have now is a table of the form

  CYLINDER  HEAD
  ...       ...
  ...       ...
  ...       ...


2 calculating all bad sectors
-----------------------------

Each sector on the drive can be addressed by three cordinates:
  Cylinder = [0..CYLINDERS-1]
  Head     = [0..HEADS-1]
  Sector   = [0..SECTORS-1]
where
  CYLINDERS ... total number of cylinders
  HEADS     ... total number of heads
  SECTORS   ... number of sectors per track

The absolute address of a sector on the disk is then calculated
according to the formula

  Abssector = HEADS*SECTORS*Cylinder + SECTORS*Head + Sector.

We can now calculate the absolute addresses of all sectors
of every bad track on our disk according to

  for each bad track given by Cylinder and Head do
  begin
    for Sector=0 to SECTORS-1 do
    begin
      Abssector = HEADS*SECTORS*Cylinder + SECTORS*Head + Sector
    end
  end

obtaining a list of all bad sectors.


3 Converting absolute sectors to partition relative sectors
-----------------------------------------------------------

Partitions are like separate disks, that means that sector counting
starts with 0 for each partition. So what we have to do next is
to generate a bad sector list for each partition we want to use
for linux. To do that, we must know where each partition starts
and ends. We can get this information from fdisk. When we start
fdisk and type 'p' to view the partition table, the begin, start
and end information will be given in terms of cylinders.
When we type 'u' to toggle the units, an then again 'p'
we get what we need: Start and End of each partition in terms
of absolute sectors.
Here is what I see on my system (I use my second disk for linux):

/# fdisk /dev/hdb

Command (m for help): p

Disk /dev/hdb: 8 heads, 17 sectors, 1024 cylinders
Units = cylinders of 136 * 512 bytes

   Device Boot  Begin   Start     End  Blocks   Id  System
/dev/hdb1           1       1     963   65483+  81  Linux/MINIX
/dev/hdb2         964     964    1024    4148   82  Linux swap

Command (m for help): u
Changing display/entry units to sectors

Command (m for help): p

Disk /dev/hdb: 8 heads, 17 sectors, 1024 cylinders
Units = sectors of 1 * 512 bytes

   Device Boot  Begin   Start     End  Blocks   Id  System
/dev/hdb1           1       1  130967   65483+  81  Linux/MINIX
/dev/hdb2      130968  130968  139263    4148   82  Linux swap

Command (m for help): q

Sector counting (as counting always should do :-) starts with 0.
The first partition begins with sector one, as sector 0 is
always the boot sector.

This is how we calculate the addresses for one partition:

  a) From the list obtained in section 2, cancel all addresses
     that are not in the range [Start..End] (including limits)
     shown by fdisk.
  b) Subtract Start from each remaining entry.


4 Converting to blocks
----------------------

A disk sector has a length of 512 bytes (this is the usual size
BIOS/DOS can handle). Linux groups two sectors to an entity
called block. A block therefore consists of two physical sectors
and has a size of 1024 bytes (I read somewhere that larger blocks
will be supported in the future). The mk(e)fs program wants to
know the addresses of bad blocks, not sectors. So we convert
our partition relatve sector addresses to partition relative
block addresses by dividing by two and taking the integer part.
Doing that we certainly get a lot of duplicate addresses
which we have to get rid of, so we simply delete redundant
entries.

What we have now is a list of bad blocks for each partition.
Mk(e)fs likes to get this information from a file,
one address per line, one file for each partition.


5 Automating the process
------------------------

Doing all the calculations by hand is tedious and error prone.
So we may decide to automate the whole thing.
We can do everything in dos when we use the proper utilities
(see later)

5.1 The Input File

We need a single file containing the coordinates of all bad tracks
of one entire disk. Each line of the file consists of two fields,
the first of which is the cylinder number and the second is
the head number. These are the first few lines of the file for my
second disk:

    48 0
   105 4
   150 2
   224 1
   380 2
   427 6
   435 1


5.2 An AWK script for doing all the calculations

In the following we present an awk script that does all the work
for us. We just have to plug in the correct values of the
partition and drive parameters and off we go.
I use gawk211.zip and sort03.arc which I downloaded from a
simtel20 mirror.
Sort is used to remove the duplicates.

#---the awk script starts here
# generates linux bad blocks file (starting count with 0)
# for partition ONE
# for micropolis drive 8 heads, 17 sectors
# input file: cyl[0.. ] head[0.. ]\n
# stdout: abs blocks of corresponding partition\n
BEGIN { start   = 1;
        end     = 130967;
        sectors = 17;
        heads   = 8;
      }
{ sec=$1*sectors*heads+$2*sectors;
  if (sec>=start && sec<=end)
    for (i=0; i<sectors; i++) print int((sec-start+i)/2) | "sort -mu"
}
#---the awk script ends here

Suppose that our input file is named 'badtrack.lst' and that the
awk file is 'part1.awk', then we can generate a bad block list
for mk(e)fs by typing the command

  gawk -f part1.awk badtrack.lst > badblk1.lst

This is the file we need. 

5.3 Making the file system

What we must do now is to have this file accessible for linux during 
installation. There are several ways to do this. I put it somewhere 
on my dos drive (partition) and mounted the drive (could be a second 
floppy drive as well). Suppose we do the installation from drive a and 
have the file badblk1.lst in the root directory of a floppy in drive b.
Then we mount the floppy b to the /user directory by

  mount -t msdos /dev/fd1 /user

Now we can make the file system (to be concrete we use my example,
that is the first partition of my second drive)

  mk(e)fs -l /user/badblk1.lst /dev/hdb1 65483

Thats it!


Bugs
----

I only tried mkfs but I'm rather convinced that it works with
mkefs as well.


Suggestions and corrections welcome

- Gerhard