[comp.os.minix] Format disks under Minix-ST

mills@ccu.umanitoba.ca (Gary Mills) (02/20/89)

Here is a command and some kernel mods to format floppy disks under Minix
on the Atari ST.  I couldn't find a formatting command in version 7 to use
as a model.  I wasn't sure how verbose it should be, but since it takes
some time to complete, I decided it should display something to let you know
what it's doing.

In the driver, I reserve one bit of the minor number to indicate a format
request.  The modifications are slight, but do clutter the nice code with
if/else statements.  The `write sector' command is replaced with a `write
track' command.  Seeks and restores have to be done blindly because there
is no track information on the disk before formatting.  This means that few
errors can be detected by the driver during formatting.  

The formatting device appears to the command as an array of 7K byte blocks,
with each block representing a track on the disk.  The command merely builds
an image of each track in memory and writes it to the device.  After 
formatting, it reads each track to detect bad sectors.  Constructive
criticism of my interleave table and track layout will be welcome.

The shar file enclosed below includes installation instructions.

-Gary Mills-             -University of Manitoba-           -Winnipeg-

==================

#! /bin/sh
# This is a shell archive, meaning:
# 1.  Remove everything above the #! /bin/sh line.
# 2.  Save the resulting text in a file
# 3.  Execute the file with /bin/sh (not csh) to create the files:
#
#		Install
#		floppy.cdif
#		format.c
#
# Created by mills () on Sat Feb 18 16:03:39 CST 1989
#
if test -f 'Install'
then
	echo shar: will not over-write existing file "'Install'"
else
echo extracting "'Install'"
sed 's/^X//' >Install <<'SHAR_EOF'
XFormatting floppy disks under Minix-st:  Gary Mills <mills@ccu.umanitoba.ca>
X
X1) Apply floppy.cdif to kernel/stfloppy.c and remake kernel. (Sect 4.2)
X2) Build a new kernel image and boot from it.  (Sect. 4.3)
X3) Create the formatting device special files.  The name must be composed
X   of "fmt" followed by the name of the block device.  The formatting 
X   device must be a character device with a minor number of 64 plus the
X   normal minor number.  For example, to format single-sided and double-
X   sided disks disks in drive zero:
X   # cd /dev
X   # mknod fmtfd0 c 2 64; chmod 600 fmtfd0
X   # mknod fmtdd0 c 2 72; chmod 600 fmtdd0
X   These last lines can be added to the Makedev script.
X4) Compile floppy.c.  The binary should probably be installed in /etc.
X5) To format a disk, type /etc/format <drive>.  For example, to format a
X   single-sided disk in drive zero:
X   # /etc/format fd0
X   The drive could also be specified as /dev/fd0, or just 0, which are
X   all equivalent.
X6) If desired, use mkfs to create a Minix file system on the disk.  Note
X   that a disk formatted as double-sided can still be used as a single-
X   sided file system or boot disk as the format is identical.
X
SHAR_EOF
if test    1189 -ne "`wc -c < 'Install'`"
then
	echo shar: error transmitting "'Install'" '(should have been    1189 characters)'
fi
fi
if test -f 'floppy.cdif'
then
	echo shar: will not over-write existing file "'floppy.cdif'"
