/**     diag_mon.c
 **
 ** Author: Ted Schmitz
 ** Date of original creation December 4, 2008
 **
 **     This file contains the main BIST menu and all related test
 ** management and test debug functions.
 **
 **/
#include "diag_mon.h"
#include "errhand.h"

#if !defined(__U_BOOT__)
#include <stdio.h>    /* common library headers */
#include <string.h>
#include <stdlib.h>
#else
#include "common.h"  /* common library headers for Uboot environment */
#endif

#include "tests.h"		/* test table */
#include "parse.h"
#ifdef STANDALONE
#include "kbhit.h"		/* UNIX kbhit() function */
#else
#include "../io_drivers.h"
#include "../ll_serial_io.h"
#endif
#include "errcodes.h"
#include "ascii_functions.h"
#include "../ll_bist.h"
#include "../ll_post.h"
#include "../ll_post_utils.h"

#include <cvmx.h>
//#include "octeon_serial.h"

/*
 * Define all external routines called here.
 */
extern int extrom_remap(int bat);

/*
 * Define all internal routines here.
 */
void disp_emode_only(void);
void disp_tmode_only(void);
void clear_mem(void * beg_adrs, unsigned long length);
void init_for_diag_mon(void);
int gen_putchar(int ch);
int gen_key_hit(void);
char gen_wait_for_one_key(void);
int save_exec_count(int count, unsigned long error_code);
int get_loop_count(int * count, unsigned long error_code);
int save_loop_count(int count, unsigned long error_code);
int get_tot_exec_count(int * count, unsigned long error_code);
int save_tot_exec_count(int count, unsigned long error_code);
void jump_to_restart_vector(void);
int write_diag_data_to_nvram(unsigned char * buffer, unsigned int offset, 
			     int length);

/* input line buffer (with a little cushion) */
char in_line[MAX_INPUT_LINE_SIZE+3];

char *  args[MAXARGS];          /* array of pointers to each arg in cmd line */
int param_count;                /* total paramters on command line including
                                   command itself. */
int exec_count;                 /* Execution count.  This value represents the
                                   number of times the entire test program will
                                   be executed. */
int cur_test;                   /* current test number */
int cur_loop;                   /* current test execution loop */
int passes_completed;           /* number of times the test program has
                                   executed all tests selected. */
int passes_that_failed;         /* total test passes that failed */
int test_failures;              /* number of tests that have failed */
int first_init_flag = FALSE;    /* 1st initialization flag.  FALSE=never has
				   been initialized.*/
unsigned long nv_test_sel_bits; /* test select bits retrieved from non-volatile
                                   storage. */
unsigned short test_modes;      /* testing modes applied to all tests */
unsigned char ext_test_modes;   /* extended testing modes applied to all 
                                   tests */
int start_cmd_flag;             /* flag to indicate how "s" command was 
                                   invoked */

/* module global variables */
static int quit_test_menu_flag; /* flag indicating if diagnostic monitor should
                                   be exited.  TRUE=yes, FALSE=no */
#ifdef STANDALONE
void test_menu(void)
{
  main();
}
#endif

/****************************************************************************
 **			Main Monitor Loop
 **
 **	This is the main loop for the diagnostic monitor.  This routine
 ** initializes the monitor, displays all the available diagnostic monitor
 ** commands, then waits for and executes commands from the operator until
 ** the "Quit" command is entered.
 **
 ** INPUT - None
 **
 ** OUTPUT - All legal commands entered by the operator are executed then
 **	     control is returned back to this routine.
 **
 ** RETURN - None
 **
 ** NOTE:  Routine name "void test_menu(void)" is used when the monitor is
 **	   part of another piece of code.  "void main(void)" is used when the
 **	   monitor is used as a stand alone module.
 **
 **/
/*void test_menu(void)	*/
#ifdef STANDALONE
int main(void)
#else
void test_menu(void)
#endif
{
  int i;
  int cmd_idx;                          /* comand table index */
  int exit_loop;                        /* loop exit flag */
  int match_cnt;                        /* number of matching chars in entered
                                           command */
  void (*cmd_ptr)(void);                /* pointer to relocated command func */
  unsigned long lwork;                  /* unsigned long working reg */
  unsigned long lwork2;                 /* unsigned long working reg #2 */
  int cmd_match;                        /* command match flag */
  int cap_count;                        /* number of capital letters in cmd */
  char * tcp;                           /* table cmd working pointer */
  char * ecp;                           /* entered cmd working pointer */
  char blank[] = " ";			/* blank ASCII string */
  int result;                           /* result of various func calls */

  /* write debug information to RAM */
  //unsigned char * dp = (unsigned char *) 0x00000010;
  //unsigned char dbuf[100];

  test_help();                          /* display test operations menu. */

  /* get the saved execution count */
  if (get_exec_count(&exec_count, ES1060) == PROBLEM_DETECTED)
    return;

  //printf("\ntest_menu = %08lx\n",&test_menu);
  /*exec_count = 1;*/                       /* set up default execution count */
#ifndef STANDALONE
  error_mode = 0;                       /* clear unused bits */
  test_modes = 0;
  ext_test_modes = 0;                   /* clr ext test modes as well */
  /* get the error mode from non-volatile storage */
  result = read_diag_data_from_nvram(&error_mode,ERROR_MODE_OS, 
                                               TOT_EMODE_BYTES);
  if (result == PROBLEM_DETECTED)
    {
    report_seeprom_problem(ES1060);     /* log the error & exit */
    return;
    }

  /* get the test mode from non-volatile storage */
   result = read_diag_data_from_nvram((unsigned char *) &test_modes,
                                                TEST_MODE_OS, TOT_TMODE_BYTES);
  if (result == PROBLEM_DETECTED)
    {
    report_seeprom_problem(ES1060);     /* log the error & exit */
    return;
    }

  /* get the extended test modes from non-volatile storage */
   result = read_diag_data_from_nvram((unsigned char *) 
                                                &ext_test_modes,
                                                EXT_TEST_MODES_OS, 
                                                EXT_TMODES_LEN);
  if (result == PROBLEM_DETECTED)
    {
    report_seeprom_problem(ES1060);     /* log the error & exit */
    return;
    }
#else
  error_mode = STOP_ON_ERROR;           /* initialize error mode */
  test_modes = 00;                      /* no test modes sel by default */
  ext_test_modes = 0;                   /* clr ext test modes as well */
#endif

  /* Clear all Test statistics the first time through this function. */
  if (first_init_flag == FALSE)
    {
    clear_ram_stats();
    first_init_flag = TRUE;             /* flag 1st init has been performed */
    }

  init_for_diag_mon();			/* generic call to initilize user's
					   hardware & software before diag
					   monitor is invoked. */
  /**
   **     Beginning of diagnostic monitor main loop
   **/
  quit_test_menu_flag = FALSE;          /* stay in diagnostic monitor for now */
  do
    {     
    printf("\nPlease enter selection or Q to quit: ");

    ecp = blank;			/* init "cmd entered" working pointer */
    start_cmd_flag = ST_CMD_FROM_MONITOR; /* start cmd entered from monitor */

    /**   The input buffer must be cleared because occasionally a character
     ** is left over from a previous command and it sometimes causes 
     ** problems for the next input.
     **/
    for (i = 0; i < sizeof(in_line); i++)
      in_line[i] = 00;

    //printf("\nABeg of cmd table = %08lx\n",(unsigned long ) 
    //       &test_cmds_table);
    //printf("\nA1st cmd adrs in table = %08lx\n",(unsigned long ) 
    //       *test_cmds_table[0].cmd);
    //cvmx_write_csr(OCTEON_MIO_UARTX_THR(0), 'A');
    gen_fgets(in_line, MAX_INPUT_LINE_SIZE);/* get a line from operator */
    //cvmx_write_csr(OCTEON_MIO_UARTX_THR(0), 'B'); /* made it */

    /* Separate command and all parameters into separate ASCII strings. */
    param_count = separate_parms(in_line, args);
    //printf("\nparameter count = %d\n",param_count);
    /**     Each command in the table is four characters in length and starts
     ** with one or more capital letters followed by the appropriate number of
     ** small letters to complete the four character command.  All the capital
     ** letters must match the command entered and if the operator entered
     ** more than the required characters, they must also match the remaining
     ** small letters in the command table.
     **
     ** For example if the operator whishs to execute the display command, all
     ** of the following strings would work in any combination of capital or
     ** small letters: d, di, dis, disp, dispxxxxxxx.
     ** However none of these would work: de, dise, dsp, etc.
     **
     **/
    //cvmx_write_csr(OCTEON_MIO_UARTX_THR(0), 'C'); /* made it */
    if (param_count != 0)		/* if any parameters entered... */
      {
      exit_loop=FALSE;			/* init while loop variables */
      cmd_idx=0;
      cmd_match=FALSE;
      while (exit_loop==FALSE)
        {
        /* point to the command description string */
        tcp = test_cmds_table[cmd_idx].cmd_desc;
        //printf("\nCommand sign on string = [%s]\n",tcp);
        /* point to the command entered by the operator */
        ecp = args[0];
        //cvmx_write_csr(OCTEON_MIO_UARTX_THR(0), 'D'); /* made it */
     //sprintf(dp, "ted:ecp %08lx, args[0] = %08lx",(unsigned long) ecp,
     //        (unsigned long)args[0]);
     //for (i = 0;i < 100; i++)
     //dp[i] = dbuf[i];

     //printf("\necp contains %p\n",ecp);
      //printf("\necp points to [%s]\n",ecp);
        match_cnt = 0;			/* init character match count */
       //cvmx_write_csr(OCTEON_MIO_UARTX_THR(0), 'd'); /* made it */

        /* count number of matching chars */
        for (i=0;((i<4) && (i<=strlen(ecp)));i++)
          {
          if ( (ecp[i] != 00) && ((tcp[i] | 0x20) == (ecp[i] | 0x20)) )
            {
            match_cnt++;          /* inc matching chars so far */
            }
          } /* end for */

        //cvmx_write_csr(OCTEON_MIO_UARTX_THR(0), 'E'); /* */
        /** Now verify proper number of chars match.
         ** If none match check next cmd in table.
         ** If all four match, execute the comand.
         ** If all capital letters from cmd table match and length of
         ** entered command = total match, execute the command.  Else check
         ** next command.
         **/

        /* count number of capital letters in cmd in table */
        tcp = test_cmds_table[cmd_idx].cmd_desc;
        for (cap_count=0;cap_count<4;cap_count++)
          if (tcp[cap_count] > 0x5a)
            break;

        ecp = args[0];    /* point to the command entered by the operator */

        //cvmx_write_csr(OCTEON_MIO_UARTX_THR(0), 'F'); /* made it */
       /* If first four chars match we have found the cmd so exit this loop */
        if (match_cnt == 4)	
          {
          cmd_match=TRUE;
          exit_loop=TRUE;
          }
        /** If just the capital letters from the command match, we have
         ** found the command so exit this loop.
         **/
        else if ( (strlen(ecp) >= cap_count) &&
                  (strlen(ecp) == match_cnt) )
          {
          cmd_match=TRUE;
          exit_loop=TRUE;
          }
        /* In all other cases, we have no match so check next cmd in table */
        else
          {
          cmd_match=FALSE;		/* force checking next cmd in table */
          }

        /**   Inc to next cmd in table if we have no match and there are
         ** more commands to check.
         **/
        if (exit_loop == FALSE)
          {
          cmd_idx++;                      /* inc to next cmd in table */
          if (test_cmds_table[cmd_idx].cmd == 0)
            exit_loop = TRUE;       /* exit loop if reached end of cmds table */
          }

        } /* end 'while (exit_loop==FALSE)...' */

      /**    If the command entered on command line was legal execute it.
       ** Else display an error message and ignore the command.
       **/
      if (cmd_match == TRUE)
        {
          //printf("\nBeg of cmd table = %08lx\n",(unsigned long ) 
          //      &test_cmds_table);
          //printf("\n1st cmd adrs in table = %08lx\n",(unsigned long ) 
          //       *test_cmds_table[0].cmd);
#ifdef STANDALONE
        (*test_cmds_table[cmd_idx].cmd)();	/* execute the command */
#else
        /**
         **  calculate relocateable function pointer 
         **/
        lwork2 = (TEXT_BASE - uboot_rel_adrs); /* cal difference */
        lwork = ((unsigned long) test_cmds_table[cmd_idx].cmd - lwork2);
        cmd_ptr = (void *)lwork;
        /*printf("Execution adrs is: %08lX\n",lwork);*/
        (*cmd_ptr)(); /* execute the command */
#endif
        }
      else
        {
        gen_putchar(BELL);                      /* sound the bell */
        printf("\nIllegal command!  Please try again.\n");
        }

      } /* end 'if (param_count != 0)...' */

    /* loop till "Q" is pressed */
    } while (quit_test_menu_flag == FALSE);

  leaving_diag_mon();			/* reset hw & sw before exiting */

#ifdef STANDALONE
  return (0);
#endif
}

