/* $Id: hps_log.c,v 2.3 91/09/03 17:37:05 annette Exp $ */
/****************************************************************/
/* hps_log.c:  HPS statistics log reported						*/
/****************************************************************/
/*																*/
/*                 Confidential Information                     */
/*      Limited Distribution to Authorized Persons Only         */
/*     Created 1986 and Protected as an Unpublished Work        */
/*          Under the U.S. Copyright Act of 1976.               */
/*         Copyright (c) 1986, 1987, 1988 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 requests the log table from the host			*/
/*        adapter or a specified cluster controller,			*/
/*		and format and display it on standard output.        	*/
/*        If reqested, it will send the table out unformatted	*/
/*                                                             	*/
/*   Options:                                                  	*/
/*        a - get log table from cluster controller.  Network  	*/
/*            address must be specified.                       	*/
/*        c - request table to be cleared                      	*/
/*        d - device name                                      	*/
/*        u - do not display table, send it out as binary      	*/
/*                                                             	*/
/****************************************************************/

/* #define DEBUG */

#include <stdio.h>
#include "hps.types.h"
#include "hps.iocb.h"
#include "hps.ioctl.h"
#include "hps.conf.h"
#include "hps.onb.h"
#include "hps.net.h"
#include "hps.asynch.h"
#include "hps.dev_type.h"
#include "hps.swap.h"

char  hps_intel    = 0;			/* host byte ordering	*/


char *xform [] = {
"Single-chan Read Bytes\t%-16uMulti-chan Read Bytes\t%u\n",
"Single-chan Write Bytes\t%-16uMulti-chan Write Bytes\t%u\n"
};

char *cform [] = {
"Real-time clock ticks\t%-16uIdle task counter\t%u\n",
"Bytes DMAed to HPS\t%-16uBytes DMAed from HPS\t%u\n",
"DMA XACK timeouts\t%-16uDMA CBRQ timeouts\t%u\n",
"DMA bus req. timeouts\t%-16uIOCB's processed\t%u\n",
"\"No memory\" errors\t%-16uResponse queue full\t%u\n",
"Network queue full\t%-16uMiscellaneous errors\t%u\n",
"Packets sent\t\t%-16uPackets received\t%u\n",
"No response errors\t%-16uBad response errors\t%u\n",
"Offline errors\t\t%-16uReconfigurations\t%u\n",
NULL,
NULL,
NULL,
NULL,
NULL,
"reserved\t\t%-16uROM size\t\t%u\n",
"ROM checksum\t\t0x%-14xEnd of RAM\t\t0x%04x\n",
"Real time clock (Hz)\t%-16dreserved\t\t%u\n"
};

char *rform [] = {
"Real-time clock ticks\t\t%u\n",
"Idle task counter\t\t%u\n",
"\"Out of memory\" errors\t\t%u\n",
"Miscellaneous errors\t\t%u\n",
"Network packets sent\t\t%u\n",
"Network packets received\t%u\n",
"No response errors\t\t%u\n",
"Bad response errors\t\t%u\n",
"Offline errors\t\t\t%u\n",
"Network reconfigurations\t%u\n",
"ROM size\t\t\t%u\n",
"ROM checksum\t\t\t0x%04x\n",
"End of RAM\t\t\t%u\n"
};

static struct
{
	INFO info;
	long table[50];
} l_buff;

extern int errno;

