/****************************************************************
 ****************************************************************
 **                                                            **
 **    (C)Copyright 2005-2006, American Megatrends .           **
 **                                                            **
 **            All Rights Reserved.                            **
 **                                                            **
 **        6145-F, Northbelt Parkway, Norcross,                **
 **                                                            **
 **        Georgia - 30071, USA. Phone-(770)-246-8600.         **
 **                                                            **
 ****************************************************************
 *****************************************************************
 *
 * Sel.c
 * Sel Command Handler
 *
 * Author: Bakka Ravinder Reddy <bakkar@ami.com>
 *
 *****************************************************************/
#define ENABLE_DEBUG_MACROS 0

#include "SEL.h"
#include "com_IPMI_Sensor.h"
#include "SELRecord.h"
#include <string.h>
//#include "Storlead_BMC_LIb.h"
#include "Support.h"
#include "main.h"
#include <stdio.h>
#include "Api.h"


/* Reserved bit macro definitions */
#define RESERVED_BITS_PARTIALADDSELENTRY                0xF0 //(BIT7 | BIT6 | BIT5 | BIT4)

#if SEL_DEVICE == 1


/*** Local Definitions ***/
#define SEL_RECORD_SIZE             16
#define CLR_SEL_PASSWORD_STR_LEN    3
#define CLEAR_SEL_GET_STATUS        0x00
#define CLEAR_SEL_ACTION            0xaa

#define SEL_ERASE_IN_PROGRESS       0x00
#define SEL_ERASE_COMPLETED         0x01
#define SEL_ALLOC_UNIT_SIZE         0x10
#define SEL_MAX_RECORD_SIZE         0x10
#define INVALID_RECORD_ID           0x00

#define OVERFLOW_FLAG               0x80
#define DELETE_SEL_SUPPORT          0x08
#define PARTIAL_ADD_SEL_SUPPORT     0x04
#define RESERVE_SEL_SUPPORT         0x02
#define GET_SEL_ALLOC_SUPPORT       0x01
#define NO_SUPPORT                  0x00


#define STATUS_DELETE_SEL           ((uint8_t)0xA5)

#define SEL_ALMOST_FULL_PERCENTAGE  75
#define SEL_PARTIAL_ADD_REQUEST_MISC_BYTES		6
#define SEL_PARTIAL_ADD_CMD_MAX_LEN				22
#define SEL_INITIALIZED 0x01
#define SEL_UNINITIALIZED 0x00


#define PRE_CLK_SET     0x00
#define POST_CLK_SET    0x80

/*** Prototype Declaration ***/
static  SELRec_T*    GetNextSELEntry ( SELRec_T* rec);
static  SELRec_T* GetSELRec(uint16_t RecID);
static uint8_t SELTimeClockSync(uint8_t Action);


/*** Global variables ***/

/*** Module variables ***/
//SELRepository_T*     m_sel;
#define SENSOR_TYPE_EVT_LOGGING                 0x10


/* System Event Message */
static uint8_t m_SysEventMsg [] = {

        0x00, 0x00,                 //Record ID
        0x02,                       //Record Type is System
        0x00, 0x00, 0x00, 0x00,     //TimeStamp
        0x20, 0x00,                 //Generator ID is BMC
        IPMI_EVM_REVISION,
        SENSOR_TYPE_SYSTEM_EVENT,
        0x6F,
        0xFF,
        0xFF,
        0xFF,
        0xFF
};

/*---------------------------------------
 * GetSELInfo
 *---------------------------------------*/
int
GetSELInfo ( uint8_t* pReq, uint8_t ReqLen,  uint8_t* pRes)
{
	SELInfo_T*   pSelInfo = ( SELInfo_T*) pRes;
	SELRepository_T* 	m_sel;

 
	m_sel = ( SELRepository_T*) g_BMCInfo.pSEL;
	pSelInfo->RecCt          = m_sel->NumRecords;
	pSelInfo->FreeSpace      = (g_BMCInfo.IpmiConfig.SELConfig.MaxSELRecord - m_sel->NumRecords) * sizeof(SELRec_T);
	pSelInfo->AddTimeStamp   = (m_sel->AddTimeStamp);
	pSelInfo->EraseTimeStamp =( m_sel->EraseTimeStamp);
  

    pSelInfo->CompletionCode = CC_NORMAL;
    pSelInfo->Version        = SEL_VERSION;
    pSelInfo->OpSupport=NO_SUPPORT;

    if(g_BMCInfo.IpmiConfig.SELConfig.SELOverFlow == TRUE)
    {
        pSelInfo->OpSupport |= OVERFLOW_FLAG;
    }

	pSelInfo->OpSupport|= RESERVE_SEL_SUPPORT;

	pSelInfo->OpSupport|= GET_SEL_ALLOC_SUPPORT;
	
	pSelInfo->OpSupport|=PARTIAL_ADD_SEL_SUPPORT;

	pSelInfo->OpSupport|= DELETE_SEL_SUPPORT;
        
  
    return sizeof (SELInfo_T);
}


/*---------------------------------------
 * GetSELAllocationInfo
 *---------------------------------------*/
