/*****************************************************************
 *****************************************************************
 ***                                                            **
 ***    (C)Copyright 2005-2006, American Megatrends Inc.        **
 ***                                                            **
 ***            All Rights Reserved.                            **
 ***                                                            **
 ***        6145-F, Northbelt Parkway, Norcross,                **
 ***                                                            **
 ***        Georgia - 30071, USA. Phone-(770)-246-8600.         **
 ***                                                            **
 *****************************************************************
 *****************************************************************
 ******************************************************************
 *
 * ChassisDevice.c
 * Chassis commands
 *
 *  Author: Rama Bisa <ramab@ami.com>
 *
 ******************************************************************/
#define ENABLE_DEBUG_MACROS 0
#include "Types.h"
#include "ChassisDevice.h"
#include "Debug.h"
#include "Support.h"
#include "IPMI_ChassisDevice.h"
#include "IPMIDefs.h"
#include "MsgHndlr.h"
#include "Util.h"
#include "Platform.h"
#include "NVRAccess.h"
#include "SharedMem.h"
#include "ChassisCtrl.h"
#include "PDKAccess.h"
#include "IPMIConf.h"
#include "featuredef.h"

/* Reserved bit macro definitions */
#define RESERVED_BITS_CHASSISCONTROL                    0xF0 //(BIT7 | BIT6 | BIT5 |BIT4)
#define RESERVED_BITS_GETCHASSISIDENTIFY                0xFE //(BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0)
#define RESERVED_BITS_SETCHASSISCAPS                    0xFC //(BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2)
#define RESERVED_BITS_SETPOWERRESTOREPOLICY             0xFC //(BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2)
#define RESERVED_BITS_SETFPBUTTONENABLES                0xF0 //(BIT7 | BIT6 | BIT5 | BIT4)

#if CHASSIS_DEVICE == 1

/*** Local Definitions ***/
#define PRP_ALWAYS_POWEROFF_SUPPORT             0x01
#define PRP_LAST_STATE_SUPPORT                  0x02
#define PRP_ALWAYS_POWERON_SUPPORT              0x04


#define CHASSIS_AMI_OEM_PARAM                   96
#define CHASSIS_SET_INPROG                      0x00
#define CHASSIS_SERVICE_PART_SEL                0x01
#define CHASSIS_SERVICE_PART_SCAN               0x02
#define CHASSIS_BOOT_FLAG_VALID_BIT_CLEAR       0x03
#define CHASSIS_BOOT_INFO_ACK                   0x04
#define CHASSIS_BOOT_FLAGS                      0x05
#define CHASSIS_BOOT_INITIATOR_INFO             0x06
#define CHASSIS_BOOT_INITIATOR_MBOX             0x07
#define CHASSIS_AMI_OEM_PARAM                   96
#define SSICB_OEM_PARAM_BLK_SIZE_TBL            0x78
#define SSICB_BOOT_ORDER_TBL                    0x7D
#define SSICB_BOOT_DEV_SELECTOR                 0x7E
#define SSICB_SLOT_CONFIG_TBL                   0x7F

#define ROLLBACK_OPTION                         0x00

/* Mask Bits */
#define BIT5_BIT2_MASK				0x3C
#define BIT6_BIT5_MASK				0x60
#define BIT1_BIT0_MASK				0x03
       
/* Reserved Bits */
#define RESERVED_VALUE_03			0x03
#define RESERVED_VALUE_10			0x10
#define RESERVED_VALUE_20			0x20
#define RESERVED_VALUE_28			0x28
#define RESERVED_VALUE_30			0x30
#define RESERVED_VALUE_34			0x34
#define RESERVED_VALUE_38			0x38
#define RESERVED_VALUE_40			0x40
#define RESERVED_VALUE_60			0x60
#define RESERVED_VALUE_80			0x80

/*** Module Varibales ***/
static const INT8U            m_BootOptParamLen [] = /**< Boot Options parameter length */
{   
    0x01,                           /**< Set in progress byte length */
    0x01,                           /**< Service Partition selector length */
    0x01,                           /**< Service Partition scan length */
    0x01,                           /**< Boot flag valid bit length */
    sizeof(BootInfoAck_T),          /**< Boot info ack length */
    sizeof(BootFlags_T),            /**< Boot Flags valid length */ 
    sizeof(BootInitiatorInfo_T),    /**< Boot init info length */   
    sizeof(BootInitiatorMboxReq_T), /**< Boot init info length */   
};

static const INT8U            m_SSIBootOptParamLen [] = /**< SSI Boot Options parameter length */
{
    sizeof(OemParamBlkSizeTbl_T), /* OEM Parameter Block Size Table length */
    0x0,                          /* Reserved */
    0x0,                          /* Reserved */
    0x0,                          /* Reserved */
    0x0,                          /* Reserved */
    sizeof(BootOrderTblReq_T),    /* Boot Order Table length */
    sizeof(INT8U),                /* SSI Boot Device Selector length*/
    sizeof(SlotConfigTbl_T)       /* Slot Configuration Table length */
};

#define MAX_BOOT_PARAMS_DATA  20
typedef struct
{
    INT8U	Params;
    INT8U	ReservedBits [MAX_BOOT_PARAMS_DATA];
    INT8U	DataLen;

} BootCfgRsvdBits_T;

static BootCfgRsvdBits_T m_RsvdBitsCheck [] = {

        /* Param        Reserved Bits      Data Size   */
        { 0,	     		{ 0xFC }, 				    				 0x1 },	/* Set In progress  */
        { 2,				{ 0xFC }, 					 				 0x1 },
        { 3,				{ 0xE0 },									 0x1 },
        { 5,				{ 0x1F,0x00,0x00,0xF0,0xE0},			  	 0x5 },
        { 6,				{ 0xF0 },					 				 0x1 }
};

/*-------------------------------------
 * GetChassisCaps
 *-------------------------------------*/
int
GetChassisCaps (_NEAR_ INT8U* pReq, INT8U ReqLen, _NEAR_ INT8U* pRes,int BMCInst)
{
    _NEAR_  GetChassisCapabilitiesRes_T*    pGetChassisCapsRes = 
        (_NEAR_ GetChassisCapabilitiesRes_T*) pRes;
    BMCInfo_t *pBMCInfo = &g_BMCInfo[BMCInst];
    
    IPMI_DBG_PRINT ("\nGET Chassis CAPABILITIES\n");

    pGetChassisCapsRes->CompletionCode = CC_NORMAL;

    OS_THREAD_MUTEX_ACQUIRE(&pBMCInfo->ChassisMutex, WAIT_INFINITE);
    _fmemcpy ( (_FAR_ INT8U*)&pGetChassisCapsRes->ChassisCapabilities,
               (_FAR_ INT8U*)&pBMCInfo->ChassisConfig.ChassisCapabilities,
                                            sizeof(ChassisCapabilities_T) );
    OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChassisMutex);
    
    return sizeof(GetChassisCapabilitiesRes_T);
}


/*-------------------------------------
 * GetChassisStatus
 *-------------------------------------*/