main(argc, argv)
int argc;
char **argv;
{


	char c, *key, *device;
	short display, clear, remote, error;
	int station;
	int i, numel;
	bit32 result;
	bit32 logsub();
	bit32 rlogsub();
	extern int xlogsub();
	int   xlogres;
	A_XBYTES xbytes;
	bit32 ltmp;
	short tmp;

	tmp = 0;
	hps_intel = *(char *)&tmp;

	device  = NULL;
	display = 1;
	clear   = 0;
	remote  = 0;
	station = 0;
	error   = 0;


	/* Scan the command line */
	if (argc >= 2)
	{
		key = argv[1];
		i = argc - 2;
		while (*key)
		{
			switch (c = *key++) /* Possible values: a, d, c, u */
			{
				case 'u':	/* Clear the "display" flag */
					display = 0;
#					ifdef DEBUG
						fprintf(stderr, "%s: NO DISPLAY\n", argv[0]);
#					endif
					break;
					
				case 'c':	/* Set the "clear" flag */
					clear = 1;
#					ifdef DEBUG
						fprintf(stderr, "%s: CLEAR\n", argv[0]);
#					endif
					break;

				case 'd':	/* Set the device name */
#					ifdef DEBUG
						fprintf(stderr, "%s: DEVICE\n", argv[0]);
#					endif
					if (i == 0)
					{
						fprintf(stderr, "%s: Need device name\n",argv[0]);
						usage(argv[0]);
						exit(1);
					}
					else 
					{
						device = argv[argc - i];
#						ifdef DEBUG
						fprintf (stderr, "device = %s\n", device);
#						endif
						i--;
					}
					break;

				case 'a':	/* Set the "remote" flag */
					remote = 1;
#					ifdef DEBUG
						fprintf(stderr, "%s: REMOTE\n", argv[0]);
#					endif
					if (i == 0)
					{
						fprintf(stderr, "%s: Need station address\n", 
							argv[0]);
						usage(argv[0]);
						exit(1);
					}
					else 
					{
						station = atoi (argv [argc - i]);
#						ifdef DEBUG
						fprintf (stderr, "station = %d\n", station);
#						endif
						if (station <= 0 || station > 256)
						{
							fprintf(stderr,
								"%s: Station address %d outof range\n",
								argv[0], station);
							usage(argv[0]);
							exit (1);
						}
						i--;
					}
					break;

				default:
					fprintf(stderr,
						"%s: \"%c\" bad keyletter\n", argv[0], c);
					usage(argv[0]);
					error = 1;
					break;
			}
		}
	}
	if (error)
		exit(1);

	/* Get the table */

	if (remote)
	{
#ifdef DEBUG
		printf ("calling rlogsub, size = %d\n", sizeof(l_buff));
#endif
		if ((result = rlogsub (station, &l_buff, sizeof(l_buff), clear, 
			device, argv[0])) != 0)
		{
			fprintf(stderr, "%s: Attempt to read cluster controller log table failed.\n", argv[0]);
			fprintf(stderr,"%s: Check if cluster is online.\n", argv[0]); 

			if (errno)
				perror (argv[0]);
			else
				errtab(result >> 16, argv[0]);

			exit(1);
		}
		if (hps_intel)
		{
			for (i=0; i<sizeof(l_buff.table)/4; ++i)
			{
				SWAP_4BYTE(&ltmp,&l_buff.table[i]);
				l_buff.table[i] = ltmp;
			}
		}

		numel = sizeof(rform) / 4;
		if (display)
		{
#			ifdef DEBUG
				fprintf (stderr, "display***\n" );
#			endif
			printf("\nModel\t\t%s\n", l_buff.info.i_model);
			printf("Firmware\t%s\nRunning\t\t%s\n\n",
				l_buff.info.i_pn, l_buff.info.i_assy);
			printf("Device type\t\t\t%d\n", l_buff.info.i_type);
			printf("Station ID\t\t\t%02x\n", l_buff.info.i_id);
			for (i=0; i<numel; ++i)
			{
				if (rform[i])
					printf (rform[i], l_buff.table[i]);
			}

			/* If downloadable, display port status */
			if (l_buff.info.i_type >= 0x20 && l_buff.info.i_type < 0x50)
				bad_ports (l_buff.table[i]);
		}
		else
			write (fileno(stdout), &l_buff, sizeof(l_buff));
	}
	else /* controller */
	{
		if ((result = logsub(&l_buff, clear, device, argv[0])) != 0)
		{
			fprintf(stderr, "%s: Attempt to read host adapter log table failed.\n", argv[0]);
			if (errno)
				perror (argv[0]);
			else
				errtab(result >> 16, argv[0]);
			exit(1);
		}

		if ((xlogres = xlogsub(&xbytes, clear, device)) != 0)
		{
			exit(1);
			/* ignore other errors for compatibility with 02A */
			/* else if (xlogres == -2) */
				/* fprintf(stderr, "%s: xlogsub() failed\n", argv[0]); */
		}
		if (hps_intel)
		{
			for (i=0; i<sizeof(l_buff.table)/4; ++i)
			{
				SWAP_4BYTE(&ltmp,&l_buff.table[i]);
				l_buff.table[i] = ltmp;
			}
			for (i=0; i<sizeof(xbytes)/4; ++i)
			{
				SWAP_4BYTE(&ltmp,&((bit32 *)&xbytes)[i]);
				((bit32 *)&xbytes)[i] = ltmp;
			}
		}
						
		if (display)
		{
			printf("\nModel\t\t%s\n", l_buff.info.i_model);
			printf("Firmware\t%s\t\tBoard assy %s\n\n",
				l_buff.info.i_pn, l_buff.info.i_assy);
			printf("Device type\t\t%d\n", l_buff.info.i_type);
			printf("Station ID\t\t%02x\t\tOption switches\t\t0x%02x\n",
				l_buff.info.i_id, l_buff.info.i_options);

			numel = sizeof(cform) / 4;
			for (i=0; i<numel; i++)
			{
				if (cform[i])
					printf (cform[i],
						l_buff.table[2*i], l_buff.table[2*i+1]);
			}

			/* print xform information */
			if (xlogres == 0)
			{
				printf(xform[0], xbytes.sc_read, xbytes.mc_read);
				printf(xform[1], xbytes.sc_write, xbytes.mc_write);
			} 

			if (l_buff.info.i_type == HPS_6830 || 
				l_buff.info.i_type == HPS_6834 ||
				l_buff.info.i_type == HPS_6236 ||
				l_buff.info.i_type == HPS_6237)
				bad_ports (l_buff.table[L_CHANSTAT]);
		}
		else
		{
			write (fileno(stdout), &l_buff, sizeof(l_buff));
			if (xlogres == 0)
				write (fileno(stdout), &xbytes, sizeof(xbytes));
		}
	}

#	ifdef DEBUG
		fprintf(stderr, "%s: Done\n", argv[0]);
#	endif
	exit(0);
}

