/* $Id: hps_dump.c,v 1.3 91/10/02 13:40:10 leynette Exp $ */
/* ex:set ts=4 sw=4: */
/****************************************************************/
/* hps_dump - program to dump HPS memory to file on host for 	*/
/*		later analysis and debug								*/
/****************************************************************/
/*                 Confidential Information                     */
/*      Limited Distribution to Authorized Persons Only         */
/*     Created 1990 and Protected as an Unpublished Work        */
/*          Under the U.S. Copyright Act of 1976.               */
/*         Copyright (c) 1990, Systech Corporation              */
/*                  All Rights Reserved                         */
/*																*/
/*	THIS SOFTWARE IS LICENSED BY AND IS THE	CONFIDENTIAL AND 	*/
/*	PROPRIETARY PROPERTY OF SYSTECH COMPUTER CORPORATION AND 	*/
/*	MAY NOT, WITHOUT THE PRIOR WRITTEN CONSENT OF SYSTECH 		*/
/*	COMPUTER CORPORATION, BE REPRODUCED, USED OR DISCLOSED 		*/
/*	EXCEPT IN ACCORDANCE WITH A SYSTECH COMPUTER CORPORATION 	*/
/*	SOFTWARE LICENSE AGREEMENT.									*/
/****************************************************************/
/* This program simply uses the loader interface to upload all	*/
/* of memory from the HPS board into a file.  This allows us a	*/
/* snapshot of a system for later analysis and debug.			*/
/* To facilitate deciphering the memory dump, a number of 		*/
/* things are also stored at the beginning of the file.			*/
/* The first 1024 bytes are defined as a header in st.dump.h.	*/
/****************************************************************/

/*
 * INCLUDES
 */

#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <time.h>
#include <string.h>
#include <memory.h>
#include "hps.std.h"
#include "hps.iocb.h"
#include "hps.ioctl.h"
#include "st.dump.h"
#include "hps.dev_type.h"
#include "hps.swap.h"

/* 
 * EXPORTS
 */

/* NOTE that these four items are required by the hdblib routine hps_lread */
char  hps_intel    = 0;			/* host byte ordering	*/
long  dumpfile     = 0;			/* MUST BE ZERO for hps_lread to read board */
long  ram_start    = 0;
long  ram_end      = 0;

/* 
 * IMPORTS 
 */

extern void exit();
extern int gaddrs();
extern bit32 logsub();

/*
 * LOCALS
 */

#define DBUFSIZE 512
#define min(x, y) ((x < y) ? x : y)

struct log_buff
{
	INFO info;
	long table[50];
};

/*
 *
 */

main(argc, argv)
int argc;
char *argv[];