int
GetChassisStatus (_NEAR_ INT8U* pReq, INT8U ReqLen, _NEAR_ INT8U* pRes,int BMCInst)
{
    INT8U                   PSGood=0;
    _NEAR_  GetChassisStatusRes_T*  pGetChassisStatusRes =
        (_NEAR_ GetChassisStatusRes_T*) pRes;
    BMCInfo_t *pBMCInfo = &g_BMCInfo[BMCInst];

    IPMI_DBG_PRINT ("\nGET Chassis STATUS\n");

    pGetChassisStatusRes->CompletionCode = CC_NORMAL;


    OS_THREAD_MUTEX_ACQUIRE(&pBMCInfo->ChassisMutex, WAIT_INFINITE);
    _fmemcpy ( (_FAR_ INT8U*)&pGetChassisStatusRes->ChassisPowerState,
                    (_FAR_ INT8U*)&pBMCInfo->ChassisConfig.ChassisPowerState,
                                    sizeof(ChassisPowerState_T));
    
    pGetChassisStatusRes->ChassisPowerState.PowerState &= ~0x01;
    if(g_PDKHandle[PDK_GETPSGOOD] != NULL)
    {
        PSGood = ((int(*)(int))g_PDKHandle[PDK_GETPSGOOD]) (BMCInst);
    }
    pGetChassisStatusRes->ChassisPowerState.PowerState |= (TRUE == PSGood) ? 0x01: 0x00;

    /* Get Last Power Event status */
    if(g_PDKHandle[PDK_GETLASTPOWEREVENT] != NULL)
    {
        pGetChassisStatusRes->ChassisPowerState.LastPowerEvent = 
                                   ((INT8U(*)(int))g_PDKHandle[PDK_GETLASTPOWEREVENT]) (BMCInst);
    }

    /*  Get the Misc Chassis Status */
    pGetChassisStatusRes->ChassisPowerState.MiscChassisState = 0x0;


    if((BMC_GET_SHARED_MEM(BMCInst)->HealthState.HardDrive))
        pGetChassisStatusRes->ChassisPowerState.MiscChassisState |= (1 <<2);
    if((BMC_GET_SHARED_MEM(BMCInst)->HealthState.CoolingSys ))
        pGetChassisStatusRes->ChassisPowerState.MiscChassisState |= ( 1<<3);


    pGetChassisStatusRes->ChassisPowerState.MiscChassisState |= CHASSIS_IDENTITY_STATE_INFO_SUPPORTED;
    if(g_BMCInfo[BMCInst].Msghndlr.ChassisIdentifyForce)
    {
        pGetChassisStatusRes->ChassisPowerState.MiscChassisState |= CHASSIS_IDENTITY_INDEFINITE_ON;
    }
    else
    {
        if(0!=g_BMCInfo[BMCInst].Msghndlr.ChassisIdentifyTimeout)
            pGetChassisStatusRes->ChassisPowerState.MiscChassisState |= CHASSIS_IDENTITY_TIMED_ON;
        else
            pGetChassisStatusRes->ChassisPowerState.MiscChassisState |= CHASSIS_IDENTITY_OFF;
    }

    if(g_PDKHandle[PDK_GETMISCCHASSISSTATE] != NULL)
    {
        ((int(*)(unsigned char*, int)) g_PDKHandle[PDK_GETMISCCHASSISSTATE]) (&pGetChassisStatusRes->ChassisPowerState.MiscChassisState, BMCInst);
    }
    OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChassisMutex);
    //return sizeof (GetChassisStatusRes_T);
    return sizeof (GetChassisStatusRes_T) ; 

}


/*-------------------------------------
 * ChassisControl
 *-------------------------------------*/
int
ChassisControl ( _NEAR_ INT8U* pReq, INT8U ReqLen, _NEAR_ INT8U* pRes,int BMCInst )
{
    _NEAR_  ChassisControlReq_T*    pChassisControlReq = 
        (_NEAR_  ChassisControlReq_T*) pReq;
    _NEAR_  ChassisControlRes_T*    pChassisControlRes = 
        (_NEAR_  ChassisControlRes_T*) pRes;
    _FAR_ BMCInfo_t* pBMCInfo = &g_BMCInfo[BMCInst];

    pChassisControlRes->CompletionCode = CC_NORMAL;

    /* Check for the reserved bytes should b zero */

    if  ( 0 !=  (pChassisControlReq->ChassisControl & RESERVED_BITS_CHASSISCONTROL ) )
    {
        pChassisControlRes->CompletionCode = CC_INV_DATA_FIELD;
        return sizeof(INT8U);	
    }

    OS_THREAD_MUTEX_ACQUIRE(&pBMCInfo->ChassisMutex, WAIT_INFINITE);
    switch (pChassisControlReq->ChassisControl & 0x0F  )
    {

        case CHASSIS_POWER_DOWN:
            IPMI_DBG_PRINT ("Chassis IS GOING FOR POWER_DOWN\n");
            pBMCInfo->HostOFFStopWDT = TRUE ;
            pBMCInfo->ChassisConfig.SysRestartCause = RESTART_CAUSE_CHASSIS_CTRL;
            OnSetRestartCause(pBMCInfo->ChassisConfig.SysRestartCause, TRUE,BMCInst);
            pBMCInfo->Msghndlr.ChassisControl= CHASSIS_POWER_DOWN;
            break;

        case CHASSIS_POWER_UP:
            IPMI_DBG_PRINT ("Chassis IS GOING FOR POWER UP\n");
            pBMCInfo->ChassisConfig.SysRestartCause = RESTART_CAUSE_CHASSIS_CTRL;
            OnSetRestartCause(pBMCInfo->ChassisConfig.SysRestartCause, TRUE,BMCInst);
            pBMCInfo->Msghndlr.ChassisControl = CHASSIS_POWER_UP;

            /* Set Last Power Event through IPMI Command */
            if(g_PDKHandle[PDK_SETLASTPOWEREVENT] != NULL)
				{
					((void(*)(INT8U,int))g_PDKHandle[PDK_SETLASTPOWEREVENT]) (PDK_LAST_POWER_ON_VIA_IPMI,BMCInst);
				}
            break;

    case CHASSIS_POWER_CYCLE:
        pBMCInfo->ChassisConfig.SysRestartCause = RESTART_CAUSE_CHASSIS_CTRL;
        OnSetRestartCause(pBMCInfo->ChassisConfig.SysRestartCause, TRUE,BMCInst);
        IPMI_DBG_PRINT ("Chassis IS GOING FOR POWER CYCLE\n");
        pBMCInfo->Msghndlr.ChassisControl = CHASSIS_POWER_CYCLE;

        /* Set Last Power Event through IPMI Command */
        if(g_PDKHandle[PDK_SETLASTPOWEREVENT] != NULL)
			{
				((void(*)(INT8U,int))g_PDKHandle[PDK_SETLASTPOWEREVENT]) (PDK_LAST_POWER_ON_VIA_IPMI,BMCInst);
			}
        break;

    case CHASSIS_HARD_RESET:
        IPMI_DBG_PRINT ("Chassis IS GOING FOR HARD RESET");
        pBMCInfo->ChassisConfig.SysRestartCause = RESTART_CAUSE_CHASSIS_CTRL;
        OnSetRestartCause(pBMCInfo->ChassisConfig.SysRestartCause, TRUE,BMCInst);
        pBMCInfo->Msghndlr.ChassisControl = CHASSIS_HARD_RESET;
        break;

    case CHASSIS_PULSE_DIAGNOSTIC_INTERRUPT:
        IPMI_DBG_PRINT ("Chassis IS GOING FOR DIAG INT\n");
        Platform_HostDiagInt (BMCInst);
        break;

    case CHASSIS_SOFT_SHUTDOWN:
        IPMI_DBG_PRINT ("Chassis IS GOING FOR SOFT SHUTDOWN\n");
        Platform_HostSoftShutDown (BMCInst);
        break;

    default:
        IPMI_DBG_PRINT ("UNKNOWN Chassis CONTROL REQUEST \n");
        pChassisControlRes->CompletionCode = CC_INV_DATA_FIELD;
        break;
    }
    FlushIPMI((INT8U*)&pBMCInfo->ChassisConfig,(INT8U*)&pBMCInfo->ChassisConfig,pBMCInfo->IPMIConfLoc.ChassisConfigAddr,sizeof(ChassisConfig_T),BMCInst);

    /* Log Power Event Audit Info */
    if ( (pChassisControlReq->ChassisControl <= CHASSIS_SOFT_SHUTDOWN ) &&
    	(g_PDKHandle[PDK_PWRONOFFAUDIT] != NULL) )	//empty
		{
			((void(*)(INT8U,int))g_PDKHandle[PDK_PWRONOFFAUDIT]) (pChassisControlReq->ChassisControl, BMCInst);
		}              
    OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChassisMutex);

    return sizeof (ChassisControlRes_T);
}


