/*****************************************************************
******************************************************************
***                                                            ***
***        (C)Copyright 2008, American Megatrends Inc.         ***
***                                                            ***
***                    All Rights Reserved                     ***
***                                                            ***
***       5555 Oakbrook Parkway, Norcross, GA 30093, USA       ***
***                                                            ***
***                     Phone 770.246.8600                     ***
***                                                            ***
******************************************************************
******************************************************************
******************************************************************
* 
* Filename: libipmi_sdr.c
*
******************************************************************/
#include <string.h>
#include <stdlib.h>

#include "libipmi_session.h"
#include "libipmi_errorcodes.h"
#include "libipmi_sdr.h"
#include "com_IPMI_Storage.h"
#include "goahead.h"
#include "com_IPMI_App.h"



/** \brief gcc method for designating a packed struct */
#define PACKED __attribute__ ((packed))



#include "com_IPMI_SDRRecord.h"



/* Get SDR Repository Info Command */
  uint16_t    IPMICMD_GetSDRRepositoryInfo( IPMI20_UDS_SESSION_T *pUDSSession,
                                        SDRRepositoryInfo_T *pResGetSDRRepositoryInfo,
                                        int timeout)
{
    uint8_t    Req[20];
    uint16_t    wRet;
    uint32_t    dwResLen;

    dwResLen = sizeof(SDRRepositoryInfo_T);
    wRet = LIBIPMI_Send_RAW_IPMI2_0_Command(pUDSSession,  
                                            NETFNLUN_IPMI_STORAGE, CMD_GET_SDR_REPOSITORY_INFO,
                                            (uint8_t*)Req, 0,
                                            (uint8_t *)pResGetSDRRepositoryInfo, &dwResLen,
                                            timeout);

    return wRet;
}

uint16_t    IPMC_GetSDRRepositoryInfo( IPMI20_UDS_SESSION_T *pUDSSession, uint8_t IpmbAddr, 
                                        SDRRepositoryInfo_T *pResGetSDRRepositoryInfo,
                                        int timeout)
{
    int wRet = 0;
    uint32_t    dwResLen;
    uint8_t     Req[50] = {0};
    uint8_t     Res[50] = {0};

    Req[0] = 0x40;  //Track | channel 0
    Req[1] = IpmbAddr;
    Req[2] = NETFNLUN_IPMI_STORAGE;
    Req[3] = 0x100 - (Req[1] + Req[2])&0xff;    //checksum1
    Req[4] = 0x20;
    Req[5] = 0x10;
    Req[6] = CMD_GET_SDR_REPOSITORY_INFO;   
    Req[7] = 0x100 - (Req[4] + Req[5] + Req[6])&0xff;

    wRet = LIBIPMI_Send_RAW_IPMI2_0_Command(pUDSSession,  
                            NETFNLUN_IPMI_APP, CMD_SEND_MSG,
                            Req, 8,
                            Res,  &dwResLen,
                            timeout);
    if((wRet != 0) || (Res[6] != 0))
    {
        printf("IPMC_GetSDRRepositoryInfo failed!\n");
        return -1;
    }


    memcpy(pResGetSDRRepositoryInfo, &Res[6], sizeof(SDRRepositoryInfo_T));
    return wRet;
}

/* Get SDR Repository Allocation Info Command */
  uint16_t    IPMICMD_GetSDRRepositoryAllocInfo( IPMI20_UDS_SESSION_T *pUDSSession,
                                        SDRRepositoryAllocInfo_T *pResGetSDRRepositoryAllocInfo,
                                        int timeout)
{
    uint8_t    Req[20];
    uint16_t    wRet;
    uint32_t    dwResLen;

    dwResLen = sizeof(SDRRepositoryAllocInfo_T);
    wRet = LIBIPMI_Send_RAW_IPMI2_0_Command(pUDSSession,  
                                            NETFNLUN_IPMI_STORAGE, CMD_GET_SDR_REPOSITORY_ALLOCATION_INFO,
                                            (uint8_t*)Req, 0,
                                            (uint8_t *)pResGetSDRRepositoryAllocInfo, &dwResLen,
                                            timeout);
    return wRet;
}

