
#include <stdio.h>
#include <exec/types.h>
#include <exec/memory.h>
#include "harddisk.h"
#include <ctype.h>



struct MsgPort *			diskport;
struct IOExtHD *			diskreq;
BYTE						sector[ HD_SECTOR ];
struct hd_FirstSector		first;


extern struct MsgPort *		CreatePort ();
extern struct IORequest *	CreateExtIO ();
extern LONG					OpenDevice ();
extern LONG					DoIO ();


main()
{
	long error;
	
	diskport = CreatePort ( 0L , 0L );
	if ( diskport == NULL ) {
		printf ( "Error in CreatePort ()\n" );
	}
	else {
		diskreq = (struct IOExtHD *)
			CreateExtIO ( diskport , (LONG) sizeof ( struct IOExtHD ) );     
		if ( diskreq == NULL ) {
			printf ( "CreateExtIO() failed\n" );
		}
		else {
		    error = OpenDevice ( HD_NAME , 0L , diskreq , 0L );
			if ( error != 0 ) {
			    printf ( "Error value returned by OpenDevice was %ld\n" , error );
			}
			else {
				diskreq->iohd_TD.iotd_Req.io_Command = CMD_READ;
			    diskreq->iohd_TD.iotd_Req.io_Data = (APTR) &first;
			    diskreq->iohd_TD.iotd_Req.io_Length = sizeof ( first );
			    diskreq->iohd_TD.iotd_Req.io_Offset = 0;
			    if ( DoIO ( diskreq ) != 0 ) {
					printf ( "Error in reading first sector information\n" );
				}
				else {
					if ( first.magic != HD_MAGIC )
						printf ( "Header sector information not found (wrong magic number)\n" );
					else
						do_commands ();
				}
			    CloseDevice ( diskreq );
			}
			DeleteExtIO ( diskreq , (LONG) sizeof ( struct IOExtHD ) );
		}
		DeletePort ( diskport );
	}
}


do_commands ()
{
	long block;
	int i;
	char buf[ 80 ];
	int retry_limit;

	while ( 1 ) {

		printf ( "\nDisk Information:\n\n" );
		printf ( "%4ld cylinders\n" , first.cylinders );
		printf ( "%4ld park cylinder\n" , first.park_cylinder );
		printf ( "%4ld heads\n" , first.heads );
		printf ( "%4ld sectors\n" , first.sectors );
		printf ( "%4ld map sectors\n" , first.map_sectors );
		printf ( "%4ld bad sectors\n" , first.bad_sectors );
		printf ( "%4ld write precompensation\n" , first.precomp );
		printf ( "\nBad blocks: " );
		for ( i = 0; i < first.bad_sectors; i++ )
			printf ( "%ld " , (long)first.map[i] );
		printf ( "\n\n" );

		diskreq->iohd_TD.iotd_Req.io_Command = CMD_FLUSH;
		DoIO ( diskreq );
		diskreq->iohd_TD.iotd_Req.io_Command = CMD_CLEAR;
		DoIO ( diskreq );

		printf ( "Enter block number or (q)uit: " );
		if ( gets ( buf ) == NULL )
			return;
		if ( buf[0] == 'q'  ||  buf[0] == 'Q' )
			return;
		if ( sscanf ( buf , "%ld" , &block ) != 1 ) {
			printf ( "Illegal block number\n" );
		}
		else {
			printf ( "Reading block %ld\n" , block );
			diskreq->iohd_TD.iotd_Req.io_Command = CMD_READ;
		    diskreq->iohd_TD.iotd_Req.io_Data = (APTR) &sector[0];
		    diskreq->iohd_TD.iotd_Req.io_Length = HD_SECTOR;
		    diskreq->iohd_TD.iotd_Req.io_Offset = block * HD_SECTOR;
			if ( DoIO ( diskreq ) != 0 ) {
				while ( 1 ) {
					printf ( "Failed to read sector - enter retry count: " );
					if ( gets ( buf ) == NULL )
						return;
					if ( sscanf ( buf , "%d" , &retry_limit ) != 1 )
						retry_limit = 1;
					if ( retry_limit <= 0 )
						break;
					for ( i = 0; i < retry_limit; i++ ) {
						printf ( "Reading block %ld\n" , block );
						diskreq->iohd_TD.iotd_Req.io_Command = CMD_READ;
					    diskreq->iohd_TD.iotd_Req.io_Data = (APTR) &sector[0];
					    diskreq->iohd_TD.iotd_Req.io_Length = HD_SECTOR;
					    diskreq->iohd_TD.iotd_Req.io_Offset = block * HD_SECTOR;
						if ( DoIO ( diskreq ) == 0 )
							break;
					}
					if ( i >= retry_limit ) {
						printf ( "Failed to read sector after %d attempts - setting buffer to 0's\n" ,
							retry_limit );
						for ( i = 0; i < HD_SECTOR; i++ )
							sector[i] = 0;
					}
					else {
						printf ( "Sector successfully read after %d retries\n" , i );
						break;
					}
				}
			}
			printf ( "(u)nlink the sector or\n(w)rite the sector? " );

			if ( gets ( buf ) == NULL )
				return;

			if ( buf[0] == 'u'  ||  buf[0] == 'U' ) {

				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 ) {
					printf ( "Bad sector map table is full!\n" );
				}
				else {
					/* write out sector at block first.bad_sectors */
					printf ( "Writing sector buffer to block %ld\n" ,
						first.bad_sectors + HD_MAP_SECTORS );
					diskreq->iohd_TD.iotd_Req.io_Command = CMD_WRITE;
				    diskreq->iohd_TD.iotd_Req.io_Data = (APTR) &sector[0];
				    diskreq->iohd_TD.iotd_Req.io_Length = HD_SECTOR;
				    diskreq->iohd_TD.iotd_Req.io_Offset =
						( first.bad_sectors + HD_MAP_SECTORS ) * HD_SECTOR;
					if ( DoIO ( diskreq ) != 0 ) {
						printf ( "Failed to write block - bad sector not removed\n" );
					}
					else {
						/* change map */
						first.map[ first.bad_sectors++ ] = block;

						/* write out sector map */
						diskreq->iohd_TD.iotd_Req.io_Command = CMD_WRITE;
					    diskreq->iohd_TD.iotd_Req.io_Data = (APTR) &first;
					    diskreq->iohd_TD.iotd_Req.io_Length = sizeof ( first );
					    diskreq->iohd_TD.iotd_Req.io_Offset = 0;
						if ( DoIO ( diskreq ) != 0 ) {
							printf ( "Failed to write first sectors\n" );
							return;
						}
						printf ( "\nUnlinked - WARNING: you must reboot for driver to learn of relinking\n\n" );
					}
				}
			}
			else if ( buf[0] == 'w'  ||  buf[0] == 'W' ) {
				printf ( "Writing block %ld\n" , block );
				diskreq->iohd_TD.iotd_Req.io_Command = CMD_WRITE;
			    diskreq->iohd_TD.iotd_Req.io_Data = (APTR) &sector;
			    diskreq->iohd_TD.iotd_Req.io_Length = HD_SECTOR;
			    diskreq->iohd_TD.iotd_Req.io_Offset = block * HD_SECTOR;
				if ( DoIO ( diskreq ) != 0 ) {
					printf ( "Failed to rewrite sector\n" );
				}
				else
					printf ( "Rewrite successful\n" );
			}
			else {
				printf ( "Sector not unlinked or rewritten\n" );
			}
		}
	}
}
