Board Management Controller (BMC) Proxy Driver

Overview

MCTP - Management Component Transport Protocol

PLDM - Platform Level Data Model

The BMC proxy allows for communication and sensor management between the BMC and AMC through MCTP/PLDM protocols. The BMC proxy is polling indefinitely and listening for incoming messages through a FAL read call. If a message is received, an internal flag is set that will start the processing of the message. The proxy calls into the MCTP code to determine whether the message is an MCTP, PLDM Type 0 or PLDM Type 2 form which will determine the exact command. The PLDM code will then form a response to the initial request, which gets sent back to the BMC via a firmware interface write by the BMC proxy driver.

Note:

The MCTP/PLDM code provided is intended to be used and an example to prove the basic functionality of a BMC stack. AMC only supports Type 0 and Type 2 DMTF messages (limited to sensor reading - i.e. no effecters).

image1

Supported commands

M - Mandatory

O - Optional

C - Conditional

Command NameCommand CodeDMTF Spec

M/O/C
Set Endpoint ID    0x01M
Get Endpoint ID    0x02M
Get Endpoint UUID    0x03M
Get MCTP Version Support    

0x04

M
Get Message Type support    0x05M
Command NameCommand CodeDMTF Spec

M/O/C
SetTID 0x01M
GetTID0x02M
GetPLDMVersion0x03M
GetPLDMTypes

0x04

M
GetPLDMCommands    0x05M
Command NameCommand CodeDMTF Spec

M/O/C
SetTID 0x01M
GetTID0x02M
SetNumericSensorEnable0x10M
GetSensorReading

0x11

M
GetPDRRepositoryInfo0x50M
GetPDR0x51M

Supported PDRs

PDR Type NumberPDR Type Name
1Terminus Locator PDR
2Numeric Sensor PDR
6Sensor Auxiliary Names PDR 

Internal APIs

BMC accepted events.

BMC_PROXY_DRIVER_EVENTS

/**
 * @enum    BMC_PROXY_DRIVER_EVENTS
 * @brief   Events raised by this proxy driver
 */
typedef enum BMC_PROXY_DRIVER_EVENTS
{
    BMC_PROXY_DRIVER_E_MSG_ARRIVAL = 0,
    BMC_PROXY_DRIVER_E_GET_PDR,
    BMC_PROXY_DRIVER_E_GET_PDR_REPOSITORY_INFO,
    BMC_PROXY_DRIVER_E_GET_SENSOR_INFO,
    BMC_PROXY_DRIVER_E_ENABLE_SENSOR,
    BMC_PROXY_DRIVER_E_INVALID_REQUEST_RECVD,
    MAX_BMC_PROXY_DRIVER_EVENTS

} BMC_PROXY_DRIVER_EVENTS;

Response result IDs.

BMC_PROXY_RESULT

/**
 * @enum    BMC_PROXY_RESPONSE_RESULT
 * @brief   The response result
 */
typedef enum BMC_PROXY_RESULT
{
    BMC_PROXY_RESULT_SUCCESS = 0,
    BMC_PROXY_RESULT_FAILURE,
    MAX_BMC_PROXY_RESULT

} BMC_PROXY_RESULT;

Response IDs.

BMC_SENSOR_RESPONSE

/**
 * @enum    BMC_SENSOR_RESPONSE
 * @brief   The response
 */
typedef enum BMC_SENSOR_RESPONSE
{
    BMC_RESPONSE_OK = 0,
    BMC_RESPONSE_ERROR,
    MAX_BMC_SENSOR_RESPONSE

} BMC_SENSOR_RESPONSE;

Enable sensor response IDs.

BMC_SET_NUMERIC_SENSOR_ENABLE_RESPONSE

/**
 * @enum    BMC_SET_NUMERIC_SENSOR_ENABLE_RESPONSE
 * @brief   The response
 */