/*-------------------------------------
 * GetChassisIdentify
 *-------------------------------------*/
int
GetChassisIdentify (_NEAR_ INT8U* pReq, INT8U ReqLen, _NEAR_ INT8U* pRes,int BMCInst)
{
    _NEAR_ ChassisIdentifyReq_T*    pChassisIdentifyReq =
        (_NEAR_ ChassisIdentifyReq_T*) pReq;
    _NEAR_ ChassisIdentifyRes_T*    pChassisIdentifyRes =
        (_NEAR_ ChassisIdentifyRes_T*) pRes;
    _FAR_ BMCInfo_t* pBMCInfo = &g_BMCInfo[BMCInst];

    IPMI_DBG_PRINT ("GET Chassis IDENTIFY\n");

    if (ReqLen <= sizeof(ChassisIdentifyReq_T)) 
    {
        OS_THREAD_MUTEX_ACQUIRE(&pBMCInfo->ChassisMutex, WAIT_INFINITE);
        if (0 != ReqLen) 
        {    
             pBMCInfo->Msghndlr.ChassisIdentifyForce = 0;
            pBMCInfo->Msghndlr.ChassisIdentifyTimeout = pChassisIdentifyReq->IdentifyInterval; 
        }
        else
        {    
             pBMCInfo->Msghndlr.ChassisIdentifyForce = 0;
             pBMCInfo->Msghndlr.ChassisIdentifyTimeout = 15;
        }

        if (ReqLen == 2)
        {
            /* Check for the reserved bytes should b zero */
            if  ( 0 !=  (pChassisIdentifyReq->ForceIdentify & RESERVED_BITS_GETCHASSISIDENTIFY ) )
            {
                pChassisIdentifyRes->CompletionCode = CC_INV_DATA_FIELD;
                OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChassisMutex);
                return sizeof(INT8U);	
            }

            if(pChassisIdentifyReq->ForceIdentify & 1)
            {
                pBMCInfo->Msghndlr.ChassisIdentifyTimeout = 0;
                pBMCInfo->Msghndlr.ChassisIdentifyForce = 1;
            }
            else
            {
                pBMCInfo->Msghndlr.ChassisIdentifyForce = 0;
            }
        }
        pBMCInfo->Msghndlr.ChassisIdentify = TRUE;

        pChassisIdentifyRes->CompletionCode = CC_NORMAL;
        OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChassisMutex);
    }    	
    else 
    {
        pChassisIdentifyRes->CompletionCode = CC_REQ_INV_LEN;
    }
    
    return sizeof(ChassisIdentifyRes_T);
}


/*-------------------------------------
 * SetChassisCaps
 *-------------------------------------*/
int
SetChassisCaps (_NEAR_ INT8U* pReq, INT8U ReqLen, _NEAR_ INT8U* pRes,int BMCInst)
{
    _NEAR_  SetChassisCapabilitiesReq_T*    pSetChassisCapsReq =
        (_NEAR_ SetChassisCapabilitiesReq_T*) pReq;
    _NEAR_  SetChassisCapabilitiesRes_T*    pSetChassisCapsRes =
        (_NEAR_ SetChassisCapabilitiesRes_T*) pRes;
    BMCInfo_t *pBMCInfo = &g_BMCInfo[BMCInst];

    IPMI_DBG_PRINT ("SET Chassis CAPABILITIES\n");

    /* Check for the reserved bytes should b zero */
    if  ( 0 !=  (pSetChassisCapsReq->ChassisCaps.CapabilitiesFlags & RESERVED_BITS_SETCHASSISCAPS ) )
    {
        pSetChassisCapsRes->CompletionCode = CC_INV_DATA_FIELD;
        return sizeof(INT8U);	
    }
    
    if ((ReqLen != 5) &&
        (ReqLen != sizeof(SetChassisCapabilitiesReq_T)))
    {
        pSetChassisCapsRes->CompletionCode= CC_REQ_INV_LEN;
        return sizeof(SetChassisCapabilitiesRes_T); 
    }

    if((pSetChassisCapsReq->ChassisCaps.CapabilitiesFlags & 0xFC ) != 0)
    {
        pSetChassisCapsRes->CompletionCode= CC_INV_DATA_FIELD;
        return sizeof(SetChassisCapabilitiesRes_T);   
    }

    OS_THREAD_MUTEX_ACQUIRE(&pBMCInfo->ChassisMutex, WAIT_INFINITE);
    _fmemcpy ((_FAR_ INT8U*) &pBMCInfo->ChassisConfig.ChassisCapabilities,
              (_FAR_ INT8U*) &pSetChassisCapsReq->ChassisCaps,
              sizeof(ChassisCapabilities_T));
    OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChassisMutex);

    FlushIPMI((INT8U*)&pBMCInfo->ChassisConfig,(INT8U*)&pBMCInfo->ChassisConfig,pBMCInfo->IPMIConfLoc.ChassisConfigAddr,sizeof(ChassisConfig_T),BMCInst);
    pSetChassisCapsRes->CompletionCode = CC_NORMAL;
    
    return sizeof (SetChassisCapabilitiesRes_T);
}


/*-------------------------------------
 * SetPowerRestorePolicy
 *-------------------------------------*/