usage(name)
char *name;

{
	fprintf (stderr, "%s: usage: %s [acdu] [addr] [devname]\n", name, name);
}


bad_ports (bit_map)
int bit_map;
{
	int i;
	short numbad;
	char pstr[60], tstr[8];

	if (!(bit_map & 0xffff))
		/* All are there and good */
		sprintf (pstr, "none");
	else
	{
		sprintf (pstr, "port  ");
		numbad = 0;
		/* check each of the 16 individually */
		for (i = 0; i < 16; ++i)
		{
			if (bit_map & 1) 
			{
				if ( ++numbad == 1 )	/* first one */
				{
					if ( bit_map & 0xfffe )	/* if any more bad */
					{
						sprintf (pstr, "%d", i);
					}
					else					/* only one */
					{
						sprintf (pstr, "port %d", i);
						break;
					}
				}
				else					/* further ones */
				{
					if ( bit_map & 0xfffe )	/* if any more bad */
					{
						sprintf ( tstr, ", %d", i );
						strcat (pstr, tstr);
					}
					else					/* last bad one */
					{
						sprintf ( tstr, " and %d", i );
						strcat (pstr, tstr);
						break;
					}
				}
			}
			bit_map = bit_map >> 1;
		}
	}
	printf ( "Failed ports\t\t\t%s\n", pstr );
}


/*
 * MODIFICATION HISTORY:
 *
 * $Log:	hps_log.c,v $
 * Revision 1.1.2.1  92/06/24  13:53:33  marker
 * Branch RISCOS_5_01_2_FIXES off of trunk.
 * 
 * Revision 2.3  91/09/03  17:37:05  annette
 * Changed error message handling.
 * INTERNAL
 * 
 * Revision 2.2  91/01/10  17:22:18  dave
 * Modify header; add footer.
 * COSMETIC
 * 
 */