typedef enum BMC_SET_NUMERIC_SENSOR_ENABLE_RESPONSE
{
    BMC_SENSOR_ENABLE_RESP_OK = 0,
    BMC_SENSOR_ENABLE_RESP_INVALID_SENSOR_ID,
    BMC_SENSOR_ENABLE_RESP_INVALID_SENSOR_OPERATIONAL_STATE,
    BMC_SENSOR_ENABLE_RESP_EVENT_GENERATION_NOT_SUPPORTED,
    BMC_SENSOR_ENABLE_RESP_NONE,
    MAX_BMC_SENSOR_ENABLE_RESP

} BMC_SET_NUMERIC_SENSOR_ENABLE_RESPONSE;

Get sensor response IDs.

BMC_GET_SENSOR_RESPONSE

/**
 * @enum    BMC_GET_SENSOR_RESPONSE
 * @brief   The response
 */
typedef enum BMC_GET_SENSOR_RESPONSE
{
    BMC_GET_SENSOR_RESP_OK = 0,
    BMC_GET_SENSOR_RESP_INVALID_SENSOR_ID,
    BMC_GET_SENSOR_RESP_INVALID_SENSOR_OPERATIONAL_STATE,
    BMC_GET_SENSOR_RESP_REARM_UNAVAILABLE_IN_PRESENT_STATE,
    BMC_GET_SENSOR_RESP_NONE,
    MAX_BMC_GET_SENSOR_RESP

} BMC_GET_SENSOR_RESPONSE;

The initialize function takes in 15 parameters:

  • The unique ID of the proxy driver

  • Pointer to the firmware interface the proxy uses

  • The port of the firmware interface

  • The priority of the task

  • Pointer to the list of temperature sensor PDRs

  • Pointer to the list of voltage sensor PDRs

  • Pointer to the list of current sensor PDRs

  • Pointer to the list of power sensor PDRs

  • Pointer to the list of names sensor PDRs

  • Total number of PDRs in the respective lists


iBMC_Initialise

/**
 * @brief   Main initialisation point for the BMC Proxy Driver
 *
 * @param   ucProxyId   Unique ID for this Proxy driver
 * @param   pxFwIf      Handle to the Firmware Interface to use
 * @param   ulFwIfPort  Port to use on the Firmware Interface
 * @param   ulTaskPrio  Priority of the Proxy driver task (if RR disabled)
 * @param   ulTaskStack Stack size of the Proxy driver task
 * @param   pxPdrTemperatureSensors Pointer to Temperature PDR
 * @param   iTotalPdrTemperature Size of Temperature PDR
 * @param   pxPdrVoltageSensors Pointer to Voltage PDR
 * @param   iTotalPdrVoltage Size of Voltage PDR
 * @param   pxPdrCurrentSensors Pointer to Current PDR
 * @param   iTotalPdrCurrent Size of Current PDR
 * @param   pxPdrPowerSensors Pointer to Power PDR
 * @param   iTotalPdrPower Size of Power PDR
 * @param   pxPdrSensorNames Pointer to Sensor Names PDR
 * @param   iTotalPdrName Size of Sensor Names PDR
 * @param   pucUuid Pointer to UUID
 *
 * @return  OK          Proxy driver initialised correctly
 *          ERROR       Proxy driver not initialised, or was already initialised
 *
 * @note    Proxy drivers can have 0 or more firmware interfaces
 */
int iBMC_Initialise( uint8_t ucProxyId,
                     FW_IF_CFG *pxFwIf,
                     uint32_t ulFwIfPort,
                     uint32_t ulTaskPrio,
                     uint32_t ulTaskStack,
                     PLDM_NUMERIC_SENSOR_PDR *pxPdrTemperatureSensors,
                     int iTotalPdrTemperature,
                     PLDM_NUMERIC_SENSOR_PDR *pxPdrVoltageSensors,
                     int iTotalPdrVoltage,
                     PLDM_NUMERIC_SENSOR_PDR *pxPdrCurrentSensors,
                     int iTotalPdrCurrent,
                     PLDM_NUMERIC_SENSOR_PDR *pxPdrPowerSensors,
                     int iTotalPdrPower,
                     PLDM_NUMERIC_SENSOR_NAME_PDR *pxPdrSensorNames,
                     int iTotalPdrName,
                     uint8_t *pucUuid );

Applications can bind into the callback to listen to incoming events and handle them accordingly.