int
GetSELAllocationInfo( uint8_t* pReq, uint8_t ReqLen,  uint8_t* pRes)
{
	SELAllocInfo_T* pAllocInfo = ( SELAllocInfo_T*) pRes;
	SELRepository_T* 	m_sel;

    pAllocInfo->CompletionCode    = CC_NORMAL;
    pAllocInfo->NumAllocUnits     =  MAX_SEL_RECORD;
    pAllocInfo->AllocUnitSize     =  (sizeof (SELRec_T));

	m_sel = ( SELRepository_T*) g_BMCInfo.pSEL;
	pAllocInfo->NumFreeAllocUnits =  ((g_BMCInfo.IpmiConfig.SELConfig.MaxSELRecord - m_sel->NumRecords));
	pAllocInfo->LargestFreeBlock  =  sizeof(SELRec_T);


    pAllocInfo->MaxRecSize        = sizeof(SELRec_T);
    
    return sizeof(SELAllocInfo_T);
}


/*---------------------------------------
 * ReserveSEL
 *---------------------------------------*/
int
ReserveSEL ( uint8_t* pReq, uint8_t ReqLen,  uint8_t* pRes)
{
    ReserveSELRes_T* pRsvSelRes = ( ReserveSELRes_T*) pRes;
   
	g_BMCInfo.IpmiConfig.SELConfig.SelReservationID++;
    if (0 == g_BMCInfo.IpmiConfig.SELConfig.SelReservationID) { g_BMCInfo.IpmiConfig.SELConfig.SelReservationID = 1; }
    pRsvSelRes->CompletionCode = CC_NORMAL;
    pRsvSelRes->ReservationID  = g_BMCInfo.IpmiConfig.SELConfig.SelReservationID;
    g_BMCInfo.IpmiConfig.SELConfig.PartialAdd=0 ;//Addded for DR#30287 
    FlushIPMIToFlash();
    return sizeof (ReserveSELRes_T);
}


/*---------------------------------------
 * GetSELEntry
 *---------------------------------------*/
int
GetSELEntry ( uint8_t* pReq, uint8_t ReqLen,  uint8_t* pRes)      
{
	SELRec_T*    pSelRec;
	SELRec_T*    pNextSelRec;
	GetSELReq_T* pGetSelReq = ( GetSELReq_T*) pReq;
	GetSELRes_T* pGetSelRes = ( GetSELRes_T*) pRes;
	uint16_t         	LastRecID = 0,FirstRecID = 0;
	SELRepository_T* 	m_sel = NULL;
	uint16_t NumRecords = 0;

   
	m_sel = ( SELRepository_T*) g_BMCInfo.pSEL;
	NumRecords = m_sel->NumRecords;
  
    pGetSelRes->CompletionCode = CC_NORMAL;
//    if (pGetSelReq->ReservationID && g_BMCInfo.SELConfig.RsrvIDCancelled)
//    {
//        pGetSelRes->CompletionCode = CC_INV_RESERVATION_ID;
//        return sizeof (uint8_t);
//    }

    /* Check if the reservation IDs match */
    if ((g_BMCInfo.IpmiConfig.SELConfig.SelReservationID != pGetSelReq->ReservationID) &&
        ((0 != pGetSelReq->Offset) || (pGetSelReq->ReservationID != 0)) )
    {
        
        pGetSelRes->CompletionCode = CC_INV_RESERVATION_ID;
        return sizeof (uint8_t);
    }

    if (0 == m_sel->NumRecords)
    { 
        pGetSelRes->CompletionCode = CC_SEL_REC_NOT_PRESENT;
        return sizeof (uint8_t);
    }
   

    FirstRecID = m_sel->FirstRecID;
    LastRecID = m_sel->LastRecID;
    //printf("---> FirstRecID %d, LastRecID %d\n", FirstRecID, LastRecID);

    /* If ID == 0x0000  return first record */
    if (0 == pGetSelReq->RecID)
    {
        pSelRec = GetSELRec(FirstRecID);
        if (0 == pSelRec) 
        {
            printf("Warning: Not find SEL Record\n");
            pGetSelRes->CompletionCode = CC_SEL_REC_NOT_PRESENT;
            return sizeof(uint8_t);
        }
        else 
        { 
            pNextSelRec = GetNextSELEntry (pSelRec); 
        }
		
        if (0 == pNextSelRec) 
        { 
            pGetSelRes->NextRecID = 0xFFFF;
        }
        else
        {
            pGetSelRes->NextRecID = pNextSelRec->EvtRecord.hdr.ID;
        }
		
		pGetSelReq->RecID = FirstRecID;
    }
    else if (0xFFFF == pGetSelReq->RecID)
    {
        pSelRec = GetSELRec(LastRecID);
        if(0== pSelRec)
        {
            pGetSelRes->CompletionCode = CC_SEL_REC_NOT_PRESENT;
            return sizeof(uint8_t);
        }
        pGetSelRes->NextRecID = 0xFFFF;
    }

	pSelRec = GetSELRec(pGetSelReq->RecID);
	if (pSelRec == 0)
	{
		pGetSelRes->CompletionCode = CC_SEL_REC_NOT_PRESENT;
		return sizeof (uint8_t);
	}

	if(LastRecID == pGetSelReq->RecID)
	{
		pGetSelRes->NextRecID = 0xFFFF;
	}
	else
	{
		pNextSelRec = GetNextSELEntry (pSelRec);
		if (0 == pNextSelRec) 
		{
			/*If the given SEL ID is the maximum SEL record ,then the next SEL ID will be the First SEL ID 
				in case of Circular SEL Implementation */
			if(g_BMCInfo.IpmiConfig.SELConfig.MaxSELRecord == NumRecords)
			{
				pGetSelRes->NextRecID = 0;
			}
			else
			{
				pGetSelRes->NextRecID = 0xFFFF;
			}
		}
		else 
		{
			pGetSelRes->NextRecID = pNextSelRec->EvtRecord.hdr.ID;
		}
	}

    if ((0xff == pGetSelReq->Size) && (sizeof (SELEventRecord_T) >= pGetSelReq->Offset)) 
    { 
        pGetSelReq->Size = sizeof (SELEventRecord_T) - pGetSelReq->Offset;        
    }
    // Check for the request bytes and offset not to exceed the actual size of the record
    else if ((pGetSelReq->Size > (sizeof(SELEventRecord_T))) ||
             (pGetSelReq->Offset > (sizeof(SELEventRecord_T))) ||
             (pGetSelReq->Size > ((sizeof(SELEventRecord_T))- pGetSelReq->Offset)))
    {
        pGetSelRes->CompletionCode = CC_PARAM_OUT_OF_RANGE;
        return sizeof (uint8_t);
    }
    
	memcpy(pGetSelRes + 1, (( uint8_t*)&pSelRec->EvtRecord) +
             pGetSelReq->Offset, pGetSelReq->Size);

    return sizeof(GetSELRes_T) + pGetSelReq->Size;
}

