
#include <stdio.h>
#include "hd.h"


char rbuf[ HD_SECTOR ];
char wbuf[ HD_SECTOR ];
FILE *input;
FILE *logfile;


main ( argc , argv )
int argc;
char **argv;
{
	char *commands;
	int done_write;
	int status;


	if ( argc != 3  &&  argc != 4 )
		usage ();

	if ( argc > 3 ) {
		input = fopen ( argv[3] , "r" );
		if ( input == NULL ) {
			fprintf ( stderr , "Failed to open '%s'\n" );
			usage ();
		}
	}
	else
		input = NULL;

	logfile = fopen ( argv[1] , "w" );
	if ( logfile == NULL ) {
		printf ( "Failed to create logfile %s\n" , argv[1] );
		usage ();
	}

	init_wbuf ();

	status = wd_open ();
	if ( status != 0 ) {
		fprintf ( stderr , "wd_open() failed - returned %d\n" , status );
		fprintf ( stderr , "continue(y/n)? " );
		if ( getchar () != 'y' ) {
			wd_close ();
			exit ( 1 );
		}
	}

	commands = argv[2];

	if ( *commands == 'f'  ||  *commands == 'F' ) {
		if ( input == NULL ) {
			fprintf ( stderr , "Inputfile must be specified when formatting a disk\n" );
			usage ();
		}
		printf ( "Formatting disk\n" );
		fprintf ( logfile , "Formatting disk\n" );
		init_first_sector ();
		format_disk ();
		commands++;
	}
	else {
		if ( input != NULL )
			fprintf ( stderr , "warning: inputfile only used when disk is reformatted\n" );
		read_first_sector ();
		if ( first.magic != HD_MAGIC ) {
			fprintf ( stderr , "incorrect magic number in sector\n" );
			wd_close ();
			exit ( 1 );
		}
	}

	done_write = 0;

	while ( *commands != '\0' ) {
		switch ( *commands++ ) {

		case 'r' :
		case 'R' :
			printf ( "Reading disk\n" );
			fprintf ( logfile , "Reading disk\n" );
			read_disk ( done_write );
			break;

		case 'w' :
		case 'W' :
			printf ( "Writing disk\n" );
			fprintf ( logfile , "Pass 3: Writing disk\n" );
			write_disk ();
			done_write = 1;
			break;

		default :
			usage ();
		}
	}

	printf ( "Done - writing bad sector table to disk\n" );
	dump_first_sector ();
	printf ( "\n%d sectors used for map information\n" , HD_MAP_SECTORS );
	printf ( "%ld sectors used so far for relinking bad sectors\n" ,
		(long)first.bad_sectors );
	printf ( "%ld tracks would be required to hold these sectors\n\n" ,
		(long)( HD_MAP_SECTORS + first.bad_sectors - 1 ) / first.sectors + 1 );
	printf ( "A total of %d sectors could be used for relinking bad sectors\n" ,
		HD_MAP_SECTORS + HD_MAP_SIZE );
	printf ( "This would require %ld reserved tracks\n" ,
		(long) ( HD_MAP_SECTORS + HD_MAP_SIZE - 1 ) / first.sectors + 1 );

	fclose ( logfile );
	wd_close ();
}


usage ()
{
	fprintf ( stderr , "Usage: initiate logfile commands [inputfile]\n" );
	fprintf ( stderr , "The commands consist of a series of command characters\n" );
	fprintf ( stderr , "If the first character is a 'f' then the hard disk is formatted\n" );
	fprintf ( stderr , "and the map table is rebuilt from the input file\n" );
	fprintf ( stderr , "If the following characters are 'r' or 'w' the entire hard disk\n" );
	fprintf ( stderr , "is read or written to and any errors added to the map table\n" );
	wd_close ();
	exit ( 1 );
}