uint16_t    IPMC_GetSDRRepositoryAllocInfo( IPMI20_UDS_SESSION_T *pUDSSession, uint8_t IpmbAddr, 
                                        SDRRepositoryAllocInfo_T *pResGetSDRRepositoryAllocInfo,
                                        int timeout)
{
    int wRet = 0;
    uint32_t    dwResLen;
    uint8_t     Req[50] = {0};
    uint8_t     Res[50] = {0};

    Req[0] = 0x40;  //Track | channel 0
    Req[1] = IpmbAddr;
    Req[2] = NETFNLUN_IPMI_STORAGE;
    Req[3] = 0x100 - (Req[1] + Req[2])&0xff;    //checksum1
    Req[4] = 0x20;
    Req[5] = 0x10;
    Req[6] = CMD_GET_SDR_REPOSITORY_ALLOCATION_INFO;   
    Req[7] = 0x100 - (Req[4] + Req[5] + Req[6])&0xff;

    wRet = LIBIPMI_Send_RAW_IPMI2_0_Command(pUDSSession,  
                            NETFNLUN_IPMI_APP, CMD_SEND_MSG,
                            Req, 8,
                            Res,  &dwResLen,
                            timeout);

    if((wRet != 0) || (Res[6] != 0))
    {
        printf("IPMC_GetSDRRepositoryAllocInfo failed!\n");
        return -1;
    }


    memcpy(pResGetSDRRepositoryAllocInfo, &Res[6], sizeof(SDRRepositoryAllocInfo_T));
    return wRet;
}

/* Reserve SDR Repository Command */
  uint16_t    IPMICMD_ReserveSDRRepository( IPMI20_UDS_SESSION_T *pUDSSession,
                                        ReserveSDRRepositoryRes_T *pResReserveSDRRepository,
                                        int timeout)
{
    uint8_t    Req[20];
    uint16_t    wRet;
    uint32_t    dwResLen;

    dwResLen = sizeof(ReserveSDRRepositoryRes_T);
    wRet = LIBIPMI_Send_RAW_IPMI2_0_Command(pUDSSession,  
                                            NETFNLUN_IPMI_STORAGE, CMD_RESERVE_SDR_REPOSITORY,
                                            (uint8_t*)Req, 0,
                                            (uint8_t *)pResReserveSDRRepository, &dwResLen,
                                            timeout);

    return wRet;
}


/* Get SDR Command */
  uint16_t    IPMICMD_GetSDR( IPMI20_UDS_SESSION_T *pUDSSession,
                                    GetSDRReq_T *pReqGetSDR,
                                    GetSDRRes_T *pResGetSDR,
                                    uint32_t        *pdwOutBuffLen,
                                    int timeout)
{
    uint16_t    wRet;
    uint32_t    dwResLen;

    dwResLen = *pdwOutBuffLen;
    wRet = LIBIPMI_Send_RAW_IPMI2_0_Command(pUDSSession,  
                                            NETFNLUN_IPMI_STORAGE, CMD_GET_SDR,
                                            (uint8_t*)pReqGetSDR, sizeof(GetSDRReq_T),
                                            (uint8_t *)pResGetSDR, &dwResLen,
                                            timeout);

    *pdwOutBuffLen = dwResLen;

    return wRet;
}


/* Add SDR Command */
  uint16_t    IPMICMD_AddSDR( IPMI20_UDS_SESSION_T *pUDSSession,
                                    uint8_t        *pReqAddSDR,
                                    uint32_t        dwInBuffLen,
                                    AddSDRRes_T *pResAddSDR,
                                    int timeout)
{
    uint16_t    wRet;
    uint32_t    dwResLen;

    dwResLen = sizeof(AddSDRRes_T);
    wRet = LIBIPMI_Send_RAW_IPMI2_0_Command(pUDSSession,  
                                            NETFNLUN_IPMI_STORAGE, CMD_ADD_SDR,
                                            (uint8_t*)pReqAddSDR, dwInBuffLen,
                                            (uint8_t *)pResAddSDR, &dwResLen,
                                            timeout);

    return wRet;
}