/*---------------------------------------
 * LockedAddSELEntry with SEL locked 
 *---------------------------------------*/
int
LockedAddSELEntry ( uint8_t* pReq, uint8_t ReqLen,  uint8_t* pRes)
{
	AddSELRes_T*     pAddSelRes = ( AddSELRes_T*) pRes;
	SELRecHdr_T*     pSelRec    = ( SELRecHdr_T*) pReq;
	uint16_t         	index = 0;
	uint16_t 			NumRecords=0;

//	m_sel = ( SELRepository_T*)g_BMCInfo.pSEL;
	NumRecords = (( SELRepository_T*)g_BMCInfo.pSEL)->NumRecords;

    /* If we dont have enough space return invalid ID */
    if (NumRecords >= g_BMCInfo.IpmiConfig.SELConfig.MaxSELRecord)
    {
		if (((( SELRepository_T*)g_BMCInfo.pSEL)->SELIndex == g_BMCInfo.IpmiConfig.SELConfig.MaxSELRecord))
		{
			(( SELRepository_T*)g_BMCInfo.pSEL)->SELIndex = 0;
		}
		/*Reset the SEL OverFlow Flag in Circular SEL mode*/
		g_BMCInfo.IpmiConfig.SELConfig.SELOverFlow = FALSE;
    }

	if((( SELRepository_T*)g_BMCInfo.pSEL)->LastRecID == 0xFFFE)
	{
		(( SELRepository_T*)g_BMCInfo.pSEL)->LastRecID = 0;
	}

	if( (( SELRepository_T*)g_BMCInfo.pSEL)->FirstRecID == 0xFFFE)
	{
		(( SELRepository_T*)g_BMCInfo.pSEL)->FirstRecID = 0;
	}

	if(NumRecords == g_BMCInfo.IpmiConfig.SELConfig.MaxSELRecord)
	{
		(( SELRepository_T*)g_BMCInfo.pSEL)->FirstRecID +=1;
	}

	/* time stamp for record type less than 0xE0*/
	if (pSelRec->Type < 0xE0)
	{
		// The timestamp gets set if the hook is not present or if the hook returns -1 
		pSelRec->TimeStamp = GetSelTimeStamp ();
	}

	pSelRec->ID = ((( SELRepository_T*)g_BMCInfo.pSEL)->LastRecID) + 1;
	index = (( SELRepository_T*)g_BMCInfo.pSEL)->SELIndex ;

	memcpy (&(( SELRepository_T*)g_BMCInfo.pSEL)->SELRecord [index].EvtRecord , pSelRec, 
				  sizeof (SELEventRecord_T));

	(( SELRepository_T*)g_BMCInfo.pSEL)->SELRecord [index].Valid  = VALID_RECORD;
	(( SELRepository_T*)g_BMCInfo.pSEL)->SELRecord [index].Len  = sizeof (SELEventRecord_T) + 2;


	if (( NumRecords < g_BMCInfo.IpmiConfig.SELConfig.MaxSELRecord))
	{
		NumRecords = ++(( SELRepository_T*)g_BMCInfo.pSEL)->NumRecords;
	}

	/*Update the First SEL entry after clear SEL command*/
	if( (( SELRepository_T*)g_BMCInfo.pSEL)->FirstRecID == 0)
	{
		(( SELRepository_T*)g_BMCInfo.pSEL)->FirstRecID = pSelRec->ID;
	}

	(( SELRepository_T*)g_BMCInfo.pSEL)->LastRecID += 1;
	(( SELRepository_T*)g_BMCInfo.pSEL)->SELIndex += 1;

	g_BMCInfo.IpmiConfig.SELConfig.LastEvtTS = (( SELRepository_T*)g_BMCInfo.pSEL)->AddTimeStamp = GetSelTimeStamp ();

	pAddSelRes->CompletionCode = CC_NORMAL;
	pAddSelRes->RecID          = pSelRec->ID;

    FlushSELToFlash();
    FlushIPMIToFlash();

	return sizeof (AddSELRes_T);
}