int
SetPowerRestorePolicy (_NEAR_ INT8U* pReq, INT8U ReqLen, _NEAR_ INT8U* pRes,int BMCInst)
{
    
    _NEAR_  SetPowerRestorePolicyReq_T* pSetPowerRestorePolicyReq =
        (_NEAR_ SetPowerRestorePolicyReq_T*) pReq;
    _NEAR_  SetPowerRestorePolicyRes_T* pSetPowerRestorePolicyRes =
        (_NEAR_ SetPowerRestorePolicyRes_T*) pRes;  
    BMCInfo_t *pBMCInfo = &g_BMCInfo[BMCInst];
    
    IPMI_DBG_PRINT ("\nSET POWER RESORE POLICY\n");
    
    /* Check for the reserved bytes should b zero */
    if ( 0 != ( pSetPowerRestorePolicyReq->PowerRestorePolicy & RESERVED_BITS_SETPOWERRESTOREPOLICY ))
    {
        pSetPowerRestorePolicyRes->CompletionCode = CC_INV_DATA_FIELD;
        return sizeof (INT8U);
    }

    // 011b = no change to the current power restore policy
   if (pSetPowerRestorePolicyReq->PowerRestorePolicy != 0x03)
   {
        OS_THREAD_MUTEX_ACQUIRE(&pBMCInfo->ChassisMutex, WAIT_INFINITE);

        pBMCInfo->ChassisConfig.PowerRestorePolicy =
        pSetPowerRestorePolicyReq->PowerRestorePolicy & 0x07;
        pBMCInfo->ChassisConfig.ChassisPowerState.PowerState &= ~0x60;
        pBMCInfo->ChassisConfig.ChassisPowerState.PowerState |= (pSetPowerRestorePolicyReq->PowerRestorePolicy << 5); 
        FlushIPMI((INT8U*)&pBMCInfo->ChassisConfig,(INT8U*)&pBMCInfo->ChassisConfig,pBMCInfo->IPMIConfLoc.ChassisConfigAddr,sizeof(ChassisConfig_T),BMCInst);
        OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChassisMutex);
   }

    pSetPowerRestorePolicyRes->CompletionCode = CC_NORMAL;
    pSetPowerRestorePolicyRes->PowerRestorePolicy = PRP_ALWAYS_POWEROFF_SUPPORT |
                                                    PRP_LAST_STATE_SUPPORT      |
                                                    PRP_ALWAYS_POWERON_SUPPORT;
    return  sizeof(SetPowerRestorePolicyRes_T);
}


/*-------------------------------------
 * GetSysRestartCause
 *-------------------------------------*/
int
GetSysRestartCause (_NEAR_ INT8U* pReq, INT8U ReqLen, _NEAR_ INT8U* pRes,int BMCInst)
{    
    _NEAR_  GetSystemRestartCauseRes_T* pGetSysRestartCauseRes =
        (_NEAR_ GetSystemRestartCauseRes_T*) pRes;
    BMCInfo_t *pBMCInfo = &g_BMCInfo[BMCInst];
    INT8U *curchannel;

    IPMI_DBG_PRINT ("GET SYSTEM RESTART CAUSE\n");

    OS_THREAD_MUTEX_ACQUIRE(&pBMCInfo->ChassisMutex, WAIT_INFINITE);
    pGetSysRestartCauseRes->CompletionCode  = CC_NORMAL;
    pGetSysRestartCauseRes->SysRestartCause = pBMCInfo->ChassisConfig.SysRestartCause;
    OS_THREAD_TLS_GET(g_tls.CurChannel,curchannel);
    pGetSysRestartCauseRes->ChannelID       = *curchannel & 0xF;
    OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChassisMutex);

    return sizeof(GetSystemRestartCauseRes_T);
}



/*-------------------------------------
 * GetPOHCounter
 *-------------------------------------*/
int
GetPOHCounter (_NEAR_ INT8U* pReq, INT8U ReqLen, _NEAR_ INT8U* pRes,int BMCInst)
{
    _NEAR_  GetPOHCounterRes_T* pGetPOHCounterRes = (_NEAR_ GetPOHCounterRes_T*) pRes;
    BMCInfo_t *pBMCInfo = &g_BMCInfo[BMCInst];

    IPMI_DBG_PRINT ("GET POH COUNTER\n");

    OS_THREAD_MUTEX_ACQUIRE(&pBMCInfo->ChassisMutex, WAIT_INFINITE);
    pGetPOHCounterRes->CompletionCode    = CC_NORMAL;
    pGetPOHCounterRes->MinutesPerCount   = POH_MINS_PER_COUNT;
    pGetPOHCounterRes->POHCounterReading = htoipmi_u32 (pBMCInfo->GenConfig.POHCounterReading);
    OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChassisMutex);

    return sizeof(GetPOHCounterRes_T);
}


/*-------------------------------------
 * SetSysBOOTOptions
 *-------------------------------------*/