/* Partial Add SDR Command */
  uint16_t    IPMICMD_PartialAddSDR( IPMI20_UDS_SESSION_T *pUDSSession,
                                    PartialAddSDRReq_T *pReqPartialAddSDR,
                                    uint32_t        dwInBuffLen,
                                    PartialAddSDRRes_T *pResPartialAddSDR,
                                    int timeout)
{
    uint16_t    wRet;
    uint32_t    dwResLen;

    dwResLen = sizeof(PartialAddSDRRes_T);
    wRet = LIBIPMI_Send_RAW_IPMI2_0_Command(pUDSSession,  
                                            NETFNLUN_IPMI_STORAGE, CMD_PARTIAL_ADD_SDR,
                                            (uint8_t*)pReqPartialAddSDR, dwInBuffLen,
                                            (uint8_t *)pResPartialAddSDR, &dwResLen,
                                            timeout);

    return wRet;
}


/* Delete SDR Command */
  uint16_t    IPMICMD_DeleteSDR( IPMI20_UDS_SESSION_T *pUDSSession,
                                    DeleteSDRReq_T *pReqDeleteSDR,
                                    DeleteSDRReq_T *pResDeleteSDR,
                                    int timeout)
{
    uint16_t    wRet;
    uint32_t    dwResLen;

    dwResLen = sizeof(DeleteSDRReq_T);
    wRet = LIBIPMI_Send_RAW_IPMI2_0_Command(pUDSSession,  
                                            NETFNLUN_IPMI_STORAGE, CMD_DELETE_SDR,
                                            (uint8_t*)pReqDeleteSDR, sizeof(DeleteSDRReq_T),
                                            (uint8_t *)pResDeleteSDR, &dwResLen,
                                            timeout);

    return wRet;
}


/* Clear SDR Repository Command */
  uint16_t    IPMICMD_ClearSDRRepository( IPMI20_UDS_SESSION_T *pUDSSession,
                                    ClearSDRReq_T *pReqClearSDR,
                                    ClearSDRRes_T *pResClearSDR,
                                    int timeout)
{
    uint16_t    wRet;
    uint32_t    dwResLen;

    dwResLen = sizeof(ClearSDRRes_T);
    wRet = LIBIPMI_Send_RAW_IPMI2_0_Command(pUDSSession,  
                                            NETFNLUN_IPMI_STORAGE, CMD_CLEAR_SDR_REPOSITORY,
                                            (uint8_t*)pReqClearSDR, sizeof(ClearSDRReq_T),
                                            (uint8_t *)pResClearSDR, &dwResLen,
                                            timeout);

    return wRet;
}


/* Get SDR Repository Time Command */
  uint16_t    IPMICMD_GetSDRRepositoryTime( IPMI20_UDS_SESSION_T *pUDSSession,
                                    GetSDRRepositoryTimeRes_T *pResGetSDRRepositoryTime,
                                    int timeout)
{
    uint8_t    Req[20];
    uint16_t    wRet;
    uint32_t    dwResLen;

    dwResLen = sizeof(GetSDRRepositoryTimeRes_T);
    wRet = LIBIPMI_Send_RAW_IPMI2_0_Command(pUDSSession,  
                                            NETFNLUN_IPMI_STORAGE, CMD_GET_SDR_REPOSITORY_TIME,
                                            (uint8_t*)Req, 0,
                                            (uint8_t *)pResGetSDRRepositoryTime, &dwResLen,
                                            timeout);

    return wRet;
}


/* Set SDR Repository Time Command */
  uint16_t    IPMICMD_SetSDRRepositoryTime( IPMI20_UDS_SESSION_T *pUDSSession,
                                    SetSDRRepositoryTimeReq_T *pReqSetSDRRepositoryTime,
                                    uint8_t *pResSetSDRRepositoryTime,
                                    int timeout)
{
    uint16_t    wRet;
    uint32_t    dwResLen;

    dwResLen = sizeof(uint8_t);
    wRet = LIBIPMI_Send_RAW_IPMI2_0_Command(pUDSSession,  
                                            NETFNLUN_IPMI_STORAGE, CMD_SET_SDR_REPOSITORY_TIME,
                                            (uint8_t*)pReqSetSDRRepositoryTime, sizeof(SetSDRRepositoryTimeReq_T),
                                            (uint8_t *)pResSetSDRRepositoryTime, &dwResLen,
                                            timeout);

    return wRet;
}