/*---------------------------------------
 * AddSELEntry
 *---------------------------------------*/
int
AddSELEntry ( uint8_t* pReq, uint8_t ReqLen,  uint8_t* pRes)
{
    int reslen = 0;

    reslen = LockedAddSELEntry(pReq, ReqLen, pRes);
   
	FlushSELToFlash();
	return reslen;
}

/*---------------------------------------
 * PartialAddSELEntry
 *---------------------------------------*/
int
PartialAddSELEntry ( uint8_t* pReq, uint8_t ReqLen,  uint8_t* pRes)
{
	PartialAddSELReq_T*  pParAddSelReq = ( PartialAddSELReq_T*) pReq;
	PartialAddSELRes_T*  pParAddSelRes = ( PartialAddSELRes_T*) pRes;
	uint16_t    RecordID=0, ReservationID=0;
	uint8_t     RecordOffset=0,Len=0;
	SELRepository_T* m_sel = ( SELRepository_T*)g_BMCInfo.pSEL; 


    ReservationID = (uint16_t)(pParAddSelReq->LSBReservationID | 
                                            ((uint16_t)pParAddSelReq->MSBReservationID << 8));

    RecordID = (uint16_t)(((uint16_t)pParAddSelReq->MSBRecordID << 8) |
                                    pParAddSelReq->LSBRecordID);


    RecordOffset = (uint32_t)pParAddSelReq->Offset;
    Len = ReqLen;

//   /*  Checks for the Valid Reservation ID */
//    while(g_BMCInfo.SELConfig.RsrvIDCancelled)
//    {
//        if((ReservationID == 0) && (pParAddSelReq->Progress == 1) && (ReqLen == SEL_PARTIAL_ADD_CMD_MAX_LEN))
//            break;
//        else
//        {
//            if(ReqLen < SEL_PARTIAL_ADD_REQUEST_MISC_BYTES)
//            {
//                pParAddSelRes->CompletionCode = CC_REQ_INV_LEN;
//                return(sizeof(PartialAddSELRes_T));	
//            }
//            else
//            {
//                pParAddSelRes->CompletionCode = CC_INV_RESERVATION_ID;
//                pParAddSelRes->RecID          = 0;
//                return(sizeof(PartialAddSELRes_T));
//            }
//        }
//    }

    /* Check for the reserved bytes should b zero */
    if  ( 0 !=  (pParAddSelReq->Progress & RESERVED_BITS_PARTIALADDSELENTRY ) )
    {
        pParAddSelRes->CompletionCode = CC_INV_DATA_FIELD;
        return sizeof(uint8_t);
    }

    if((pParAddSelReq->Progress>1)|| (pParAddSelReq->Offset>SEL_RECORD_SIZE))
    {
        pParAddSelRes->CompletionCode = CC_PARAM_OUT_OF_RANGE;
        return(sizeof(PartialAddSELRes_T));
    }
    else if(g_BMCInfo.IpmiConfig.SELConfig.PartialAdd==0)
    {
        if(((RecordOffset+(Len-SEL_PARTIAL_ADD_REQUEST_MISC_BYTES)==SEL_RECORD_SIZE)&&(pParAddSelReq->Progress!=1))||
        (( RecordOffset+(Len-SEL_PARTIAL_ADD_REQUEST_MISC_BYTES)<SEL_RECORD_SIZE)&&(pParAddSelReq->Progress==1))||
        (RecordOffset+(Len-SEL_PARTIAL_ADD_REQUEST_MISC_BYTES)>SEL_RECORD_SIZE))

        {
            pParAddSelRes->CompletionCode = CC_REQ_INV_LEN;
            return(sizeof(PartialAddSELRes_T));
        }
    }
    else if((ReservationID==0)&&(Len==SEL_PARTIAL_ADD_CMD_MAX_LEN)&&(pParAddSelReq->Progress!=1))
    {
        pParAddSelRes->CompletionCode =CC_INV_DATA_FIELD;
        return(sizeof(PartialAddSELRes_T));
    }

    /*Checking for reservation ID <<Added few more condition checking */
    if(((ReservationID == g_BMCInfo.IpmiConfig.SELConfig.SelReservationID)&&(g_BMCInfo.IpmiConfig.SELConfig.PartialAdd==0)) ||  
    ((ReservationID == g_BMCInfo.IpmiConfig.SELConfig.SelReservationID) && (ReqLen <= SEL_PARTIAL_ADD_CMD_MAX_LEN))
    ||((ReservationID == 0) && (pParAddSelReq->Progress == 1) && (ReqLen == SEL_PARTIAL_ADD_CMD_MAX_LEN)))  
    {
        if(g_BMCInfo.IpmiConfig.SELConfig.PartialAdd==0)
        {
            // Requirement says partial adds must start at 0, with no
            // gaps or overlaps. First request must be to RecordID = 0.
            if ((RecordID != 0) || (RecordOffset != 0))
            {
                pParAddSelRes->CompletionCode = CC_INV_DATA_FIELD;
                return(sizeof(PartialAddSELRes_T));// Modified from sizeof (uint8_t);
            }

            memset((void *)&g_BMCInfo.IpmiConfig.SELConfig.SelPartialAddRecord, 0xFF, sizeof(SELEventRecord_T));

            // Fill in the record ID into the partial add record. The
            // record ID is always the offset in memory of where the
            // SEL record starts (which includes a delete time first).
            RecordID = g_BMCInfo.IpmiConfig.SELConfig.SelPartialAddRecord.hdr.ID = m_sel->LastRecID +1;

            g_BMCInfo.IpmiConfig.SELConfig.PartialAddRecordID=RecordID;
            g_BMCInfo.IpmiConfig.SELConfig.PartialAddRecOffset = 0;
            g_BMCInfo.IpmiConfig.SELConfig.PartialAdd=1;
        }
        else
        {
            if (RecordID != g_BMCInfo.IpmiConfig.SELConfig.PartialAddRecordID)
            {
                pParAddSelRes->CompletionCode = CC_INV_DATA_FIELD;
                return sizeof (PartialAddSELRes_T); 
            }
        }

        if (pParAddSelReq->Offset != g_BMCInfo.IpmiConfig.SELConfig.PartialAddRecOffset)
        {
            pParAddSelRes->CompletionCode = CC_INV_DATA_FIELD;
            return(sizeof(PartialAddSELRes_T));
        }

        // Checking for Exceeding data values //
        if((g_BMCInfo.IpmiConfig.SELConfig.PartialAddRecOffset + Len - SEL_PARTIAL_ADD_REQUEST_MISC_BYTES) > SEL_MAX_RECORD_SIZE)
            {
            pParAddSelRes->CompletionCode = CC_REQ_INV_LEN;
            return(sizeof(PartialAddSELRes_T));
        }

        if((( g_BMCInfo.IpmiConfig.SELConfig.PartialAddRecOffset + Len - SEL_PARTIAL_ADD_REQUEST_MISC_BYTES) < SEL_MAX_RECORD_SIZE) && 
        (pParAddSelReq->Progress == 1))	
        {
            pParAddSelRes->CompletionCode = CC_REQ_INV_LEN;
            return(sizeof(PartialAddSELRes_T));
        }

        if(((g_BMCInfo.IpmiConfig.SELConfig.PartialAddRecOffset + Len - SEL_PARTIAL_ADD_REQUEST_MISC_BYTES) == SEL_MAX_RECORD_SIZE) &&
            (pParAddSelReq->Progress != 1))
        {
            pParAddSelRes->CompletionCode = CC_REQ_INV_LEN;
            return(sizeof(PartialAddSELRes_T));
        }


        memcpy((void *)((uint8_t *)&g_BMCInfo.IpmiConfig.SELConfig.SelPartialAddRecord + RecordOffset),
			(void *)pParAddSelReq->RecordData, 
			((uint8_t)(Len - SEL_PARTIAL_ADD_REQUEST_MISC_BYTES)));
        g_BMCInfo.IpmiConfig.SELConfig.PartialAddRecordID=RecordID;
        pParAddSelRes->RecID = RecordID;
        g_BMCInfo.IpmiConfig.SELConfig.PartialAddRecOffset +=	(Len - SEL_PARTIAL_ADD_REQUEST_MISC_BYTES);
        g_BMCInfo.IpmiConfig.SELConfig.PartialAdd=1;
        pParAddSelRes->CompletionCode = CC_NORMAL;
        //if the progress bit is 1 indicates that this is the last data of the record so put the entire record in sel repository

        if(pParAddSelReq->Progress==1)
        {
            // Checking for complete filling of gap
            if((pParAddSelReq->Offset + Len) == SEL_PARTIAL_ADD_CMD_MAX_LEN)
            {
                g_BMCInfo.IpmiConfig.SELConfig.PartialAdd=0;
                LockedAddSELEntry ( (uint8_t*)&g_BMCInfo.IpmiConfig.SELConfig.SelPartialAddRecord, sizeof(SELEventRecord_T),  pRes);
            }
            else
            {
                pParAddSelRes->CompletionCode = CC_REQ_INV_LEN;
                return(sizeof(PartialAddSELRes_T));
            }
        }
    }
    else
    {
        if(ReservationID != g_BMCInfo.IpmiConfig.SELConfig.SelReservationID)
        {
            pParAddSelRes->CompletionCode = CC_INV_RESERVATION_ID;
            return(sizeof(PartialAddSELRes_T));
        }
        else
        {
            pParAddSelRes->CompletionCode = CC_INV_DATA_FIELD;
            return(sizeof(PartialAddSELRes_T));
        }
    }

	FlushSELToFlash();
    FlushIPMIToFlash();
    return sizeof (PartialAddSELRes_T);
}