Current list of supported events:

  • BMC_PROXY_DRIVER_E_SMBUS_MSG_ARRIVAL

  • BMC_PROXY_DRIVER_E_GET_PDR

  • BMC_PROXY_DRIVER_E_GET_PDR_REPOSITORY_INFO

  • BMC_PROXY_DRIVER_E_GET_SENSOR_INFO

  • BMC_PROXY_DRIVER_E_ENABLE_SENSOR

  • BMC_PROXY_DRIVER_E_INVALID_REQUEST_RECVD

iBMC_BindCallback

/**
 * @brief   Bind into this proxy driver
 *
 * @param   pxCallback  Callback to bind into the proxy driver
 *
 * @return  OK          Callback successfully bound
 *          ERROR       Callback not bound
 */
int iBMC_BindCallback( EVL_CALLBACK *pxCallback );

Function used to respond to the BMC_PROXY_DRIVER_E_GET_SENSOR_INFO event.

iBMC_SendResponseForGetSensor

/**
 * @brief   Response to a Sensor Info request
 *
 * @param   pxSignal        Current event occurence (used for tracking)
 * @param   usSensorId      Sensor Id
 * @param   ssSensorInfo    Sensor Value
 * @param   ucSensorState   Sensor Operational State
 * @param   xSensorResponse The response to the sensor query, OK, Invalid ID etc
 *
 * @return  OK          Command was successful
 *          ERROR       Command failed
 */
int iBMC_SendResponseForGetSensor( EVL_SIGNAL *pxSignal,
                                   uint16_t usSensorId,
                                   int16_t ssSensorInfo,
                                   uint8_t ucSensorState,
                                   BMC_GET_SENSOR_RESPONSE xSensorResponse );

Responds back to a request from the proxy to enable a sensor.

iBMC_SetResponse

/**
* @brief Response to an enable sensor request
*
* @param pxSignal Current event occurence (used for tracking)
* @param xBmcResponse Enable sensor response
*
* @return OK Command was successful
* ERROR Command failed
*/
int iBMC_SetResponse( EVL_SIGNAL *pxSignal, uint16_t usSensorId, BMC_SENSOR_RESPONSE xBmcResponse );

Returns the board UUID

iBMC_GetUuid

/**
 * @brief   Get the UUID
 *
 * @param   pucUuid   pointer to UUID location
 *
 * @return  OK or ERROR
 */
int iBMC_GetUuid( uint8_t * pucUuid );

If a BMC_PROXY_DRIVER_E_GET_SENSOR_INFO event is received, the application can call iBMC_GetSensorIdRequest to get more information about the request like the sensor ID and operational state.

iBMC_GetSensorIdRequest

/**
 * @brief   Function called after certain events are raised to get the sensor id
 *
 * @param   pxSignal            pointer to signal raised
 * @param   pusSensorId         pointer sensor id
 * @param   pucOperationalState pointer to the new state (if required)
 *
 * @return  OK or ERROR
 */
int iBMC_GetSensorIdRequest( EVL_SIGNAL *pxSignal, int16_t *pssSensorId, uint8_t *pucOperationalState );

Performs a FAL write with the supplied buffer and size.

iBMC_ResponseDataWrite

/**
 * @brief   Start a Data Write
 *
 * @param   pucData     Pointer to the data
 * @param   usDatasize  Size of data received
 *
 * @return  OK or ERROR
 */
int iBMC_ResponseDataWrite( uint8_t *pucData, uint16_t usDataSize );

Prints the statistics associated with the proxy.

iBMC_PrintStatistics

/**
 * @brief   Print all the stats gathered by the application
 *
 * @return  OK          Stats retrieved from proxy driver successfully
 *          ERROR       Stats not retrieved successfully
 *
 */
int iBMC_PrintStatistics( void );

Clears the statistics associated with the proxy.

iBMC_ClearStatistics

/**
 * @brief   Clear all the stats in the application
 *
 * @return  OK          Stats cleared successfully
 *          ERROR       Stats not cleared successfully
 *
 */
int iBMC_ClearStatistics( void );

Gets the current health state of the proxy.

iBMC_GetState

