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