/*---------------------------------------
 * DeleteSELEntry
 *---------------------------------------*/
int
DeleteSELEntry ( uint8_t* pReq, uint8_t ReqLen,  uint8_t* pRes)
{
	DeleteSELReq_T*  pDelSelReq = ( DeleteSELReq_T*) pReq;
	DeleteSELRes_T*  pDelSelRes = ( DeleteSELRes_T*) pRes;
	uint16_t LastRecID = 0,FirstRecID = 0;
	SELRepository_T* 	m_sel = NULL;
	SELRec_T *pRec = NULL, *pNextRec = NULL;
	

	m_sel = ( SELRepository_T*) g_BMCInfo.pSEL;

    /* Check if the reservation IDs match */
    if (((g_BMCInfo.IpmiConfig.SELConfig.SelReservationID != pDelSelReq->ReservationID) &&
       (pDelSelReq->ReservationID != 0)) || (pDelSelReq->ReservationID == 0))
    {
        pDelSelRes->CompletionCode = CC_INV_RESERVATION_ID;
        return sizeof (uint8_t);
    }


    LastRecID = m_sel->LastRecID;
    FirstRecID = m_sel->FirstRecID;

    if ( pDelSelReq->RecID == 0x0000 )
    {
        pDelSelReq->RecID = FirstRecID ;
    }
    else if ( pDelSelReq->RecID == 0xFFFF )
    {
        pDelSelReq->RecID = LastRecID;
    }

    pRec= GetSELRec(pDelSelReq->RecID);
    if ( pRec == 0 ||(pRec->Valid != VALID_RECORD) )
    {
        pDelSelRes->CompletionCode = CC_SDR_REC_NOT_PRESENT;
        return sizeof (uint8_t);
    }

	//Update first record id after delete first sel entity.
	if(pDelSelReq->RecID == m_sel->FirstRecID)
	{
		pNextRec = GetNextSELEntry(pRec);
		if(pNextRec != NULL)
		{
			m_sel->FirstRecID = pNextRec->EvtRecord.hdr.ID;
		}
		else	//No sel
		{
			m_sel->FirstRecID = 0;
		}
	}
	pRec->Valid = STATUS_DELETE_SEL;
	m_sel->NumRecords--;
	/*Update the Last Deleted SEL time*/
	m_sel->EraseTimeStamp = GetSelTimeStamp ();

//    /*Update the First and last Record ID if the requested RecID is either First or Last*/
//	FindRecOrder();
	
    pDelSelRes->CompletionCode  = CC_NORMAL;
    pDelSelRes->RecID           = pDelSelReq->RecID;

	FlushSELToFlash();
    FlushIPMIToFlash();
    return sizeof (DeleteSELRes_T);
}


