From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mga02.intel.com (mga02.intel.com []) by mx.groups.io with SMTP id smtpd.web12.3173.1614652144809506276 for ; Mon, 01 Mar 2021 18:29:05 -0800 Authentication-Results: mx.groups.io; dkim=missing; spf=fail (domain: intel.com, ip: , mailfrom: nathaniel.l.desimone@intel.com) IronPort-SDR: 03LwGFK28WTE7U/RwJTHHKo7ghOpaALvy3wo6i8WirA4tTcPBxMReZacYdPyQX1pgRxSIoDbte I98Vg0nriLrQ== X-IronPort-AV: E=McAfee;i="6000,8403,9910"; a="173797234" X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="173797234" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by orsmga101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 01 Mar 2021 18:29:02 -0800 IronPort-SDR: CHwjJyqcvAMi9O/VzAcIVjuGIb4I8TZTtJdvR4vyn3lvvOHcbdKmY0pZX/z6FIJvaFONtzyIN7 hl3eQu3uUOBQ== X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="427169869" Received: from nldesimo-desk1.amr.corp.intel.com ([10.212.174.59]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 01 Mar 2021 18:29:01 -0800 From: "Nate DeSimone" To: devel@edk2.groups.io Cc: Isaac Oram , Sai Chaganty , Liming Gao , Michael Kubacki Subject: [edk2-platforms] [PATCH v1 4/9] IpmiFeaturePkg: Add GenericIpmi driver common code Date: Mon, 1 Mar 2021 18:27:59 -0800 Message-Id: <20210302022804.8641-5-nathaniel.l.desimone@intel.com> X-Mailer: git-send-email 2.27.0.windows.1 In-Reply-To: <20210302022804.8641-1-nathaniel.l.desimone@intel.com> References: <20210302022804.8641-1-nathaniel.l.desimone@intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: Isaac Oram REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3242 Adds phase independent code for the generic IPMI transport driver. Cc: Sai Chaganty Cc: Liming Gao Cc: Michael Kubacki Signed-off-by: Isaac Oram Co-authored-by: Nate DeSimone --- .../GenericIpmi/Common/IpmiBmc.c | 297 +++++++++++ .../GenericIpmi/Common/IpmiBmc.h | 44 ++ .../GenericIpmi/Common/IpmiBmcCommon.h | 179 +++++++ .../GenericIpmi/Common/IpmiHooks.c | 96 ++++ .../GenericIpmi/Common/IpmiHooks.h | 81 +++ .../GenericIpmi/Common/IpmiPhysicalLayer.h | 29 ++ .../GenericIpmi/Common/KcsBmc.c | 483 ++++++++++++++++++ .../GenericIpmi/Common/KcsBmc.h | 236 +++++++++ 8 files changed, 1445 insertions(+) create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Common/IpmiBmc.c create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Common/IpmiBmc.h create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Common/IpmiBmcCommon.h create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Common/IpmiHooks.c create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Common/IpmiHooks.h create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Common/IpmiPhysicalLayer.h create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Common/KcsBmc.c create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Common/KcsBmc.h diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Common/IpmiBmc.c b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Common/IpmiBmc.c new file mode 100644 index 0000000000..03b8174e37 --- /dev/null +++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Common/IpmiBmc.c @@ -0,0 +1,297 @@ +/** @file + IPMI Transport common layer driver + + @copyright + Copyright 1999 - 2021 Intel Corporation.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include "IpmiBmc.h" + +EFI_STATUS +UpdateErrorStatus ( + IN UINT8 BmcError, + 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 +EFIAPI +IpmiSendCommandToBmc ( + IN IPMI_TRANSPORT *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 + +--*/ +{ + IPMI_BMC_INSTANCE_DATA *IpmiInstance; + UINT8 DataSize; + EFI_STATUS Status; + IPMI_COMMAND *IpmiCommand; + IPMI_RESPONSE *IpmiResponse; + UINT8 RetryCnt = IPMI_SEND_COMMAND_MAX_RETRY; + UINT8 Index; + + IpmiInstance = INSTANCE_FROM_SM_IPMI_BMC_THIS (This); + + while (RetryCnt--) { + // + // 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*) IpmiInstance->TempData; + IpmiResponse = (IPMI_RESPONSE*) IpmiInstance->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++; + return Status; + } + + // + // Get Response to IPMI Command from BMC. + // Subtract 1 from DataSize so memory past the end of the buffer can't be written + // + DataSize = MAX_TEMP_DATA - 1; + Status = ReceiveBmcDataFromPort ( + IpmiInstance->KcsTimeoutPeriod, + IpmiInstance->IpmiIoBase, + Context, + (UINT8 *) IpmiResponse, + &DataSize + ); + + if (Status != EFI_SUCCESS) { + IpmiInstance->BmcStatus = BMC_SOFTFAIL; + IpmiInstance->SoftErrorCount++; + return Status; + } + + // + // 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; + } + + 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 + ); + // + // Intel Server System Integrated Baseboard Management Controller (BMC) Firmware v0.62 + // D4h C Insufficient privilege, in KCS channel this indicates KCS Policy Control Mode is Deny All. + // In authenticated channels this indicates invalid authentication/privilege. + // + if (IpmiResponse->CompletionCode == COMP_INSUFFICIENT_PRIVILEGE) { + return EFI_SECURITY_VIOLATION; + } else { + return EFI_DEVICE_ERROR; + } + } + + // + // Verify the response data buffer passed in is big enough. + // + if ((DataSize - IPMI_RESPONSE_HEADER_SIZE) > *ResponseDataSize) { + // + //Verify the response data matched with the cmd sent. + // + if ((IpmiResponse->NetFunction != (NetFunction | 0x1)) || (IpmiResponse->Command != Command)) { + if (0 == RetryCnt) { + return EFI_DEVICE_ERROR; + } else { + continue; + } + } + return EFI_BUFFER_TOO_SMALL; + } + + break; + } + // + // 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 +EFIAPI +IpmiBmcStatus ( + IN IPMI_TRANSPORT *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 + +--*/ +{ + IPMI_BMC_INSTANCE_DATA *IpmiInstance; + + IpmiInstance = INSTANCE_FROM_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; +} diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Common/IpmiBmc.h b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Common/IpmiBmc.h new file mode 100644 index 0000000000..d306a085e5 --- /dev/null +++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Common/IpmiBmc.h @@ -0,0 +1,44 @@ +/** @file + IPMI Transport common layer driver head file + + @copyright + Copyright 1999 - 2021 Intel Corporation.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef _IPMI_BMC_H_ +#define _IPMI_BMC_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "IpmiBmcCommon.h" +#include "KcsBmc.h" + + +#define BMC_KCS_TIMEOUT 5 // [s] Single KSC request timeout + +// +// IPMI Instance signature +// +#define SM_IPMI_BMC_SIGNATURE SIGNATURE_32 ('i', 'p', 'm', 'i') +#define IPMI_SEND_COMMAND_MAX_RETRY 3 // Number of retries +#define INSTANCE_FROM_SM_IPMI_BMC_THIS(a) \ + CR ( \ + a, \ + IPMI_BMC_INSTANCE_DATA, \ + IpmiTransport, \ + SM_IPMI_BMC_SIGNATURE \ + ) + +#endif // _IPMI_BMC_H_ diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Common/IpmiBmcCommon.h b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Common/IpmiBmcCommon.h new file mode 100644 index 0000000000..1e5dfd81f1 --- /dev/null +++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Common/IpmiBmcCommon.h @@ -0,0 +1,179 @@ +/** @file + IPMI Transport common layer driver common head file + + @copyright + Copyright 1999 - 2021 Intel Corporation.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef _IPMI_COMMON_BMC_H_ +#define _IPMI_COMMON_BMC_H_ + +#define MAX_TEMP_DATA 255 // 160 Modified to increase number of bytes transfered per command +#define BMC_SLAVE_ADDRESS 0x20 +#define MAX_SOFT_COUNT 10 +#define COMP_CODE_NORMAL 0x00 + +// +// IPMI command completion codes to check for in the UpdateErrorStatus routine. +// These completion codes indicate a soft error and a running total of the occurrences +// of these errors is maintained. +// +#define COMP_CODE_NODE_BUSY 0xC0 +#define COMP_CODE_TIMEOUT 0xC3 +#define COMP_CODE_OUT_OF_SPACE 0xC4 +#define COMP_CODE_OUT_OF_RANGE 0xC9 +#define COMP_CODE_CMD_RESP_NOT_PROVIDED 0xCE +#define COMP_CODE_FAIL_DUP_REQUEST 0xCF +#define COMP_CODE_SDR_REP_IN_UPDATE_MODE 0xD0 +#define COMP_CODE_DEV_IN_FW_UPDATE_MODE 0xD1 +#define COMP_CODE_BMC_INIT_IN_PROGRESS 0xD2 +// +// Intel Server System Integrated Baseboard Management Controller (BMC) Firmware v0.62 +// D4h C Insufficient privilege, in KCS channel this indicates KCS Policy Control Mode is Deny All. +// In authenticated channels this indicates invalid authentication/privilege. +// +#define COMP_INSUFFICIENT_PRIVILEGE 0xD4 +#define COMP_CODE_UNSPECIFIED 0xFF + +#define COMPLETION_CODES \ + { \ + COMP_CODE_NODE_BUSY, COMP_CODE_TIMEOUT, COMP_CODE_OUT_OF_SPACE, COMP_CODE_OUT_OF_RANGE, \ + COMP_CODE_CMD_RESP_NOT_PROVIDED, COMP_CODE_FAIL_DUP_REQUEST, COMP_CODE_SDR_REP_IN_UPDATE_MODE, \ + COMP_CODE_DEV_IN_FW_UPDATE_MODE, COMP_CODE_BMC_INIT_IN_PROGRESS, COMP_INSUFFICIENT_PRIVILEGE, COMP_CODE_UNSPECIFIED \ + } + +// +// Dxe Ipmi instance data +// +typedef struct { + UINTN Signature; + UINT64 KcsTimeoutPeriod; + UINT8 SlaveAddress; + UINT8 TempData[MAX_TEMP_DATA]; + BMC_STATUS BmcStatus; + UINT64 ErrorStatus; + UINT8 SoftErrorCount; + UINT16 IpmiIoBase; + IPMI_TRANSPORT IpmiTransport; + EFI_HANDLE IpmiSmmHandle; +} IPMI_BMC_INSTANCE_DATA; + +// +// Structure of IPMI Command buffer +// +#define IPMI_COMMAND_HEADER_SIZE 2 + +typedef struct { + UINT8 Lun : 2; + UINT8 NetFunction : 6; + UINT8 Command; + UINT8 CommandData[MAX_TEMP_DATA - IPMI_COMMAND_HEADER_SIZE]; +} IPMI_COMMAND; + +// +// Structure of IPMI Command response buffer +// +#define IPMI_RESPONSE_HEADER_SIZE 3 + +typedef struct { + UINT8 Lun : 2; + UINT8 NetFunction : 6; + UINT8 Command; + UINT8 CompletionCode; + UINT8 ResponseData[MAX_TEMP_DATA - IPMI_RESPONSE_HEADER_SIZE]; +} IPMI_RESPONSE; + +EFI_STATUS +EFIAPI +IpmiSendCommandToBmc ( + IN IPMI_TRANSPORT *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_SUCCESS - Command completed successfully + +--*/ +; + + +EFI_STATUS +EFIAPI +IpmiBmcStatus ( + IN IPMI_TRANSPORT *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 + +--*/ +; + +VOID +GetDeviceSpecificTestResults ( + IN IPMI_BMC_INSTANCE_DATA *IpmiInstance + ) +/*++ + +Routine Description: + + This is a BMC specific routine to check the device specific self test results as defined + in the Bensley BMC core specification. + +Arguments: + + IpmiInstance - Data structure describing BMC variables and used for sending commands + +Returns: + + VOID + +--*/ +; + +#endif diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Common/IpmiHooks.c b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Common/IpmiHooks.c new file mode 100644 index 0000000000..86ff7c0fdf --- /dev/null +++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Common/IpmiHooks.c @@ -0,0 +1,96 @@ +/** @file + IPMI common hook functions + + @copyright + Copyright 2014 - 2021 Intel Corporation.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include "IpmiHooks.h" + +EFI_STATUS +IpmiSendCommand ( + IN IPMI_TRANSPORT *This, + IN UINT8 NetFunction, + IN UINT8 Lun, + IN UINT8 Command, + IN UINT8 *CommandData, + IN UINT32 CommandDataSize, + IN OUT UINT8 *ResponseData, + IN OUT UINT32 *ResponseDataSize + ) +/*++ + +Routine Description: + + Send Ipmi Command in the right mode: HECI or KCS, to the + appropiate device, ME or 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 + +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 + +--*/ +{ + // + // This Will be unchanged ( BMC/KCS style ) + // + return IpmiSendCommandToBmc ( + This, + NetFunction, + Lun, + Command, + CommandData, + (UINT8) CommandDataSize, + ResponseData, + (UINT8*) ResponseDataSize, + NULL + ); +} // IpmiSendCommand() + +EFI_STATUS +IpmiGetBmcStatus ( + IN IPMI_TRANSPORT *This, + OUT BMC_STATUS *BmcStatus, + OUT SM_COM_ADDRESS *ComAddress + ) +/*++ + +Routine Description: + + Updates the BMC status and returns the Com Address + +Arguments: + + This - Pointer to IPMI protocol instance + BmcStatus - BMC status + ComAddress - Com Address + +Returns: + + EFI_SUCCESS - Success + +--*/ +{ + return IpmiBmcStatus ( + This, + BmcStatus, + ComAddress, + NULL + ); +} diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Common/IpmiHooks.h b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Common/IpmiHooks.h new file mode 100644 index 0000000000..083c9e70b0 --- /dev/null +++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Common/IpmiHooks.h @@ -0,0 +1,81 @@ +/** @file + IPMI common hook functions head file + + @copyright + Copyright 2014 - 2021 Intel Corporation.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef _IPMI_HOOKS_H +#define _IPMI_HOOKS_H + +#include "IpmiBmc.h" + +// +// Internal(hook) function list +// +EFI_STATUS +IpmiSendCommand ( + IN IPMI_TRANSPORT *This, + IN UINT8 NetFunction, + IN UINT8 Lun, + IN UINT8 Command, + IN UINT8 *CommandData, + IN UINT32 CommandDataSize, + IN OUT UINT8 *ResponseData, + IN OUT UINT32 *ResponseDataSize + ) +/*++ + +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 + +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 + +--*/ +; + +EFI_STATUS +IpmiGetBmcStatus ( + IN IPMI_TRANSPORT *This, + OUT BMC_STATUS *BmcStatus, + OUT SM_COM_ADDRESS *ComAddress + ) +/*++ + +Routine Description: + + Updates the BMC status and returns the Com Address + +Arguments: + + This - Pointer to IPMI protocol instance + BmcStatus - BMC status + ComAddress - Com Address + +Returns: + + EFI_SUCCESS - Success + +--*/ +; + +#endif diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Common/IpmiPhysicalLayer.h b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Common/IpmiPhysicalLayer.h new file mode 100644 index 0000000000..0215bd0e5a --- /dev/null +++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Common/IpmiPhysicalLayer.h @@ -0,0 +1,29 @@ +/** @file + IPMI Common physical layer functions. + + @copyright + Copyright 2014 - 2021 Intel Corporation.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef _IPMI_PHYSICAL_LAYER_H +#define _IPMI_PHYSICAL_LAYER_H + +// +// KCS physical interface layer +// +EFI_STATUS +InitializeIpmiKcsPhysicalLayer ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + + +EFI_STATUS +SmmInitializeIpmiKcsPhysicalLayer ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +#endif + diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Common/KcsBmc.c b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Common/KcsBmc.c new file mode 100644 index 0000000000..7243d37cc5 --- /dev/null +++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Common/KcsBmc.c @@ -0,0 +1,483 @@ +/** @file + KCS Transport Hook. + + @copyright + Copyright 1999 - 2021 Intel Corporation.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include "KcsBmc.h" + +EFI_STATUS +KcsErrorExit ( + UINT64 KcsTimeoutPeriod, + UINT16 KcsPort, + VOID *Context + ) +/*++ + +Routine Description: + + Check the KCS error status + +Arguments: + + IpmiInstance - The pointer of IPMI_BMC_INSTANCE_DATA + KcsPort - The base port of KCS + Context - The Context for this operation + +Returns: + + EFI_DEVICE_ERROR - The device error happened + EFI_SUCCESS - Successfully check the KCS error status + +--*/ +{ + EFI_STATUS Status; + UINT8 KcsData; + KCS_STATUS KcsStatus; + UINT8 BmcStatus; + UINT8 RetryCount; + UINT64 TimeOut; + + TimeOut = 0; + RetryCount = 0; + while (RetryCount < KCS_ABORT_RETRY_COUNT) { + + TimeOut = 0; + do { + MicroSecondDelay (KCS_DELAY_UNIT); + KcsStatus.RawData = IoRead8 (KcsPort + 1); + if (KcsStatus.RawData == 0xFF || (TimeOut >= KcsTimeoutPeriod)) { + RetryCount = KCS_ABORT_RETRY_COUNT; + break; + } + TimeOut++; + } while (KcsStatus.Status.Ibf); + + if (RetryCount >= KCS_ABORT_RETRY_COUNT) { + break; + } + + KcsData = KCS_ABORT; + IoWrite8 ((KcsPort + 1), KcsData); + + TimeOut = 0; + do { + MicroSecondDelay (KCS_DELAY_UNIT); + KcsStatus.RawData = IoRead8 (KcsPort + 1); + if (KcsStatus.RawData == 0xFF || (TimeOut >= KcsTimeoutPeriod)) { + Status = EFI_DEVICE_ERROR; + goto LabelError; + } + TimeOut++; + } while (KcsStatus.Status.Ibf); + + KcsData = IoRead8 (KcsPort); + + KcsData = 0x0; + IoWrite8 (KcsPort, KcsData); + + TimeOut = 0; + do { + MicroSecondDelay (KCS_DELAY_UNIT); + KcsStatus.RawData = IoRead8 (KcsPort + 1); + if (KcsStatus.RawData == 0xFF || (TimeOut >= KcsTimeoutPeriod)) { + Status = EFI_DEVICE_ERROR; + goto LabelError; + } + TimeOut++; + } while (KcsStatus.Status.Ibf); + + if (KcsStatus.Status.State == KcsReadState) { + TimeOut = 0; + do { + MicroSecondDelay (KCS_DELAY_UNIT); + KcsStatus.RawData = IoRead8 (KcsPort + 1); + if (KcsStatus.RawData == 0xFF || (TimeOut >= KcsTimeoutPeriod)) { + Status = EFI_DEVICE_ERROR; + goto LabelError; + } + TimeOut++; + } while (!KcsStatus.Status.Obf); + + BmcStatus = IoRead8 (KcsPort); + + KcsData = KCS_READ; + IoWrite8 (KcsPort, KcsData); + + TimeOut = 0; + do { + MicroSecondDelay (KCS_DELAY_UNIT); + KcsStatus.RawData = IoRead8 (KcsPort + 1); + if (KcsStatus.RawData == 0xFF || (TimeOut >= KcsTimeoutPeriod)) { + Status = EFI_DEVICE_ERROR; + goto LabelError; + } + TimeOut++; + } while (KcsStatus.Status.Ibf); + + if (KcsStatus.Status.State == KcsIdleState) { + TimeOut = 0; + do { + MicroSecondDelay (KCS_DELAY_UNIT); + KcsStatus.RawData = IoRead8 (KcsPort + 1); + if (KcsStatus.RawData == 0xFF || (TimeOut >= KcsTimeoutPeriod)) { + Status = EFI_DEVICE_ERROR; + goto LabelError; + } + TimeOut++; + } while (!KcsStatus.Status.Obf); + + KcsData = IoRead8 (KcsPort); + break; + + } else { + RetryCount++; + continue; + } + + } else { + RetryCount++; + continue; + } + } + + if (RetryCount >= KCS_ABORT_RETRY_COUNT) { + Status = EFI_DEVICE_ERROR; + goto LabelError; + } + + return EFI_SUCCESS; + +LabelError: + return Status; +} + +EFI_STATUS +KcsCheckStatus ( + UINT64 KcsTimeoutPeriod, + UINT16 KcsPort, + KCS_STATE KcsState, + BOOLEAN *Idle, + VOID *Context + ) +/*++ + +Routine Description: + + Ckeck KCS status + +Arguments: + + IpmiInstance - The pointer of IPMI_BMC_INSTANCE_DATA + KcsPort - The base port of KCS + KcsState - The state of KCS to be checked + Idle - If the KCS is idle + Context - The context for this operation + +Returns: + + EFI_SUCCESS - Checked the KCS status successfully + +--*/ +{ + EFI_STATUS Status; + KCS_STATUS KcsStatus; + UINT8 KcsData; + UINT64 TimeOut; + + if (Idle == NULL) { + return EFI_INVALID_PARAMETER; + } + + *Idle = FALSE; + + TimeOut = 0; + do { + MicroSecondDelay (KCS_DELAY_UNIT); + KcsStatus.RawData = IoRead8 (KcsPort + 1); + if (KcsStatus.RawData == 0xFF || (TimeOut >= KcsTimeoutPeriod)) { + Status = EFI_DEVICE_ERROR; + goto LabelError; + } + TimeOut++; + } while (KcsStatus.Status.Ibf); + + if (KcsState == KcsWriteState) { + KcsData = IoRead8 (KcsPort); + } + + if (KcsStatus.Status.State != KcsState) { + if ((KcsStatus.Status.State == KcsIdleState) && (KcsState == KcsReadState)) { + *Idle = TRUE; + } else { + Status = KcsErrorExit (KcsTimeoutPeriod, KcsPort, Context); + goto LabelError; + } + } + + if (KcsState == KcsReadState) { + TimeOut = 0; + do { + MicroSecondDelay (KCS_DELAY_UNIT); + KcsStatus.RawData = IoRead8 (KcsPort + 1); + if (KcsStatus.RawData == 0xFF || (TimeOut >= KcsTimeoutPeriod)) { + Status = EFI_DEVICE_ERROR; + goto LabelError; + } + TimeOut++; + } while (!KcsStatus.Status.Obf); + } + + if (KcsState == KcsWriteState || (*Idle == TRUE)) { + KcsData = IoRead8 (KcsPort); + } + + return EFI_SUCCESS; + +LabelError: + return Status; +} + +EFI_STATUS +SendDataToBmc ( + UINT64 KcsTimeoutPeriod, + UINT16 KcsPort, + VOID *Context, + UINT8 *Data, + UINT8 DataSize + ) +/*++ + +Routine Description: + + Send data to BMC + +Arguments: + + IpmiInstance - The pointer of IPMI_BMC_INSTANCE_DATA + Context - The context of this operation + Data - The data pointer to be sent + DataSize - The data size + +Returns: + + EFI_SUCCESS - Send out the data successfully + +--*/ +{ + KCS_STATUS KcsStatus; + UINT8 KcsData; + UINT16 KcsIoBase; + EFI_STATUS Status; + UINT8 i; + BOOLEAN Idle; + UINT64 TimeOut; + + KcsIoBase = KcsPort; + + TimeOut = 0; + + do { + MicroSecondDelay (KCS_DELAY_UNIT); + KcsStatus.RawData = IoRead8 (KcsIoBase + 1); + if ((KcsStatus.RawData == 0xFF) || (TimeOut >= KcsTimeoutPeriod)) { + if ((Status = KcsErrorExit (KcsTimeoutPeriod, KcsIoBase, Context)) != EFI_SUCCESS) { + return Status; + } + } + TimeOut++; + } while (KcsStatus.Status.Ibf); + + KcsData = KCS_WRITE_START; + IoWrite8 ((KcsIoBase + 1), KcsData); + if ((Status = KcsCheckStatus (KcsTimeoutPeriod, KcsIoBase, KcsWriteState, &Idle, Context)) != EFI_SUCCESS) { + return Status; + } + + for (i = 0; i < DataSize; i++) { + if (i == (DataSize - 1)) { + if ((Status = KcsCheckStatus (KcsTimeoutPeriod, KcsIoBase, KcsWriteState, &Idle, Context)) != EFI_SUCCESS) { + return Status; + } + + KcsData = KCS_WRITE_END; + IoWrite8 ((KcsIoBase + 1), KcsData); + } + + Status = KcsCheckStatus (KcsTimeoutPeriod, KcsIoBase, KcsWriteState, &Idle, Context); + if (EFI_ERROR (Status)) { + return Status; + } + + IoWrite8 (KcsIoBase, Data[i]); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +ReceiveBmcData ( + UINT64 KcsTimeoutPeriod, + UINT16 KcsPort, + VOID *Context, + UINT8 *Data, + UINT8 *DataSize + ) +/*++ + +Routine Description: + + Routine Description: + + Receive data from BMC + +Arguments: + + IpmiInstance - The pointer of IPMI_BMC_INSTANCE_DATA + Context - The context of this operation + Data - The buffer pointer + DataSize - The buffer size + +Returns: + + EFI_SUCCESS - Received data successfully + +--*/ +{ + UINT8 KcsData; + UINT16 KcsIoBase; + EFI_STATUS Status; + BOOLEAN Idle; + UINT8 Count; + + Count = 0; + KcsIoBase = KcsPort; + + while (TRUE) { + + if ((Status = KcsCheckStatus (KcsTimeoutPeriod, KcsIoBase, KcsReadState, &Idle, Context)) != EFI_SUCCESS) { + return Status; + } + + if (Idle) { + *DataSize = Count; + break; + } + + // + //Need to check Data Size -1 to account for array access + // + if (Count >= *DataSize) { + return EFI_DEVICE_ERROR; + } + + Data[Count] = IoRead8 (KcsIoBase); + + Count++; + + KcsData = KCS_READ; + IoWrite8 (KcsIoBase, KcsData); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +ReceiveBmcDataFromPort ( + UINT64 KcsTimeoutPeriod, + UINT16 KcsPort, + VOID *Context, + UINT8 *Data, + UINT8 *DataSize + ) +/*++ + +Routine Description: + + Receive data from BMC + +Arguments: + + IpmiInstance - The pointer of IPMI_BMC_INSTANCE_DATA + Context - The context of this operation + Data - The buffer pointer to receive data + DataSize - The buffer size + +Returns: + + EFI_SUCCESS - Received the data successfully + +--*/ +{ + EFI_STATUS Status; + UINT16 KcsIoBase; + UINT8 i; + UINT8 MyDataSize; + + MyDataSize = *DataSize; + KcsIoBase = KcsPort; + + for (i = 0; i < KCS_ABORT_RETRY_COUNT; i++) { + Status = ReceiveBmcData (KcsTimeoutPeriod, KcsIoBase, Context, Data, DataSize); + if (EFI_ERROR (Status)) { + if ((Status = KcsErrorExit (KcsTimeoutPeriod, KcsIoBase, Context)) != EFI_SUCCESS) { + return Status; + } + + *DataSize = MyDataSize; + } else { + return Status; + } + } + + return EFI_DEVICE_ERROR; +} + +EFI_STATUS +SendDataToBmcPort ( + UINT64 KcsTimeoutPeriod, + UINT16 KcsPort, + VOID *Context, + UINT8 *Data, + UINT8 DataSize + ) +/*++ + +Routine Description: + + Send data to BMC + +Arguments: + + IpmiInstance - The pointer of IPMI_BMC_INSTANCE_DATA + Context - The context of this operation + Data - The data pointer to be sent + DataSize - The data size + +Returns: + + EFI_SUCCESS - Send out the data successfully + +--*/ +{ + EFI_STATUS Status; + UINT16 KcsIoBase; + UINT8 i; + + KcsIoBase = KcsPort; + + for (i = 0; i < KCS_ABORT_RETRY_COUNT; i++) { + Status = SendDataToBmc (KcsTimeoutPeriod, KcsIoBase, Context, Data, DataSize); + if (EFI_ERROR (Status)) { + if ((Status = KcsErrorExit (KcsTimeoutPeriod, KcsIoBase, Context)) != EFI_SUCCESS) { + return Status; + } + } else { + return Status; + } + } + + return EFI_DEVICE_ERROR; +} diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Common/KcsBmc.h b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Common/KcsBmc.h new file mode 100644 index 0000000000..a8684cc4f6 --- /dev/null +++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Common/KcsBmc.h @@ -0,0 +1,236 @@ +/** @file + KCS Transport Hook head file. + + @copyright + Copyright 1999 - 2021 Intel Corporation.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef _KCS_BMC_H +#define _KCS_BMC_H + +#include +#include +#include +#include + +#define KCS_WRITE_START 0x61 +#define KCS_WRITE_END 0x62 +#define KCS_READ 0x68 +#define KCS_GET_STATUS 0x60 +#define KCS_ABORT 0x60 +#define KCS_DELAY_UNIT 50 // [s] Each KSC IO delay + +// +// In OpenBMC, UpdateMode: the bit 7 of byte 4 in get device id command is used for the BMC status: +// 0 means BMC is ready, 1 means BMC is not ready. +// At the very beginning of BMC power on, the status is 1 means BMC is in booting process and not ready. It is not the flag for force update mode. +// +#define BMC_READY 0 + + +#define KCS_ABORT_RETRY_COUNT 1 + +//#define TIMEOUT64(a,b) ((INT64)((b) - (a)) < 0) + +typedef enum { + KcsIdleState, + KcsReadState, + KcsWriteState, + KcsErrorState +} KCS_STATE; + +typedef union { + UINT8 RawData; + struct { + UINT8 Obf : 1; + UINT8 Ibf : 1; + UINT8 SmAtn : 1; + UINT8 CD : 1; + UINT8 Oem1 : 1; + UINT8 Oem2 : 1; + UINT8 State : 2; + } Status; +} KCS_STATUS; + + +// +//External Fucntion List +// +EFI_STATUS +SendDataToBmcPort ( + UINT64 KcsTimeoutPeriod, + UINT16 KcsPort, + VOID *Context, + UINT8 *Data, + UINT8 DataSize + ) +/*++ + +Routine Description: + + Send data to BMC + +Arguments: + + IpmiInstance - The pointer of IPMI_BMC_INSTANCE_DATA + Context - The context of this operation + Data - The data pointer to be sent + DataSize - The data size + +Returns: + + EFI_SUCCESS - Send out the data successfully + +--*/ +; + +EFI_STATUS +ReceiveBmcDataFromPort ( + UINT64 KcsTimeoutPeriod, + UINT16 KcsPort, + VOID *Context, + UINT8 *Data, + UINT8 *DataSize + ) +/*++ + +Routine Description: + + Routine Description: + + Receive data from BMC + +Arguments: + + IpmiInstance - The pointer of IPMI_BMC_INSTANCE_DATA + Context - The context of this operation + Data - The buffer pointer + DataSize - The buffer size + +Returns: + + EFI_SUCCESS - Received data successfully + +--*/ +; + +// +//Internal Fucntion List +// +EFI_STATUS +KcsErrorExit ( + UINT64 KcsTimeoutPeriod, + UINT16 KcsPort, + VOID *Context + ) +/*++ + +Routine Description: + + Check the KCS error status + +Arguments: + + IpmiInstance - The pointer of IPMI_BMC_INSTANCE_DATA + KcsPort - The base port of KCS + Context - The Context for this operation + +Returns: + + EFI_DEVICE_ERROR - The device error happened + EFI_SUCCESS - Successfully check the KCS error status + +--*/ +; + +EFI_STATUS +KcsCheckStatus ( + UINT64 KcsTimeoutPeriod, + UINT16 KcsPort, + KCS_STATE KcsState, + BOOLEAN *Idle, + VOID *Context + ) +/*++ + +Routine Description: + + Ckeck KCS status + +Arguments: + + IpmiInstance - The pointer of IPMI_BMC_INSTANCE_DATA + KcsPort - The base port of KCS + KcsState - The state of KCS to be checked + Idle - If the KCS is idle + Context - The context for this operation + +Returns: + + EFI_SUCCESS - Checked the KCS status successfully + +--*/ +; + + +EFI_STATUS +SendDataToBmc ( + UINT64 KcsTimeoutPeriod, + UINT16 KcsPort, + VOID *Context, + UINT8 *Data, + UINT8 DataSize + ) +/*++ + +Routine Description: + + Send data to BMC + +Arguments: + + IpmiInstance - The pointer of IPMI_BMC_INSTANCE_DATA + Context - The context of this operation + Data - The data pointer to be sent + DataSize - The data size + +Returns: + + EFI_SUCCESS - Send out the data successfully + +--*/ +; + + +EFI_STATUS +ReceiveBmcData ( + UINT64 KcsTimeoutPeriod, + UINT16 KcsPort, + VOID *Context, + UINT8 *Data, + UINT8 *DataSize + ) +/*++ + +Routine Description: + + Routine Description: + + Receive data from BMC + +Arguments: + + IpmiInstance - The pointer of IPMI_BMC_INSTANCE_DATA + Context - The context of this operation + Data - The buffer pointer + DataSize - The buffer size + +Returns: + + EFI_SUCCESS - Received data successfully + +--*/ +; + +#endif -- 2.27.0.windows.1