/*      -*- linux-c -*-
 *
 * Copyright (c) 2004 by Intel Corp.
 * (C) Copyright Nokia Siemens Networks 2010
 * (C) Copyright Ulrich Kleber 2011
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  This
 * file and program are licensed under a BSD style license.  See
 * the Copying file included with the OpenHPI distribution for
 * full licensing terms.
 *
 * Filename: hpiwdt.c
 * Authors:  Andy Cress <arcress@users.sourceforge.net>
 *      Ulrich Kleber <ulikleber@users.sourceforge.net>
 * 
 * Changes:
 * 03/15/04 Andy Cress - v1.0 added strings for use & actions in show_wdt
 * 10/13/04  kouzmich  - porting to HPI B
 * 12/02/04 Andy Cress - v1.1 fixed domain/RPT loop, added some decoding
 * 09/06/2010 ulikleber New option -D to select domain
 * 01/02/2011 ulikleber Refactoring to use glib for option parsing and
 *                      introduce common options for all clients
 *
 */
/* 
 * This tool reads and enables the watchdog timer via HPI.
 * Note that there are other methods for doing this, and the
 * standard interface is for the driver to expose a /dev/watchdog
 * device interface.
 * WARNING: If you enable the watchdog, make sure you have something
 * set up to keep resetting the timer at regular intervals, or it
 * will reset your system.
 */

#include "oh_clients.h"

#define  uchar  unsigned char
#define OH_SVN_REV "$Revision: 7438 $"

#define NUSE  6
char *usedesc[NUSE] = {"reserved", "BIOS FRB2", "BIOS/POST",
                    "OS Load", "SMS/OS", "OEM" };
#define NACT  5
char *actions[NACT] = {"No action", "Hard Reset", "Power down",
		    "Power cycle", "Reserved" };

static gboolean fenable    = FALSE;
static gboolean fdisable = FALSE;
static gboolean freset     = FALSE;
static gint     ftimeout   = 0;
static oHpiCommonOptionsT copt;

static GOptionEntry my_options[] =
{
  { "enable",  'e', 0, G_OPTION_ARG_NONE, &fenable,  "enables the watchdog timer",  NULL },
  { "disable", 'd', 0, G_OPTION_ARG_NONE, &fdisable, "disables the watchdog timer", NULL },
  { "reset",   'r', 0, G_OPTION_ARG_NONE, &freset,   "resets the watchdog timer",   NULL },
  { "timeout", 't', 0, G_OPTION_ARG_INT,  &ftimeout, "sets timeout to n seconds",   "n" },
  { NULL }
};

static void
show_wdt(SaHpiWatchdogNumT  wdnum, SaHpiWatchdogT *wdt)
{
  int icount, pcount;
  char ustr[12]; 
  char astr[16]; 
  char estr[30]; 
  char *pstr;
  icount = wdt->InitialCount /1000;        /*1000 msec = 1 sec*/
  pcount = wdt->PresentCount /1000;

  if (wdt->TimerUse > NUSE) sprintf(ustr,"%u", wdt->TimerUse );
  else strcpy(ustr, usedesc[wdt->TimerUse]);
  if (wdt->TimerAction > NACT) sprintf(astr,"%u", wdt->TimerAction );
  else strcpy(astr, actions[wdt->TimerAction]);
  printf("Watchdog: Num=%u, Log=%d, Running=%d, TimerUse=%s, TimerAction=%s\n",
	wdnum,wdt->Log,wdt->Running,ustr, astr);
  if (wdt->TimerUseExpFlags == 0) strcpy(estr,"none");
  else {
	estr[0] = 0;
	if (wdt->TimerUseExpFlags & 0x01) strcat(estr,"FRB2 ");
	if (wdt->TimerUseExpFlags & 0x02) strcat(estr,"POST ");
	if (wdt->TimerUseExpFlags & 0x04) strcat(estr,"OS_Load ");
	if (wdt->TimerUseExpFlags & 0x08) strcat(estr,"SMS_OS ");
	if (wdt->TimerUseExpFlags & 0x10) strcat(estr,"OEM ");
  }
  printf("          ExpiredUse=%s, Timeout=%u sec, Counter=%u sec\n",
	estr, icount,pcount);
  switch(wdt->PretimerInterrupt) {
  case 1:  pstr = "SMI";    break;
  case 2:  pstr = "NMI";    break;
  case 3:  pstr = "MsgInt"; break;
  default: pstr = "none";   break;
  }
  printf("          PreTimerInterrupt=%s, PreTimeoutInterval=%u msec\n",
	 pstr,wdt->PreTimeoutInterval);
  return;
}