/*---------------------------------------
 * ClearSEL
 *---------------------------------------*/
int
ClearSEL ( uint8_t* pReq, uint8_t ReqLen,  uint8_t* pRes)     
{
	ClearSELReq_T* pClrSelReq = ( ClearSELReq_T*) pReq;
	ClearSELRes_T* pClrSelRes = ( ClearSELRes_T*) pRes;
	SELRepository_T* 	m_sel = NULL;

	m_sel = ( SELRepository_T*) g_BMCInfo.pSEL;
    
    if (memcmp(pClrSelReq->CLR, "CLR", CLR_SEL_PASSWORD_STR_LEN))
    {
        pClrSelRes->CompletionCode = CC_INV_DATA_FIELD;
        return sizeof (uint8_t);
    }
    
    if (pClrSelReq->InitOrStatus == CLEAR_SEL_GET_STATUS)
    {
        pClrSelRes->CompletionCode = CC_NORMAL;
        pClrSelRes->EraseProgress  = SEL_ERASE_COMPLETED;
        return sizeof (ClearSELRes_T);
    }


    if (pClrSelReq->InitOrStatus != CLEAR_SEL_ACTION)
    {
        pClrSelRes->CompletionCode = CC_INV_DATA_FIELD;
        return sizeof (uint8_t);
    }

	/* Clear the fields of the SEL */
	m_sel->LastRecID        = 0;
	m_sel->FirstRecID       = 0;
	m_sel->SELIndex         = 0;
	m_sel->NumRecords   = 0;
	memset (&m_sel->SELRecord [0], 0xFF, g_BMCInfo.IpmiConfig.SELConfig.MaxSELRecord * sizeof (SELRec_T));
	
	/*Update the Last Deleted SEL time*/
	g_BMCInfo.IpmiConfig.SELConfig.LastEvtTS  = m_sel->EraseTimeStamp = GetSelTimeStamp (); 

    pClrSelRes->CompletionCode = CC_NORMAL;
    pClrSelRes->EraseProgress  = SEL_ERASE_COMPLETED;
    g_BMCInfo.IpmiConfig.SELConfig.SELOverFlow = FALSE;
    g_BMCInfo.IpmiConfig.SELConfig.selalmostfull = 0;

	FlushSELToFlash();
    FlushIPMIToFlash();
    return sizeof (ClearSELRes_T);
}