/****************************************************************************
 **    			 Quit The Test Menu
 **
 **	This routine simply displays an exit message just before the 
 ** diagnostic monitor terminates execution.
 **
 ** INPUT - None
 **
 ** OUTPUT - Exit message is displayed on the screen.
 **
 ** RETURN - None
 **
 **/
void quit_test_menu(void)
{
  printf("\nExiting Diagnostic Monitor...\n");
  quit_test_menu_flag = TRUE;           /* set flag to exit diag monitor */
}

/****************************************************************************
 **                     Set All Default Testing Parameters
 **
 **     This routine sets all testing parameters to their default values. 
 **
 ** INPUT - None
 **
 ** OUPUT - All testing parameters are changed to values listed below:
 **         * Error mode is set to STOP_ON_ERROR.
 **         * Execution Count is set to zero to run one time.
 **         * All tests are selected except those listed in table 
 **           "disabled_tests[]".
 **
 ** RETURN - none
 **
 **  NOTE: The array containing all the test routines that are to be
 **	   disabled when the "SDefaults" command is issued ("disabled_tests[]")
 **        is located in the "tests.c" file.
 **
 **/
void set_defaults(void)
{
#if 0
  int index;                            /* test table index */
  int i;                                /* disable test table index */
  struct tests * tt = test_table;       /* pointer to tests table */
#endif
  int result;                           /* result of various func calls */
  unsigned long product_id;             /* temp product id place-holder */

  test_modes = TM_DISABLE_POST;         /* normally disable ll POST */
  ext_test_modes = 0;                   /* clear all ext test modes as well */

  error_mode = get_def_error_mode();    /* get default emode 4 this platform */
  exec_count = 1;                       /* run tests one time */

  /** This is the old way and it worked fine.  But changed to use a simple 
   ** test select bit constant set up in symbol "DEFAULT_LL_TESTS".  This 
   ** symbol always contains the test select bit pattern for all the 
   ** default tests for both the assembly and "C" tests.
   **/
#if 0 
  /* First enable all tests in the test table & the NVRAM bit variable */
  for (index = 0; tt[index].test_number !=0; index++)
    {
    tt[index].enabled = TRUE;
    nv_test_sel_bits |= (0x01L << index); /* enable next test in nv ram reg */
    }

  /**     Now disable all tests that are not needed in this mode or not
   ** working.  To do this, disable all the tests listed in the array 
   ** disabled_tests[].
   **/
  for (index = 0; tt[index].test_number !=0; index++)
    {
    for (i = 0; disabled_tests[i] != 0; i++)
      {
      if (tt[index].test == disabled_tests[i])
        {
        tt[index].enabled = FALSE;	/* disable this test */
        nv_test_sel_bits &= ~(0x01L << index);/* dis test in nv storage reg */
        }
      }
    }
#else

  /* set any unique platform dependent defaults */
  set_defaults_for_this_platform(); 
  
#endif

  /* write the new test select sequence to non-volatile storage */
  result = write_diag_data_to_nvram((unsigned char *) 
				    &nv_test_sel_bits,
				    CUR_SEL_TESTS_OS, TEST_SEL_LEN);

  if (result == PROBLEM_DETECTED)
    {
    report_seeprom_problem(ES1070);     /* log the error & exit */
    return;
    }

  /* write the new error mode to non-volatile storage */
  result = write_diag_data_to_nvram(&error_mode,ERROR_MODE_OS, 
                                              TOT_EMODE_BYTES);
  if (result == PROBLEM_DETECTED)
    {
    report_seeprom_problem(ES1070);     /* log the error & exit */
    return;
    }

  /* write the new test modes to non-volatile storage */
  result = write_diag_data_to_nvram((unsigned char *) &test_modes,
                                              TEST_MODE_OS, TOT_TMODE_BYTES);
  if (result == PROBLEM_DETECTED)
    {
    report_seeprom_problem(ES1070);     /* log the error & exit */
    return;
    }

  /* write the new extended test modes to non-volatile storage */
  result = write_diag_data_to_nvram((unsigned char *) &ext_test_modes,
                                              EXT_TEST_MODES_OS, 
                                              EXT_TMODES_LEN);
  if (result == PROBLEM_DETECTED)
    {
    report_seeprom_problem(ES1070);     /* log the error & exit */
    return;
    }

 /* DEBUG - write a valid product id to non-volatile storage 
            REMOVE this code later after a function is added to set the
            appropriate product id trough NIST menu. */
  product_id = PROD_TYPE_NPA_5644;
  result = write_diag_data_to_nvram((unsigned char *) &product_id,
                                              PROD_ID_OS, 4);

  /* save the new execution count */
  if (save_exec_count(exec_count, ES1070) == PROBLEM_DETECTED)
    return;

  /* re-calc & store new check sum */
  if (calc_write_seeprom_csum_timed() == PROBLEM_DETECTED)
     report_seeprom_problem(ES1080);     /* log the error & exit */

}

/****************************************************************************
 **             Set All Default Testing Parameters & Start Testing
 **
 **     This routine sets all testing parameters to their default values and
 ** runs all the selected tests.
 **
 ** INPUT - None
 **
 ** OUTPUT - All testing parameters are set to defaults defined in function
 **	     "set_defaults()" then the "start_testing()" function is called.
 **
 ** RETURN - None
 **/
void set_def_run(void)
{

  set_defaults();                       /* set up all testing defaults */
  start_testing();                      /* start testing */

}

/****************************************************************************
 **             Execute The Tests Enabled In The Test Table
 **
 **     This routine executes all the subtests enabled in the test table. All
 ** the current testing parameters are used during execution of each subtest.
 **
 **     If the execution count is set to zero, tests will execute continiously
 ** until a key is pressed.
 **
 ** INPUT - If the "C" option is entered after the start command on the
 **         command line, all statistics will be cleared before testing
 **         begins.
 **	  - All the testing parameters such as error mode, execution count,
 **	    etc., are used during test execution.
 **
 ** OUTPUT -  When any test detects an error, the next course of action is 
 **           determined by the error mode as follows: (There may be other
 **           other error modes)
 **
 ** 	      ERROR MODE          ACTION TAKEN
 ** 	      ----------------  ------------------------------------------
 ** 	      STOP_ON_ERROR     All testing is terminated.
 ** 	      CONT_ON_ERROR     This routine does nothing, however, the test 
 **                             will display the error condition then 
 **                             continue execution of the test. 
 **                             execute the next selected subtest.
 ** 	      RESTART_ON_ERROR  The current test will terminate, all error 
 **                             information will have already been saved by 
 **                             the error handler, and testing will start
 **                             over from the first test selected for
 **                             execution if more passes remain to be executed.
 **                             If all passes are completed,  testing will be
 **                             terminated.
 **           SKIP_ON_ERROR     Log the error, then skip the remaining steps in
 **                             the current subtest and continue testing with 
 **                             the next selected subtest.
 **           GTNF_ON_ERROR     Log the error then immediately attempt to
 **                             bring up normal firmware.
 **
 ** RETURN - Nothing
 **
 **/
