/** @file IPMI Manageability Protocol common file. Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include #include #include #include #include #include "IpmiProtocolCommon.h" /** This functions setup the IPMI transport hardware information according to the specification of transport token acquired from transport library. @param[in] TransportToken The transport interface. @param[out] HardwareInformation Pointer to receive the hardware information. @retval EFI_SUCCESS Hardware information is returned in HardwareInformation. Caller must free the memory allocated for HardwareInformation once it doesn't need it. @retval EFI_UNSUPPORTED No hardware information for the specification specified in the transport token. #retval EFI_OUT_OF_RESOURCES Not enough memory for MANAGEABILITY_TRANSPORT_KCS_HARDWARE_INFO. **/ EFI_STATUS SetupIpmiTransportHardwareInformation ( IN MANAGEABILITY_TRANSPORT_TOKEN *TransportToken, OUT MANAGEABILITY_TRANSPORT_HARDWARE_INFORMATION *HardwareInformation ) { MANAGEABILITY_TRANSPORT_KCS_HARDWARE_INFO *KcsHardwareInfo; KcsHardwareInfo = AllocatePool (sizeof (MANAGEABILITY_TRANSPORT_KCS_HARDWARE_INFO)); if (KcsHardwareInfo == NULL) { DEBUG ((DEBUG_ERROR, "%a: Not enough memory for MANAGEABILITY_TRANSPORT_KCS_HARDWARE_INFO.\n", __FUNCTION__)); return EFI_OUT_OF_RESOURCES; } if (CompareGuid (&gManageabilityTransportKcsGuid, TransportToken->Transport->ManageabilityTransportSpecification)) { // This is KCS transport interface. KcsHardwareInfo->MemoryMap = MANAGEABILITY_TRANSPORT_KCS_IO_MAP_IO; KcsHardwareInfo->IoBaseAddress.IoAddress16 = IPMI_KCS_BASE_ADDRESS; KcsHardwareInfo->IoDataInAddress.IoAddress16 = IPMI_KCS_REG_DATA_IN; KcsHardwareInfo->IoDataOutAddress.IoAddress16 = IPMI_KCS_REG_DATA_OUT; KcsHardwareInfo->IoCommandAddress.IoAddress16 = IPMI_KCS_REG_COMMAND; KcsHardwareInfo->IoStatusAddress.IoAddress16 = IPMI_KCS_REG_STATUS; HardwareInformation->Kcs = KcsHardwareInfo; return EFI_SUCCESS; } else { DEBUG ((DEBUG_ERROR, "%a: No implementation of setting hardware information.", __FUNCTION__)); ASSERT (FALSE); } return EFI_UNSUPPORTED; } /** This functions setup the final header/body/trailer packets for the acquired transport interface. @param[in] TransportToken The transport interface. @param[in] NetFunction IPMI function. @param[in] Command IPMI command. @param[out] PacketHeader The pointer to receive header of request. @param[in, out] PacketBody The request body. When IN, it is the caller's request body. When OUT and NULL, the request body is not changed. When OUT and non-NULL, the request body is changed to conform the transport interface. @param[in, out] PacketBodySize The request body size. When OUT and non-zero, it is the new data length of request body. When OUT and zero, the request body is unchanged. @param[out] PacketTrailer The pointer to receive trailer of request. @retval EFI_SUCCESS Request packet is returned. @retval EFI_UNSUPPORTED Request packet is not returned because the unsupported transport interface. **/ EFI_STATUS SetupIpmiRequestTransportPacket ( IN MANAGEABILITY_TRANSPORT_TOKEN *TransportToken, IN UINT8 NetFunction, IN UINT8 Command, OUT MANAGEABILITY_TRANSPORT_HEADER *PacketHeader OPTIONAL, IN OUT UINT8 **PacketBody OPTIONAL, IN OUT UINT32 *PacketBodySize OPTIONAL, OUT MANAGEABILITY_TRANSPORT_TRAILER *PacketTrailer OPTIONAL ) { MANAGEABILITY_IPMI_TRANSPORT_HEADER *IpmiHeader; if (CompareGuid (&gManageabilityTransportKcsGuid, TransportToken->Transport->ManageabilityTransportSpecification)) { // This is KCS transport interface. IpmiHeader = AllocateZeroPool (sizeof (MANAGEABILITY_IPMI_TRANSPORT_HEADER)); if (IpmiHeader == NULL) { return EFI_OUT_OF_RESOURCES; } IpmiHeader->Command = Command; IpmiHeader->Lun = 0; IpmiHeader->NetFn = NetFunction; if (PacketHeader != NULL) { *PacketHeader = (MANAGEABILITY_TRANSPORT_HEADER *)IpmiHeader; } if (PacketTrailer != NULL) { *PacketTrailer = NULL; } if (PacketBody != NULL) { *PacketBody = NULL; } if (PacketBodySize != NULL) { *PacketBodySize = 0; } } else { DEBUG ((DEBUG_ERROR, "%a: No implementation of building up packet.", __FUNCTION__)); ASSERT (FALSE); } return EFI_SUCCESS; } /** Common code to submit IPMI commands @param[in] TransportToken TRansport token. @param[in] NetFunction Net function of the command. @param[in] Command IPMI Command. @param[in] RequestData Command Request Data. @param[in] RequestDataSize Size of Command Request Data. @param[out] ResponseData Command Response Data. The completion code is the first byte of response data. @param[in, out] ResponseDataSize Size of Command Response Data. @retval EFI_SUCCESS The command byte stream was successfully submit to the device and a response was successfully received. @retval EFI_NOT_FOUND The command was not successfully sent to the device or a response was not successfully received from the device. @retval EFI_NOT_READY Ipmi Device is not ready for Ipmi command access. @retval EFI_DEVICE_ERROR Ipmi Device hardware error. @retval EFI_TIMEOUT The command time out. @retval EFI_UNSUPPORTED The command was not successfully sent to the device. @retval EFI_OUT_OF_RESOURCES The resource allocation is out of resource or data size error. **/ EFI_STATUS CommonIpmiSubmitCommand ( IN MANAGEABILITY_TRANSPORT_TOKEN *TransportToken, IN UINT8 NetFunction, IN UINT8 Command, IN UINT8 *RequestData OPTIONAL, IN UINT32 RequestDataSize, OUT UINT8 *ResponseData OPTIONAL, IN OUT UINT32 *ResponseDataSize OPTIONAL ) { EFI_STATUS Status; UINT8 *ThisRequestData; UINT32 ThisRequestDataSize; MANAGEABILITY_TRANSFER_TOKEN TransferToken; MANAGEABILITY_TRANSPORT_HEADER IpmiTransportHeader; MANAGEABILITY_TRANSPORT_TRAILER IpmiTransportTrailer; MANAGEABILITY_TRANSPORT_ADDITIONAL_STATUS TransportAdditionalStatus; if (TransportToken == NULL) { DEBUG ((DEBUG_ERROR, "%a: No transport toke for IPMI\n", __FUNCTION__)); return EFI_UNSUPPORTED; } Status = TransportToken->Transport->Function.Version1_0->TransportStatus ( TransportToken, &TransportAdditionalStatus ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "%a: Transport for IPMI has problem - (%r)\n", __FUNCTION__, Status)); return Status; } ThisRequestData = RequestData; ThisRequestDataSize = RequestDataSize; IpmiTransportHeader = NULL; IpmiTransportTrailer = NULL; Status = SetupIpmiRequestTransportPacket ( TransportToken, NetFunction, Command, &IpmiTransportHeader, &ThisRequestData, &ThisRequestDataSize, &IpmiTransportTrailer ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "%a: Fail to build packets - (%r)\n", __FUNCTION__, Status)); return Status; } ZeroMem (&TransferToken, sizeof (MANAGEABILITY_TRANSFER_TOKEN)); TransferToken.TransmitHeader = IpmiTransportHeader; TransferToken.TransmitTrailer = IpmiTransportTrailer; // Transmit packet. if ((ThisRequestData == NULL) || (ThisRequestDataSize == 0)) { // Transmit parameter were not changed by SetupIpmiRequestTransportPacket(). TransferToken.TransmitPackage.TransmitPayload = RequestData; TransferToken.TransmitPackage.TransmitSizeInByte = RequestDataSize; } else { TransferToken.TransmitPackage.TransmitPayload = ThisRequestData; TransferToken.TransmitPackage.TransmitSizeInByte = ThisRequestDataSize; } TransferToken.TransmitPackage.TransmitTimeoutInMillisecond = MANAGEABILITY_TRANSPORT_NO_TIMEOUT; // Receive packet. TransferToken.ReceivePackage.ReceiveBuffer = ResponseData; TransferToken.ReceivePackage.ReceiveSizeInByte = *ResponseDataSize; TransferToken.ReceivePackage.TransmitTimeoutInMillisecond = MANAGEABILITY_TRANSPORT_NO_TIMEOUT; TransportToken->Transport->Function.Version1_0->TransportTransmitReceive ( TransportToken, &TransferToken ); if (IpmiTransportHeader != NULL) { FreePool ((VOID *)IpmiTransportHeader); } if (IpmiTransportTrailer != NULL) { FreePool ((VOID *)IpmiTransportTrailer); } if (ThisRequestData != NULL) { FreePool ((VOID *)ThisRequestData); } // Return transfer status. // Status = TransferToken.TransferStatus; TransportAdditionalStatus = TransferToken.TransportAdditionalStatus; if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "%a: Failed to send IPMI command.\n", __FUNCTION__)); return Status; } if (ResponseDataSize != NULL) { *ResponseDataSize = TransferToken.ReceivePackage.ReceiveSizeInByte; } return Status; }