123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278 |
- /** @file
- Generic IPMI transport layer during PEI phase
- @copyright
- Copyright 2016 - 2021 Intel Corporation. <BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #include "PeiIpmiBmc.h"
- EFI_STATUS
- UpdateErrorStatus (
- IN UINT8 BmcError,
- PEI_IPMI_BMC_INSTANCE_DATA *IpmiInstance
- )
- /*++
- Routine Description:
- Check if the completion code is a Soft Error and increment the count. The count
- is not updated if the BMC is in Force Update Mode.
- Arguments:
- BmcError - Completion code to check
- IpmiInstance - BMC instance data
- Returns:
- EFI_SUCCESS - Status
- --*/
- {
- UINT8 Errors[] = COMPLETION_CODES;
- UINT16 CodeCount;
- UINT8 i;
- CodeCount = sizeof (Errors) / sizeof (Errors[0]);
- for (i = 0; i < CodeCount; i++) {
- if (BmcError == Errors[i]) {
- //
- // Don't change Bmc Status flag if the BMC is in Force Update Mode.
- //
- if (IpmiInstance->BmcStatus != BMC_UPDATE_IN_PROGRESS) {
- IpmiInstance->BmcStatus = BMC_SOFTFAIL;
- }
- IpmiInstance->SoftErrorCount++;
- break;
- }
- }
- return EFI_SUCCESS;
- }
- EFI_STATUS
- PeiIpmiSendCommandToBmc (
- IN PEI_IPMI_TRANSPORT_PPI *This,
- IN UINT8 NetFunction,
- IN UINT8 Lun,
- IN UINT8 Command,
- IN UINT8 *CommandData,
- IN UINT8 CommandDataSize,
- IN OUT UINT8 *ResponseData,
- IN OUT UINT8 *ResponseDataSize,
- IN VOID *Context
- )
- /*++
- Routine Description:
- Send IPMI command to BMC
- Arguments:
- This - Pointer to IPMI protocol instance
- NetFunction - Net Function of command to send
- Lun - LUN of command to send
- Command - IPMI command to send
- CommandData - Pointer to command data buffer, if needed
- CommandDataSize - Size of command data buffer
- ResponseData - Pointer to response data buffer
- ResponseDataSize - Pointer to response data buffer size
- Context - Context
- Returns:
- EFI_INVALID_PARAMETER - One of the input values is bad
- EFI_DEVICE_ERROR - IPMI command failed
- EFI_BUFFER_TOO_SMALL - Response buffer is too small
- EFI_UNSUPPORTED - Command is not supported by BMC
- EFI_SUCCESS - Command completed successfully
- --*/
- {
- PEI_IPMI_BMC_INSTANCE_DATA *IpmiInstance;
- UINT8 DataSize;
- EFI_STATUS Status;
- IPMI_COMMAND *IpmiCommand;
- IPMI_RESPONSE *IpmiResponse;
- UINT8 Index;
- UINT8 TempData[MAX_TEMP_DATA];
- IpmiInstance = INSTANCE_FROM_PEI_SM_IPMI_BMC_THIS (This);
- //
- // The TempData buffer is used for both sending command data and receiving
- // response data. Since the command format is different from the response
- // format, the buffer is cast to both structure definitions.
- //
- IpmiCommand = (IPMI_COMMAND*) TempData;
- IpmiResponse = (IPMI_RESPONSE*) TempData;
- //
- // Send IPMI command to BMC
- //
- IpmiCommand->Lun = Lun;
- IpmiCommand->NetFunction = NetFunction;
- IpmiCommand->Command = Command;
- //
- // Ensure that the buffer is valid before attempting to copy the command data
- // buffer into the IpmiCommand structure.
- //
- if (CommandDataSize > 0) {
- if (CommandData == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- CopyMem (
- IpmiCommand->CommandData,
- CommandData,
- CommandDataSize
- );
- }
- Status = SendDataToBmcPort (
- IpmiInstance->KcsTimeoutPeriod,
- IpmiInstance->IpmiIoBase,
- Context,
- (UINT8 *) IpmiCommand,
- (CommandDataSize + IPMI_COMMAND_HEADER_SIZE)
- );
- if (Status != EFI_SUCCESS) {
- IpmiInstance->BmcStatus = BMC_SOFTFAIL;
- IpmiInstance->SoftErrorCount++;
- DEBUG ((EFI_D_ERROR, "PEI Phase SendDataToBmcPort failed Status:%r\n", Status));
- return Status;
- }
- //
- // Get Response to IPMI Command from BMC.
- //
- DataSize = MAX_TEMP_DATA;
- Status = ReceiveBmcDataFromPort (
- IpmiInstance->KcsTimeoutPeriod,
- IpmiInstance->IpmiIoBase,
- Context,
- (UINT8 *) IpmiResponse,
- &DataSize
- );
- if (Status != EFI_SUCCESS) {
- IpmiInstance->BmcStatus = BMC_SOFTFAIL;
- IpmiInstance->SoftErrorCount++;
- DEBUG ((EFI_D_ERROR, "PEI Phase ReceiveBmcDataFromPort failed Status:%r\n", Status));
- return Status;
- }
- if ((IpmiResponse->CompletionCode != COMP_CODE_NORMAL) &&
- (IpmiInstance->BmcStatus == BMC_UPDATE_IN_PROGRESS)) {
- //
- // If the completion code is not normal and the BMC is in Force Update
- // mode, then update the error status and return EFI_UNSUPPORTED.
- //
- UpdateErrorStatus (
- IpmiResponse->CompletionCode,
- IpmiInstance
- );
- return EFI_UNSUPPORTED;
- } else if (IpmiResponse->CompletionCode != COMP_CODE_NORMAL) {
- //
- // Otherwise if the BMC is in normal mode, but the completion code
- // is not normal, then update the error status and return device error.
- //
- UpdateErrorStatus (
- IpmiResponse->CompletionCode,
- IpmiInstance
- );
- return EFI_DEVICE_ERROR;
- }
- //
- // If we got this far without any error codes, but the DataSize is 0 then the
- // command response failed, so do not continue.
- //
- //
- // Some abnormal case, in order to avoid that BMC sent illegal data size.
- // If we got this far without any error codes, but the DataSize less than IPMI_RESPONSE_HEADER_SIZE, then the
- // command response failed, so do not continue.
- if (DataSize < IPMI_RESPONSE_HEADER_SIZE) {
- return EFI_DEVICE_ERROR;
- }
- //
- // Verify the response data buffer passed in is big enough.
- //
- if ((DataSize - IPMI_RESPONSE_HEADER_SIZE) > *ResponseDataSize) {
- return EFI_BUFFER_TOO_SMALL;
- }
- //
- // Copy data over to the response data buffer.
- //
- *ResponseDataSize = DataSize - IPMI_RESPONSE_HEADER_SIZE;
- CopyMem (
- ResponseData,
- IpmiResponse->ResponseData,
- *ResponseDataSize
- );
- //
- // Add completion code in response data to meet the requirement of IPMI spec 2.0
- //
- *ResponseDataSize += 1; // Add one byte for Completion Code
- for (Index = 1; Index < *ResponseDataSize; Index++) {
- ResponseData [*ResponseDataSize - Index] = ResponseData [*ResponseDataSize - (Index + 1)];
- }
- ResponseData [0] = IpmiResponse->CompletionCode;
- IpmiInstance->BmcStatus = BMC_OK;
- return EFI_SUCCESS;
- }
- EFI_STATUS
- PeiIpmiBmcStatus (
- IN PEI_IPMI_TRANSPORT_PPI *This,
- OUT BMC_STATUS *BmcStatus,
- OUT SM_COM_ADDRESS *ComAddress,
- IN VOID *Context
- )
- /*++
- Routine Description:
- Updates the BMC status and returns the Com Address
- Arguments:
- This - Pointer to IPMI protocol instance
- BmcStatus - BMC status
- ComAddress - Com Address
- Context - Context
- Returns:
- EFI_SUCCESS - Success
- --*/
- {
- PEI_IPMI_BMC_INSTANCE_DATA *IpmiInstance;
- IpmiInstance = INSTANCE_FROM_PEI_SM_IPMI_BMC_THIS (This);
- if ((IpmiInstance->BmcStatus == BMC_SOFTFAIL) && (IpmiInstance->SoftErrorCount >= MAX_SOFT_COUNT)) {
- IpmiInstance->BmcStatus = BMC_HARDFAIL;
- }
- *BmcStatus = IpmiInstance->BmcStatus;
- ComAddress->ChannelType = SmBmc;
- ComAddress->Address.BmcAddress.LunAddress = 0x0;
- ComAddress->Address.BmcAddress.SlaveAddress = IpmiInstance->SlaveAddress;
- ComAddress->Address.BmcAddress.ChannelAddress = 0x0;
- return EFI_SUCCESS;
- }
|