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.web11.3132.1614652142744425290 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: eIJImEL9ikjhmtiFtXOYxmXuE5ddN9/5LVJV7lWaXsqG53kh699gSsuTcc8mpE6Woua7lLK+qX 79/fddWU4YMg== X-IronPort-AV: E=McAfee;i="6000,8403,9910"; a="173797235" X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="173797235" 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: OMcIcvG97p9d8wd1G007JbnhfKEJ+JGssASkExBXPHoK+UJLYgwZK4gxBj087yjnFWpZVd0HZ1 HVj5LdeYx61A== X-IronPort-AV: E=Sophos;i="5.81,216,1610438400"; d="scan'208";a="427169873" 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:02 -0800 From: "Nate DeSimone" To: devel@edk2.groups.io Cc: Isaac Oram , Sai Chaganty , Liming Gao , Michael Kubacki Subject: [edk2-platforms] [PATCH v1 5/9] IpmiFeaturePkg: Add GenericIpmi PEIM Date: Mon, 1 Mar 2021 18:28:00 -0800 Message-Id: <20210302022804.8641-6-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 the PEI version of 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/Pei/PeiGenericIpmi.c | 362 ++++++++++++++++++ .../GenericIpmi/Pei/PeiGenericIpmi.h | 138 +++++++ .../GenericIpmi/Pei/PeiGenericIpmi.inf | 58 +++ .../GenericIpmi/Pei/PeiIpmiBmc.c | 277 ++++++++++++++ .../GenericIpmi/Pei/PeiIpmiBmc.h | 38 ++ .../GenericIpmi/Pei/PeiIpmiBmcDef.h | 156 ++++++++ 6 files changed, 1029 insertions(+) create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Pei/PeiGenericIpmi.c create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Pei/PeiGenericIpmi.h create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Pei/PeiGenericIpmi.inf create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Pei/PeiIpmiBmc.c create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Pei/PeiIpmiBmc.h create mode 100644 Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Pei/PeiIpmiBmcDef.h diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Pei/PeiGenericIpmi.c b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Pei/PeiGenericIpmi.c new file mode 100644 index 0000000000..31f613925d --- /dev/null +++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Pei/PeiGenericIpmi.c @@ -0,0 +1,362 @@ +/** @file + Generic IPMI stack during PEI phase + + @copyright + Copyright 2017 - 2021 Intel Corporation.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include "PeiGenericIpmi.h" +#include + + +/////////////////////////////////////////////////////////////////////////////// +// Function Implementations +// + +/***************************************************************************** + @brief + Internal function + + @param[in] PeiServices General purpose services available to every PEIM. + + @retval EFI_SUCCESS Always return EFI_SUCCESS +**/ +EFI_STATUS +EFIAPI +PeiInitializeIpmiKcsPhysicalLayer ( + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + PEI_IPMI_BMC_INSTANCE_DATA *mIpmiInstance; + + mIpmiInstance = NULL; + + // + // Send Pre-Boot signal to BMC + // + if (PcdGetBool (PcdSignalPreBootToBmc)) { + Status = SendPreBootSignaltoBmc (PeiServices); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // Enable OEM specific southbridge SIO KCS I/O address range 0xCA0 to 0xCAF at here + // if the the I/O address range has not been enabled. + // + + mIpmiInstance = AllocateZeroPool (sizeof (PEI_IPMI_BMC_INSTANCE_DATA)); + if (mIpmiInstance == NULL) { + DEBUG ((EFI_D_ERROR,"IPMI Peim:EFI_OUT_OF_RESOURCES of memory allocation\n")); + return EFI_OUT_OF_RESOURCES; + } + + // + // Calibrate TSC Counter. Stall for 10ms, then multiply the resulting number of + // ticks in that period by 100 to get the number of ticks in a 1 second timeout + // + DEBUG ((DEBUG_INFO,"IPMI Peim:IPMI STACK Initialization\n")); + mIpmiInstance->KcsTimeoutPeriod = (BMC_KCS_TIMEOUT_PEI *1000*1000) / KCS_DELAY_UNIT_PEI; + DEBUG ((EFI_D_INFO,"IPMI Peim:KcsTimeoutPeriod = 0x%x\n", mIpmiInstance->KcsTimeoutPeriod)); + + // + // Initialize IPMI IO Base. + // + mIpmiInstance->IpmiIoBase = PcdGet16 (PcdIpmiIoBaseAddress); + DEBUG ((EFI_D_INFO,"IPMI Peim:IpmiIoBase=0x%x\n",mIpmiInstance->IpmiIoBase)); + mIpmiInstance->Signature = SM_IPMI_BMC_SIGNATURE; + mIpmiInstance->SlaveAddress = BMC_SLAVE_ADDRESS; + mIpmiInstance->BmcStatus = BMC_NOTREADY; + mIpmiInstance->IpmiTransportPpi.IpmiSubmitCommand = PeiIpmiSendCommand; + mIpmiInstance->IpmiTransportPpi.GetBmcStatus = PeiGetIpmiBmcStatus; + + mIpmiInstance->PeiIpmiBmcDataDesc.Flags = EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST; + mIpmiInstance->PeiIpmiBmcDataDesc.Guid = &gPeiIpmiTransportPpiGuid; + mIpmiInstance->PeiIpmiBmcDataDesc.Ppi = &mIpmiInstance->IpmiTransportPpi; + + // + // Get the Device ID and check if the system is in Force Update mode. + // + Status = GetDeviceId (mIpmiInstance); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR,"IPMI Peim:Get BMC Device Id Failed. Status=%r\n",Status)); + } + + // + // Do not continue initialization if the BMC is in Force Update Mode. + // + if (mIpmiInstance->BmcStatus == BMC_UPDATE_IN_PROGRESS || mIpmiInstance->BmcStatus == BMC_HARDFAIL) { + return EFI_UNSUPPORTED; + } + + // + // Just produce PPI + // + Status = PeiServicesInstallPpi (&mIpmiInstance->PeiIpmiBmcDataDesc); + if (EFI_ERROR (Status)) { + return Status; + } + + return EFI_SUCCESS; +} + +/***************************************************************************** + @bref + PRE-BOOT signal will be sent in very early PEI phase, to enable necessary KCS access for host boot. + + @param[in] PeiServices General purpose services available to every PEIM. + + @retval EFI_SUCCESS Indicates that the signal is sent successfully. +**/ +EFI_STATUS +SendPreBootSignaltoBmc ( + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + EFI_PEI_CPU_IO_PPI *CpuIoPpi; + UINT32 ProvisionPort = 0; + UINT8 PreBoot = 0; + + // + // Locate CpuIo service + // + CpuIoPpi = (**PeiServices).CpuIo; + ProvisionPort = PcdGet32 (PcdSioMailboxBaseAddress) + MBXDAT_B; + PreBoot = 0x01;// PRE-BOOT + + Status = CpuIoPpi->Io.Write ( + PeiServices, + CpuIoPpi, + EfiPeiCpuIoWidthUint8, + ProvisionPort, + 1, + &PreBoot + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "SendPreBootSignaltoBmc () Write PRE-BOOT Status=%r\n", Status)); + return Status; + } + + return EFI_SUCCESS; +} + +/***************************************************************************** + @bref + The entry point of the Ipmi PEIM. Instals Ipmi PPI interface. + + @param FileHandle Handle of the file being invoked. + @param PeiServices Describes the list of possible PEI Services. + + @retval EFI_SUCCESS Indicates that Ipmi initialization completed successfully. +**/ +EFI_STATUS +PeimIpmiInterfaceInit ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + + + // + // Performing Ipmi KCS physical layer initialization + // + Status = PeiInitializeIpmiKcsPhysicalLayer (PeiServices); + + return EFI_SUCCESS; +} // PeimIpmiInterfaceInit() + + +EFI_STATUS +PeiIpmiSendCommand ( + IN PEI_IPMI_TRANSPORT_PPI *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 PeiIpmiSendCommandToBmc ( + This, + NetFunction, + Lun, + Command, + CommandData, + (UINT8) CommandDataSize, + ResponseData, + (UINT8 *) ResponseDataSize, + NULL + ); +} // IpmiSendCommand() + +EFI_STATUS +PeiGetIpmiBmcStatus ( + IN PEI_IPMI_TRANSPORT_PPI *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 PeiIpmiBmcStatus ( + This, + BmcStatus, + ComAddress, + NULL + ); +} + + +EFI_STATUS +GetDeviceId ( + IN PEI_IPMI_BMC_INSTANCE_DATA *mIpmiInstance + ) +/*++ + +Routine Description: + Execute the Get Device ID command to determine whether or not the BMC is in Force Update + Mode. If it is, then report it to the error manager. + +Arguments: + mIpmiInstance - Data structure describing BMC variables and used for sending commands + StatusCodeValue - An array used to accumulate error codes for later reporting. + ErrorCount - Counter used to keep track of error codes in StatusCodeValue + +Returns: + Status + +--*/ +{ + EFI_STATUS Status; + UINT32 DataSize; + SM_CTRL_INFO *pBmcInfo; + UINTN Retries; + + // + // Set up a loop to retry for up to PcdIpmiBmcReadyDelayTimer seconds. Calculate retries not timeout + // so that in case KCS is not enabled and IpmiSendCommand() returns + // immediately we will not wait all the PcdIpmiBmcReadyDelayTimer seconds. + // + Retries = PcdGet8 (PcdIpmiBmcReadyDelayTimer); + // + // Get the device ID information for the BMC. + // + DataSize = sizeof (mIpmiInstance->TempData); + while (EFI_ERROR (Status = PeiIpmiSendCommand ( + &mIpmiInstance->IpmiTransportPpi, + IPMI_NETFN_APP, + 0, + IPMI_APP_GET_DEVICE_ID, + NULL, + 0, + mIpmiInstance->TempData, + &DataSize + ))) { + DEBUG ((EFI_D_ERROR, "[IPMI] BMC does not respond (status: %r), %d retries left\n", + Status, Retries)); + + if (Retries-- == 0) { + ReportStatusCode (EFI_ERROR_CODE | EFI_ERROR_MAJOR, EFI_COMPUTING_UNIT_FIRMWARE_PROCESSOR | EFI_CU_FP_EC_COMM_ERROR); + mIpmiInstance->BmcStatus = BMC_HARDFAIL; + return Status; + } + // + // Handle the case that BMC FW still not enable KCS channel after AC cycle. just stall 1 second + // + MicroSecondDelay (1*1000*1000); + } + pBmcInfo = (SM_CTRL_INFO*) &mIpmiInstance->TempData[0]; + DEBUG ((DEBUG_INFO, "[IPMI PEI] BMC Device ID: 0x%02X, firmware version: %d.%02X UpdateMode:%x\n", + pBmcInfo->DeviceId, pBmcInfo->MajorFirmwareRev, pBmcInfo->MinorFirmwareRev, pBmcInfo->UpdateMode)); + // + // 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. + // + if (pBmcInfo->UpdateMode == BMC_READY) { + mIpmiInstance->BmcStatus = BMC_OK; + return EFI_SUCCESS; + } else { + // + // Updatemode = 1 mean BMC is not ready, continue waiting. + // + while (Retries-- != 0) { + MicroSecondDelay(1*1000*1000); //delay 1 seconds + DEBUG ((DEBUG_INFO, "[IPMI PEI] UpdateMode Retries:%x \n",Retries)); + Status = PeiIpmiSendCommand ( + &mIpmiInstance->IpmiTransportPpi, + IPMI_NETFN_APP, + 0, + IPMI_APP_GET_DEVICE_ID, + NULL, + 0, + mIpmiInstance->TempData, + &DataSize + ); + if (!EFI_ERROR (Status)) { + pBmcInfo = (SM_CTRL_INFO*) &mIpmiInstance->TempData[0]; + DEBUG ((DEBUG_INFO, "[IPMI PEI] UpdateMode Retries:%x pBmcInfo->UpdateMode:%x\n", Retries, pBmcInfo->UpdateMode)); + if (pBmcInfo->UpdateMode == BMC_READY) { + mIpmiInstance->BmcStatus = BMC_OK; + return EFI_SUCCESS; + } + } + } + } + + mIpmiInstance->BmcStatus = BMC_HARDFAIL; + return Status; +} // GetDeviceId() diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Pei/PeiGenericIpmi.h b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Pei/PeiGenericIpmi.h new file mode 100644 index 0000000000..d31af85325 --- /dev/null +++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Pei/PeiGenericIpmi.h @@ -0,0 +1,138 @@ +/** @file + Generic IPMI stack head file during PEI phase + + @copyright + Copyright 2017 - 2021 Intel Corporation.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef _PEI_IPMI_INIT_H_ +#define _PEI_IPMI_INIT_H_ + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "PeiIpmiBmcDef.h" +#include "PeiIpmiBmc.h" + +// +// Prototypes +// +#define MBXDAT_B 0x0B +#define BMC_KCS_TIMEOUT_PEI 5 // [s] Single KSC request timeout +#define KCS_DELAY_UNIT_PEI 1000 // [s] Each KSC IO delay +#define IPMI_DEFAULT_IO_BASE 0xCA2 + +// +// Internal(hook) function list +// +EFI_STATUS +SendPreBootSignaltoBmc ( + IN CONST EFI_PEI_SERVICES **PeiServices + ) + /*++ + +Routine Description: + Send Pre-Boot signal to BMC + +Arguments: + PeiServices - General purpose services available to every PEIM. + +Returns: + EFI_SUCCESS - Success +--*/ +; + +EFI_STATUS +PeiIpmiSendCommand ( + IN PEI_IPMI_TRANSPORT_PPI *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 +PeiGetIpmiBmcStatus ( + IN PEI_IPMI_TRANSPORT_PPI *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 +--*/ +; + +// +// internal function list +// +EFI_STATUS +GetDeviceId ( + IN PEI_IPMI_BMC_INSTANCE_DATA *mIpmiInstance + ) +/*++ + +Routine Description: + Execute the Get Device ID command to determine whether or not the BMC is in Force Update + Mode. If it is, then report it to the error manager. + +Arguments: + mIpmiInstance - Data structure describing BMC variables and used for sending commands + StatusCodeValue - An array used to accumulate error codes for later reporting. + ErrorCount - Counter used to keep track of error codes in StatusCodeValue + +Returns: + Status + +--*/ +; +#endif //_PEI_IPMI_INIT_H_ + diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Pei/PeiGenericIpmi.inf b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Pei/PeiGenericIpmi.inf new file mode 100644 index 0000000000..0ef2c18116 --- /dev/null +++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Pei/PeiGenericIpmi.inf @@ -0,0 +1,58 @@ +## @file +# Generic IPMI during PEI phase +# +# @copyright +# Copyright 2017 - 2021 Intel Corporation.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PeiGenericIpmi + FILE_GUID = 0B161208-2958-460C-B97F-B912A8AD0F8D + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + ENTRY_POINT = PeimIpmiInterfaceInit + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# +# HOB Guid C Name: gEfiHtBistHobGuid Hob Type: GUID_EXTENSION +# +[Sources] + ../Common/IpmiBmcCommon.h + ../Common/KcsBmc.c + ../Common/KcsBmc.h + PeiIpmiBmc.c + PeiIpmiBmc.h + PeiIpmiBmcDef.h + PeiGenericIpmi.c + PeiGenericIpmi.h + +[Packages] + MdePkg/MdePkg.dec + OutOfBandManagement/IpmiFeaturePkg/IpmiFeaturePkg.dec + +[LibraryClasses] + PeimEntryPoint + PciLib + MemoryAllocationLib + DebugLib + IoLib + TimerLib + +[Guids] + +[Ppis] + gPeiIpmiTransportPpiGuid #ALWAYS PRODUCE + +[Pcd] + gIpmiFeaturePkgTokenSpaceGuid.PcdIpmiIoBaseAddress + gIpmiFeaturePkgTokenSpaceGuid.PcdIpmiBmcReadyDelayTimer + gIpmiFeaturePkgTokenSpaceGuid.PcdSioMailboxBaseAddress + gIpmiFeaturePkgTokenSpaceGuid.PcdSignalPreBootToBmc + +[Depex] + TRUE diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Pei/PeiIpmiBmc.c b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Pei/PeiIpmiBmc.c new file mode 100644 index 0000000000..32665b3e22 --- /dev/null +++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Pei/PeiIpmiBmc.c @@ -0,0 +1,277 @@ +/** @file + Generic IPMI transport layer during PEI phase + + @copyright + Copyright 2016 - 2021 Intel Corporation.
+ 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; + + 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*) 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++; + 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; +} diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Pei/PeiIpmiBmc.h b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Pei/PeiIpmiBmc.h new file mode 100644 index 0000000000..40b9429e84 --- /dev/null +++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Pei/PeiIpmiBmc.h @@ -0,0 +1,38 @@ +/** @file + Generic IPMI transport layer head file during PEI phase + + @copyright + Copyright 2016 - 2021 Intel Corporation.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef _PEI_IPMI_BMC_H_ +#define _PEI_IPMI_BMC_H_ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "PeiIpmiBmcDef.h" +#include "KcsBmc.h" + +// +// IPMI Instance signature +// +#define SM_IPMI_BMC_SIGNATURE SIGNATURE_32 ('i', 'p', 'm', 'i') + +#define INSTANCE_FROM_PEI_SM_IPMI_BMC_THIS(a) \ + CR ( \ + a, \ + PEI_IPMI_BMC_INSTANCE_DATA, \ + IpmiTransportPpi, \ + SM_IPMI_BMC_SIGNATURE \ + ) + +#endif // _PEI_IPMI_BMC_H_ diff --git a/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Pei/PeiIpmiBmcDef.h b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Pei/PeiIpmiBmcDef.h new file mode 100644 index 0000000000..3fbe70ce62 --- /dev/null +++ b/Features/Intel/OutOfBandManagement/IpmiFeaturePkg/GenericIpmi/Pei/PeiIpmiBmcDef.h @@ -0,0 +1,156 @@ +/** @file + Generic IPMI transport layer common head file during PEI phase + + @copyright + Copyright 2016 - 2021 Intel Corporation.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef _PEI_IPMI_COMMON_BMC_H_ +#define _PEI_IPMI_COMMON_BMC_H_ + +#include + +#define MAX_TEMP_DATA 160 +#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 +#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_CODE_UNSPECIFIED \ + } +// +// Ensure proper structure formats +// +#pragma pack(1) +// +// Pei 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; + PEI_IPMI_TRANSPORT_PPI IpmiTransportPpi; + EFI_PEI_PPI_DESCRIPTOR PeiIpmiBmcDataDesc; +} PEI_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; +#pragma pack() + +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_SUCCESS - Command completed successfully + +--*/ +; + + +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 + +--*/ +; + + +#endif //_PEI_IPMI_COMMON_BMC_H_ -- 2.27.0.windows.1