void start_testing(void)
{
  struct tests * tt = test_table;	/* pointer to tests table */
  int index;                            /* test table index */
  int any_failures_flag;        	/* flag to indicate if any failures
                                           have occured in any of the previous 
                                           tests in this pass.  FALSE=no */
  void (*test_ptr)(void);               /* pointer to relocated test func */
  unsigned long lwork;                  /* 32-bit working register */
  unsigned long lwork2;                 /* 32-bit working reg #2 */
  int result;                           /* result of various func calls */

  error_flag = PASS;                    /* init error flag to "no fails" */
  /* get the test mode from non-volatile storage */
  result = read_diag_data_from_nvram((unsigned char *) &test_modes,
                                               TEST_MODE_OS, TOT_TMODE_BYTES);
  if (result == PROBLEM_DETECTED)
    {
    report_seeprom_problem(ES1000);     /* log the error & exit */
    return;
    }

  /*   If low-level POST testing is disabled exit */
  if (should_diags_be_executed(test_modes) == FALSE)
    return;

  /**     Clear all testing statistics if "C" option was entered after 
   ** "Start" command on the command line.
   **/
  if ((param_count > 1) && ((args[1][0] | 0x20) == 'c'))
    clear_all_test_stats();

  /**   If the "s" command was issued from the monitor and the test mode
   ** selected is "continuous test mode" then start testing with the
   ** selected phase one tests first.  To do that, reset the unit.
   **/
  if (((test_modes & TM_CONT_TEST) == TM_CONT_TEST) &&
      (start_cmd_flag == ST_CMD_FROM_MONITOR))
    {
    cur_loop = 1;			/* init current testing loop */
    if (save_loop_count(cur_loop, ES1005) == PROBLEM_DETECTED)
      return;
      /* Set TM_NO_COUNT_DOWN so that we don't display count down message */
      test_modes |= TM_NO_COUNT_DOWN;
      /* write the new test modes to non-volatile storage */
      result = write_diag_data_to_nvram((unsigned char *) &test_modes,
                                              TEST_MODE_OS, TOT_TMODE_BYTES);
        if (calc_write_seeprom_csum_timed()  ==  PROBLEM_DETECTED)
          {
          //report_seeprom_problem(ES1120);     /* log the error & exit */
          //return;
          }
    jump_to_restart_vector();
    /*reset_unit();*/
    }

  /* get the error mode from non-volatile storage */
  result = read_diag_data_from_nvram(&error_mode, ERROR_MODE_OS, 
                                               TOT_EMODE_BYTES);
  if (result == PROBLEM_DETECTED)
    {
    report_seeprom_problem(ES1000);     /* log the error & exit */
    return;
    }

  /* get all the test selection bits from non-volatile storage */
  result = read_diag_data_from_nvram((unsigned char *) 
                                               &nv_test_sel_bits,
                                               CUR_SEL_TESTS_OS, 
                                               TEST_SEL_LEN);
  if (result == PROBLEM_DETECTED)
    {
    report_seeprom_problem(ES1000);     /* log the error & exit */
    return;
    }

  /* Set up the test selection flags according to sel bits from NV storage */
  for (index = 0; 
       ((index < MAX_LL_TESTS) && (tt[index].test_number !=0)); 
       index++)
    tt[index].enabled = ((nv_test_sel_bits >> index) & 0x1L);

#ifndef STANDALONE
  /* see if there are any phase two tests enabled */
  result = 0;
  for (index = 0; tt[index].test_number !=0; index++)
    {
    if ((tt[index].enabled == TRUE) && (tt[index].test_type == TT_P2))
      result++;
    }
#endif

  if ((test_modes & TM_CONT_TEST) != TM_CONT_TEST)
    printf("\n");

  /*  At least one phase two test must be selected */
  if (result == 0)
    {
    printf("\nAll low-level phase two POST tests are disabled!\n");
    printf("Use 'SSubtests' command to enable tests!\n\n");
    /*return;*/
    }

  /* exit each pass if in continuous P1 & P2 test mode */
  if ((test_modes & TM_CONT_TEST) == TM_CONT_TEST)
    {
    if (get_loop_count(&cur_loop, ES1000) == PROBLEM_DETECTED)
      return;

    /* start loop count at one when it gets cleared somewhere else */
    if (cur_loop == 0)
      {
      cur_loop = 1;			/* init current testing loop */
      if (save_loop_count(cur_loop, ES1005) == PROBLEM_DETECTED)
        return;
      }
    }
  else
    {
    cur_loop = 1;			/* init current testing loop */
    if (save_loop_count(cur_loop, ES1005) == PROBLEM_DETECTED)
      return;
    }

  /* get the current value of the total passes complete */
  if (get_tot_exec_count(&passes_completed, ES1000) == PROBLEM_DETECTED)
    return;

  do
    {
    /* Check to see if a failure has already been detected */
    if ((test_modes & TM_ERR_PENDING) == TM_ERR_PENDING)
      {
      error_flag = FAIL;                 /* let other funcs know we failed */
      any_failures_flag = TRUE;          /* init fail flag for this pass */
      }
    else
      {
      any_failures_flag = FALSE;          /* init fail flag for this pass */
      }

    /* Only output "Starting pass number" message when not output by level 1 */
    if ((test_modes & TM_CONT_TEST) != TM_CONT_TEST)
        printf("Starting Phase II Tests: Pass Number %d\n",cur_loop);
    else
        printf("Testing is underway...\nStarting Phase II Tests: Pass Number %d\n", cur_loop);

    for (index = 0; tt[index].test_number !=0; index++)
      {
      /**   Exit immediately if any errors detected in phase one tests and we
       ** are in the appropriate error mode.
       **/
      if (any_failures_flag == TRUE)
        {
        if (
            (error_mode == STOP_ON_ERROR) ||
            (error_mode == RESTART_ON_ERROR) ||
            (error_mode == GTNF_ON_ERROR)
           )
          {
          test_failures++;              /* inc number of tests that failed */
          break;
          }
        }
      cur_test = tt[index].test_number;   /* setup cur test num */
      /* do not exec test if any key is pressed */
      if (gen_key_hit() == TRUE)	/* exit this command if a key is hit */
        break;
#ifdef STANDALONE
      if ((tt[index].enabled == TRUE) && (tt[index].test_type == TM_IN))
#else
      if ((tt[index].enabled == TRUE) && (tt[index].test_type == TT_P2))
#endif
        { /*  Execute this test if it is selected & it is a phase two test */
        printf("Starting -> %3d - %s Test...",tt[index].test_number,
               tt[index].sign_on_message);
        error_flag = PASS;               /* initialize error condition */
        tt[index].total_passes++;        /* inc tot passes for this test */

        /* calculate relocateable function pointer */
        lwork2 = (TEXT_BASE - uboot_rel_adrs); /* cal difference */
        lwork = ((unsigned long) tt[index].test - lwork2);
        test_ptr = (void *)lwork;
        (*test_ptr)();                   /* execute the test */
        if (error_flag == FAIL)          /* check error flag */
          { /* error detected by last test */
          any_failures_flag = TRUE;      /* save failure status for later */
          printf("\n");
          test_failures++;              /* inc number of tests that failed */
          tt[index].total_failures++;   /* inc tot failures for this test */
          }
        else
          {
	      /**     Display "Passed" after test sign-on message if no failures 
           ** were detected during execution of last subtest.
           **
           ** HOWEVER, do not display "Passed" message after tests that are
           **          currently not implemented.
           **/
          if (tt[index].test_mode != TM_NA)
            printf("Passed\n");		
          }

        if (gen_key_hit() == TRUE)	/* exit this command if a key is hit */
          break;

        /**    Exit the testing loop when a failure occurs and certain
	 ** error modes are selected.
	 **/
        if (
	    /* stop testing if in stop mode */
	    (error_flag && (error_mode == STOP_ON_ERROR)) ||
            /* exit this part of loop to see if we should start over */
            (error_flag && (error_mode == RESTART_ON_ERROR)) ||
            (error_flag && (error_mode == GTNF_ON_ERROR))
	   )
          break;                        

        } /* end 'if (tt[index]...' */

      } /* end 'for (index = 0...' */

    passes_completed++;                 /* inc test program executions */
    if (save_tot_exec_count(passes_completed, ES1005) == PROBLEM_DETECTED)
      return;

    if (any_failures_flag == TRUE)
      {
      /* get the saved total failures count */
      if (get_total_fails_count(&passes_that_failed, ES1000) == PROBLEM_DETECTED)
        return;

      passes_that_failed++;             /* inc total failed passes */
      if (save_total_fails_count(passes_that_failed, ES1005) == 
          PROBLEM_DETECTED)
        return;
      }

    /* exit if a faliure has been detected & we are in stop-on-error mode */
    if ((any_failures_flag == TRUE) && (error_mode == STOP_ON_ERROR))
      break;

    cur_loop++;                         /* inc test loop count */
    if (save_loop_count(cur_loop, ES1005) == PROBLEM_DETECTED)
      return;

    if (gen_key_hit() == TRUE)		/* exit this command if a key is hit */
      break;

    /* exit each pass if in continuous P1 & P2 test mode */
    if ((test_modes & TM_CONT_TEST) == TM_CONT_TEST)
      break;

    } while ((cur_loop <= exec_count) || (exec_count == 0));

  /**   If we are in the "continuous test mode" and we still have at
   ** least one more execution pass to complete, and no failures have been
   ** detected so far, jump to start the phase one tests now.  Later we will
   ** fall back into this code and check the counters again.  If an error
   ** is detected and we are in the "Goto Normal Firmware" error mode,
   ** then exit to normal formware now.
   **
   ** Once the counts are satisfied go to the main menu and wait for 
   ** further instructions.  Unless the "exit-to-nf" flag is also set.  
   ** Then exit to normal firmware.
   **/
#if 0
  printf("test modes = %04x\n",test_modes);
  printf("cur_loop = %0d, exec_count = %0d\n",cur_loop,exec_count);
#endif
  if ((test_modes & TM_CONT_TEST) == TM_CONT_TEST)
    { /* enter here when in continuous test mode */

    /* stop testing if error encountered & in stop on error mode */
    if ((any_failures_flag == TRUE) && (error_mode == STOP_ON_ERROR))
      test_menu();                      /* start main menu */

    /* stop testing if error encountered & in GO TO NF on error mode */
    if ((any_failures_flag == TRUE) && (error_mode == GTNF_ON_ERROR))
      {
      if ((test_modes & TM_EXIT_TO_NF) == TM_EXIT_TO_NF)
        return;                           /* exit diag monitor */
      else
        test_menu();                      /* start main menu */
      }

    if ((cur_loop <= exec_count) || (exec_count == 0))
      {
      /** WARNING!!!  If the above conditions are met, the unit will be
       **             reset!!
       **/
      /* Set TM_NO_COUNT_DOWN so that we don't display count down message */
      test_modes |= TM_NO_COUNT_DOWN;
      /* write the new test modes to non-volatile storage */
      result = write_diag_data_to_nvram((unsigned char *) &test_modes,
                                              TEST_MODE_OS, TOT_TMODE_BYTES);
        if (calc_write_seeprom_csum_timed()  ==  PROBLEM_DETECTED)
          {
          //report_seeprom_problem(ES1120);     /* log the error & exit */
          //return;
          }
      jump_to_restart_vector();
      /*reset_unit();*/
      }
    else
      {
      /* Re-enter monitor after all test executions have been performed,
         unless the "exit-to-nf" flag is set.  Then hand control to NF
         by exiting this function. */
      if ((test_modes & TM_EXIT_TO_NF) != TM_EXIT_TO_NF)
        { /* enter here to bring monitor back up */
        test_menu();                      /* start main menu */
        }
      else
        { 
        /**    Enter here to reset the current loop count so we loop
         ** the proper number of times next time the unit is powered up.
         ** This is the only mode that needs to clear this count.
         **/
        cur_loop = 0;			/* clear current testing loop */
        if (save_loop_count(cur_loop, ES1005) == PROBLEM_DETECTED)
          return;
        }
      }

    } /* end "if ((test_modes & TM_CONT_TEST... " */

}

/****************************************************************************
 **              Display All Subtests And Testing Information
 **
 **     This command displays all the subtests in the test table along with
 ** all the pertinent information for each subtest.  The subtests are not
 ** necessarily displayed in the order of execution. This command also 
 ** displays all the current testing parameters.
 **
 ** INPUT - "param_count" will contain the number of fields entered on the
 **	    the command line including the command.
 **       - If a subtest number is entered after the command, display will
 **	    begin with that subtest number and continue to end of list.  The
 **	    subtest number will be stored in "args[1]".
 **
 **         If no options are entered on command line all subtests are 
 **	    displayed starting with subtest one.
 **
 ** OUTPUT - All pertinent test information followed by all the information
 **	     for each subtest is displayed on the screen.
 **
 ** RETURN - None
 **/
void disp_tests(void)
{
  struct tests * tt = test_table;       /* pointer to tests table */
  int index;                            /* test table index */
  int line_count;                       /* num of lines displayed on screen */
  char sel;                             /* ASCII Y or N for selected or not */
  int result;                           /* result of various func calls */

  char header[] = "\n TN GN   TT   Sel Test Name\n";

  /* get all the test selection bits from non-volatile storage */
  result = read_diag_data_from_nvram((unsigned char *) 
                                               &nv_test_sel_bits,
                                               CUR_SEL_TESTS_OS, 
                                               TEST_SEL_LEN);
  if (result == PROBLEM_DETECTED)
    {
    report_seeprom_problem(ES1010);     /* log the error & exit */
    return;
    }

  /* Set up the test selection flags according to sel bits from NV storage */
  for (index = 0; 
       ((index < MAX_LL_TESTS) && (tt[index].test_number !=0)); 
       index++)
    tt[index].enabled = ((nv_test_sel_bits >> index) & 0x1L);

  /**
   **     Display all related testing parameters first.
   **/
  printf("\nCurrent test mode = ");
  disp_tmode_only();

  printf("\nCurrent error mode = ");
  disp_emode_only();

  /* get the saved execution count */
  if (get_exec_count(&exec_count, ES1010) == PROBLEM_DETECTED)
    return;

  printf("\nCurrent execution count = %0d\n",exec_count);

  /* see if all default tests are selected */
  printf("All default tests are selected? ");
#if 0  /* old way */
  if ((nv_test_sel_bits & DEFAULT_LL_TESTS) == DEFAULT_LL_TESTS)
    printf("Yes\n");
  else
    printf("No\n");
#else /* new way */
  if ((all_def_tests_for_this_platform_are_sel(nv_test_sel_bits)) == TRUE)
    printf("Yes\n");
  else
    printf("No\n");
#endif

  printf("\n");

  /**    If no optional subtest entered, start the display from the first 
   ** subtest in the test table.  Else convert the first parameter to a number
   ** so we can compare it later.
   **/
  if (param_count > 1)
    {
    /* conv 1st argument to test number */
    index = conv_ascii_decimal_string_to_binary(args[1]); 
    index--;                            /* adjust to actual subtest num */
    }
  else
    index = 0;                          /* start display at 1st test */

  /**     If a starting subtest number was entered after the command, make
   ** sure it is equal to or less than the largest subtest number in
   ** the test table.  If the optional subtest entered was illegal start the
   ** display from the first subtest in the test table.
   **
   **     Start by counting the number of subtests available.
   **/
  for (line_count = 0; tt[line_count].test_number !=0; line_count++);
  if ((index > (line_count - 1)) || (index < 0))
    index = 0;

  printf("%s",header);			/* display initial header */
  line_count = 6;                       /* init display line count */
  for ( ; tt[index].test_number !=0; index++)
    {
    /* do not display tests that are not yet available */
    if (tt[index].test_mode == TM_NA) 
      continue;

    /* determine select status of this subtest for later */
    if (tt[index].enabled == TRUE)
      sel = 'Y';
    else
      sel = 'N';

#ifdef STANDALONE /* debugging with standard GCC tools */
    /* display subtest number and group number */
    printf("%03d %02d %02d ",
           tt[index].test_number,
           tt[index].block_number,
           tt[index].group_number);

    /* display proper test type */
    if(tt[index].test_type == TT_CA)
      printf("Card   ");
    else if(tt[index].test_type == TT_FA)
      printf("Fabric ");
    else if(tt[index].test_type == TT_I2C)
      printf("I2C    ");
    else if(tt[index].test_type == TT_EN)
      printf("Ethern ");

    /* display proper test mode */
    if(tt[index].test_mode == TM_NI)
      printf("NonI ");
    else if(tt[index].test_mode == TM_IN)
      printf("Intru");
    else if(tt[index].test_mode == TM_PR)
      printf("Port ");
    else if(tt[index].test_mode == TM_LB)
      printf("LoopB");
#else  /* normal code for default platform */

     /* display subtest number and group number */
    printf("%03d %02d ",
           tt[index].test_number,
           tt[index].group_number);

   /* display proper test type */
    if(tt[index].test_type == TT_P1)
      printf("Phase 1");
    else if(tt[index].test_type == TT_P2)
      printf("Phase 2");

#if 0 /* disable for now */
    /* display proper test mode */
    if(tt[index].test_mode == TM_NI)
      printf("NonI ");
    else if(tt[index].test_mode == TM_IN)
      printf("Intru");
    else if(tt[index].test_mode == TM_PR)
      printf("Port ");
    else if(tt[index].test_mode == TM_LB)
      printf("LoopB");
#endif
#endif

    /* now display select status and the subtest's sign on message */
    printf(" %c  %s\n",
           sel,
           tt[index].sign_on_message);
 
    line_count++;                       /* inc num of lines displayed */
    /* redisplay header after screenful of tests if operator presses C/R */
    if ((line_count > 0) && ((line_count % 23) == 0))
      {
      printf("\nPress RETURN to continue, any other key to exit display : ");
      if (wait_for_enter_key() == FALSE)
        break;
      else
        printf("%s",header);
      }

    } /* end for */
}