/**
* @brief Gets the current state of the proxy driver
*
* @param pxState Pointer to the state
*
* @return OK If successful
* ERROR If not successful
*/
int iBMC_GetState( MODULE_STATE *pxState );

BMC Proxy Handling Requests

The request API’s allows an application to get a copy of the internal proxy request data received via the FAL.

  • iBMC_GetSensorIdRequest

The requests data is stored within the BMC proxy when the event is generated and the callback has been invoked to notify any registered users.

When the request from the application is made a protected copy of the data is made and returned that will allow the user to perform the relevant action.

A global mutex is held until a MCTP message is processed and response created. Any BMC request calls that change private data are within the flow of that message making them protected.

image2

BMC Proxy Handling Responses

The response API’s are used by the application to respond back to the request with data/result code once the relevant action has been performed.

  • iBMC_SetResponse

  • iBMC_GetSensorInfoResponse

Within each response a the relevant flag is set, signaling to the proxy that the event has been handled and the requested data is available.

A global mutex is held until a MCTP message is processed and response created. Any BMC response calls that change private data are within the flow of that message making them protected.

Examples

The initialize function needs a unique id for the proxy, a handle to a FW_IF (already created and initialized), and a task priority/size passed in, as well as the PDR sensor lists and total values.

iBMC_Initialise Example

if( OK == iBMC_Initialise( AMC_EVENT_UNIQUE_ID_BMC, &xSMBusIf, 0, AMC_TASK_PRIO_DEFAULT, AMC_TASK_DEFAULT_STACK,
                               pxPdrTemperatureSensors, TOTAL_PDR_TEMPERATURE,
                               pxPdrVoltageSensors,     TOTAL_PDR_VOLTAGE,
                               pxPdrCurrentSensors,     TOTAL_PDR_CURRENT,
                               pxPdrPowerSensors,       TOTAL_PDR_POWER,
                               pxPdrSensorNames,        TOTAL_PDR_NUMERIC_ASCI_SENSORS ) )

Define a function based on the function pointer prototype and bind in using the API.

iBMC_Initialise Example

/**
 * @brief   BMC Proxy Driver EVL callback
 */
static int iBmcCallback( EVL_SIGNAL *pxSignal )
{
    int iStatus = ERROR;

    if( ( NULL != pxSignal ) && ( AMC_EVENT_UNIQUE_ID_BMC == pxSignal->ucModule ) )
    {
        switch( pxSignal->ucEventType )
        {
        default:
        {
            break;
        }
        }
    }

    return iStatus;
}

Example of calling the response (iBMC_GetSensorInfoResponse) from within the callback to send the result back to the proxy.

BMC_PRIVATE_DATA

/**
 * @brief   RMI Handler EVL callback
 */
static int iBmcProxyCallback( EVL_SIGNAL *pxSignal )
{
    int iStatus = ERROR;

    if( ( NULL != pxSignal ) && ( AMC_EVENT_UNIQUE_ID_BMC == pxSignal->ucModule ) )
    {
        if( MAX_BMC_PROXY_DRIVER_EVENTS >= pxSignal->ucEventType )
        {
            switch( pxSignal->ucEventType )
            {

            case BMC_PROXY_DRIVER_E_GET_PDR:
            {
                INC_STAT_COUNTER( OUT_OF_BAND_STATS_BMC_PDR_REQUEST )
                break;
            }

            case BMC_PROXY_DRIVER_E_GET_PDR_REPOSITORY_INFO:
            {
                INC_STAT_COUNTER( OUT_OF_BAND_STATS_BMC_PDR_INFO_REQUEST )
                break;
            }

            case BMC_PROXY_DRIVER_E_GET_SENSOR_INFO:
            {
                INC_STAT_COUNTER( OUT_OF_BAND_STATS_BMC_SENSOR_INFO_REQUEST )

                /* TODO: Get info on requested sensor */

                /* TODO: Set the result code based on the collection */

                iBMC_GetSensorInfoResponse( pxSignal,
                                            sSensorId,
                                            sSensorDataResponse,
                                            ucSensorOperationalState,
                                            xSensorResponse );

                break;
            }
            default:
            {
                INC_STAT_COUNTER( OUT_OF_BAND_STATS_BMC_UNSUPPORTED_REQUEST )
                break;
            }
            }

            iStatus = OK;
        }
    }

    return iStatus;
}