else
echo extracting "'floppy.cdif'"
sed 's/^X//' >floppy.cdif <<'SHAR_EOF'
X*** stfloppy.Oc	Thu Jan 15 11:02:47 1989
X--- stfloppy.c	Thu Feb 18 11:14:24 1989
X***************
X*** 48,53 ****
X--- 48,54 ----
X  #define	FDC_DELAY	32	/* for dma[rw]dat() */
X  
X  /* Parameters for the disk drive. */
X+ #define TRACK_SIZE	7168	/* track size in bytes for formatting */
X  #define SECTOR_SIZE	512	/* physical sector size in bytes */
X  #define NR_SECTORS	9	/* number of sectors per track */
X  #define NR_CYLINDERS	80	/* number of cylinders */
X***************
X*** 84,90 ****
X  } xfer;
X  
X  #define	DRIVE(d)	((d) & 0x07)
X! #define	DTYPE(d)	(((d) >> 3) & 0x1F)
X  
X  FORWARD int	fdcint();
X  
X--- 85,92 ----
X  } xfer;
X  
X  #define	DRIVE(d)	((d) & 0x07)
X! #define	DTYPE(d)	(((d) >> 3) & 0x07)
X! #define FORMAT(d)	((d) & 0x40)
X  
X  FORWARD int	fdcint();
X  
X***************
X*** 152,158 ****
X  	return(EINVAL);
X    if ((nbytes % SECTOR_SIZE) != 0)
X  	return(EINVAL);
X!   xp->x_secnum = (int)(mp->POSITION/SECTOR_SIZE);
X    rp = proc_addr(mp->PROC_NR);
X    xp->x_address = umap(rp, D, (vir_bytes) mp->ADDRESS, (vir_bytes) nbytes);
X    if (xp->x_address == 0)
X--- 154,166 ----
X  	return(EINVAL);
X    if ((nbytes % SECTOR_SIZE) != 0)
X  	return(EINVAL);
X!   if (FORMAT(xp->x_drive)) {
X! 	if (nbytes != TRACK_SIZE || xp->x_rw != DISK_WRITE)
X! 		return(EINVAL);
X! 	xp->x_secnum = (int)(mp->POSITION/TRACK_SIZE);
X!   }
X!   else
X! 	xp->x_secnum = (int)(mp->POSITION/SECTOR_SIZE);
X    rp = proc_addr(mp->PROC_NR);
X    xp->x_address = umap(rp, D, (vir_bytes) mp->ADDRESS, (vir_bytes) nbytes);
X    if (xp->x_address == 0)
X***************
X*** 186,192 ****
X    xp = &xfer;
X  
X    d = DTYPE(xp->x_drive);
X!   cylinder = xp->x_secnum / NR_SECTORS;
X    head = cylinder % nr_heads[d];
X    cylinder = cylinder / nr_heads[d];
X    if (cylinder >= NR_CYLINDERS)
X--- 194,203 ----
X    xp = &xfer;
X  
X    d = DTYPE(xp->x_drive);
X!   if (FORMAT(xp->x_drive))
X! 	cylinder = xp->x_secnum;
X!   else
X! 	cylinder = xp->x_secnum / NR_SECTORS;
X    head = cylinder % nr_heads[d];
X    cylinder = cylinder / nr_heads[d];
X    if (cylinder >= NR_CYLINDERS)
X***************
X*** 211,217 ****
X  	 * This way the controller can get back into sync with reality.
X  	 */
X  	TRACE(printf("fd%d: recalibrate\n", xp->x_drive));
X! 	dmawdat(FDC_CS, RESTORE|VBIT|hbit, FDC_DELAY);
X  	xp->x_cmd = RESTORE;
X  	return(1);
X    }
X--- 222,231 ----
X  	 * This way the controller can get back into sync with reality.
X  	 */
X  	TRACE(printf("fd%d: recalibrate\n", xp->x_drive));
X! 	if (FORMAT(xp->x_drive))
X! 		dmawdat(FDC_CS, RESTORE|hbit, FDC_DELAY);
X! 	else
X! 		dmawdat(FDC_CS, RESTORE|VBIT|hbit, FDC_DELAY);
X  	xp->x_cmd = RESTORE;
X  	return(1);
X    }
X***************
X*** 225,231 ****
X    if (cylinder != curcyl[d]) {
X  	curcyl[d] = cylinder;	/* be optimistic */
X  	dmawdat(FDC_DR, cylinder, FDC_DELAY);
X! 	dmawdat(FDC_CS, SEEK|RATE3|VBIT|hbit, FDC_DELAY);
X  	xp->x_cmd = SEEK;
X  	return(1);
X    }
X--- 239,252 ----
X    if (cylinder != curcyl[d]) {
X  	curcyl[d] = cylinder;	/* be optimistic */
X  	dmawdat(FDC_DR, cylinder, FDC_DELAY);
X! 	if (FORMAT(xp->x_drive)) {
X! 		if (cylinder == 0)
X! 			dmawdat(FDC_CS, RESTORE|hbit, FDC_DELAY);
X! 		else
X! 			dmawdat(FDC_CS, SEEK|RATE3|hbit, FDC_DELAY);
X! 	}
X! 	else
X! 		dmawdat(FDC_CS, SEEK|RATE3|VBIT|hbit, FDC_DELAY);
X  	xp->x_cmd = SEEK;
X  	return(1);
X    }
X***************
X*** 248,255 ****
X  	xp->x_cmd = F_READ;
X    } else {
X  	/* Issue the command */
X! 	dmacomm(WRBIT | FDC | SCREG, 1, FDC_DELAY);
X! 	dmawdat(WRBIT | FDC_CS, F_WRITE|hbit, FDC_DELAY);
X  	xp->x_cmd = F_WRITE;
X    }
X    return(1);
X--- 269,282 ----
X  	xp->x_cmd = F_READ;
X    } else {
X  	/* Issue the command */
X! 	if (FORMAT(xp->x_drive)) {
X! 		dmacomm(WRBIT | FDC | SCREG, TRACK_SIZE/SECTOR_SIZE, FDC_DELAY);
X! 		dmawdat(WRBIT | FDC_CS, WRITETR|hbit, FDC_DELAY);
X! 	}
X! 	else {
X! 		dmacomm(WRBIT | FDC | SCREG, 1, FDC_DELAY);
X! 		dmawdat(WRBIT | FDC_CS, F_WRITE|hbit, FDC_DELAY);
X! 	}
X  	xp->x_cmd = F_WRITE;
X    }
X    return(1);
X***************
X*** 358,365 ****
X    case X_OK:
X  	xp->x_errors = 0;
X  	xp->x_secnum++;
X! 	xp->x_address += SECTOR_SIZE;
X! 	xp->x_count -= SECTOR_SIZE;
X  	if (xp->x_count == 0)
X  		return(1);
X  	break;
X--- 385,398 ----
X    case X_OK:
X  	xp->x_errors = 0;
X  	xp->x_secnum++;
X! 	if (FORMAT(xp->x_drive)) {
X! 		xp->x_address += TRACK_SIZE;
X! 		xp->x_count -= TRACK_SIZE;
X! 	}
X! 	else {
X! 		xp->x_address += SECTOR_SIZE;
X! 		xp->x_count -= SECTOR_SIZE;
X! 	}
X  	if (xp->x_count == 0)
X  		return(1);
X  	break;
SHAR_EOF
if test    4392 -ne "`wc -c < 'floppy.cdif'`"
then
	echo shar: error transmitting "'floppy.cdif'" '(should have been    4392 characters)'