/****************************************************************************
 **     		Display/Set Error Mode
 **
 **	This routine displays/and or sets the error mode selected then 
 ** enables the operator to set a new error mode.
 **
 ** INPUT - "param_count" will contain the nunmber of fields entered on the
 **	    the command line including the command.  If no parameters are
 **	    entered after the command, the current error mode is displayed
 **	    and the operator is given the chance to enter a new error
 **	    mode.  If only a C/R is entered or an illegal error mode is
 **	    entered, the current error mode is left unchanged.  If a legal
 **	    error mode is entered after the command, the current error mode
 **	    will be changed to the new error mode.
 **       - Any new error mode entered after the command will be stored in 
 **	    "args[1]".
 **
 ** OUTPUT - If a legal error mode is entered after the command or after
 **	     the current error mode is displayed, the current error mode
 **	     will be changed to the new error mode.
 **
 ** RETURN - None
 **
 *****************************************************************************/
void set_error_mode(void)
{
  /* if no new error mode entered, display current mode and ask for new one */
  if (param_count < 2)
    {
    printf("\nCurrent Error Mode is: ");
    disp_emode_only();                          /* disp error mode */
    /* get the new error mode from the operator (if a legal mode entered) */
    gen_fgets(in_line, MAX_INPUT_LINE_SIZE);/* get a line from operator */

    /* Separate command and all parameters into separate ASCII strings. */
    param_count = separate_parms(in_line, args);

    /* exit if only C/R entered */
    if ((in_line[0] == '\n') || (in_line[0] == 0))
      return;

    /* if proper number of parameters entered (one in this case) process it */
    if (param_count == 1)
      {
      if (((in_line[0] | 0x20) == 's') && ((in_line[1] | 0x20) != 'k'))
        error_mode = STOP_ON_ERROR;
      else if ((in_line[0] | 0x20) == 'c')	/* cont-on-error selected ? */
        error_mode = CONT_ON_ERROR;             /* stop-on-error selected ? */
      else if ((in_line[0] | 0x20) == 'r')	/* restart-on-error seltd ? */
        error_mode = RESTART_ON_ERROR;
      else if ((in_line[0] | 0x20) == 'g')	/* goto-nf-on-error seltd? */
        error_mode = GTNF_ON_ERROR;
      else if (((in_line[0] | 0x20) == 's') && ((in_line[1] | 0x20) == 'k'))
        error_mode = SKIP_ON_ERROR;             /* skip-on-error selected ? */
      else
        {
        printf("\nIllegal error mode [%s] entered!  Error mode unchanged.\n",
	       in_line);
        }

      /* write the new error mode to non-volatile storage */
      if (write_diag_data_to_nvram(&error_mode, 
          ERROR_MODE_OS, TOT_EMODE_BYTES) == PROBLEM_DETECTED)
        {
        report_seeprom_problem(ES1090);     /* log the error & exit */
        return;
        }

      /* re-calc & store new check sum */
      if (calc_write_seeprom_csum_timed()  ==  PROBLEM_DETECTED)
        {
        report_seeprom_problem(ES1100);     /* log the error & exit */
        return;
        }

      }
    else
      {
      /* Enter here when too many parameters are entered on the command line */
      printf("\nOnly one error mode may be entered on command line!\n");
      printf("Error mode unchanged.\n");
      }
    }
  else if (param_count == 2)
    {
    /**   Enter here when a parameter was entered after the the command to
     ** see if it is a legal error mode. If so, change the current error mode
     ** to the new error mode, else display an error message.
     **/
    if (((args[1][0] | 0x20) == 's') && ((args[1][1] | 0x20) != 'k'))
      error_mode = STOP_ON_ERROR;
    else if ((args[1][0] | 0x20) == 'c')
      error_mode = CONT_ON_ERROR;
    else if ((args[1][0] | 0x20) == 'r')
      error_mode = RESTART_ON_ERROR;
    else if ((args[1][0] | 0x20) == 'g')
      error_mode = GTNF_ON_ERROR;
    else if (((args[1][0] | 0x20) == 's') && ((args[1][1] | 0x20) == 'k'))
      error_mode = SKIP_ON_ERROR;
    else
      printf("\nIllegal error mode [%s] entered!  Error mode unchanged.\n",
	     in_line);

      /* write the new error mode to non-volatile storage */
      if (write_diag_data_to_nvram(&error_mode, 
          ERROR_MODE_OS, TOT_EMODE_BYTES) ==  PROBLEM_DETECTED)
        {
        report_seeprom_problem(ES1090);     /* log the error & exit */
        return;
        }

      /* re-calc & store new check sum */
      if (calc_write_seeprom_csum_timed()  ==  PROBLEM_DETECTED)
        {
        report_seeprom_problem(ES1100);     /* log the error & exit */
        return;
        }
    }
  else
    {
    /* Enter here when too many parameters are entered on the command line */
    printf("\nOnly one error mode may be entered on command line!\n");
    printf("Error mode unchanged.\n");
    }
}

/*****************************************************************************
 **              Display The Current Error Mode Only
 **
 **      This routine just displays the current error mode with no leading
 ** message or trailing carriage return.
 **
 ** INPUT - None
 **
 ** OUTPUT - The current error mode will be display at the current cursor
 **          position.
 **
 ** RETURN - None
 **
 *****************************************************************************/
void disp_emode_only(void)
{
#ifndef STANDALONE
  int result;                           /* result of various func calls */
  /* get the error mode from non-volatile storage */
  result = read_diag_data_from_nvram(&error_mode,ERROR_MODE_OS, 
                                               TOT_EMODE_BYTES);
  if (result == PROBLEM_DETECTED)
    {
    report_seeprom_problem(ES1020);     /* log the error & exit */
    return;
    }
#endif

  if (error_mode == CONT_ON_ERROR)
    printf("Continue On Error ");
  else if (error_mode == STOP_ON_ERROR)
    printf("Stop On Error ");
  else if (error_mode == RESTART_ON_ERROR)
    printf("Restart On Error ");
  else if (error_mode == SKIP_ON_ERROR)
    printf("Skip On Error ");
  else if (error_mode == GTNF_ON_ERROR)
    printf("Go To Normal Firmware On Error ");
  else
    { /* force stop on error for all other values */
    error_mode = STOP_ON_ERROR;

      /* write the new error mode to non-volatile storage */
      if (write_diag_data_to_nvram(&error_mode, 
          ERROR_MODE_OS, TOT_EMODE_BYTES) ==  PROBLEM_DETECTED)
        {
        report_seeprom_problem(ES1090);     /* log the error & exit */
        return;
        }

      /* re-calc & store new check sum */
      if (calc_write_seeprom_csum_timed()  ==  PROBLEM_DETECTED)
        {
        report_seeprom_problem(ES1100);     /* log the error & exit */
        return;
        }

    printf("Stop On Error ");
    }
}

/****************************************************************************
 **     		Display/Set Test Mode(s)
 **
 **	This routine displays/and or sets the test modes selected then 
 ** enables the operator to set a new test mode(s).
 **
 ** INPUT - "param_count" will contain the nunmber of fields entered on the
 **	    the command line including the command.  If no parameters are
 **	    entered after the command, the current test modes are displayed
 **	    and the operator is given the chance to enter new test
 **	    mode(s).  If only a C/R is entered or an illegal test mode is
 **	    entered, the current test modes are left unchanged.  If legal
 **	    test modes are entered after the command, the current test modes
 **	    will be changed to the new test mode(s).
 **       - Any new test mode(s) entered after the command will be stored in 
 **	    "args[1]", "args[2]","args[3]", etc.
 **
 **         NOTE:  Any combination of test modes can be entered on the command
 **         line simultaniously. Each will set the appropriate bit in the
 **         test mode field.  All bits will take effect immediately including
 **         the "disable POST" flag.
 **
 ** OUTPUT - If legal test  mode(s) are entered after the command or after
 **	     the current test modes are displayed, the current test modes
 **	     will be changed to the new test modes.
 **
 ** RETURN - None
 **
 *****************************************************************************/