/*---------------------------------------
 * GetSELTime
 *---------------------------------------*/
int
GetSELTime ( uint8_t* pReq, uint8_t ReqLen,  uint8_t* pRes)
{
    GetSELTimeRes_T* pGetSelTimeRes = ( GetSELTimeRes_T*) pRes;

    pGetSelTimeRes->CompletionCode = CC_NORMAL;
    pGetSelTimeRes->Time           = (GET_SYSTEM_TIME_STAMP ());
    
    return sizeof (GetSELTimeRes_T);
}


/**
 * @fn setUTC_Offset
 * @brief Set the UTC offset in the linux kernel.
 * @param[in] UTCOffset - Offset value in minutes.
 * @retval 0, on success.
 *         1, on failure.
 */
static int setUTC_Offset (int16_t UTCOffset)
{
    int mins = 0, hrs = 0;
    
    if ((SEL_UTC_MIN_RANGE > UTCOffset) || (SEL_UTC_MAX_RANGE < UTCOffset) || (0 != (UTCOffset % 15)))
    {
        return 1;
    }
    
    hrs = UTCOffset / 60;
    mins = UTCOffset % 60;
    
    printf ("hrs : %d, mins : %d\n", hrs, mins);

	g_BMCInfo.IpmiConfig.SELTimeUTCOffset = UTCOffset;
    FlushIPMIToFlash();
    return 0;
}

/*---------------------------------------
 * SetSELTime
 *---------------------------------------*/
int
SetSELTime ( uint8_t* pReq, uint8_t ReqLen,  uint8_t* pRes)
{
    uint32_t localTime = 0;
    SetSELTimeReq_T* pSetSelTimeReq = ( SetSELTimeReq_T*) pReq;
   
    localTime = (pSetSelTimeReq->Time);

    SELTimeClockSync(PRE_CLK_SET);

    SET_SYSTEM_TIME_STAMP (&localTime);

    SELTimeClockSync(POST_CLK_SET);

    pRes [0] = CC_NORMAL;
    
	return sizeof (*pRes);
}


/*---------------------------------------
 * GetSELTimeUTC_Offset
 *---------------------------------------*/
int
GetSELTimeUTC_Offset ( uint8_t* pReq, uint8_t ReqLen,  uint8_t* pRes)
{
    GetSELTimeUTCOffsetRes_T* pGetSelTimeUTCOffsetRes = ( GetSELTimeUTCOffsetRes_T*) pRes;
    pGetSelTimeUTCOffsetRes->CompletionCode = CC_NORMAL;
    pGetSelTimeUTCOffsetRes->UTCOffset = (g_BMCInfo.IpmiConfig.SELTimeUTCOffset);

    return sizeof (GetSELTimeUTCOffsetRes_T);
}



/*---------------------------------------
 * SetSELTimeUTC_Offset
 *---------------------------------------*/
int
SetSELTimeUTC_Offset ( uint8_t* pReq, uint8_t ReqLen,  uint8_t* pRes)
{
	SetSELTimeUTCOffsetReq_T* pSetSELTimeUTCOffsetReq = ( SetSELTimeUTCOffsetReq_T*) pReq;
	SetSELTimeUTCOffsetRes_T* pSetSELTimeUTCOffsetRes = ( SetSELTimeUTCOffsetRes_T*) pRes;
	int16_t UTCOffset;

    UTCOffset = (int16_t) (pSetSELTimeUTCOffsetReq->UTCOffset);

    if (((UTCOffset <= SEL_UTC_MAX_RANGE) && (UTCOffset >= SEL_UTC_MIN_RANGE)) || (UTCOffset == UNSPECIFIED_UTC_OFFSET))
    {
        if (0 != setUTC_Offset ((UTCOffset == UNSPECIFIED_UTC_OFFSET) ? 0 : UTCOffset))
        {
            pSetSELTimeUTCOffsetRes->CompletionCode = CC_INV_DATA_FIELD;
            return sizeof (*pRes);
        }
        
        pSetSELTimeUTCOffsetRes->CompletionCode = CC_NORMAL;
    }
    else
    {
        pSetSELTimeUTCOffsetRes->CompletionCode = CC_PARAM_OUT_OF_RANGE;
    }
    
    return sizeof (*pRes);
}


/*---------------------------------------
 * GetAuxiliaryLogStatus
 *---------------------------------------*/
int
GetAuxiliaryLogStatus( uint8_t* pReq, uint8_t ReqLen,  uint8_t* pRes)
{
    return 0;
}


/*---------------------------------------
 * SetAuxiliaryLogStatus
 *---------------------------------------*/
int
SetAuxiliaryLogStatus( uint8_t* pReq, uint8_t ReqLen,  uint8_t* pRes)
{
    return 0;
}