int
SetSysBOOTOptions (_NEAR_ INT8U* pReq, INT8U ReqLen, _NEAR_ INT8U* pRes,int BMCInst)
{
    _NEAR_ SetBootOptionsReq_T* pBootOptReq = (_NEAR_ SetBootOptionsReq_T*) pReq;
    _NEAR_ SetBootOptionsRes_T* pBootOptRes = (_NEAR_ SetBootOptionsRes_T*) pRes;
    BMCInfo_t *pBMCInfo = &g_BMCInfo[BMCInst];
    INT8U                Parameter;
    BootOptions_T*       pBootOptions;
    INT8U				u8SetInProgress;
    INT8U				u8TempData,SSIComputeBladeSupport;
    int i,j=0;

    Parameter = pBootOptReq->ParamValidCumParam & 0x7F;

     SSIComputeBladeSupport = g_corefeatures.ssi_support;

    /*Check for validity of parameter */
    if(SSIComputeBladeSupport)
    {
        if ((Parameter >= sizeof (m_BootOptParamLen)) && (Parameter != CHASSIS_AMI_OEM_PARAM) &&
            (Parameter != SSICB_OEM_PARAM_BLK_SIZE_TBL) && (Parameter < SSICB_BOOT_ORDER_TBL || Parameter > SSICB_SLOT_CONFIG_TBL))
        {
            pBootOptRes->CompletionCode = CC_PARAM_NOT_SUPPORTED;
            return sizeof (SetBootOptionsRes_T);
        }
    }
    else
   {
        if ((Parameter >= sizeof (m_BootOptParamLen)) && (Parameter != CHASSIS_AMI_OEM_PARAM))
        {
            pBootOptRes->CompletionCode = CC_PARAM_NOT_SUPPORTED;
            return sizeof (SetBootOptionsRes_T);
        }
    }
    /*Check if ReqLen valid for OEM Parameter */
    if (CHASSIS_AMI_OEM_PARAM == Parameter)
    {
        if ((ReqLen - 1) != sizeof (AMI_BootOpt_T))
        {
            pBootOptRes->CompletionCode= CC_REQ_INV_LEN;
            return sizeof (INT8U);  
        }
    }
    else if (Parameter >= SSICB_OEM_PARAM_BLK_SIZE_TBL && Parameter <= SSICB_SLOT_CONFIG_TBL)
    {
      if(SSIComputeBladeSupport)
      {
        if ((ReqLen - 1) != m_SSIBootOptParamLen[Parameter-SSICB_OEM_PARAM_BLK_SIZE_TBL])
        {
            pBootOptRes->CompletionCode= CC_REQ_INV_LEN;
            return sizeof (INT8U);
        }
      }
    }
    else
    {
        /*Check if valid message length */
        //if ( ((ReqLen - 1) != m_BootOptParamLen[Parameter]) && (ReqLen != sizeof (Parameter)))
        if ((ReqLen - 1) != m_BootOptParamLen[Parameter])
        {
            pBootOptRes->CompletionCode= CC_REQ_INV_LEN;
            return sizeof (INT8U);  
        }
    }
#if 0  
   Bit is 1 - Parameter is locked 
   Bit is 0 - Parameter is unlocked 

if locked 
	if no req to unlock then  return invalid 
	if req to unlock    then  unlock and procced 
else 
	Proceed
#endif
    /* Check for Reserved Bits */
    for (i = 0; i < sizeof (m_RsvdBitsCheck)/ sizeof (m_RsvdBitsCheck[0]); i++)
    {
        /* Check if this Parameter Selector needs Reserved bit checking !! */
        if (m_RsvdBitsCheck[i].Params == Parameter)
        {
            //IPMI_DBG_PRINT_2 ("Param - %x, DataLen - %x\n", pSetLanReq->ParameterSelect, m_RsvdBitsCheck[i].DataLen);

            for (j = 0; j < m_RsvdBitsCheck[i].DataLen; j++)
            {
                //	IPMI_DBG_PRINT_2 ("Cmp  %x,  %x\n", pReq[2+j], m_RsvdBitsCheck[i].ReservedBits[j]);
                if ( 0 != (pReq[1+j] & m_RsvdBitsCheck[i].ReservedBits[j]))
                {
                    /* Alarm !!! Somebody is trying to set Reseved Bits */
                    *pRes = CC_INV_DATA_FIELD;
                    return sizeof (*pRes);
                }
            }
        }
     }

    OS_THREAD_MUTEX_ACQUIRE(&pBMCInfo->ChassisMutex, WAIT_INFINITE);
    pBootOptions = &(BMC_GET_SHARED_MEM(BMCInst)->sBootOptions);
    u8SetInProgress = pBootOptions->u8SetInProgress;
    /* if locked */
    if (pBootOptions->ParameterValid &  (1 << Parameter) )
    {
        /*if not req to unlock */
        if (0 != (pBootOptReq->ParamValidCumParam & 0x80))
        {
            pBootOptRes->CompletionCode = CC_INV_DATA_FIELD;
            OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChassisMutex);
            return sizeof (INT8U);
        }
    }
 

    /*Check for valid bit settings */
    if (0 != (pBootOptReq->ParamValidCumParam & 0x80))
    {
        /* The valid bit for parameters 0 - 7  are SET/RESET to 
         *  corresponding bits 0-7 in ParameterValid field
         */ 
        pBootOptions->ParameterValid |= (1 << Parameter);
    }
    else
    {
        pBootOptions->ParameterValid &= ~(1 << Parameter);
    }

    /*if only the parameter byte is provided then exit */
    if (ReqLen == sizeof (Parameter))
    {
        pBootOptRes->CompletionCode = CC_NORMAL;
        OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChassisMutex);
        return sizeof (SetBootOptionsRes_T);
    }

    switch (Parameter)
    {
        case CHASSIS_SET_INPROG:
            /* Commit Write is optional and supported
             * only if rollback is supported */
            if ( (BMC_BOOT_OPTION_SET_IN_PROGRESS != pBootOptReq->BootParam.SetInProgress) &&
                (BMC_BOOT_OPTION_SET_COMPLETE != pBootOptReq->BootParam.SetInProgress) )
            {
                pBootOptRes->CompletionCode = CC_PARAM_NOT_SUPPORTED;
                OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChassisMutex);
                return sizeof(SetBootOptionsRes_T);
            }
            else if ((BMC_BOOT_OPTION_SET_IN_PROGRESS == (u8SetInProgress & 0x03)) &&
                (BMC_BOOT_OPTION_SET_IN_PROGRESS == pBootOptReq->BootParam.SetInProgress))
            {
                IPMI_DBG_PRINT ("\nSET IN PROGRESS ALREADY SET \n");

                pBootOptRes->CompletionCode = CC_SET_IN_PROGRESS;
                OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChassisMutex);
                return sizeof(SetBootOptionsRes_T); 
            }

            /*Set the new setinpogress byte */
            pBootOptions->u8SetInProgress = pBootOptReq->BootParam.SetInProgress;
            break;       
            
        case CHASSIS_SERVICE_PART_SEL:
            pBootOptions->ServicePartitionSelector =
                pBootOptReq->BootParam.ServicePartitionSelector;
            break;
            
        case CHASSIS_SERVICE_PART_SCAN:
            pBootOptions->ServicePartitionScan = 
                pBootOptReq->BootParam.ServicePartitionScan;
            /*Update in NVRAM*/
            pBMCInfo->ChassisConfig.SysPartitionScan = pBootOptReq->BootParam.ServicePartitionScan;
            FlushIPMI((INT8U*)&pBMCInfo->ChassisConfig,(INT8U*)&pBMCInfo->ChassisConfig.SysPartitionScan,pBMCInfo->IPMIConfLoc.ChassisConfigAddr,sizeof(INT8U),BMCInst);
            break;
            
        case CHASSIS_BOOT_FLAG_VALID_BIT_CLEAR:
            pBootOptions->BootFlagValidBitClearing =
                pBootOptReq->BootParam.BootFlagValidBitClearing;
            break;

        case CHASSIS_BOOT_INFO_ACK:
            _fmemcpy ((_FAR_ INT8U*)&pBootOptions->BootInfoAck,
                      (_FAR_ INT8U*)&pBootOptReq->BootParam.BootInfoAck,
                       sizeof (BootInfoAck_T));
            break;

        case CHASSIS_BOOT_FLAGS:
            u8TempData = (pBootOptReq->BootParam.BootFlags.Data2 & BIT5_BIT2_MASK);        	
            if((u8TempData == RESERVED_VALUE_28) ||(u8TempData == RESERVED_VALUE_30) ||(u8TempData == RESERVED_VALUE_34)||(u8TempData == RESERVED_VALUE_38))
            {
                /* Alarm !!! Somebody is trying to set Reseved Bits */
                *pRes = CC_INV_DATA_FIELD;
                OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChassisMutex);
                return sizeof (*pRes);
            }
            u8TempData = (pBootOptReq->BootParam.BootFlags.Data3 & BIT6_BIT5_MASK);
            if((u8TempData  == RESERVED_VALUE_60))
            {
                /* Alarm !!! Somebody is trying to set Reseved Bits */
                *pRes = CC_INV_DATA_FIELD;
                OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChassisMutex);
                return sizeof (*pRes);
            }
            u8TempData = (pBootOptReq->BootParam.BootFlags.Data3 & BIT1_BIT0_MASK);
            if((u8TempData  == RESERVED_VALUE_03))
            {
                /* Alarm !!! Somebody is trying to set Reseved Bits */
                *pRes = CC_INV_DATA_FIELD;
                OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChassisMutex);
                return sizeof (*pRes);
            }
            if((pBootOptReq->BootParam.BootFlags.Data5 == RESERVED_VALUE_20)||(pBootOptReq->BootParam.BootFlags.Data5 == RESERVED_VALUE_40)||(pBootOptReq->BootParam.BootFlags.Data5 == RESERVED_VALUE_80))
            {
                /* Alarm !!! Somebody is trying to set Reseved Bits */
                *pRes = CC_INV_DATA_FIELD;
                OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChassisMutex);
                return sizeof (*pRes);
            }
            _fmemcpy ((_FAR_ INT8U*)&pBootOptions->BootFlags,
            (_FAR_ INT8U*)&pBootOptReq->BootParam.BootFlags,
            sizeof (BootFlags_T));
            break;

        case CHASSIS_BOOT_INITIATOR_INFO:
            _fmemcpy ((_FAR_ INT8U*)&pBootOptions->BootInitiatorInfo,
                      (_FAR_ INT8U*)&pBootOptReq->BootParam.BootInitiatorInfo,
                      sizeof (BootInitiatorInfo_T));
            break;
            
        case CHASSIS_BOOT_INITIATOR_MBOX:
            if (pBootOptReq->BootParam.BootMailBox.BlockSel >= MAX_BOOT_INIT_MAILBOX_BLOCKS)
            {
                IPMI_DBG_PRINT ("\n ONLY FIVE BLOCKS ARE USED \n");

                pBootOptRes->CompletionCode = CC_INV_DATA_FIELD;
                OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChassisMutex);
                return sizeof(SetBootOptionsRes_T); 
                
            }

            _fmemcpy ((_FAR_ INT8U*)&pBootOptions->BootMailBox[pBootOptReq->BootParam.BootMailBox.BlockSel], 
                      (_FAR_ INT8U*) &pBootOptReq->BootParam.BootMailBox.BootMBox,
                      sizeof (BootInitiatorMailbox_T));
            break;


        case CHASSIS_AMI_OEM_PARAM:
            _fmemcpy ((_FAR_ INT8U*)&pBMCInfo->ChassisConfig.OemBootOpt,
                      (_FAR_ INT8U*) &pBootOptReq->BootParam.Oem,
                      sizeof (AMI_BootOpt_T));
            FlushIPMI((INT8U*)&pBMCInfo->ChassisConfig,(INT8U*)&pBMCInfo->ChassisConfig,pBMCInfo->IPMIConfLoc.ChassisConfigAddr,sizeof(ChassisConfig_T),BMCInst);
            break;

        case SSICB_OEM_PARAM_BLK_SIZE_TBL:
            if(SSIComputeBladeSupport)
            {
                    _fmemcpy ((_FAR_ INT8U*)&pBootOptions->OemParamBlkSizeTbl,
                    (_FAR_ INT8U*)&pBootOptReq->BootParam.OemParamBlkSizeTbl,
                    sizeof(OemParamBlkSizeTbl_T));
                    break;
            }
            else
            {
                    pBootOptRes->CompletionCode = CC_PARAM_NOT_SUPPORTED;
                    OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChassisMutex);
                    return sizeof (SetBootOptionsRes_T);
            }
        case SSICB_BOOT_ORDER_TBL:
            if(SSIComputeBladeSupport)
            {
            if (pBootOptReq->BootParam.BootOrderTbl.BlockSel >= g_coremacros.ssi_bot_dev_num)
            {
                pBootOptRes->CompletionCode = CC_INV_DATA_FIELD;
                OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChassisMutex);
                return sizeof(INT8U); 
            }
            _fmemcpy ((_FAR_ INT8U*)&pBootOptions->BootOrderTbl[(pBootOptReq->BootParam.BootOrderTbl.BlockSel) * sizeof(BootOrderTbl_T)],
                        (_FAR_ INT8U*)&pBootOptReq->BootParam.BootOrderTbl,
                      sizeof(BootOrderTbl_T));
            break;
            }
            else
            {
                pBootOptRes->CompletionCode = CC_PARAM_NOT_SUPPORTED;
                OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChassisMutex);
                return sizeof (SetBootOptionsRes_T);
            }
        case SSICB_BOOT_DEV_SELECTOR:
            if(SSIComputeBladeSupport)
            {
                pBootOptions->BootDevSelector = pBootOptReq->BootParam.BootDevSelector;
                break;
            }
            else
            {
                pBootOptRes->CompletionCode = CC_PARAM_NOT_SUPPORTED;
                OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChassisMutex);
                return sizeof (SetBootOptionsRes_T);
            }
        case SSICB_SLOT_CONFIG_TBL:
            if(SSIComputeBladeSupport)
            {
                _fmemcpy ((_FAR_ INT8U*)&pBootOptions->SlotConfigTbl,
                (_FAR_ INT8U*)&pBootOptReq->BootParam.SlotConfigTbl,
                sizeof(SlotConfigTbl_T));
                break;
            }
            else
            {
                pBootOptRes->CompletionCode = CC_PARAM_NOT_SUPPORTED;
                OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChassisMutex);
                return sizeof (SetBootOptionsRes_T);
            }
     default:
            pBootOptRes->CompletionCode = CC_PARAM_NOT_SUPPORTED;
            OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChassisMutex);
        return sizeof (SetBootOptionsRes_T);

    }

    if (0 != ROLLBACK_OPTION)
    {
        if (BMC_BOOT_OPTION_COMMIT_WRITE == (u8SetInProgress & 0x03))
        {
            /* Writing to nvRAM when "commit write" is given */
            FlushIPMI((INT8U*)&pBMCInfo->ChassisConfig,(INT8U*)&pBMCInfo->ChassisConfig,pBMCInfo->IPMIConfLoc.ChassisConfigAddr,sizeof(ChassisConfig_T),BMCInst);
            /* Setting  this to "set complete", don't need mutex protection */
            pBootOptions->u8SetInProgress  = BMC_BOOT_OPTION_SET_COMPLETE;
        }
        
    }
    else
    {
        /* Since roll back feature is not provided
           the data is  written to nvram */
        FlushIPMI((INT8U*)&pBMCInfo->ChassisConfig,(INT8U*)&pBMCInfo->ChassisConfig,pBMCInfo->IPMIConfLoc.ChassisConfigAddr,sizeof(ChassisConfig_T),BMCInst);
    }
    OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChassisMutex);

    pBootOptRes->CompletionCode = CC_NORMAL;
    return sizeof(SetBootOptionsRes_T);
}