void set_test_modes(void)
{
  unsigned short temp_tmodes;           /* temp storage for test modes */
  unsigned char ext_temp_tmodes;        /* temp storage for ext test modes */
  int parm_no;                          /* parameter number */
  int clear_flag;                       /* clear all test modes flag */

  clear_flag = FALSE;                   /* flag "do not clear" test modes */
  temp_tmodes = test_modes;             /* init temp test modes vars */
  ext_temp_tmodes = ext_test_modes;

  /* if no new test modes entered, display current mode and ask for new one */
  if (param_count < 2)
    {
    printf("\nCurrent Test Mode(s) are: ");
    disp_tmode_only();                  /* disp test modes */

    /* get the new error mode from the operator (if a legal mode entered) */
    gen_fgets(in_line, MAX_INPUT_LINE_SIZE);/* get a line from operator */

    /* Separate all parameters into separate ASCII strings. */
    param_count = separate_parms(in_line, args);

    /* if anything other then just a C/R entered, process it, else exit. */
    if (param_count > 0)
      {
      temp_tmodes = 0;                  /* clear all test modes to start with */
      ext_temp_tmodes = 0;
      /* enable indivudual test mode(s) entered by operator */
      for(parm_no=0;parm_no<param_count;parm_no++)
       {
       /* check for every test mode */
       if (
           ((args[parm_no][0] | 0x20) == 'd') &&
           ((args[parm_no][1] | 0x20) == 'b')
          )
         temp_tmodes |= TM_DIS_BUSY_IND;  /* disable busy indicators */
       else if ((args[parm_no][0] | 0x20) == 'd')
         temp_tmodes |= TM_DISABLE_POST;  /* disable post */
       else if (
                ((args[parm_no][0] | 0x20) == 'e') &&
                ((args[parm_no][1] | 0x20) == 'x')
               )
         temp_tmodes |= TM_EXIT_TO_NF;   /* exit to NF when done */
#ifdef INCL_AUTO_DISABLE_TM    
/* don't need this mode now but may use it again in the future */
       else if (
                ((args[parm_no][0] | 0x20) == 'a') &&
                ((args[parm_no][1] | 0x20) == 'd')
               )
         {
         /* Auto Disable mode  */
         ext_temp_tmodes |= ETM_AUTO_DIS; /* sel BIST "Auto Disable" mode */
         }
#endif
       else if ((args[parm_no][0] | 0x20) == 'e')
         temp_tmodes |= TM_EXT_TESTS;     /* enable extended testing mode */
       else if ((args[parm_no][0] | 0x20) == 'i')
         temp_tmodes |= TM_OP_INTER_TESTS;/* enable op intervention tests */
       else if ((args[parm_no][0] | 0x20) == 'q')
         temp_tmodes |= TM_QUICK_POST_EN; /* enable quick POST tests */
       else if ((args[parm_no][0] | 0x20) == 'l')
         temp_tmodes |= TM_EN_LB_TESTS;   /* enable loop back tests */
       else if ((args[parm_no][0] | 0x20) == 'b')
         temp_tmodes |= TM_EN_BURN_IN_MODE;/* enable burn-in test mode */
       else if (
                ((args[parm_no][0] | 0x20) == 'c') &&
                ((args[parm_no][1] | 0x20) == 't')
               )
         temp_tmodes |= TM_CONT_TEST;   /* enable continuous test mode */
       else if ((args[parm_no][0] | 0x20) == 'c')
         clear_flag = TRUE;                /* flag all test modes to be clrd */
       else
         {
         printf("\nIllegal test mode [%s] entered!  Test modes unchanged.\n",
                args[parm_no]);
         return;  /* exit on error */
         }
 
        test_modes = temp_tmodes;       /* overwrt old tmodes with new */
        ext_test_modes = ext_temp_tmodes;
        if (clear_flag == TRUE)
          {
          test_modes = 0;               /* clear all test modes */
          ext_test_modes = 0;
          }

        /* write the new test modes to non-volatile storage */
        if (write_diag_data_to_nvram((unsigned char *) 
           &test_modes, TEST_MODE_OS, TOT_TMODE_BYTES) ==  PROBLEM_DETECTED)
          {
          report_seeprom_problem(ES1110);     /* log the error & exit */
          return;
          }

        /* write the new extended test modes to non-volatile storage */
        if (write_diag_data_to_nvram((unsigned char *) 
          &ext_test_modes, EXT_TEST_MODES_OS, EXT_TMODES_LEN) 
            ==  PROBLEM_DETECTED)
          {
          report_seeprom_problem(ES1110);     /* log the error & exit */
          return;
          }

        /* re-calc & store new check sum */
        if (calc_write_seeprom_csum_timed()  ==  PROBLEM_DETECTED)
          {
          report_seeprom_problem(ES1120);     /* log the error & exit */
          return;
          }
       } /* end for */

      } /* end if (param_count > 0) */

    } /* end if (param_count < 2) */
  else
    {
    /**   Enter here when one or more parameters were entered after the 
     ** command to check for legal test mode(s). If so, change the current 
     ** test modes to the new test modes, else display an error message.
     **/
    temp_tmodes = 0;                  /* clear all test modes to start with */
    ext_temp_tmodes = 0;
    /* enable indivudual test mode(s) entered by operator */
    for(parm_no=1;parm_no<param_count;parm_no++)
      {
      /* check for every test mode */
      if (
          ((args[parm_no][0] | 0x20) == 'd') &&
          ((args[parm_no][1] | 0x20) == 'b')
         )
        temp_tmodes |= TM_DIS_BUSY_IND;  /* disable busy indicators */
      else if ((args[parm_no][0] | 0x20) == 'd')
        temp_tmodes |= TM_DISABLE_POST;  /* disable post */
      else if (
               ((args[parm_no][0] | 0x20) == 'e') &&
               ((args[parm_no][1] | 0x20) == 'x')
              )
        temp_tmodes |= TM_EXIT_TO_NF;   /* exit to NF when done */
#ifdef INCL_AUTO_DISABLE_TM    
/* don't need this mode now but may use it again in the future */
      else if (
               ((args[parm_no][0] | 0x20) == 'a') &&
               ((args[parm_no][1] | 0x20) == 'd')
              )
        ext_temp_tmodes |= ETM_AUTO_DIS; /* sel BIST "Auto Disable" mode */
#endif
      else if ((args[parm_no][0] | 0x20) == 'e')
        temp_tmodes |= TM_EXT_TESTS;     /* enable extended testing mode */
      else if ((args[parm_no][0] | 0x20) == 'i')
        temp_tmodes |= TM_OP_INTER_TESTS;/* enable op intervention tests */
      else if ((args[parm_no][0] | 0x20) == 'q')
        temp_tmodes |= TM_QUICK_POST_EN; /* enable quick POST tests */
      else if ((args[parm_no][0] | 0x20) == 'l')
        temp_tmodes |= TM_EN_LB_TESTS;   /* enable loop back tests */
      else if ((args[parm_no][0] | 0x20) == 'b')
        temp_tmodes |= TM_EN_BURN_IN_MODE;/* enable burn-in test mode */
      else if (
               ((args[parm_no][0] | 0x20) == 'c') &&
               ((args[parm_no][1] | 0x20) == 't')
              )
        temp_tmodes |= TM_CONT_TEST;   /* enable continuous test mode */
      else if ((args[parm_no][0] | 0x20) == 'c')
        clear_flag = TRUE;                /* flag all test modes to be clrd */
      else
        {
        printf("\nIllegal test mode [%s] entered!  Test modes unchanged.\n",
               args[parm_no]);
        return;  /* exit on error */
        }
 
      test_modes = temp_tmodes;       /* overwrt old tmodes with new */
      ext_test_modes = ext_temp_tmodes;
      if (clear_flag == TRUE)
        {
        test_modes = 0;               /* clear all test modes */
        ext_test_modes = 0;
        }

      /* write the new test modes to non-volatile storage */
      if (write_diag_data_to_nvram((unsigned char *) 
        &test_modes, TEST_MODE_OS, TOT_TMODE_BYTES) ==  PROBLEM_DETECTED)
        {
        report_seeprom_problem(ES1110);     /* log the error & exit */
        return;
        }

      /* write the new extended test modes to non-volatile storage */
      if (write_diag_data_to_nvram((unsigned char *) 
        &ext_test_modes, EXT_TEST_MODES_OS, EXT_TMODES_LEN) 
          ==  PROBLEM_DETECTED)
        {
        report_seeprom_problem(ES1110);     /* log the error & exit */
        return;
        }

      /* re-calc & store new check sum */
      if (calc_write_seeprom_csum_timed()  ==  PROBLEM_DETECTED)
        {
        report_seeprom_problem(ES1120);     /* log the error & exit */
        return;
        }

      } /* end for */

    } /* end else */
}

/*****************************************************************************
 **              Display The Current Test Mode(s) Only
 **
 **      This routine just displays all the current test mode(s) with no 
 ** leading message or trailing carriage return.
 **
 ** INPUT - None
 **
 ** OUTPUT - All the current test modes will be displayed at the current 
 **          cursor position.
 **
 ** RETURN - None
 **
 *****************************************************************************/
void disp_tmode_only(void)
{
#ifndef STANDALONE
  int result;                           /* result of various func calls */

  /* get the test modes from non-volatile storage */
  result = read_diag_data_from_nvram((unsigned char *) &test_modes,
                                               TEST_MODE_OS, TOT_TMODE_BYTES);
  if (result == PROBLEM_DETECTED)
    {
    report_seeprom_problem(ES1030);     /* log the error & exit */
    return;
    }

  /* get the ext test modes from non-volatile storage */
  result = read_diag_data_from_nvram((unsigned char *) 
                                               &ext_test_modes,
                                               EXT_TEST_MODES_OS, 
                                               EXT_TMODES_LEN);
  if (result == PROBLEM_DETECTED)
    {
    report_seeprom_problem(ES1030);     /* log the error & exit */
    return;
    }
#endif

  if ((test_modes & TM_DIS_BUSY_IND) == TM_DIS_BUSY_IND)
    printf("DB ");
    
  if ((test_modes & TM_DISABLE_POST) == TM_DISABLE_POST)
    printf("D ");
    
  if ((test_modes & TM_EXT_TESTS) == TM_EXT_TESTS)
    printf("E ");
    
  if ((test_modes & TM_OP_INTER_TESTS) == TM_OP_INTER_TESTS)
    printf("I ");
    
  if ((test_modes & TM_QUICK_POST_EN) == TM_QUICK_POST_EN)
    printf("Q ");
    
  if ((test_modes & TM_EN_LB_TESTS) == TM_EN_LB_TESTS)
    printf("L ");
    
  if ((test_modes & TM_EN_BURN_IN_MODE) == TM_EN_BURN_IN_MODE)
    printf("B ");
    
  if ((test_modes & TM_CONT_TEST) == TM_CONT_TEST)
    printf("CT ");

  if ((test_modes & TM_EXIT_TO_NF) == TM_EXIT_TO_NF)
    printf("EX ");
#ifdef INCL_AUTO_DISABLE_TM    
  if ((ext_test_modes & ETM_AUTO_DIS) == ETM_AUTO_DIS)
    printf("AD ");
#endif

}

/*****************************************************************************
 **     	     Display Diagnostic Monitor Help Menu
 **
 **	This routine displays the diagnostic monitor's help menu.  The display
 ** stops after every screen full of text and allows the operator to press
 ** the enter key for the next screen or any other key to exit the help menu.
 **
 ** NOTE: Strings ending in "H" or "H\n" are designated as "hidden" commands.  
 **       These are valid commands but no help is displayed for them.
 **
 ** INPUT - None
 **
 ** OUTPUT - The help menu is displayed as described above.
 **
 ** RETURN - None
 **
 **/
void test_help(void)
{
  int line_count;                       /* num of lines displayed on screen */
  int str_len;                          /* string length excluding null */
  int i;

  printf("\n        Low Level Diagnostic Monitor Operations Menu\n"
         "          %s - Version "
         DIAG_MON_VERSION
         "\n                    Table Of Operations\n\n",comp_info);
  i = 0;
  line_count  = 4;			/* set lines displayed so far */
  while (test_cmds_table[i].cmd != 0)	/* display commands avail */
    {
    str_len = strlen(test_cmds_table[i].cmd_desc); /* get cmd length */

    /* do not display "Hidden" command help strings */
    if ((test_cmds_table[i].cmd_desc[(str_len -1)] != 'H') &&
        (test_cmds_table[i].cmd_desc[(str_len -2)] != 'H'))
      {
      printf("%s",test_cmds_table[i].cmd_desc);
      line_count++;			/* inc num of lines displayed */
      }

    i++;				/* inc cmd table index */

    /**   Stop every screenful of commands. If operator presses C/R continue,
     ** else exit test help menu.
     **/
    if (
       (line_count > 0) && 	      /* if not the first line on this screen */
       ((line_count % MAX_DISP_LINES) == 0) && /* and the max lines displayed */
       (test_cmds_table[i].cmd != 0)  /* and there are lines left to disp */
       )
      {
      printf("\nPress RETURN to continue, any other key to exit display : ");
      if (wait_for_enter_key() == TRUE)
        {
        printf("\n");
        }
      else
        {
        printf("\n");
        break;                          /* exit if some ofther key pressed */
        }
      }
      
    }
    
}

/****************************************************************************
 **                 Enable Or Disable Group Of Subtests
 **
 **	 Each subtest is part of a group and block of related subtests. This
 ** command allows the operator to enable or disable entire groups of
 ** subtests.
 **
 ** INPUT - "args[0][0]" = 's' if the subtest group(s) are to be enabled or
 **	    'd' if the subtest group(s) are to be disabled.  The first
 **	    argument in the "args" list is the command.  The only two commands
 **	    that can call this routine are "SGroup" or "DGroup" for select 
 **	    subtest group(s) and deselect subtest group(s) respectively.
 **	  - The subtest group(s) to be enabled or disabled are in the 
 **	    "args" list starting in "args[1][0]".
 **
 ** OUTPUT - The selected subtest group(s) will be enabled or disabled.
 **
 ** RETURN - None
 **
 **/
void setup_subtest_groups(void)
{
  struct tests * tt = test_table;       /* pointer to tests table */
  int index;                            /* test table index */
  int parm_no;                          /* parameter number */
  int sel_state;			/* subtest select/deselect option */
  unsigned char grp_no_entered;		/* storage for conv group no */

  int result;                           /* result of various func calls */
  /* get all the test selection bits from non-volatile storage */
  result = read_diag_data_from_nvram((unsigned char *) 
                                               &nv_test_sel_bits,
                                               CUR_SEL_TESTS_OS, 
                                               TEST_SEL_LEN);
  if (result == PROBLEM_DETECTED)
    {
    report_seeprom_problem(ES1040);     /* log the error & exit */
    return;
    }

  if ((args[0][0] | 0x20) == 's')
    sel_state = ENABLE;			/* enable subtest group(s) */
  else
    sel_state = DISABLE;		/* disable subtest group(s) */

  /* If "all" entered enable/disable all subtests */
  if ((args[1][0] | 0x20) == 'a')
    {
    for (index = 0; tt[index].test_number !=0; index++)
      {
      tt[index].enabled = sel_state;

      /* set up select bits in non-volatile storage */
      if (sel_state == ENABLE)
        nv_test_sel_bits |= (0x01L << index);
      else
         nv_test_sel_bits &= ~(0x01L << index);

      }
    }
  else
    {
    /* Enable/disable group(s) of subtests if any entered on command line */
    for(parm_no=1;parm_no<param_count;parm_no++)
      {
      /* conv next param to group no */
      grp_no_entered = conv_ascii_decimal_string_to_binary(args[parm_no]);    
      for (index = 0; tt[index].test_number !=0; index++)
        if (tt[index].group_number == grp_no_entered)
          {
          tt[index].enabled = sel_state;

          /* set up select bits in non-volatile storage */
          if (sel_state == ENABLE)
            nv_test_sel_bits |= (0x01L << index);
          else
            nv_test_sel_bits &= ~(0x01L << index);       
          }
      } /* end for */
    } /* end else */

  /* write the new test select sequence to non-volatile storage */
  if (write_diag_data_to_nvram((unsigned char *) &nv_test_sel_bits,
      CUR_SEL_TESTS_OS, TEST_SEL_LEN) == PROBLEM_DETECTED)
    {
    report_seeprom_problem(ES1130);     /* log the error & exit */
    return;
    }

  /* re-calc & store new check sum */
  if (calc_write_seeprom_csum_timed() == PROBLEM_DETECTED)
    {
    report_seeprom_problem(ES1140);     /* log the error & exit */
    return;
    }

}