int
main(int argc, char **argv)
{
  SaErrorT rv;
  SaHpiSessionIdT sessionid;
  SaHpiDomainInfoT domainInfo;
  SaHpiRptEntryT rptentry;
  SaHpiEntryIdT rptentryid;
  SaHpiEntryIdT nextrptentryid;
  SaHpiResourceIdT resourceid;
  SaHpiWatchdogNumT  wdnum;
  SaHpiWatchdogT     wdt;
  GOptionContext *context;

  /* Print version strings */
  oh_prog_version(argv[0]);

  /* Parsing options */
  static char usetext[]="- Read and Enables the watchdog timer.\n  "
                        OH_SVN_REV; 
  OHC_PREPARE_REVISION(usetext);
  context = g_option_context_new (usetext);
  g_option_context_add_main_entries (context, my_options, NULL);

  if (!ohc_option_parse(&argc, argv, 
                context, &copt, 
                OHC_ALL_OPTIONS 
                    - OHC_ENTITY_PATH_OPTION  //TODO: Feature 880127
                    - OHC_VERBOSE_OPTION )) { // no verbose mode implemented
                g_option_context_free (context);
		return 1;
  }
  g_option_context_free (context);
  if (ftimeout == 0) ftimeout = 120;
  else fenable = TRUE;
  
  rv = ohc_session_open_by_option ( &copt, &sessionid);
  if (rv != SA_OK) return rv;

  rv = saHpiDiscover(sessionid);
  if (copt.debug) DBG("saHpiDiscover rv = %s",oh_lookup_error(rv));
  rv = saHpiDomainInfoGet(sessionid, &domainInfo);
  if (copt.debug) DBG("saHpiDomainInfoGet rv = %s",oh_lookup_error(rv));
  printf("DomainInfo: UpdateCount = %x, UpdateTime = %lx\n",
       domainInfo.RptUpdateCount, (unsigned long)domainInfo.RptUpdateTimestamp);

  /* walk the RPT list */
  rptentryid = SAHPI_FIRST_ENTRY;
  while ((rv == SA_OK) && (rptentryid != SAHPI_LAST_ENTRY))
  {
     rv = saHpiRptEntryGet(sessionid,rptentryid,&nextrptentryid,&rptentry);
     if (rv != SA_OK) printf("RptEntryGet: rv = %s\n",oh_lookup_error(rv));
     if (rv == SA_OK) {
	/* handle WDT for this RPT entry */
	resourceid = rptentry.ResourceId;
	rptentry.ResourceTag.Data[rptentry.ResourceTag.DataLength] = 0;
	if (copt.debug)
	   printf("rptentry[%u] resourceid=%u capab=%x tag: %s\n",
		rptentryid, resourceid, rptentry.ResourceCapabilities, 
		rptentry.ResourceTag.Data);

	if (rptentry.ResourceCapabilities & SAHPI_CAPABILITY_WATCHDOG) {
	   printf("%s has watchdog capability\n",rptentry.ResourceTag.Data);

	   wdnum = SAHPI_DEFAULT_WATCHDOG_NUM;
	   rv = saHpiWatchdogTimerGet(sessionid,resourceid,wdnum,&wdt);
	   if (copt.debug) DBG("saHpiWatchdogTimerGet rv = %s",oh_lookup_error(rv));
	   if (rv != 0) {
		printf("saHpiWatchdogTimerGet error = %s\n",oh_lookup_error(rv));
		rv = 0;
		rptentryid = nextrptentryid; 
		continue;
	   }
	   show_wdt(wdnum,&wdt);

	   if (fdisable) {
	      printf("Disabling watchdog timer ...\n");
	      /* clear FRB2, timeout back to 120 sec */
	      /* TODO: add setting wdt values here */
	      wdt.TimerUse = SAHPI_WTU_NONE;    /* 1=FRB2 2=POST 3=OSLoad 4=SMS_OS 5=OEM */
	      wdt.TimerAction = SAHPI_WA_NO_ACTION; /* 0=none 1=reset 2=powerdown 3=powercycle */
	      wdt.PretimerInterrupt = SAHPI_WPI_NONE; /* 0=none 1=SMI 2=NMI 3=message */
	      wdt.PreTimeoutInterval = 60000; /*msec*/
	      wdt.InitialCount = 120000; /*msec*/
	      wdt.PresentCount = 120000; /*msec*/

	      rv = saHpiWatchdogTimerSet(sessionid,resourceid,wdnum,&wdt);
	      if (copt.debug) DBG("saHpiWatchdogTimerSet rv = %s",oh_lookup_error(rv));
	      if (rv == 0) show_wdt(wdnum,&wdt);
	   } else if (fenable) {
	      printf("Enabling watchdog timer ...\n");
	      /* hard reset action, no pretimeout, clear SMS/OS when done */
	      /* use ftimeout for timeout */
	      wdt.TimerUse = SAHPI_WTU_SMS_OS;    /* 1=FRB2 2=POST 3=OSLoad 4=SMS_OS 5=OEM */
	      wdt.TimerAction = SAHPI_WA_RESET; /* 0=none 1=reset 2=powerdown 3=powercycle */
	      wdt.PretimerInterrupt = SAHPI_WPI_NMI; /* 0=none 1=SMI 2=NMI 3=message */
	      wdt.PreTimeoutInterval = (ftimeout / 2) * 1000; /*msec*/
	      wdt.InitialCount = ftimeout * 1000; /*msec*/
	      wdt.PresentCount = ftimeout * 1000; /*msec*/

	      rv = saHpiWatchdogTimerSet(sessionid,resourceid,wdnum,&wdt);
	      if (copt.debug) DBG("saHpiWatchdogTimerSet rv = %s",oh_lookup_error(rv));
	      if (rv == 0) show_wdt(wdnum,&wdt);
	   }
	   if (freset && !fdisable) {
	      printf("Resetting watchdog timer ...\n");
	      rv = saHpiWatchdogTimerReset(sessionid,resourceid,wdnum);
	      if (copt.debug) DBG("saHpiWatchdogTimerReset rv = %s",oh_lookup_error(rv));
	   }
	} /*watchdog capability*/
	rptentryid = nextrptentryid;  /* get next RPT (usu only one anyway) */
     }  /*endif RPT ok*/
  }  /*end while loop*/
 
  rv = saHpiSessionClose(sessionid);

  return 0;
}
 
/* end hpiwdt.c */