/*-------------------------------------
 * GetSysBOOTOptions
 *-------------------------------------*/
int 
GetSysBOOTOptions (_NEAR_ INT8U* pReq, INT8U ReqLen, _NEAR_ INT8U* pRes,int BMCInst)
{
    _NEAR_  GetBootOptionsReq_T* pGetBootOptReq = (_NEAR_ GetBootOptionsReq_T*) pReq;
    _NEAR_  GetBootOptionsRes_T* pGetBootOptRes = (_NEAR_ GetBootOptionsRes_T*) pRes;
    BMCInfo_t *pBMCInfo = &g_BMCInfo[BMCInst];
    INT8U                ParamSel,SSIComputeBladeSupport;
    int                  ResponseLength;
    BootOptions_T        sBootOptions;


    IPMI_DBG_PRINT ("GET SYSTEM BOOT OPTIONS\n");

    if(pGetBootOptReq->ParamSel & RESERVED_VALUE_80)
    {
        /* Alarm !!! Somebody is trying to set Reseved Bits */
        *pRes = CC_INV_DATA_FIELD;
        return sizeof (*pRes);
    }

    ParamSel = pGetBootOptReq->ParamSel & 0x7F;

    SSIComputeBladeSupport = g_corefeatures.ssi_support;

    /*Check for validity of parameter */
    if(SSIComputeBladeSupport)
    {
    if ((ParamSel >= sizeof (m_BootOptParamLen)) && (ParamSel != CHASSIS_AMI_OEM_PARAM) &&
        (ParamSel != SSICB_OEM_PARAM_BLK_SIZE_TBL) && (ParamSel < SSICB_BOOT_ORDER_TBL || ParamSel > SSICB_SLOT_CONFIG_TBL))
        {
            pGetBootOptRes->CompletionCode = CC_PARAM_NOT_SUPPORTED;
            return sizeof(INT8U);
        }
    }
    else
    {
        if ((ParamSel >= sizeof (m_BootOptParamLen)) && (ParamSel != CHASSIS_AMI_OEM_PARAM))
        {
            pGetBootOptRes->CompletionCode = CC_PARAM_NOT_SUPPORTED;
            return sizeof(INT8U);
        }
    }

    /*Check the validity of Setselector & Blockselector */
    if(SSIComputeBladeSupport)
    {
        if (((0 != pGetBootOptReq->SetSel) && (ParamSel != CHASSIS_BOOT_INITIATOR_MBOX || ParamSel != SSICB_BOOT_ORDER_TBL)) ||
            (ParamSel == CHASSIS_BOOT_INITIATOR_MBOX && pGetBootOptReq->SetSel >= MAX_BOOT_INIT_MAILBOX_BLOCKS) ||
            (ParamSel == SSICB_BOOT_ORDER_TBL && pGetBootOptReq->SetSel >= g_coremacros.ssi_bot_dev_num) ||
            (0 != pGetBootOptReq->BlockSel))
        {
            IPMI_DBG_PRINT ("Set Selector or Block Selector is invalid\n") ;
            pGetBootOptRes->CompletionCode = CC_INV_DATA_FIELD;
            return sizeof(INT8U);
        }
    }
    else
    {
        if (((0 != pGetBootOptReq->SetSel) && (ParamSel != CHASSIS_BOOT_INITIATOR_MBOX)) ||
            (pGetBootOptReq->SetSel >= MAX_BOOT_INIT_MAILBOX_BLOCKS)                      ||
            (0 != pGetBootOptReq->BlockSel))
        {
            IPMI_DBG_PRINT ("Set Selector or Block Selector is invalid\n") ;
            pGetBootOptRes->CompletionCode = CC_INV_DATA_FIELD;
            return sizeof(INT8U);
        }
   }
    pGetBootOptRes->CompletionCode  = CC_NORMAL;
    pGetBootOptRes->ParamVersion    = CHASSIS_PARAMETER_VERSION;
    pGetBootOptRes->ParameterValid  = ParamSel;

    OS_THREAD_MUTEX_ACQUIRE(&pBMCInfo->ChassisMutex, WAIT_INFINITE);
    // get a local copy of the boot option from the shared memory
    sBootOptions = BMC_GET_SHARED_MEM(BMCInst)->sBootOptions;
    /*Set the Parameter valid bit if needed */
    if (sBootOptions.ParameterValid & (1 << ParamSel))
    {
        pGetBootOptRes->ParameterValid |= 0x80;
    }

    /*Set initial length of Completion code,Param revision & Paramvalid */
    ResponseLength = 0x03;

    /*Load the specific parameter */
    switch (ParamSel)
    {
        case CHASSIS_SET_INPROG :
            pGetBootOptRes->BootParams.SetInProgress = sBootOptions.u8SetInProgress;
            ResponseLength += sizeof (sBootOptions.u8SetInProgress); 
            break;

        case CHASSIS_SERVICE_PART_SEL:
            pGetBootOptRes->BootParams.ServicePartitionSelector =
                sBootOptions.ServicePartitionSelector;
            ResponseLength += sizeof (sBootOptions.ServicePartitionScan); 
            break;
    
        case CHASSIS_SERVICE_PART_SCAN:
            pGetBootOptRes->BootParams.ServicePartitionScan = pBMCInfo->ChassisConfig.SysPartitionScan;
            ResponseLength += sizeof (sBootOptions.ServicePartitionScan); 
            break;
        
        case CHASSIS_BOOT_FLAG_VALID_BIT_CLEAR:
            pGetBootOptRes->BootParams.BootFlagValidBitClearing =
                sBootOptions.BootFlagValidBitClearing;
            ResponseLength += sizeof (sBootOptions.BootFlagValidBitClearing); 
            break;
    
        case CHASSIS_BOOT_INFO_ACK:
            _fmemcpy ((_FAR_ INT8U*)&pGetBootOptRes->BootParams.BootInfoAck,
                      (_FAR_ INT8U*)&sBootOptions.BootInfoAck,
                      sizeof (BootInfoAck_T));
            pGetBootOptRes->BootParams.BootInfoAck.WriteMask = 0;
            ResponseLength += sizeof (BootInfoAck_T); 
            break;
               
        case CHASSIS_BOOT_FLAGS:
            _fmemcpy ((_FAR_ INT8U*)&pGetBootOptRes->BootParams.BootFlags,
                      (_FAR_ INT8U*)&sBootOptions.BootFlags,
                      sizeof (BootFlags_T));
            ResponseLength += sizeof (BootFlags_T); 
            break;

        case CHASSIS_BOOT_INITIATOR_INFO:
            _fmemcpy ((_FAR_ INT8U*)&pGetBootOptRes->BootParams.BootInitiatorInfo,
                      (_FAR_ INT8U*)&sBootOptions.BootInitiatorInfo,
                      sizeof (BootInitiatorInfo_T));
            ResponseLength += sizeof (BootInitiatorInfo_T); 
            break;
        
        case CHASSIS_BOOT_INITIATOR_MBOX:
			pGetBootOptRes->BootParams.BootMailBox.BlockSel = pGetBootOptReq->SetSel;
            _fmemcpy ((_FAR_ INT8U*)&pGetBootOptRes->BootParams.BootMailBox.BootMBox,
                      (_FAR_ INT8U*)&sBootOptions.BootMailBox[pGetBootOptReq->SetSel],
                      sizeof (BootInitiatorMailbox_T));
            ResponseLength += sizeof (BootInitiatorMboxReq_T); 
            break;

        case CHASSIS_AMI_OEM_PARAM:
            _fmemcpy ((_FAR_ INT8U*)&pGetBootOptRes->BootParams.Oem,
                      (_FAR_ INT8U*)&pBMCInfo->ChassisConfig.OemBootOpt, 
                      sizeof (AMI_BootOpt_T));
            ResponseLength += sizeof (AMI_BootOpt_T); 
            break;

        case SSICB_OEM_PARAM_BLK_SIZE_TBL:
            if(SSIComputeBladeSupport)
            {
                _fmemcpy ((_FAR_ INT8U*)&pGetBootOptRes->BootParams.OemParamBlkSizeTbl,
                          (_FAR_ INT8U*)&sBootOptions.OemParamBlkSizeTbl,
                          sizeof(OemParamBlkSizeTbl_T));
                ResponseLength += sizeof(OemParamBlkSizeTbl_T);
                break;
            }
            else
            {
                pGetBootOptRes->CompletionCode  = CC_PARAM_NOT_SUPPORTED ;
                ResponseLength  = 1 ; 
                break;
            }

        case SSICB_BOOT_ORDER_TBL:
            if(SSIComputeBladeSupport)
             {
            _fmemcpy ((_FAR_ INT8U*)&pGetBootOptRes->BootParams.BootOrderTbl,
                      (_FAR_ INT8U*)&sBootOptions.BootOrderTbl[pGetBootOptReq->SetSel * sizeof(BootOrderTbl_T)],
                      sizeof(BootOrderTbl_T));
            ResponseLength += sizeof(BootOrderTbl_T);
            break;
            }
            else
            {
                pGetBootOptRes->CompletionCode  = CC_PARAM_NOT_SUPPORTED ;
                ResponseLength  = 1 ; 
                break;
            }

        case SSICB_BOOT_DEV_SELECTOR:
            if(SSIComputeBladeSupport)
            {
                pGetBootOptRes->BootParams.BootDevSelector = sBootOptions.BootDevSelector; 
                ResponseLength += sizeof(sBootOptions.BootDevSelector);
                break;
            }
            else
            {
                pGetBootOptRes->CompletionCode  = CC_PARAM_NOT_SUPPORTED ;
                ResponseLength  = 1 ; 
                break;
            }

        case SSICB_SLOT_CONFIG_TBL:
            if(SSIComputeBladeSupport)
            {
            _fmemcpy ((_FAR_ INT8U*)&pGetBootOptRes->BootParams.SlotConfigTbl,
                      (_FAR_ INT8U*)&sBootOptions.SlotConfigTbl,
                      sizeof(SlotConfigTbl_T));
            ResponseLength += sizeof(SlotConfigTbl_T);
            break;
            }
            else
            {
                pGetBootOptRes->CompletionCode  = CC_PARAM_NOT_SUPPORTED ;
                ResponseLength  = 1 ; 
                break;
            }

        default :
        pGetBootOptRes->CompletionCode  = CC_PARAM_NOT_SUPPORTED ;
         ResponseLength  = 1 ; 
    }

    OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChassisMutex);
    return ResponseLength; 
}