/****************************************************************************
 **                  Enable or Disable Subtest(s)
 **
 **	This command allows the operator to enable or disable individual
 ** subtests.
 **
 ** INPUT - "args[0][0]" = 's' if the subtest(s) are to be enabled or 'd'
 **         if the subtest(s) are to be disabled.  The first argument in the
 **         "args" list is the command.  The only two commands that can
 **         call this routine are "SSub" or "DSub" for select subtest(s) and
 **         deselect subtest(s) respectively.  
 **	  - The subtest(s) to be enabled or disabled are in the "args"
 **	    list starting in "args[1][0]".
 **
 ** OUTPUT - The selected subtest(s) will be enabled or disabled.
 **
 ** RETURN - None
 **
 **/
void sel_des_subtest(void)
{
  struct tests * tt = test_table;       /* pointer to tests table */
  int index;                            /* test table index */
  int parm_no;                          /* parameter number */
  unsigned char test_no_entered;        /* converted test number */
  int sel_state;                        /* new subtest state */

  int result;                           /* result of various func calls */
  /* get all the test selection bits from non-volatile storage */
  result = read_diag_data_from_nvram((unsigned char *) 
                                               &nv_test_sel_bits,
                                               CUR_SEL_TESTS_OS, 
                                               TEST_SEL_LEN);
  if (result == PROBLEM_DETECTED)
    {
    report_seeprom_problem(ES1050);     /* log the error & exit */
    return;
    }

  /* determine if this is an "ss" or "ds" command */
  if ((args[0][0] | 0x20) == 's')
    sel_state = ENABLE;                 /* enable subtest(s) */
  else
    sel_state = DISABLE;                /* disable subtest(s) */

  /* If "all" entered enable/disable all subtests */
  if ((args[1][0] | 0x20) == 'a')
    for (index = 0; tt[index].test_number !=0; index++)
      {
      tt[index].enabled = sel_state;

      /* set up select bits in non-volatile storage */
      if (sel_state == ENABLE)
        nv_test_sel_bits |= (0x01L << index);
      else
         nv_test_sel_bits &= ~(0x01L << index);       

      }
  else
    {
    /* enable/disable indivudual subtest(s) entered by operator */
    for(parm_no=1;parm_no<param_count;parm_no++)
      {
      /* conv next param to test no */
      test_no_entered = conv_ascii_decimal_string_to_binary(args[parm_no]);
      tt[test_no_entered-1].enabled = sel_state;  /* enable/disable the test */

      /* set up select bits in non-volatile storage */
      if (sel_state == ENABLE)
        nv_test_sel_bits |= (0x01L << (test_no_entered-1));
      else
         nv_test_sel_bits &= ~(0x01L << (test_no_entered-1));       

      } /* end for */
    } /* end else */

  /* write the new test select sequence to non-volatile storage */
  if (write_diag_data_to_nvram((unsigned char *) &nv_test_sel_bits,
      CUR_SEL_TESTS_OS, TEST_SEL_LEN) == PROBLEM_DETECTED)
    {
    report_seeprom_problem(ES1150);     /* log the error & exit */
    return;
    }

  /* re-calc & store new check sum */
  if (calc_write_seeprom_csum_timed() == PROBLEM_DETECTED)
    {
    report_seeprom_problem(ES1160);     /* log the error & exit */
    return;
    }

}

/****************************************************************************
 **     	Set/Display Test Program Execution Count
 **
 **    This command enables the operator to view and/or set up a new
 ** execution count.  The execution count determines how many times the
 ** selected tests will be executed.   There may be other parameters that
 ** also effect the number of times individual subtests are executed such
 ** as how many voltage margins are selected (if any are used) for testing.
 **
 ** INPUT - "param_count" will contain the nunmber of fields entered on the
 **	    the command line including the command.  If no parameters are
 **	    entered after the command, the current execution count is
 **	    displayed and the operator is given the chance to enter a new
 **	    count. If only a C/R is entered or an illegal decimal number is
 **	    entered, the current execution count is left unchanged.  If a
 **	    legal value is entered after the command, the current execution
 **	    count will be changed to the new count.
 **       - Any new execution count entered after the command will be stored in 
 **	    "args[1]".
 **
 ** OUTPUT - If a legal decimal number is entered after the command or after
 **	     the current execution count is displayed, the current execution
 **	     count will be changed to the new value.
 **
 ** RETURN - None
 **
 **/
void set_exec_count(void)
{
  int new_count;			/* new execution count */

  /* if no new exec count entered, display current count & ask for new one */
  if (param_count < 2)
    {
    /* get the saved execution count */
    if (get_exec_count(&exec_count, ES1290) == PROBLEM_DETECTED)
      return;
    printf("\nCurrent execution count is: %d ",exec_count);
    /* get the new error mode from the operator (if a legal mode entered) */
    gen_fgets(in_line, MAX_INPUT_LINE_SIZE);/* get a line from operator */

    /* if operator entered anything other than just a C/R, proc the value */
    if ((strlen(in_line)) > 0)
      {
        /*    if (((sscanf(in_line, "%d", &new_count)) == 1) && (new_count >= 0))*/
      new_count = conv_ascii_decimal_string_to_binary(in_line);
      if (new_count >= 0)
        {
        exec_count = new_count;
        /* save the new execution count */
        if (save_exec_count(exec_count, ES1300) == PROBLEM_DETECTED)
          return;  
        /* re-calc & store new check sum */
        if (calc_write_seeprom_csum_timed() == PROBLEM_DETECTED)
          report_seeprom_problem(ES1082);     /* log the error & exit */
        }
      else
        printf("Illegal count entered!  Execution count unchanged.\n");
      }
    }
  else
    {
    /**    Enter here when operator entered a new execution count after the
     ** the command on the command line.
     **/
      /*    if (((sscanf(args[1], "%d", &new_count)) == 1) && (new_count >= 0))*/
    new_count = conv_ascii_decimal_string_to_binary(args[1]);
    if (new_count >= 0)
      {
      exec_count = new_count;
      /* save the new execution count */
      if (save_exec_count(exec_count, ES1300) == PROBLEM_DETECTED)
        return;  
      /* re-calc & store new check sum */
      if (calc_write_seeprom_csum_timed() == PROBLEM_DETECTED)
        report_seeprom_problem(ES1082);     /* log the error & exit */
      }
    else
      printf("Illegal count entered!  Execution count unchanged.\n");
    }

}

/****************************************************************************
 **                      Display Test Statistics
 **
 **     This routine displays all the test related statistics including the
 ** first failure information, last failure information, and other testing 
 ** data as it becomes available.
 **
 ** INPUT - None
 **
 ** OUTPUT - All the test statistics will be displayed on the screen.
 **
 ** RETURN - None
 **
 **/
void disp_stats(void)
{
  struct tests * tt = test_table;       /* pointer to tests table */
  int index;                            /* test table index */
  int line_count;                       /* number of lines displayed on crt */
  int last_test;                        /* calculated last test no in table */
  int rows;                             /* calculated total number of rows */
  const int max_line_count = 19;        /* max lines displayed each screen */

  char header[] = "\n"
  "Test Total Total   Test Total Total   Test Total Total   Test Total Total\n"
  "Num  Execs Fails   Num  Execs Fails   Num  Execs Fails   Num  Execs Fails\n";

  /**  First diaplay any errors encountered previously and saved in 
   ** non-volatile memory.
   **/
  disp_non_volatile_failure_info();

  /* get the saved total failures count */
  if (get_total_fails_count(&passes_that_failed, ES1350) == PROBLEM_DETECTED)
    return;

  /* get the saved total passes completed count */
  if (get_tot_exec_count(&passes_completed, ES1350) == PROBLEM_DETECTED)
    return;

  /**
   **   Display totals for all tests combined
   **/
  printf("\n\nTotal passes completed = %0d\n",passes_completed);
  printf("Total passes with no failures detected = %0d\n",
       passes_completed-passes_that_failed);
  printf("Total passes that failed = %0d\n",passes_that_failed);
  printf("Total number of tests that failed = %0d\n",test_failures);

  /**
   **   Display saved first fail information (if any)
   **/
  printf("\n                   First Failure Information\n");
  if (first_fail.eh.error_stop != 0)
    disp_failure(&first_fail);
  else
    printf("...No errors detected so far.\n");

  /**
   **   Display saved last fail information (if any)
   **/
  printf("\n                   Last Failure Information\n");
  if (last_fail.eh.error_stop != 0)
   disp_failure(&last_fail);
  else
    printf("...No errors detected so far.\n");

  printf("\nPress RETURN to continue, any other key to exit display : ");
  if (wait_for_enter_key() == FALSE)
    return;                   /* if key pressed is not a C/R, exit display */

  /**
   **   Display statistics for each subtest
   **
   **   Start by counting the number of tests available. 
   **/
  for (line_count = 0; tt[line_count].test_number !=0; line_count++) ;
  last_test = line_count;               /* save cal last test number */

  printf("%s",header);                  /* display initial header */
  line_count = 0;                       /* init display line count */
#if 0
  index = 00;                           /* start at test 1 */
  for ( ; tt[index].test_number !=0; index++)
    {
    printf("%03d  %05d %05d   ",
           tt[index].test_number,
           tt[index].total_passes,
           tt[index].total_failures);

    if ((tt[index].test_number + max_line_count) <= last_test)
      printf("%03d  %05d %05d   ",
             tt[index + max_line_count].test_number,
             tt[index + max_line_count].total_passes,
             tt[index + max_line_count].total_failures);

    if ((tt[index].test_number + (max_line_count*2)) <= last_test)
      printf("%03d  %05d %05d   ",
             tt[(index + (max_line_count*2))].test_number,
             tt[(index + (max_line_count*2))].total_passes,
             tt[(index + (max_line_count*2))].total_failures);

    if ((tt[index].test_number + (max_line_count*3)) <= last_test)
      printf("%03d  %05d %05d",
             tt[(index + (max_line_count*3))].test_number,
             tt[(index + (max_line_count*3))].total_passes,
             tt[(index + (max_line_count*3))].total_failures);

    printf("\n");			/* do C/R & L/F at end of line */

    line_count++;                       /* inc num of lines displayed */

    /* redisp header after every screenful of tests if operator presses C/R */
    if ((line_count > 0) && ((line_count % max_line_count) == 0))
      {
      index += (max_line_count*3);    	/* inc to next screen of data */
      if ((index + 1) > last_test)
        break;                		/* exit display if all data displayed */

      printf("\nPress RETURN to continue, any other key to exit display : ");
      if (wait_for_enter_key() == FALSE)
        break; /* if key pressed is not a C/R, exit display */
      else
        printf("\n%s",header);/* disp hdr in prep for next screen of data */
      }

    } /* end 'for ( ; tt[index]...' */
#else
    rows = (last_test + 3) / 4;
    for (index = 0; index < rows; index++) {
        int j;
        for (j = 0; j < 4; j++) {
            if ((index + j * rows) < last_test) {
                printf("%03d  %05d %05d   ",
                    tt[index + j * rows].test_number,
                    tt[index + j * rows].total_passes,
                    tt[index + j * rows].total_failures);
            }
        }
        printf("\n");
        line_count++;

        /* redisp header after every screenful of tests if operator presses C/R */
        if ((line_count > 0) && ((line_count % max_line_count) == 0))
        {
        index += (max_line_count*3);    	/* inc to next screen of data */
        if ((index + 1) > last_test)
            break;                		/* exit display if all data displayed */

        printf("\nPress RETURN to continue, any other key to exit display : ");
        if (wait_for_enter_key() == FALSE)
            break; /* if key pressed is not a C/R, exit display */
        else
            printf("\n%s",header);/* disp hdr in prep for next screen of data */
        }
    } /* end 'for index' */
#endif

}