/* Enter SDR Repository Update Mode Command */
  uint16_t    IPMICMD_EnterSDRUpdateMode( IPMI20_UDS_SESSION_T *pUDSSession,
                                    EnterSDRUpdateModeRes_T *pResEnterSDRUpdateMode,
                                    int timeout)
{
    uint8_t    Req[20];
    uint16_t    wRet;
    uint32_t    dwResLen;

    dwResLen = sizeof(EnterSDRUpdateModeRes_T);
    wRet = LIBIPMI_Send_RAW_IPMI2_0_Command(pUDSSession,  
                                            NETFNLUN_IPMI_STORAGE, CMD_ENTER_SDR_REPOSITORY_UPDATE_MODE,
                                            (uint8_t*)Req, 0,
                                            (uint8_t *)pResEnterSDRUpdateMode, &dwResLen,
                                            timeout);

    return wRet;
}

/* Exit SDR Repository Update Mode Command */
  uint16_t    IPMICMD_ExitSDRUpdateMode( IPMI20_UDS_SESSION_T *pUDSSession,
                                    ExitSDRUpdateModeRes_T *pResExitSDRUpdateMode,
                                    int timeout)
{
    uint8_t    Req[20];
    uint16_t    wRet;
    uint32_t    dwResLen;

    dwResLen = sizeof(ExitSDRUpdateModeRes_T);
    wRet = LIBIPMI_Send_RAW_IPMI2_0_Command(pUDSSession,  
                                            NETFNLUN_IPMI_STORAGE, CMD_EXIT_SDR_REPOSITORY_UPDATE_MODE,
                                            (uint8_t*)Req, 0,
                                            (uint8_t *)pResExitSDRUpdateMode, &dwResLen,
                                            timeout);

    return wRet;
}

/* Run Initialization Agent Command */
  uint16_t    IPMICMD_RunInitAgent( IPMI20_UDS_SESSION_T *pUDSSession,
                                    RunInitAgentReq_T *pReqRunInitAgent,
                                    RunInitAgentRes_T *pResRunInitAgent,
                                    int timeout)
{
    uint16_t    wRet;
    uint32_t    dwResLen;

    dwResLen = sizeof(RunInitAgentRes_T);
    wRet = LIBIPMI_Send_RAW_IPMI2_0_Command(pUDSSession,  
                                            NETFNLUN_IPMI_STORAGE, CMD_RUN_INITIALIZATION_AGENT,
                                            (uint8_t*)pReqRunInitAgent, sizeof(RunInitAgentReq_T),
                                            (uint8_t *)pResRunInitAgent, &dwResLen,
                                            timeout);

    return wRet;
}