Example of requesting the data associated with an event (iBMC_GetSensorIdRequest) from within the callback and to send the result back to the proxy.

BMC_PRIVATE_DATA

/**
 * @brief   RMI Handler EVL callback
 */
static int iBmcProxyCallback( EVL_SIGNAL *pxSignal )
{
    int iStatus = ERROR;

    if( ( NULL != pxSignal ) && ( AMC_EVENT_UNIQUE_ID_BMC == pxSignal->ucModule ) )
    {
        if( MAX_BMC_PROXY_DRIVER_EVENTS >= pxSignal->ucEventType )
        {
            switch( pxSignal->ucEventType )
            {

            case BMC_PROXY_DRIVER_E_GET_PDR:
            {
                INC_STAT_COUNTER( OUT_OF_BAND_STATS_BMC_PDR_REQUEST )
                break;
            }

            case BMC_PROXY_DRIVER_E_GET_PDR_REPOSITORY_INFO:
            {
                INC_STAT_COUNTER( OUT_OF_BAND_STATS_BMC_PDR_INFO_REQUEST )
                break;
            }

            case BMC_PROXY_DRIVER_E_GET_SENSOR_INFO:
            {
                INC_STAT_COUNTER( OUT_OF_BAND_STATS_BMC_SENSOR_INFO_REQUEST )

                /* call into BMC Proxy to get required sensor id */
                iBMC_GetSensorIdRequest( pxSignal, &sSensorId, &ucSensorOperationalState )

                break;
            }
            default:
            {
                INC_STAT_COUNTER( OUT_OF_BAND_STATS_BMC_UNSUPPORTED_REQUEST )
                break;
            }
            }

            iStatus = OK;
        }
    }

    return iStatus;
}

Common PDR header

Structure to store the MCTP/PLDM common header, used in the response buffer.

TypeNameDescription
uint32recordHandleAn opaque number that is used for accessing individual PDRs within a PDR Repository.
uint8PDRHeaderVersionThis field is provided in case a future version of this specification requires a modification to the format of the PDR Header.
uint8PDRTypeThe type of the PDR.
uint16recordChangeNumberMechanism for preventing the use of invalid PDR data if a record's data gets updated while the record was in the process of being read out.
uint16dataLengthThe total number of PDR data bytes following this field. 

Numeric sensor PDR

Structure that represents a single numeric sensor PDR.

TypeNameDescription
uint16PLDMTerminusHandleA handle that identifies PDRs that belong to a particular PLDM terminus. 
uint16sensorIDID of the sensor relative to the given PLDM Terminus ID. 
uint16entityTypeThe Type value for the entity that is associated with this sensor.
uint16entityInstanceNumberThe Instance Number for the entity that is associated with this sensor. See 9.1 for more information. 
uint16containerIDThe containerID for the containing entity that instantiates the entity that is measured by this sensor.
uint8_tsensorInitIndicates whether the sensor requires initialization by the initializationAgent.
uint8_tsensorAuxiliaryNamesPDR

true =  sensor has a Sensor Auxiliary Names PDR

false = sensor does not have an associated Sensor Auxiliary Names PDR 