/*-------------------------------------
 * SetFPButtonEnables
 *-------------------------------------*/
int
SetFPButtonEnables (_NEAR_ INT8U* pReq, INT8U ReqLen, _NEAR_ INT8U* pRes,int BMCInst)
{
#if 0 //FQLI
    _FAR_   PMConfig_T*          pPMConfig;
    bool                         bRet;
    SetFPBtnEnablesRes_T*        pFPBtnEnablesRes = (SetFPBtnEnablesRes_T*)pRes;
    SetFPBtnEnablesReq_T*   pFPBtnEnablesReq = (SetFPBtnEnablesReq_T*)pReq;

    IPMI_DBG_PRINT ("PwrCtrl - SetFrontPanelEnables\n");
    pFPBtnEnablesRes->CompletionCode = CC_INV_CMD;

    if (pReq)
    {
        pFPBtnEnablesRes->CompletionCode = CC_NORMAL;

        // retrieve chassis status from the NVStore
        pPMConfig = (_FAR_ PMConfig_T*)GetNVRAddr(NVRH_PMCONFIG);

        // store the front panel enables to the NVStore
        pPMConfig->ChassisConfig.ChassisPowerState.FPBtnEnables = pFPBtnEnablesReq->ButtonEnables;

        // enable / disable front panel buttons. do the set before store the value in case the
        // action fails. if failed to set the passthrough buttons, the current reading will be
        // used to be the current settings.
        bRet = PDK_SetFPEnable(&pFPBtnEnablesReq->ButtonEnables);
        if (bRet != TRUE)
        {
            pFPBtnEnablesRes->CompletionCode = CC_UNSPECIFIED_ERR;
        }

      	FlushPMC(&pPMConfig->ChassisConfig.ChassisPowerState.sFrontPanelButton, sizeof(ChassisPowerState_T));
    }

    return sizeof (SetFPBtnEnablesRes_T);

#else //AMI

    _NEAR_  SetFPBtnEnablesReq_T* pFPBtnEnablesReq = (_NEAR_ SetFPBtnEnablesReq_T*)pReq;
    _NEAR_  SetFPBtnEnablesRes_T* pFPBtnEnablesRes = (_NEAR_ SetFPBtnEnablesRes_T*)pRes;
    BMCInfo_t *pBMCInfo = &g_BMCInfo[BMCInst];

    IPMI_DBG_PRINT ("Set FP Button Enables\n");

    /* Check for the reserved bytes should b zero */

    if  ( 0 !=  (pFPBtnEnablesReq->ButtonEnables & RESERVED_BITS_SETFPBUTTONENABLES ) )
    {
        pFPBtnEnablesRes->CompletionCode = CC_INV_DATA_FIELD;
        return sizeof(INT8U);	
    }

    OS_THREAD_MUTEX_ACQUIRE(&pBMCInfo->ChassisMutex, WAIT_INFINITE);
    pBMCInfo->ChassisConfig.ChassisPowerState.FPBtnEnables = pFPBtnEnablesReq->ButtonEnables;

    if(g_PDKHandle[PDK_FPENABLE] != NULL)
    {
        ((int(*)(INT8U,int))g_PDKHandle[PDK_FPENABLE]) (pFPBtnEnablesReq->ButtonEnables,BMCInst);
    }

    /* Save in NVR */
    FlushIPMI((INT8U*)&pBMCInfo->ChassisConfig,(INT8U*)&pBMCInfo->ChassisConfig,pBMCInfo->IPMIConfLoc.ChassisConfigAddr,sizeof(ChassisConfig_T),BMCInst);
    pFPBtnEnablesRes->CompletionCode = 0x00;
    OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChassisMutex);

    return sizeof (SetFPBtnEnablesRes_T);