/****************************************************************************
 **             Clear All Volatile & Non-Volatile Test Statistics
 **
 **      This routine clears all testing related statistics including first
 ** and last fail information stored in RAM and in non-volatile storage.  The
 ** function that clears the information kept in non-volatile storage is 
 ** also called by this routine.
 **
 ** INPUT - None
 **
 ** OUTPUT - All test statistics will be cleared in RAM & NVRAM. 
 **
 ** RETURN - None
 **/
void clear_all_test_stats(void)
{
  clear_ram_stats();                    /* clear test statistics in RAM */
  clear_nv_stats();                     /* clear test statistics in NVRAM */
}

/****************************************************************************
 **                  Clear All Volatile Test Statistics
 **
 **      This routine clears all testing related statistics including first
 ** and last fail information stored in RAM.  The test statistics kept in
 ** non-volatile storage is not effected by this function.
 **
 ** INPUT - None
 **
 ** OUTPUT - All test statistics will be cleared in RAM. 
 **
 ** RETURN - None
 **/
void clear_ram_stats(void)
{
  struct tests * tt = test_table;       /* pointer to tests table */
  int index;                            /* test index */

  /* clear statistics for each subtest */
  for (index = 0; tt[index].test_number !=0; index++)
    {
    tt[index].total_passes = 00;        /* clear test's exec counter */
    tt[index].total_failures = 00;      /* clear test's fail counter */
    }

  /* clear general testing statistics */
  clear_mem(&first_fail, sizeof(first_fail));/* clear first failure data */
  clear_mem(&last_fail, sizeof(first_fail)); /* clear last failure data */
  test_failures = 0;                    /* clear tot tests that failed count */
}

/****************************************************************************
 **                  Clear All Non-Volatile Test Statistics
 **
 **      This routine clears all testing related statistics including first
 ** and last fail information stored in non-volatile storage.  Information kept
 ** in RAM is not cleared by this routine.
 **
 ** INPUT - None
 **
 ** OUTPUT - All test statistics will be cleared in non-volatile storage.
 **
 ** RETURN - None
 **/
void clear_nv_stats(void)
{
  unsigned long lwork;                  /* 32-bit working reg */
  struct _locations {
    unsigned int offset;
    int          length;
  } locations[] = {
      { FF_TEST_NO_OS, TOT_TEST_NUM_BYTES },
      { FF_ERROR_CODE_OS, TOT_ERR_CODE_BYTES },
      { LF_ERROR_CODE_OS, TOT_ERR_CODE_BYTES },
      { FF_ERR_ADRS_OS, TOT_FAIL_ADRS_BYTES },
      { FF_EXP_DATA_OS, TOT_EXP_DATA_BYTES },
      { FF_REC_DATA_OS, TOT_REC_DATA_BYTES },
  };
  int   i;

  /* clear all error information in non-volatile storage */
  passes_completed = 0;                 /* clear loops completed counter */
  passes_that_failed = 0;               /* clear loops that failed counter */
  lwork = 0;

  cur_loop = 0;			        /* clear current testing loop */
  if (save_loop_count(cur_loop, ES1005) == PROBLEM_DETECTED)
    return;

  for (i = 0; i < sizeof(locations) / sizeof(locations[0]); i++) {
    if (write_diag_data_to_nvram((unsigned char *) &lwork, locations[i].offset,
            locations[i].length) == PROBLEM_DETECTED) {
        report_seeprom_problem(ES1170);
        return;
    }
  }

  if (save_total_fails_count(passes_that_failed,ES1170) == PROBLEM_DETECTED)
    return;

  if (save_tot_exec_count(passes_completed,ES1170) == PROBLEM_DETECTED)
    return;

  /* re-calc & store new check sum */
  if (calc_write_seeprom_csum_timed() == PROBLEM_DETECTED)
    {
    report_seeprom_problem(ES1180);     /* log the error & exit */
    return;
    }

  /* Go through and verify that we erased everything */
  if (get_loop_count(&cur_loop, ES1005) == PROBLEM_DETECTED)
    return;

  if (cur_loop != 0) {
    report_seeprom_problem_long(ES1175, 0, cur_loop, CURRENT_LOOP_COUNT_OS);
    return;
  }

  for (i = 0; i < sizeof(locations) / sizeof(locations[0]); i++) {
    if (read_diag_data_from_nvram((unsigned char *) &lwork, locations[i].offset,
            locations[i].length) == PROBLEM_DETECTED) {
        report_seeprom_problem(ES1170);
        return;
    }
    if (lwork != 0) {
        report_seeprom_problem_long(ES1175, 0, lwork, locations[i].offset);
        return;
    }
  }

  if (get_total_fails_count(&passes_that_failed, ES1170) == PROBLEM_DETECTED)
    return;

  if (passes_that_failed != 0) {
    report_seeprom_problem_long(ES1175, 0, passes_that_failed, TOT_FAILS_OS);
    return;
  }

  if (get_tot_exec_count(&passes_completed, ES1170) == PROBLEM_DETECTED)
    return;

  if (passes_completed != 0) {
    report_seeprom_problem_long(ES1175, 0, passes_completed, TOT_TEST_EXECS_OS);
    return;
  }
}

/****************************************************************************
 **                  Generic Clear Memory Routine
 **
 **      This is a generic clear memory routine which can be used to clear
 ** any length of writable memory.  The memory is cleared a byte at a time.
 **
 ** INPUT - "beg_adrs" is a byte pointer to the first location to be cleared.
 **	 - "length" is the number of bytes to be cleared.
 **
 ** OUTPUT - The memory pointed to by "beg_adrs" will be filled with zeros for
 **	    length specified by "length" parameter.
 **
 ** RETURN - None
 **
 **/
void clear_mem(void * beg_adrs, unsigned long length)
{
  unsigned long bytes_cleared;		/* num of bytes cleared so far */
  char * bptr;				/* byte pointer */
  
  bptr = (char *) beg_adrs;		/* set up byte pointer */
  
  bytes_cleared = 00;
  while (bytes_cleared < length)
    {
    *bptr = 00;				/* clear next byte */
    bptr++;				/* inc mem pointer */
    bytes_cleared++;			/* inc byte cunter */
    }
}

/*****************************************************************************
 **                 Get Execution Count Function
 **
 **  This function retrieves the execution count from where ever it is stored
 ** and returns it to the calling code.
 **
 ** INPUT - "count" = pointer to 32-bit location of where count is to be
 **          stored.
 **       - "error_code" = the error code to be reported if problems are
 **         encountered retrieving the execution count.
 **
 ** OUTPUT - Nothing
 **
 ** RETURN - "NO_PROBLEM_DETECTED" will be returned if the no problems where
 **          encountered retrieving the count.  "PROBLEM_DETECTED" returned
 **          otherwise.
 **
 ****************************************************************************/
int get_exec_count(int * count, unsigned long error_code)
{
  int result;                           /* result of las function call */
  int lwork;                            /* 32-bit working register */

  result = read_diag_data_from_nvram((unsigned char *)&lwork, 
                                               EXEC_COUNT_OS, 
                                                TOT_EXEC_COUNT_LEN);

  /* if problems retrieving the execution count, return default count */
  if (result == PROBLEM_DETECTED)
    {
    report_seeprom_problem(error_code); /* log the error & exit */
    *count = DEFAULT_EXEC_COUNT;
    return PROBLEM_DETECTED;
    }
  else
    {
    *count = lwork;
    return NO_PROBLEM_DETECTED;
    }

}

/*****************************************************************************
 **                  Save Execution Count Function
 **
 **  This function saves the execution count to where ever it is stored,
 ** be that RAM or non-volatile storage.
 **
 ** INPUT - "count" = the execution count to be saved.
 **       - "error_code" = the error code to be reported if problems are
 **         encountered retrieving the execution count.
 **
 ** OUTPUT - Nothing
 **
 ** RETURN - "NO_PROBLEM_DETECTED" will be returned if the no problems where
 **          encountered saving the count.  "PROBLEM_DETECTED" returned
 **          otherwise.
 **
 ****************************************************************************/
int save_exec_count(int count, unsigned long error_code)
{
  int lwork;                            /* 32-bit working register */

  lwork = count;
  if (write_diag_data_to_nvram((unsigned char *) &lwork,
      EXEC_COUNT_OS, TOT_EXEC_COUNT_LEN)== PROBLEM_DETECTED)
    {
    report_seeprom_problem(error_code);     /* log the error & exit */
    return PROBLEM_DETECTED;
    }

  return NO_PROBLEM_DETECTED;

}

/*****************************************************************************
 **                 Get Current Loop Count Function
 **
 **  This function retrieves the current test loop count from where ever it 
 ** is stored and returns it to the calling code.
 **
 ** INPUT - "count" = pointer to 32-bit location of where count is to be
 **          stored.
 **       - "error_code" = the error code to be reported if problems are
 **         encountered retrieving the current loop count.
 **
 ** OUTPUT - Nothing
 **
 ** RETURN - "NO_PROBLEM_DETECTED" will be returned if the no problems where
 **          encountered retrieving the count.  "PROBLEM_DETECTED" returned
 **          otherwise.
 **
 ****************************************************************************/
int get_loop_count(int * count, unsigned long error_code)
{
  int result;                           /* result of las function call */
  int lwork;                            /* 32-bit working register */

  result = read_diag_data_from_nvram((unsigned char *)&lwork, 
                                               CURRENT_LOOP_COUNT_OS, 
                                               LOOP_COUNT_LEN);

  /* if problems retrieving the loop count, return default count */
  if (result == PROBLEM_DETECTED)
    {
    report_seeprom_problem(error_code); /* log the error & exit */
    *count = DEFAULT_EXEC_COUNT;
    return PROBLEM_DETECTED;
    }
  else
    {
    *count = lwork;
    return NO_PROBLEM_DETECTED;
    }

}

/*****************************************************************************
 **                  Save Current Loop Count Function
 **
 **  This function saves the current test loop count to where ever it is 
 ** stored, be that RAM or non-volatile storage.
 **
 ** INPUT - "count" = the current loop count to be saved.
 **       - "error_code" = the error code to be reported if problems are
 **         encountered retrieving the current loop count.
 **
 ** OUTPUT - Nothing
 **
 ** RETURN - "NO_PROBLEM_DETECTED" will be returned if the no problems where
 **          encountered saving the count.  "PROBLEM_DETECTED" returned
 **          otherwise.
 **
 ****************************************************************************/
int save_loop_count(int count, unsigned long error_code)
{
  int lwork;                            /* 32-bit working register */

  lwork = count;
  if (write_diag_data_to_nvram((unsigned char *) &lwork,
      CURRENT_LOOP_COUNT_OS, LOOP_COUNT_LEN)== PROBLEM_DETECTED)
    {
    report_seeprom_problem(error_code);     /* log the error & exit */
    return PROBLEM_DETECTED;
    }

  /* re-calc & store new check sum */
  if (calc_write_seeprom_csum_timed() == PROBLEM_DETECTED)
    {
    report_seeprom_problem(ES1310);     /* log the error & exit */
    return PROBLEM_DETECTED;
    }

  return NO_PROBLEM_DETECTED;

}

/*****************************************************************************
 **                 Get Total Execution Count Function
 **
 **  This function retrieves the total test execution count from where ever it 
 ** is stored and returns it to the calling code.
 **
 ** INPUT - "count" = pointer to 32-bit location of where count is to be
 **          stored.
 **       - "error_code" = the error code to be reported if problems are
 **         encountered retrieving the total test execution count.
 **
 ** OUTPUT - Nothing
 **
 ** RETURN - "NO_PROBLEM_DETECTED" will be returned if the no problems where
 **          encountered retrieving the count.  "PROBLEM_DETECTED" returned
 **          otherwise.
 **
 ****************************************************************************/