init_first_sector ()
{
	int i;
	UBYTE *p;
	long interleave_factor;
	struct posn posn;
	char buf[ 128 ];

	if ( fgets ( buf , sizeof(buf) , input ) != NULL
	&&  sscanf ( buf , "%ld" , &first.cylinders ) != 1 ) {
		fprintf ( stderr , "Failed to read number of cylinders\n" );
		usage ();
	}
	if ( fgets ( buf , sizeof(buf) , input ) != NULL
	&&  sscanf ( buf , "%ld" , &first.park_cylinder ) != 1 ) {
		fprintf ( stderr , "Failed to read parking cylinder\n" );
		usage ();
	}
	if ( fgets ( buf , sizeof(buf) , input ) != NULL
	&&  sscanf ( buf , "%ld" , &first.heads ) != 1 ) {
		fprintf ( stderr , "Failed to read number of heads (surfaces)\n" );
		usage ();
	}
	if ( fgets ( buf , sizeof(buf) , input ) != NULL
	&&  sscanf ( buf , "%ld" , &first.sectors ) != 1 ) {
		fprintf ( stderr , "Failed to read number of sectors\n" );
		usage ();
	}
	if ( fgets ( buf , sizeof(buf) , input ) != NULL
	&&  sscanf ( buf , "%ld" , &interleave_factor ) != 1 ) {
		fprintf ( stderr , "Failed to read interleave factor\n" );
		usage ();
	}

	first.magic = HD_MAGIC;
	first.map_sectors = HD_MAP_SECTORS;
	first.bad_sectors = 0;

	fprintf ( logfile , "%3ld cylinders\n" , first.cylinders );
	fprintf ( logfile , "%3ld park cylinder\n" , first.park_cylinder );
	fprintf ( logfile , "%3ld heads\n" , first.heads );
	fprintf ( logfile , "%3ld sectors\n" , first.sectors );
	fprintf ( logfile , "%3ld interleave factor\n" , interleave_factor );

	p = &first.pad[0];
	for ( i = 0; i < sizeof ( first.pad ); i++ )
		*p++ = 0x55;

	new_interleave ( interleave_factor );

	for ( i = 0; i < HD_MAP_SIZE; i++ )
		first.map[i] = MAP_MARK_FREE;

	while ( fgets ( buf , sizeof(buf) , input ) != NULL ) {

		switch ( sscanf ( buf , "%ld %ld %ld\n" ,
			&posn.cylinder , &posn.surface , &posn.sector ) ) {

		case 2 :
			for ( posn.sector = 0; posn.sector < first.sectors; posn.sector++ ) {
				posn.block = posn.sector
					+ ( posn.surface * first.sectors )
					+ ( posn.cylinder * first.sectors * first.heads );
				bad_sector ( &posn , 0 , "input" );
			}
			break;

		case 3 :
			posn.block = posn.sector
				+ ( posn.surface * first.sectors )
				+ ( posn.cylinder * first.sectors * first.heads );
			bad_sector ( &posn , 0 , "input" );
			break;

		default :
			fprintf ( stderr , "Error in bad sector file\n" );
			wd_close ();
			exit ( 1 );
		}
	}
}


read_first_sector ()
{
	int i;
	char *p;
	struct posn posn;

	posn.cylinder = 0;
	posn.surface = 0;
	posn.sector = 0;
	posn.block = 0;
	p = (char*) &first;
	for ( i = 0; i < HD_MAP_SECTORS; i++ ) {
		if ( read_sector ( &posn , p ) != 0 ) {
			fprintf ( stderr , "Read error when reading map sector %d\n" , i );
			wd_close ();
			exit ( 1 );
		}
		posn.sector++;
		posn.block++;
		p += HD_SECTOR;
	}
	if ( first.magic != HD_MAGIC ) {
		fprintf ( stderr , "Incorrect magic number in bad sector map\n" );
		fprintf ( stderr , "Want %08lx, Found %08lx\n" ,
			(long)HD_MAGIC , (long)first.magic );
		wd_close ();
		exit ( 1 );
	}
	if ( first.map_sectors != HD_MAP_SECTORS ) {
		fprintf ( stderr , "error: differing number of map sectors\n" );
		fprintf ( stderr , "(program is hard coded for %d sectors, disk wants %d sectors\n" ,
			HD_MAP_SECTORS , (int)first.map_sectors );
		wd_close ();
		exit ( 1 );
	}

	fprintf ( logfile , "%3ld cylinders\n" , first.cylinders );
	fprintf ( logfile , "%3ld park cylinder\n" , first.park_cylinder );
	fprintf ( logfile , "%3ld heads\n" , first.heads );
	fprintf ( logfile , "%3ld sectors\n" , first.sectors );
}


init_wbuf ()
{
	int i;

	for ( i = 0; i < HD_SECTOR; i++ )
		wbuf[i] = i;
}


format_disk ()
{
	struct posn posn;
	int status;
	int i;

	for ( posn.cylinder = 0; posn.cylinder < first.cylinders; posn.cylinder++ ) {
		printf ( "%03ld " , posn.cylinder );
		for ( posn.surface = 0; posn.surface < first.heads; posn.surface++ ) {
			posn.sector = 0;
			posn.block = posn.sector
				+ ( posn.surface * first.sectors )
				+ ( posn.cylinder * first.sectors * first.heads );
			printf ( "%ld " , posn.surface );
			fflush ( stdout );

			wd_format_track ( &posn );
		}
		printf ( "\n" );
	}
}


read_disk ( check )
int check;
{
	struct posn posn;
	int status;
	int i;

	for ( posn.cylinder = 0; posn.cylinder < first.cylinders; posn.cylinder++ ) {
		printf ( "%03ld " , posn.cylinder );
		fflush ( stdout );
		for ( posn.surface = 0; posn.surface < first.heads; posn.surface++ ) {
			/*
			printf ( "%03ld %ld " , posn.cylinder , posn.surface );
			fflush ( stdout );
			*/
			for ( posn.sector = 0; posn.sector < first.sectors; posn.sector++ ) {
				posn.block = posn.sector
					+ ( posn.surface * first.sectors )
					+ ( posn.cylinder * first.sectors * first.heads );

				if ( is_bad ( &posn ) ) {
					/*
					putchar ( 's' );
					fflush ( stdout );
					*/
					continue;
				}
				/*
				putchar ( '.' );
				fflush ( stdout );
				*/

				status = read_sector ( &posn , rbuf );
				if ( status != 0 )
					bad_sector ( &posn , status , "read" );

				if ( check ) {
					if ( ! cmp_equal ( rbuf , wbuf ) )
						bad_sector ( &posn , 0 , "compare" );
				}
			}
			/*
			printf ( "\n" );
			*/
		}
	}
}