fi
fi
if test -f 'format.c'
then
	echo shar: will not over-write existing file "'format.c'"
else
echo extracting "'format.c'"
sed 's/^X//' >format.c <<'SHAR_EOF'
X/* format.c: format a floppy disk */
X
X/* Author:  Gary Mills <mills@ccu.umanitoba.ca> */
X
X#include <stdio.h>
X
X#define TRACK_SIZE	7168
X#define NR_SECTORS	9
X#define NR_CYLINDERS	80
X#define TRACK_CAP	(512*NR_SECTORS)
X#define TRK_NDX		3
X
Xstruct desc {
X	int rep;	/* repetition count */
X	int val;	/* byte value */
X};
Xtypedef struct desc DESC;
X
XDESC leader[] = {
X	160,	0x4e,	/* pre-index gap */
X	12,	0,	/* sync before index */
X	3,	0xf6,	/* C2 */
X	1,	0xfc,	/* index mark */
X	80,	0xff,	/* gap 1 */
X	0,	0
X};
X
XDESC brack[] = {
X	12,	0,	/* sync before id */
X	3,	0xf5,	/* A1 */
X	1,	0xfe,	/* id address mark */
X	1,	0,	/* track */
X	1,	0,	/* side */
X	1,	0,	/* sector */
X	1,	2,	/* sector length (512) */
X	1,	0xf7,	/* crc */
X	22,	0x4e,	/* gap 2 */
X	12,	0,	/* sync before data */
X	3,	0xf5,	/* A1 */
X	1,	0xfb,	/* data address mark */
X	512,	0,	/* data */
X	1,	0xf7,	/* crc */
X	64,	0x4e,	/* gap 3 */
X	0,	0
X};
X
XDESC trail[] = {
X	TRACK_SIZE,	0x4e,	/* gap */
X	0,	0
X};
X
Xint interleave[NR_SECTORS] = { 1,6,2,7,3,8,4,9,5 };
Xint verbose = 1;
X
Xint nr_heads;
Xint o_trk, b_len;
Xchar *mark;
Xshort disk;
Xchar image[TRACK_SIZE];
Xchar b_dev[128], f_dev[128], c_dev[128];
X
Xchar *strrchr();
Xchar *fill();
X
Xmain(argc, argv) int argc; char *argv[]; {
X	char *drive;
X	char *pt;
X	int n;
X	int head, cyl;
X
X	if ( argc != 2 ) {
X		fprintf(stderr, "Usage: format drive\n");
X		exit(1);
X	}
X	drive = argv[1];
X	if ( *drive >= '0' && *drive <= '9' )
X		sprintf(b_dev, "/dev/fd%c", *drive);
X	else if ( *drive == '/' )
X		strcpy(b_dev, drive);
X	else
X		sprintf(b_dev, "/dev/%s", drive);
X	strcpy(f_dev, b_dev);
X	strcpy(c_dev, b_dev);
X	if ( !( pt = strrchr(b_dev, '/') ) ) {
X		fprintf(stderr, "Invalid drive %s\n", drive);
X		exit(1);
X	}
X	++pt;
X	sprintf(f_dev + (pt - b_dev), "fmt%s", pt);
X	sprintf(c_dev + (pt - b_dev), "r%s", pt);
X	if ( *pt == 'f' )
X		nr_heads = 1;
X	else if ( *pt == 'd' )
X		nr_heads = 2;
X	else {
X		fprintf(stderr, "Invalid drive %s\n", drive);
X		exit(1);
X	}
X
X	b_len = 0;
X	for ( n = 0; brack[n].rep; ++n ) {
X		if ( n == TRK_NDX )
X			o_trk = b_len;
X		b_len += brack[n].rep;
X	}
X
X	pt = fill(image, &leader[0]);
X	mark = pt + o_trk;
X	for ( n = 0; n < NR_SECTORS; ++n )
X		pt = fill(pt, &brack[0]);
X	fill(pt, &trail[0]);
X
X	if ( ( disk = open(f_dev, 1) ) < 0 ) {
X		fprintf(stderr, "Cannot open %s\n", f_dev);
X		exit(1);
X	}
X	if ( verbose ) 
X		fprintf(stderr, "Formatting\n");
X	for ( cyl = 0; cyl < NR_CYLINDERS; ++cyl ) {
X		if ( verbose )
X			fprintf(stderr, "Cyl: %d\r", cyl);
X		for ( head = 0; head < nr_heads; ++head ) {
X			pt = mark;
X			for ( n = 0; n < NR_SECTORS; ++n ) {
X				pt[0] = cyl;
X				pt[1] = head;
X				pt[2] = interleave[n];
X				pt += b_len;
X			}
X			if ( write(disk, image, TRACK_SIZE) != TRACK_SIZE ) {
X				perror("I/O Error");
X				exit(1);
X			}
X		}
X	}
X	close(disk);
X
X	if ( ( disk = open(c_dev, 0) ) < 0 ) {
X		fprintf(stderr, "Cannot open %s\n", c_dev);
X		exit(1);
X	}
X	if ( verbose )
X		fprintf(stderr, "Verifying \n");
X	for ( cyl = 0; cyl < NR_CYLINDERS; ++cyl ) {
X		if ( verbose )
X			fprintf(stderr, "Cyl: %d\r", cyl);
X		for ( head = 0; head < nr_heads; ++head ) {
X			if ( read(disk, image, TRACK_CAP) != TRACK_CAP ) {
X				fprintf(stderr, "Error reading cylinder %d\n", cyl);
X				exit(1);
X			}
X		}
X	}
X	close(disk);
X	if ( verbose )
X		fprintf(stderr, "Complete   \n");
X
X	exit(0);
X}
X
Xchar *
Xfill(pt, st) char *pt; DESC *st; {
X	char *lim = &image[TRACK_SIZE];
X	register int n;
X
X	while ( (n = st->rep ) && pt < lim ) {
X		while ( --n >= 0 && pt < lim ) 
X			*pt++ = st->val;
X		++st;
X	}
X	return pt;
X}
X
Xchar *
Xstrrchr(s, c) char *s, c; {
X	register char *pt = NULL;
X	while ( *s ) {
X		if ( c == *s )
X			pt = s;
X		++s;
X	}
X	return pt;
X}
X
X/**/
X
SHAR_EOF
if test    3593 -ne "`wc -c < 'format.c'`"
then
	echo shar: error transmitting "'format.c'" '(should have been    3593 characters)'
fi
fi
# end of shell archive
exit 0