/*---------------------------------------
 * GetNextSELEntry
 *---------------------------------------*/
static  SELRec_T*
GetNextSELEntry ( SELRec_T* rec)
{ 
	SELRec_T* pRec = rec;
	SELRec_T* pLastRec = (((SELRepository_T*)g_BMCInfo.pSEL)->SELRecord + g_BMCInfo.IpmiConfig.SELConfig.MaxSELRecord - 1);
	pRec++;
	while (1)
	{
		if(pRec > pLastRec)
		{
			pRec = ((SELRepository_T*)g_BMCInfo.pSEL)->SELRecord;
		}
		
		if(pRec == rec)
		{
			break;
		}
		
		if (pRec->Valid == VALID_RECORD)
		{
			return pRec;
		}
		else if (pRec->Valid == STATUS_DELETE_SEL)
		{
			pRec++;
		}
		else
		{
			break;
		}
		
	}

     return 0;
}

/*
 @ fn GetSELRec
 @ brief This function is used to get the SEL Record based Record ID
 @ params RecID[in] Record ID BMCInst[in]
 @ returns SELRecord pointer on success and 0 on failures
 */
static  SELRec_T* GetSELRec(uint16_t RecID)
{
	int i=0;
    //int j;
	SELRepository_T*  m_sel;

	m_sel = ( SELRepository_T*) g_BMCInfo.pSEL;

	for(i=0;i<g_BMCInfo.IpmiConfig.SELConfig.MaxSELRecord;i++)
	{
        // printf("i = %d: ", i);
        // for(j=0;j<18;j++)
        //     printf("%#x ", ((uint8_t*)(&m_sel->SELRecord[i]))[j]);
        // printf("\n");
		if((m_sel->SELRecord[i].EvtRecord.hdr.ID == RecID) && (m_sel->SELRecord[i].Valid== VALID_RECORD))
		{
			return &m_sel->SELRecord[i];
		}
	}
	
	return 0;
}

/*---------------------------------------
 * GetSelTimeStamp
 *---------------------------------------*/
uint32_t GetSelTimeStamp()
{
    return (GET_SYSTEM_TIME_STAMP());
}

#endif  /* SEL_DEVICE */

/*---------------------------------------------------------------------------
 * @fn SELTimeClockSync
 *
 * @brief This function is invoked when set SEL time, generate a pair of
 *        events(pre and post clock setting) correlating the timestamps
 *        for events occurring before and after the new clock value.
 *
 * @param   Action  - Specify pre-event or post-event.
 * @param   BMCInst - Index of BMC instance.
 *
 * @return  0	- if success.
 *			-1	- if error.
 *---------------------------------------------------------------------------*/
static uint8_t SELTimeClockSync(uint8_t Action)
{
    SELEventRecord_T *EventRec = (SELEventRecord_T*)m_SysEventMsg;
    uint8_t pRes[sizeof(AddSELRes_T)];

    EventRec->SensorNum  = 0xFF;
    EventRec->EvtDirType = 0x6F;    // Sensor Specific
    EventRec->EvtData1   = 0x05;    // Offset 05h - Timestamp Clock Sync
    EventRec->EvtData2   = Action;
    EventRec->EvtData3   = 0xFF;

    LockedAddSELEntry((uint8_t*)EventRec, sizeof(SELEventRecord_T), pRes);
    
    return 0;
}


///*---------------------------------------------------------------------------
// * @fn SetSELPolicy
// *
// * @brief This function is invoked when switch SEL policy, make appropriate
// *        adjustment for environment variables that related to SEL buffer.
// *
// * @param   Policy  - Specify Linear SEL policy or Circular SEL policy.
// * @param   BMCInst - Index of BMC instance.
// *---------------------------------------------------------------------------*/
//void
//SetSELPolicy(uint8_t Policy)
//{
////    SELRepository_T* m_sel = NULL;

//	m_sel = (SELRepository_T*)g_BMCInfo.pSEL;

//    switch (Policy)
//    {
//        case LINEAR_SEL:
//            /* Reset LastRecID because GetNextSELEntry func will stop finding the next record if RecID >= LastRecRD,
//               but RecID may greater than LastRecID in Circular SEL mode. */
///*            LOCK_BMC_SHARED_MEM(BMCInst);
//            BMC_GET_SHARED_MEM (BMCInst)->m_LastRecID = m_sel->SELRecord[pBMCInfo->SELConfig.MaxSELRecord].EvtRecord.hdr.ID;
//            BMC_GET_SHARED_MEM (BMCInst)->m_SELIndex = m_sel->NumRecords;
//            BMC_GET_SHARED_MEM (BMCInst)->m_FirstRecID = m_sel->SELRecord[0].EvtRecord.hdr.ID;
//            UNLOCK_BMC_SHARED_MEM(BMCInst);*/
//            break;

//        case CIRCULAR_SEL:
//            /*Update the Last and First Record ID when switch back to Circular-linear-Circular cycle */
////            if(m_sel->NumRecords == g_BMCInfo.SELConfig.MaxSELRecord)
////            {
////                FindRecOrder();
////            }
//            break;
//    }
//}