write_disk ()
{
	struct posn posn;
	int status;
	int i;

	for ( posn.cylinder = 0; posn.cylinder < first.cylinders; posn.cylinder++ ) {
		for ( posn.surface = 0; posn.surface < first.heads; posn.surface++ ) {
			printf ( "%03ld %ld " , posn.cylinder , posn.surface );
			fflush ( stdout );
			for ( posn.sector = 0; posn.sector < first.sectors; posn.sector++ ) {
				posn.block = posn.sector
					+ ( posn.surface * first.sectors )
					+ ( posn.cylinder * first.sectors * first.heads );

				if ( is_bad ( &posn ) ) {
					putchar ( 's' );
					fflush ( stdout );
					continue;
				}
				putchar ( '.' );
				fflush ( stdout );

				status = write_sector ( &posn , wbuf );
				if ( status != 0 )
					bad_sector ( &posn , status , "write" );
			}
			printf ( "\n" );
		}
	}
}


bad_sector ( posn , status , msg )
struct posn *posn;
int status;
char *msg;
{
	fprintf ( logfile ,
		"%s: Cylinder %ld, Head %ld, Sector %ld:  Status %d\n" ,
		msg , posn->cylinder , posn->surface , posn->sector , status );
	printf ( "\n%s: Cylinder %ld, Head %ld, Sector %ld:  Status %d\n" ,
		msg , posn->cylinder , posn->surface , posn->sector , status );

	/* ok, now add it to the table of bad sectors */

	while ( first.bad_sectors < HD_MAP_SIZE
	&&  first.map[ first.bad_sectors ] == MAP_MARK_BAD )
		first.bad_sectors++;

	if ( first.bad_sectors < HD_MAP_SIZE ) {
		first.map[ first.bad_sectors++ ] = posn->block;
	}
	else {
		fprintf ( logfile , "   Overflow:  Too many bad sectors!\n" );
		printf ( "   Overflow:  Too many bad sectors!\n" );
	}

	/* if a bad sector, mark the bad map table so dont try and replace */
	/* a bad sector with a bad sector */

	if ( posn->block < HD_MAP_SECTORS ) {
		printf ( "FATAL ERROR! bad sector in map table\n" );
		fprintf ( logfile , "FATAL ERROR! bad sector in map table\n" );
	}
	else if ( posn->block < HD_MAP_SECTORS + HD_MAP_SIZE )
		first.map[ posn->block - HD_MAP_SECTORS ] = MAP_MARK_BAD;
}


cmp_equal ( buf1 , buf2 )
register char *buf1 , *buf2;
{
	register int i;

	for ( i = 0; i < HD_SECTOR; i++ )
		if ( buf1[i] != buf2[i] )
			return ( 0 );
	return ( 1 );
}


dump_first_sector ()
{
	struct posn posn;
	int i , j;
	LONG *pl;
	char *p;
	int count;

	fprintf ( logfile , "\nInitial Sector\n" );
	pl = (LONG*) &first;
	for ( i = 0; i < sizeof(first)/sizeof(long); i++ ) {
		fprintf ( logfile , "%08lx " , *pl++ );
		if ( ( i + 1 ) % 8 == 0 )
			fprintf ( logfile , "\n" );
	}
	fprintf ( logfile , "\n" );

	posn.surface = 0;
	posn.cylinder = 0;
	posn.sector = 0;
	posn.block = 0;
	p = (char*) &first;
	count = HD_MAP_SECTORS;
	while ( count-- > 0 ) {
		if ( write_sector ( &posn , p ) != 0 )
			fprintf ( stderr , "Failed to write map sector %d\n" ,
				posn.sector );
		posn.sector++;
		posn.block++;
		p += HD_SECTOR;
	}
}


is_bad ( posn )
struct posn *posn;
{
	int i;

	for ( i = 0; i < first.bad_sectors; i++ ) {
		if ( posn->block == first.map[ i ] )
			return ( 1 );
	}
	return ( 0 );
}


new_interleave ( interleave )
long interleave;
{
	int i;
	int j;

	for ( i = 0; i < first.sectors; i++ )
		first.interleave[i*2+1] = first.sectors;	/* mark as free */
	j = 0;
	for ( i = 0; i < first.sectors; i++ ) {
		while ( first.interleave[j*2+1] != first.sectors ) {
			j++;
			while ( j >= first.sectors ) j -= first.sectors;
		}
		first.interleave[j*2+1] = i;
		j += interleave;
		while ( j >= first.sectors ) j -= first.sectors;
	}
	for ( i = 0; i < first.sectors; i++ )
		printf ( "%d " , first.interleave[i*2+1] );
	printf ( "\n" );
}