/***************** High level SDR commands *********************/
static uint16_t ipmb_get_sdr( IPMI20_UDS_SESSION_T *pUDSSession,
                                              uint16_t reservation_id,
                                              uint16_t record_id,
                          GetSDRRes_T *pGetSDRRes,
                          uint32_t *dwRecordLen,
                                              int timeout )
{
#define IPMB_SDR_MAX_SINGLE_READ    (22)    //32 bytes - ipmb message header - response header - checksum2
    uint8_t offset = (uint8_t)0;
    uint8_t remaining_bytes;
    uint8_t bytes_to_read;
    uint32_t dwRetLen;
    uint16_t wRet;
    
    uint8_t data_buffer[255];
    GetSDRReq_T get_sdr_req;
    SDRRecHdr_T *sdr_record;
    
    uint8_t *output_buffer;
    uint32_t    output_buffer_ix=0;
    
    output_buffer = (uint8_t *)pGetSDRRes;
    
    /* Find the record length first */
    get_sdr_req.ReservationID =  (reservation_id);
    get_sdr_req.RecID =  ( record_id );
    get_sdr_req.Offset = 0;
    get_sdr_req.Size = sizeof(SDRRecHdr_T);
    dwRetLen = sizeof(SDRRecHdr_T) + sizeof(GetSDRRes_T);
    wRet = IPMICMD_GetSDR( pUDSSession, &get_sdr_req, (GetSDRRes_T *)&data_buffer[0],
            &dwRetLen, timeout );
    
    if(wRet != LIBIPMI_E_SUCCESS)
        return wRet;
        
    /* We got record length. Now we read the record */
    sdr_record = (SDRRecHdr_T*)&data_buffer[sizeof(GetSDRRes_T)];
    offset = sizeof(SDRRecHdr_T);
    remaining_bytes = sdr_record->Len;
    
    /* copy to output buffer */
    memcpy(&output_buffer[output_buffer_ix], data_buffer, dwRetLen);
    output_buffer_ix += dwRetLen;
    
    do {
        bytes_to_read = (remaining_bytes > IPMB_SDR_MAX_SINGLE_READ)? IPMB_SDR_MAX_SINGLE_READ : remaining_bytes;
        
        get_sdr_req.ReservationID =  (reservation_id);
        get_sdr_req.RecID =  ( record_id );
        get_sdr_req.Offset = offset;
        get_sdr_req.Size = bytes_to_read;
        dwRetLen = bytes_to_read + sizeof(GetSDRRes_T);
        wRet = IPMICMD_GetSDR( pUDSSession, &get_sdr_req, (GetSDRRes_T*)&data_buffer[0],
                &dwRetLen, timeout );
        
        if(wRet != LIBIPMI_E_SUCCESS)
            return wRet;
        
        memcpy(&output_buffer[output_buffer_ix], &data_buffer[sizeof(GetSDRRes_T)], bytes_to_read);
        output_buffer_ix += bytes_to_read;
        
        offset += bytes_to_read;
        remaining_bytes -= bytes_to_read;
    
    }while( remaining_bytes > 0 );
    
    sdr_record = (SDRRecHdr_T*)&output_buffer[sizeof(GetSDRRes_T)];
    *dwRecordLen = sdr_record->Len + sizeof(SDRRecHdr_T);

    return LIBIPMI_E_SUCCESS;   
}

  uint16_t LIBIPMI_HL_GetSDR( IPMI20_UDS_SESSION_T *pUDSSession,
                                              uint16_t reservation_id,
                                              uint16_t record_id,
                          GetSDRRes_T *pGetSDRRes,
                          uint32_t *dwDataLen,
                                              int timeout )
{
    uint16_t    wRet=LIBIPMI_E_SUCCESS;
    
    GetSDRReq_T get_sdr_req;
        
    get_sdr_req.ReservationID =  (reservation_id);
    get_sdr_req.RecID =  ( record_id );
    get_sdr_req.Offset = 0;
    get_sdr_req.Size = 0xff;
    wRet = IPMICMD_GetSDR( pUDSSession, &get_sdr_req, pGetSDRRes,
                       dwDataLen, timeout );

    return wRet;    
}