#endif //FQLI
}


/*-------------------------------------
 * SetPowerCycleInterval
 *-------------------------------------*/
int
SetPowerCycleInterval (_NEAR_ INT8U* pReq, INT8U ReqLen, _NEAR_ INT8U* pRes,int BMCInst)
{    
    _NEAR_  SetPowerCycleIntervalReq_T* pSetPowerCycleInterval =
        (_NEAR_ SetPowerCycleIntervalReq_T*) pReq;
    _NEAR_  SetPowerCycleIntervalRes_T* pSetPowerCycleIntervalRes =
        (_NEAR_ SetPowerCycleIntervalRes_T*) pRes;
    BMCInfo_t *pBMCInfo = &g_BMCInfo[BMCInst];

    OS_THREAD_MUTEX_ACQUIRE(&pBMCInfo->ChassisMutex, WAIT_INFINITE);
    pBMCInfo->ChassisConfig.PowerCycleInterval = pSetPowerCycleInterval->PowerCycleInterval;

    pSetPowerCycleIntervalRes->CompletionCode  = CC_NORMAL;

    FlushIPMI((INT8U*)&pBMCInfo->ChassisConfig,(INT8U*)&pBMCInfo->ChassisConfig,pBMCInfo->IPMIConfLoc.ChassisConfigAddr,sizeof(ChassisConfig_T),BMCInst);
    OS_THREAD_MUTEX_RELEASE(&pBMCInfo->ChassisMutex);
    return sizeof(SetPowerCycleIntervalRes_T);
}

#endif /* CHASSIS_DEVICE */