int get_tot_exec_count(int * count, unsigned long error_code)
{
  int result;                           /* result of las function call */
  int lwork;                            /* 32-bit working register */

  result = read_diag_data_from_nvram((unsigned char *)&lwork, 
                                               TOT_TEST_EXECS_OS, 
                                               TOT_EXEC_COUNT_LEN);

  /* if problems retrieving the loop count, return default count */
  if (result == PROBLEM_DETECTED)
    {
    report_seeprom_problem(error_code); /* log the error & exit */
    *count = DEFAULT_EXEC_COUNT;
    return PROBLEM_DETECTED;
    }
  else
    {
    *count = lwork;
    return NO_PROBLEM_DETECTED;
    }

}

/*****************************************************************************
 **                  Save Total Test Execution Count Function
 **
 **  This function saves the total test execution count to where ever it is 
 ** stored, be that RAM or non-volatile storage.
 **
 ** INPUT - "count" = the total execution count to be saved.
 **       - "error_code" = the error code to be reported if problems are
 **         encountered retrieving the current loop count.
 **
 ** OUTPUT - Nothing
 **
 ** RETURN - "NO_PROBLEM_DETECTED" will be returned if the no problems where
 **          encountered saving the count.  "PROBLEM_DETECTED" returned
 **          otherwise.
 **
 ****************************************************************************/
int save_tot_exec_count(int count, unsigned long error_code)
{
  int lwork;                            /* 32-bit working register */

  lwork = count;
  if (write_diag_data_to_nvram((unsigned char *) &lwork,
      TOT_TEST_EXECS_OS, TOT_EXEC_COUNT_LEN)== PROBLEM_DETECTED)
    {
    report_seeprom_problem(error_code);     /* log the error & exit */
    return PROBLEM_DETECTED;
    }

  /* re-calc & store new check sum */
  if (calc_write_seeprom_csum_timed() == PROBLEM_DETECTED)
    {
    report_seeprom_problem(ES1310);     /* log the error & exit */
    return PROBLEM_DETECTED;
    }

  return NO_PROBLEM_DETECTED;

}

/*****************************************************************************
 **              Get Total Passes That Failed Counter Function
 **
 **  This function retrieves the count which keeps track of how many times
 ** a failures was detected from where ever it is stored and returns it to 
 ** the calling code.
 **
 ** INPUT - "count" = pointer to 32-bit location of where counter is to be
 **          stored.
 **       - "error_code" = the error code to be reported if problems are
 **         encountered retrieving the total faiures count.
 **
 ** OUTPUT - Nothing
 **
 ** RETURN - "NO_PROBLEM_DETECTED" will be returned if the no problems where
 **          encountered retrieving the counter.  "PROBLEM_DETECTED" returned
 **          otherwise.
 **
 ****************************************************************************/
int get_total_fails_count(int * count, unsigned long error_code)
{
  int result;                           /* result of las function call */
  int lwork;                            /* 32-bit working register */

  result = read_diag_data_from_nvram((unsigned char *)&lwork, 
                                               TOT_FAILS_OS, 
                                               TOT_FAILS_LEN);

  /* if problems retrieving the loop count, return default count */
  if (result == PROBLEM_DETECTED)
    {
    report_seeprom_problem(error_code); /* log the error & exit */
    *count = DEFAULT_EXEC_COUNT;
    return PROBLEM_DETECTED;
    }
  else
    {
    *count = lwork;
    return NO_PROBLEM_DETECTED;
    }

}

/*****************************************************************************
 **             Save Total Passes That Failed Counter Function
 **
 **  This function saves the the count which keeps track of how many times
 ** a failures was detected to where ever it is stored, be that RAM or 
 ** non-volatile storage.
 **
 ** INPUT - "count" = the current failure count to be saved.
 **       - "error_code" = the error code to be reported if problems are
 **         encountered saving the total failure count.
 **
 ** OUTPUT - Nothing
 **
 ** RETURN - "NO_PROBLEM_DETECTED" will be returned if the no problems where
 **          encountered saving the count.  "PROBLEM_DETECTED" returned
 **          otherwise.
 **
 ****************************************************************************/
int save_total_fails_count(int count, unsigned long error_code)
{
  int lwork;                            /* 32-bit working register */

  lwork = count;
  if (write_diag_data_to_nvram((unsigned char *) &lwork,
      TOT_FAILS_OS, TOT_FAILS_LEN)== PROBLEM_DETECTED)
    {
    report_seeprom_problem(error_code);     /* log the error & exit */
    return PROBLEM_DETECTED;
    }

  /* re-calc & store new check sum */
  if (calc_write_seeprom_csum_timed() == PROBLEM_DETECTED)
    {
    report_seeprom_problem(ES1340);     /* log the error & exit */
    return PROBLEM_DETECTED;
    }

  return NO_PROBLEM_DETECTED;

}

/*****************************************************************************
 **                    Jump To Restart Vector Function
 **
 **   This function calculates the absolute address of the restart vector
 ** then jumps to that address effectively causing a warm reset.
 ** The code does not return once the jump is made.
 **
 ** WARNING!!!  This function jumps to the restart vector and does not come
 **             back!!!
 **
 ** INPUT - Nothing
 **
 ** OUTPUT - Nothing
 **
 ** RETURN - Nothing
 **
 ****************************************************************************/
void jump_to_restart_vector(void)
{
  /**   If the "Auto Disable" mode is currently active, we must be in the 
   ** continuous test mode or a similar mode that requires BIST to run the 
   ** phase one tests again.  But we have to fake out the low-level code in 
   ** thinking the "Auto Disable" mode has just been started so the test will 
   ** run again correctly. To do that we must leave the "Auto Disable" bit set 
   ** but clear the "Middle Of BIST" bit.  When the code restarts, phase one 
   ** BIST will think we just started the "Auto Disable" mode and set the 
   ** "Middle Of BIST" bit and start testing again.
   **
   **   All testing parameters will finally be complete at some future
   ** time and then this adjustment will no longer be necessary and all the
   ** proper bits will be set and/or cleared to end the "Auto Disable" mode 
   ** when the BIST code is finally exited normally.
   **
   **/

  /* first get the current extended test modes */
  if (read_diag_data_from_nvram((unsigned char *) &ext_test_modes,
    EXT_TEST_MODES_OS, EXT_TMODES_LEN) == PROBLEM_DETECTED)
    {
    report_seeprom_problem(ES2570);     /* log the error & exit */
    return;
    }

  if ((ext_test_modes & ETM_AUTO_DIS) == ETM_AUTO_DIS)
    {
    ext_test_modes &= ~ETM_MIDL_OF_BIST;   /* clr "Middle of bist" flag */

    /* clear "Middle of bist" again so "Auto Disable" mode works on restart */
    if (write_diag_data_to_nvram((unsigned char *) &ext_test_modes,
      EXT_TEST_MODES_OS, EXT_TMODES_LEN) == PROBLEM_DETECTED)
      {
      report_seeprom_problem(ES2570);     /* log the error & exit */
      return;
      }

    /* don't forget to recalculate the csum on the diag area of SEEPROM */
    if (calc_write_seeprom_csum_timed() == PROBLEM_DETECTED)
      report_seeprom_problem(ES2570);   /* log the error & exit */

    } /* end 'if ((ext_test_modes & ETM_AUTO_DIS...' */

#if 0
  void (*ptr)(void);                    /* function pointer */

  /* this works on the Octeon processor but not reliably.  In fact reseting the
     Octeon this way only works once then the secodn time around there is a
     problem setting upt the SDRAM controller.  This may be fixable but I have 
     not spent any time looking into this issue yet. */
  ptr = (void *) (RESTART_VECTOR);      /* jump to researt vector */

  printf("\nJumping to restart vector %016qx...\n",RESTART_VECTOR);
  (*ptr)();
#else
  reset_unit();                         /* force actual hard reset */
#endif
}

/*****************************************************************************
 **                                                                         **
 **   The following functions are the general purpose calls that then call  **
 ** the appropriate function for the platform on which the code is running. **
 **                                                                         **
 ****************************************************************************/

char * gen_fgets(char * buffer, int max_chars)
{

#ifdef STANDALONE
  char * bptr;               /* 8-bit pointer */
  size_t length;             /* length of input string */

  /* standard io call */
  bptr = fgets(buffer, max_chars, stdin);
  length = strlen(in_line);
  /* write null over newline char if present */
  if ((buffer[length-1] == '\n') || (buffer[length-1] == '\r'))
    buffer[length-1] = 0;

  return bptr;
#else
  return (char *) get_line(buffer);
  printf("\nIn 'gen_fgets' string returned = [%s]\n",buffer);
#endif

}

int gen_putchar(int ch)
{
#ifdef STANDALONE
  /* standard io call */
  return putchar(ch);
#else
  llputchar((char) ch);
  return ch;
#endif

}

int gen_key_hit(void)
{
#ifdef STANDALONE
  /* standard io call */
  //return key_hit();
  return kbhit(); /* part of "kbhit.c" module */
#else
  return check_for_key();
#endif

}

char gen_wait_for_one_key(void)
{
#ifdef STANDALONE
  /* standard io call */
  //return wait_for_one_key();
  fflush(0);        /* make sure all outputs finish */
  return readch();  /* part of "kbhit.c" module */
#else
  wait_for_key();  /* wait for a key to be pressed */
  return llgetchar(); /* read and return key pressed */
#endif
}

/***************************************************************************
 **    Generic Function To Save Diagnostic Data In Non-Volatile Storage
 **
 **   This function is called to save diagnostic data "Ted Droppings" in some
 ** type of non-volatile storage somplace.  The type and location of the 
 ** non-volatile storage is dependent on the platform.
 **
 ** INPUT - "buffer" = pointer to data that is to be written to NVRAM.
 **       - "offset" = offset of 1st byte to be written to NVRAM.
 **       - "length" = how many consecutive bytes to be written to NVRAM.
 **
 ** OUTPUT - nothing
 **
 ** RETURN -"NO_PROBLEM_DETECTED" will be returned to the calling code if
 **          the SEEPROM responded correctly, "PROBLEM_DETECTED" returned
 **          otherwise.
 **
 ****************************************************************************/
int write_diag_data_to_nvram(unsigned char * buffer, unsigned int offset, 
			     int length)
{
#ifdef STANDALONE
extern char seeprom_data[];

  unsigned char csum;                   /* calculated check sum */
  int i;
  int j;

  j = 0;
  /* write the new data in its proper location */
  for (i = offset; i < (offset + length) ;i++)
    {
    seeprom_data[i] = buffer[j];
    j++;
    }

  /**
   ** now calculate a new checksum 
   **/

  /* calc all but last byte into check sum */
  for (i = 0; i < (MAX_BYTES_TO_READ-1); i++)
    {
    csum += seeprom_data[i];
    }

  csum &= 0xFF;                         /* ensure csum is 8-bits */
  seeprom_data[CHECKSUM_OS] = csum;     /* store checksum */

  return NO_PROBLEM_DETECTED;

#else
  return write_select_data_to_seeprom_timed(buffer, offset, length);
#endif
}

/***************************************************************************
 **    Generic Function To Read Diagnostic Data From Non-Volatile Storage
 **
 **   This function is called to get diagnostic data "Ted Droppings" from
 ** some type of non-volatile storage somplace.  The type and location of the 
 ** non-volatile storage is dependent on the platform.
 **
 ** INPUT - "buffer" = pointer to where data read from NVRAM is to be
 **         written.
 **       - "offset" = offset of 1st byte to be read from NVRAM.
 **       - "length" = how many consecutive bytes to be read from NVRAM.
 **
 ** OUTPUT - nothing
 **
 ** RETURN - "NO_PROBLEM_DETECTED" will be returned to the calling code if
 **          the SEEPROM responded correctly, "PROBLEM_DETECTED" returned
 **          otherwise.
 **
 ****************************************************************************/
int read_diag_data_from_nvram(unsigned char * buffer, unsigned int offset, 
			      int length)
{
#ifdef STANDALONE
extern char seeprom_data[];

  int i;
  int j;

  j = 0;
  /* read the data from its proper location */
  for (i = offset; i < (offset + length) ;i++)
    {
    buffer[j] = seeprom_data[i];
    j++;
    }

  return NO_PROBLEM_DETECTED;

#else
  return read_select_data_from_seeprom_timed(buffer, offset, length);
#endif
}