uint16_t IPMC_GetSDR( IPMI20_UDS_SESSION_T *pUDSSession, uint8_t IpmbAddr,
                                              uint16_t reservation_id,
                                              uint16_t record_id,
                          GetSDRRes_T *pGetSDRRes,
                          uint32_t *dwDataLen,
                                              int timeout )
{
    int wRet = 0;
    uint32_t    dwResLen;
    uint8_t     Req[50] = {0};
    uint8_t     Res[100] = {0};

    //first do a SEL reservation
    Req[0] = 0x40;  //Track | channel 0
    Req[1] = IpmbAddr;
    Req[2] = NETFNLUN_IPMI_STORAGE;
    Req[3] = 0x100 - (Req[1] + Req[2])&0xff;    //checksum1
    Req[4] = 0x20;
    Req[5] = 0x10;
    Req[6] = CMD_GET_SDR;   
    Req[7] = reservation_id&0xff;
    Req[8] = (reservation_id>>8)&0xff;
    Req[9] = (record_id)&0xff;
    Req[10] = (record_id>>8)&0xff;
    Req[11] = 0;    //offset
    Req[12] = 0xff; //size
    Req[13] = 0x100 - (Req[4] + Req[5] + Req[6] + Req[7] + Req[8] + Req[9] + Req[10] + Req[11] + Req[12])&0xff;

    wRet = LIBIPMI_Send_RAW_IPMI2_0_Command(pUDSSession,  
                            NETFNLUN_IPMI_APP, CMD_SEND_MSG,
                            Req, 14,
                            Res,  &dwResLen,
                            timeout);
    // printf("======> ");
    // int i;
    // for(i=0;i<dwResLen;i++)
    //     printf("%#x ", Res[i]);
    // printf("\n");

    if((wRet != 0) || (Res[6] != 0))
    {
        printf("IPMC_GetSDR!\n");
        return -1;
    }

    *dwDataLen = dwResLen - 7;
    memcpy(pGetSDRRes, &Res[6], *dwDataLen);
    return wRet;    
}

  uint16_t Storlead_GetCompleteSDR( IPMI20_UDS_SESSION_T *pUDSSession, uint8_t IpmbAddr,
                                              uint16_t record_id,
                                              uint16_t *next_record_id,
                                              uint8_t *sdr_buffer,
                                              size_t buffer_len,
                                              int timeout )
{
    uint16_t wRet;
    ReserveSDRRepositoryRes_T reservation;
    SDRRepositoryAllocInfo_T alloc_info;
    uint8_t *temp_buffer;
    GetSDRRes_T *get_sdr_res;
    uint32_t blen = 0;
    int max_sdr_len;

    /* Get repository allocation information */
    if(IpmbAddr == 0x20)
    {
        wRet = IPMICMD_GetSDRRepositoryAllocInfo( pUDSSession, &alloc_info, timeout );
    }
    else
    {
        wRet = IPMC_GetSDRRepositoryAllocInfo( pUDSSession, IpmbAddr, &alloc_info, timeout );   
    }
    if( wRet != LIBIPMI_E_SUCCESS )
        return( wRet );
    
    reservation.ReservationID = 0; //Setting reservation ID as zero as we are trying to get complete SDR.
    
    /* Determine max SDR entry length */
    max_sdr_len = alloc_info.MaxRecSize *  ( alloc_info.AllocUnitSize );

    /* Make sure the calling function has space for this thing */
    if( buffer_len < (size_t) max_sdr_len )
        return( STATUS_CODE( IPMI_ERROR_FLAG, OEMCC_NOMEM ) );

    
    temp_buffer = (uint8_t*)walloc( max_sdr_len + sizeof( GetSDRRes_T ) );
    if( temp_buffer == NULL )
        return( STATUS_CODE( IPMI_ERROR_FLAG, OEMCC_NOMEM ) );
    
    get_sdr_res = (GetSDRRes_T *)temp_buffer;
    if(IpmbAddr == 0x20)
    {
        wRet = LIBIPMI_HL_GetSDR(pUDSSession,  (reservation.ReservationID),
                        record_id, (GetSDRRes_T *)temp_buffer, &blen, timeout);
    }
    else
    {
        wRet = IPMC_GetSDR(pUDSSession,  IpmbAddr, (reservation.ReservationID),
                        record_id, (GetSDRRes_T *)temp_buffer, &blen, timeout);
    }
    if( wRet != LIBIPMI_E_SUCCESS )
    {
        printf("---> LIBIPMI_HL_GetSDR error!\n");
        wfree( temp_buffer );
        return( wRet );
    }

    *next_record_id =  ( get_sdr_res->NextRecID );

    memcpy( sdr_buffer, temp_buffer + sizeof( GetSDRRes_T ), blen );
    wfree( temp_buffer );

    return( wRet );
}

//LIBIPMI_HL_GetAllSDRs
  uint16_t Storlead_GetAllSDRs( IPMI20_UDS_SESSION_T *pUDSSession, uint8_t IpmbAddr,
                                          uint8_t *sdr_buffer, size_t buffer_len,
                                          int timeout )
{
    uint16_t wRet;
    uint16_t record_id = 0;
    int max_sdr_len;
    int sdr_count;
    SDRRepositoryAllocInfo_T alloc_info;
    SDRRepositoryInfo_T repo_info;
    int i;

    /* Get repository allocation information */
    if(IpmbAddr == 0x20)
    {
        wRet = IPMICMD_GetSDRRepositoryAllocInfo( pUDSSession, &alloc_info, timeout );
    }
    else
    {
        wRet = IPMC_GetSDRRepositoryAllocInfo( pUDSSession, IpmbAddr, &alloc_info, timeout );   
    }
    if( wRet != LIBIPMI_E_SUCCESS )
        return( wRet );

    /* Get repository information */
    if(IpmbAddr == 0x20)
    {    
        wRet = IPMICMD_GetSDRRepositoryInfo( pUDSSession, &repo_info, timeout );
    }
    else
    {
        wRet = IPMC_GetSDRRepositoryInfo( pUDSSession, IpmbAddr, &repo_info, timeout );
    }
    if( wRet != LIBIPMI_E_SUCCESS )
        return( -1 );

    /* Determine max SDR entry length */
    max_sdr_len = alloc_info.MaxRecSize *  ( alloc_info.AllocUnitSize );

    /* Determine total number of SDRs stored */
    sdr_count =  ( repo_info.RecCt );

    /* Make sure the passed buffer is large enough */
    if( buffer_len < (size_t) ( max_sdr_len * sdr_count ) )
        return( STATUS_CODE( IPMI_ERROR_FLAG, OEMCC_NOMEM ) );

    //printf("---> LIBIPMI_HL_GetAllSDRs, max_sdr_len: %d, sdr_count: %d\n", max_sdr_len, sdr_count);
    /* Read all the SDRs in this loop */
    for( i = 0; i < sdr_count; i++ )
    {
        uint16_t next_record_id;

        /* Read the full SDR into the buffer */
        wRet = Storlead_GetCompleteSDR( pUDSSession, IpmbAddr, record_id, &next_record_id,
                                          &sdr_buffer[ i * max_sdr_len ],
                                          max_sdr_len, timeout );
        //printf("---> i: %d, record_id: %d, next_record_id: %d\n", i, record_id, next_record_id);
        if( wRet != LIBIPMI_E_SUCCESS )
            return( wRet );

        record_id = next_record_id;
    }

    return( wRet );
}