{
	char *devname;			/* Raw device name */
	char *dumpfilename; 	/* Dump file name */
	char buffer[DBUFSIZE];	/* For transfer from board to file */
	int blknum;				/* Block number for transfer */
	int	blksize;			/* Block size for transfer */
	int dfile;				/* File descriptor for dumpfile */
	int hpsfd;				/* File descriptor for raw device */
	struct st_dump_hdr dump_hdr;	/* Standard header for dump file */
	short tmp;				/* For determining byte sex of machine */
	long now;				/* Temp variable for the time */
	long dumpaddr;			/* Variable for actual dump process */
	struct log_buff l_buff;	/* Temp variable for the log table */

	/* Determine byte sex of machine we are on */
	tmp = 0;
	hps_intel = *(char *)&tmp;

	/* Set up the file names from defaults or arguments */
	switch(argc)
	{
		case 1:		/* No parameters */
			dumpfilename = DFILENAME;
			devname = RAW_DEVNAME;
			break;
		case 2:		/* one parameter, use as the dumpfile name */
			dumpfilename = argv[1];
			devname = RAW_DEVNAME;
			break;
		case 3: 	/* two params, use as dumpfile name and raw device name */
			dumpfilename = argv[1];
			devname = argv[2];
			break;
		default:	/* Anything else - complain */
			usage(argv[0]);
			exit(1);
			break;
	}

	if ((dfile = open(dumpfilename, O_WRONLY | O_CREAT, 0444)) < 0)
	{
		fprintf(stderr, "%s: Unable to create dumpfile %s\n", argv[0], 
								dumpfilename);
		perror(argv[0]);
		exit(1);
	}

	/* Fill in the dumpfile header */
	/* First a sanity check on the compiler */
	if (sizeof(dump_hdr) != DTOT_LEN)
	{
		fprintf(stderr, "%s: Internal error - dumpfile header was %d bytes, \n",
								argv[0], sizeof(dump_hdr));
		fprintf(stderr, "     Not %d bytes as expected\n", DTOT_LEN);
		exit(1);
	}

	/* Zero out the whole thing */
	memset(&dump_hdr, '\0', sizeof(dump_hdr));

	/* Fill in the id string */
	strcpy(dump_hdr.du_idstr, DU_ID_STRING);

	/* Fill in the date/time stamp */
	now = time((long *) 0);
	strcpy(dump_hdr.du_date, ctime(&now));

	/* Grab the log table from the board */
	if ((logsub(&l_buff, 0, devname, argv[0])) != 0)
	{
		fprintf(stderr, "%s: Unable to get log table\n", argv[0]);
		exit(1);
	}
	dump_hdr.du_loginfo = l_buff.info;
	memcpy(dump_hdr.du_logtable, l_buff.table, sizeof(l_buff.table));

	/* And the system address table from the board */
	if (gaddrs(dump_hdr.du_sysaddrtable, devname) != 0)
	{
		fprintf(stderr, "%s: Unable to get system address table\n", argv[0]);
		exit(1);
	}

	/* Determine the address ranges */
	switch (l_buff.info.i_type)
	{
		case HPS_6840:
		case HPS_6860:
		case HPS_6940:
		case HPS_6960:
		case HPS_6945:
			ram_start = 0x100000;
			ram_end = 	0x17FFFF;
			break;

		case HPS_6245:
		case HPS_6240:
		case HPS_6270:
#ifdef HPS_6180
		case HPS_6180:
#endif
			ram_start = 0x1000000;
			ram_end = 	0x10FFFFF;
			break;

#ifdef HPS_6280
		case HPS_6280:
			ram_start = 0x1000000;
			ram_end = 	0x11FFFFF;
			break;
#endif

#ifdef NTX_8023
		case NTX_8023:
			ram_start = 0x1000000;
			ram_end = 	0x11FFFFF;
			break;
#endif

		case HPS_6236:
		case HPS_6237:
			ram_start = 0x1000000;
			ram_end = 	0x107FFFF;
			break;

		default:
			ram_start = 0x1000000;
			ram_end =   0x10FFFFF;
			fprintf(stderr,"%s: Unknown board type: 0x%x\n", argv[0],
								l_buff.info.i_type);
			fprintf(stderr,"%s: Assuming ram start of 0x%x and ram_end of 0x%x\n",
				argv[0], ram_start, ram_end);
			break;
	}
	printf("Using ram start of 0x%x and ram_end of 0x%x\n",
					ram_start, ram_end);

	/* Store the ram boundaries in the header in Motorola format */
	if (hps_intel)
	{
		SWAP_4BYTE(&dump_hdr.du_startaddr, &ram_start);
		SWAP_4BYTE(&dump_hdr.du_endaddr, &ram_end);
	}
	else
	{
		dump_hdr.du_startaddr = ram_start;
		dump_hdr.du_endaddr = ram_end;
	}

	/* Now write the whole header at once to the dumpfile */
	write(dfile, &dump_hdr, sizeof(dump_hdr));

	/* Open HPS raw driver */
	if ((hpsfd = open(devname, O_RDWR)) < 0)
	{
		fprintf(stderr, "%s: Cannot open file %s\n", argv[0], devname);
		perror(argv[0]);
		exit(1);
	}

	for (blknum = 0, dumpaddr = ram_start; 
		 dumpaddr <= ram_end; 
		 dumpaddr += DBUFSIZE, blknum++)
	{
		/* Get the block */
		blksize = min(DBUFSIZE, (ram_end - ram_start) + 1);
		if (hps_lread(hpsfd, buffer, dumpaddr, blksize, argv[0]) != blksize)
		{
			fprintf(stderr, "%s: Failed read on hps board.\n", argv[0]);
			exit(1);
		}
		if (write(dfile, buffer, blksize) != blksize)
		{
			fprintf(stderr, "%s: Failed write to dump file.\n", argv[0]);
			exit(1);
		}
		if ((blknum % 128) == 0)
			printf("Successful read of 0x%x\n", dumpaddr);
	}
	close(hpsfd);
/*	close(dfile); */
	return(0);
}

/*
 *	FUNCTION usage - display usage statement for this program
 *
 *	DESCRIPTION
 *		Display simple usage statement for this program
 *
 *	PARAMETERS
 *		pname - program name
 *
 *	RETURN VALUES
 *		None
 */

 usage(pname)
 char *pname;
 {
	fprintf(stderr, "usage: %s [dumpfile_name [raw_device_name]]\n", pname);
	fprintf(stderr, "     dumpfile_name and raw_device_name are optional.\n");
	fprintf(stderr, "     Examples:\n");
	fprintf(stderr, "        %s\n", pname);
	fprintf(stderr, "        %s hpscore\n", pname);
	fprintf(stderr, "        %s hpscore /dev/rhp1\n", pname);
	fprintf(stderr, "     dumpfile_name must be specified before a raw \n");
	fprintf(stderr, "     device name may be specified.\n");
 }