uint8_tbaseUnitThe base unit of the reading returned by this sensor.
int8_tunitModifierA power-of-10 multiplier for the baseUnit.
uint8_trateUnitvalue: { None, Per MicroSecond, Per MilliSecond, Per Second, Per Minute, Per Hour, Per Day, Per Week, Per Month, Per Year } 
uint8_tbaseOEMUnitHandleThis value is used to locate the corresponding PLDM OEM Unit PDR that defines the OEMUnit when the OEMUnit value is used for the baseUnit. 
uint8_tauxUnitThe base unit of the reading returned by this sensor.
int8_tauxUnitModifierA power-of-10 multiplier for the auxUnit.
uint8_tauxrateUnitvalue: { None, Per MicroSecond, Per MilliSecond, Per Second, Per Minute, Per Hour, Per Day, Per Week, Per Month, Per Year }
uint8_trelThe relationship between the base unit and the auxiliary unit.
uint8_tauxOEMUnitHandleThis value is used to locate the PLDM OEM Unit PDR that defines the OEMUnit if the OEMUnit value is used for the auxUnit. 
uint8_tisLinearIndicates whether a sensor is linear or dynamic in its range. For example, this value can be used by a MAP to populate the IsLinear attribute of CIM_NumericSensor. 
uint8_tsensorDataSizeThe bit width and format of reading and threshold values that the sensor returns value: { uint8, sint8, uint16, sint16, uint32, sint32 } 
floatresolutionThe resolution of the sensor in Units
floatoffsetA constant value that is added in as part of the conversion process of converting a raw sensor reading to Units
uint16_taccuracyGiven as a +/- percentage in 1/100ths of a % from 0.00 to 100.00. For example, the integer value 510 corresponds to ± 5.10%
uint8_tplusToleranceTolerance is given in +/- counts of the reading value.
uint8_tminusToleranceTolerance is given in +/- counts of the reading value.
int16_thysteresisThe amount of hysteresis associated with the sensor thresholds, given in raw sensor counts.
uint8_tsupportedThresholdsFor PLDM: bit field where bit position represents whether a given threshold is supported
uint8_tthresholdAndHysteresisVolatilityIdentifies under which conditions any threshold or hysteresis settings that were set through the SetSensorThresholds or SetSensorHysteresis command may be lost.
floatstateTransitionInterval How long the sensor device takes to do an enabledState change (worst case)
floatupdateIntervalPolling or update interval in seconds expressed using a floating point number (generally corresponds to the CIM PollingInterval property) 
int16_tmaxReadableThe maximum value that the sensor may return. The size of this field is given by the sensorDataSize field in this PDR.
int16_tminReadableThe minimum value that the sensor may return. The size of this field is given by the sensorDataSize field in this PDR. 
uint8_trangeFieldFormatIndicates the format used for the following nominalValue, normalMax, normalMin, criticalHigh, criticalLow, fatalHigh, and fatalLow fields.
uint8_trangeFieldSupportIndicates which of the fields that identify the operating ranges of the parameter monitored by the sensor are supported. (This bitfield indicates whether the following nominalValue, normalMax, and so on, fields contain valid range values.)  
int16_tnominalValueThis value presents the nominal value for the parameter that is monitored by the sensor. The size of this field is given by the rangeFieldFormat field in this PDR. This value is given directly in the specified units without the use of any conversion formula. 
int16_tnormalMaxThe upper limit of the normal operating range for the parameter that is monitored by the numeric sensor.
int16_tnormalMinThe lower limit of the normal operating range for the parameter that is monitored by the numeric sensor.
int16_twarningHighA warning condition that occurs when the monitored value is greater than the value reported by warningHigh.
int16_twarningLowA warning condition that occurs when the monitored value is less than or equal to the value reported by warningLow.
int16_tcriticalHighA critical condition that occurs when the monitored value is greater than or equal to the value reported by criticalHigh.
int16_tcriticalLowA critical condition that occurs when the monitored value is less than the value reported by criticalLow.
int16_tfatalHighA fatal condition that occurs when the monitored value is greater than the value reported by fatalHigh.
int16_tfatalLowA fatal condition that occurs when the monitored value is less than the value reported by fatalLow.

Sensor name PDR

Structure that stores the sensor names PDR.

TypeNameDescription
uint16PLDMTerminusHandleID of the sensor relative to the given PLDM terminus 
uint16sensorIDID of the sensor relative to the given PLDM terminus 
uint8sensorCount For each sensor x in sensorCount, there can be 1..nameStringCount[x] strings, where each set of strings corresponds to a sensor in a composite sensor.
uint8nameStringCountNumber of following pairs [0..N] of nameLanguageTag + sensorName fields for sensor[1]
uint8nameLanguageTagA null-terminated ISO646 ASCII string that holds a language tag.
uint8sensorNameA null-terminated unicode string for the auxiliary name of the sensor

Page Revision: v. 34