//int CacheGetAllSDRS(IPMI20_UDS_SESSION_T* pUDSSession,uint8_t* sdr_buffer,uint32_t* buff_size,uint32_t* max_sdr_len,uint32_t* sdr_count);

  uint16_t LIBIPMI_HL_GetAllSDRs_Cached( IPMI20_UDS_SESSION_T *pUDSSession,
                                          uint8_t *sdr_buffer, 
                                          uint32_t* sdr_buff_size,
                                          uint32_t* max_sdr_len,
                                          uint32_t * sdr_count,
                                          int timeout )
{
    uint16_t wRet;

//  wRet = CacheGetAllSDRS(pUDSSession,sdr_buffer,sdr_buff_size,max_sdr_len,sdr_count);

    
    return wRet;
}

  uint16_t LIBIPMI_HL_GetSpecificSDR( IPMI20_UDS_SESSION_T *pUDSSession,
                                                uint8_t *sdr_buffer, 
                                                uint32_t* sdr_buff_size,
                                                int SensorNumber,
                                                int timeout )
{
    ReserveSDRRepositoryRes_T ResReserveSDRRepository;
    uint8_t *data_buffer = walloc(255);
    FullSensorRec_T *sdr_record = (FullSensorRec_T*) &data_buffer[sizeof(GetSDRRes_T)];
    GetSDRReq_T ReqGetSDR;
    GetSDRRes_T *pResGetSDR = (GetSDRRes_T *) &data_buffer[0];
    uint32_t      dwRetLen = 255;   //sizeof(data_buffer);
    int wRet = 0;
    
    wRet = IPMICMD_ReserveSDRRepository(pUDSSession, &ResReserveSDRRepository, timeout);
        
    pResGetSDR->NextRecID = 0;
    while (1)
    {
        ReqGetSDR.ReservationID = ResReserveSDRRepository.ReservationID;
        ReqGetSDR.RecID = pResGetSDR->NextRecID;
        ReqGetSDR.Offset = 0;
        ReqGetSDR.Size = 0xff;
        wRet = IPMICMD_GetSDR(pUDSSession, &ReqGetSDR, pResGetSDR, &dwRetLen, timeout);
        //TODO: IPMICMD_GetSDR replaced by LIBIPMI_HL_GetSDR, by jimbo
        //wRet = LIBIPMI_HL_GetSDR(pUDSSession, ReqGetSDR.ReservationID, ReqGetSDR.RecID, pResGetSDR, &dwRetLen, timeout );
        if (wRet != LIBIPMI_E_SUCCESS)
        {
            printf("Get SDR error!\n");
            break;
        }
        
        if (sdr_record->SensorNum == SensorNumber)
        {
            //printf("Find %d: %s\n", sdr_record->SensorNum , sdr_record->IDStr);
            break;  // found
        }
    }
    
    dwRetLen -= sizeof(GetSDRRes_T);
    *sdr_buff_size = *sdr_buff_size >= dwRetLen ? dwRetLen : *sdr_buff_size;
    memcpy(sdr_buffer, sdr_record, *sdr_buff_size);

    //printf("sdr_buff_size: %d\n", *sdr_buff_size);
        
    wfree(data_buffer);
    return wRet;
}

