/** @file KCS instance of Manageability Transport Library Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent */ #include #include #include #include #include #include #include #include #include "ManageabilityTransportKcs.h" MANAGEABILITY_TRANSPORT_KCS *mSingleSessionToken = NULL; EFI_GUID *SupportedManageabilityProtocol[] = { &gManageabilityProtocolIpmiGuid, &gManageabilityProtocolMctpGuid }; UINT8 NumberOfSupportedProtocol = (sizeof (SupportedManageabilityProtocol)/sizeof (EFI_GUID *)); MANAGEABILITY_TRANSPORT_KCS_HARDWARE_INFO mKcsHardwareInfo; /** This function initializes the transport interface. @param [in] TransportToken The transport token acquired through AcquireTransportSession function. @param [in] HardwareInfo The hardware information assigned to KCS transport interface. @retval EFI_SUCCESS Transport interface is initialized successfully. @retval EFI_INVALID_PARAMETER The invalid transport token. @retval EFI_NOT_READY The transport interface works fine but @retval is not ready. @retval EFI_DEVICE_ERROR The transport interface has problems. @retval EFI_ALREADY_STARTED Teh protocol interface has already initialized. @retval Otherwise Other errors. **/ EFI_STATUS EFIAPI KcsTransportInit ( IN MANAGEABILITY_TRANSPORT_TOKEN *TransportToken, IN MANAGEABILITY_TRANSPORT_HARDWARE_INFORMATION HardwareInfo OPTIONAL ) { CHAR16 *ManageabilityProtocolName; if (TransportToken == NULL) { DEBUG ((DEBUG_ERROR, "%a: Invalid transport token.\n", __FUNCTION__)); return EFI_INVALID_PARAMETER; } if (HardwareInfo.Kcs == NULL) { DEBUG ((DEBUG_INFO, "%a: Hardware information is not provided, use dfault settings.\n", __FUNCTION__)); mKcsHardwareInfo.MemoryMap = MANAGEABILITY_TRANSPORT_KCS_IO_MAP_IO; mKcsHardwareInfo.IoBaseAddress.IoAddress16 = PcdGet16 (PcdIpmiKcsIoBaseAddress); mKcsHardwareInfo.IoDataInAddress.IoAddress16 = mKcsHardwareInfo.IoBaseAddress.IoAddress16 + IPMI_KCS_DATA_IN_REGISTER_OFFSET; mKcsHardwareInfo.IoDataOutAddress.IoAddress16 = mKcsHardwareInfo.IoBaseAddress.IoAddress16 + IPMI_KCS_DATA_OUT_REGISTER_OFFSET; mKcsHardwareInfo.IoCommandAddress.IoAddress16 = mKcsHardwareInfo.IoBaseAddress.IoAddress16 + IPMI_KCS_COMMAND_REGISTER_OFFSET; mKcsHardwareInfo.IoStatusAddress.IoAddress16 = mKcsHardwareInfo.IoBaseAddress.IoAddress16 + IPMI_KCS_STATUS_REGISTER_OFFSET; } else { mKcsHardwareInfo.MemoryMap = ((MANAGEABILITY_TRANSPORT_KCS_HARDWARE_INFO *)HardwareInfo.Kcs)->MemoryMap; mKcsHardwareInfo.IoBaseAddress = ((MANAGEABILITY_TRANSPORT_KCS_HARDWARE_INFO *)HardwareInfo.Kcs)->IoBaseAddress; mKcsHardwareInfo.IoDataInAddress = ((MANAGEABILITY_TRANSPORT_KCS_HARDWARE_INFO *)HardwareInfo.Kcs)->IoDataInAddress; mKcsHardwareInfo.IoDataOutAddress = ((MANAGEABILITY_TRANSPORT_KCS_HARDWARE_INFO *)HardwareInfo.Kcs)->IoDataOutAddress; mKcsHardwareInfo.IoCommandAddress = ((MANAGEABILITY_TRANSPORT_KCS_HARDWARE_INFO *)HardwareInfo.Kcs)->IoCommandAddress; mKcsHardwareInfo.IoStatusAddress = ((MANAGEABILITY_TRANSPORT_KCS_HARDWARE_INFO *)HardwareInfo.Kcs)->IoStatusAddress; } // Get protocol specification name. ManageabilityProtocolName = HelperManageabilitySpecName (TransportToken->ManageabilityProtocolSpecification); DEBUG ((DEBUG_INFO, "%a: KCS transport hardware for %s is:\n", __FUNCTION__, ManageabilityProtocolName)); if (mKcsHardwareInfo.MemoryMap) { DEBUG ((DEBUG_INFO, "Memory Map I/O\n", __FUNCTION__)); DEBUG ((DEBUG_INFO, "Base Memory Address : 0x%08x\n", mKcsHardwareInfo.IoBaseAddress.IoAddress32)); DEBUG ((DEBUG_INFO, "Data in Address : 0x%08x\n", mKcsHardwareInfo.IoDataInAddress.IoAddress32)); DEBUG ((DEBUG_INFO, "Data out Address : 0x%08x\n", mKcsHardwareInfo.IoDataOutAddress.IoAddress32)); DEBUG ((DEBUG_INFO, "Command Address : 0x%08x\n", mKcsHardwareInfo.IoCommandAddress.IoAddress32)); DEBUG ((DEBUG_INFO, "Status Address : 0x%08x\n", mKcsHardwareInfo.IoStatusAddress.IoAddress32)); } else { DEBUG ((DEBUG_INFO, "I/O Map I/O\n")); DEBUG ((DEBUG_INFO, "Base I/O port : 0x%04x\n", mKcsHardwareInfo.IoBaseAddress.IoAddress16)); DEBUG ((DEBUG_INFO, "Data in I/O port : 0x%04x\n", mKcsHardwareInfo.IoDataInAddress.IoAddress16)); DEBUG ((DEBUG_INFO, "Data out I/O port: 0x%04x\n", mKcsHardwareInfo.IoDataOutAddress.IoAddress16)); DEBUG ((DEBUG_INFO, "Command I/O port : 0x%04x\n", mKcsHardwareInfo.IoCommandAddress.IoAddress16)); DEBUG ((DEBUG_INFO, "Status I/O port : 0x%04x\n", mKcsHardwareInfo.IoStatusAddress.IoAddress16)); } return EFI_SUCCESS; } /** This function returns the transport interface status. The generic EFI_STATUS is returned to caller directly, The additional information of transport interface could be optionally returned in TransportAdditionalStatus to describes the status that can't be described obviously through EFI_STATUS. See the definition of MANAGEABILITY_TRANSPORT_STATUS. @param [in] TransportToken The transport token acquired through AcquireTransportSession function. @param [out] TransportAdditionalStatus The additional status of transport interface. NULL means no additional status of this transport interface. @retval EFI_SUCCESS Transport interface status is returned. @retval EFI_INVALID_PARAMETER The invalid transport token. @retval EFI_DEVICE_ERROR The transport interface has problems to return @retval EFI_UNSUPPORTED The transport interface doesn't have status report. Otherwise Other errors. **/ EFI_STATUS EFIAPI KcsTransportStatus ( IN MANAGEABILITY_TRANSPORT_TOKEN *TransportToken, OUT MANAGEABILITY_TRANSPORT_ADDITIONAL_STATUS *TransportAdditionalStatus OPTIONAL ) { UINT8 TransportStatus; if (TransportToken == NULL) { DEBUG ((DEBUG_ERROR, "%a: Invalid transport token.\n", __FUNCTION__)); return EFI_INVALID_PARAMETER; } if (TransportAdditionalStatus == NULL) { return EFI_SUCCESS; } TransportStatus = IPMI_KCS_GET_STATE (KcsRegisterRead8 (KCS_REG_STATUS)); *TransportAdditionalStatus = MANAGEABILITY_TRANSPORT_ADDITIONAL_STATUS_NO_ERRORS; if (TransportStatus != IpmiKcsIdleState) { if (TransportStatus == IpmiKcsReadState) { // // Transport is in read state. *TransportAdditionalStatus |= MANAGEABILITY_TRANSPORT_ADDITIONAL_STATUS_BUSY_IN_READ; return EFI_NOT_READY; } else if (TransportStatus == IpmiKcsWriteState) { // // Transport is in read state. *TransportAdditionalStatus |= MANAGEABILITY_TRANSPORT_ADDITIONAL_STATUS_BUSY_IN_WRITE; return EFI_NOT_READY; } else { return EFI_DEVICE_ERROR; } } return EFI_SUCCESS; } /** This function resets the transport interface. The generic EFI_STATUS is returned to caller directly after reseting transport interface. The additional information of transport interface could be optionally returned in TransportAdditionalStatus to describes the status that can't be described obviously through EFI_STATUS. See the definition of MANAGEABILITY_TRANSPORT_ADDITIONAL_STATUS. @param [in] TransportToken The transport token acquired through AcquireTransportSession function. @param [out] TransportAdditionalStatus The additional status of specific transport interface after the reset. NULL means no additional status of this transport interface. @retval EFI_SUCCESS Transport interface status is returned. @retval EFI_INVALID_PARAMETER The invalid transport token. @retval EFI_TIMEOUT The reset process is time out. @retval EFI_DEVICE_ERROR The transport interface has problems to return status. Otherwise Other errors. **/ EFI_STATUS EFIAPI KcsTransportReset ( IN MANAGEABILITY_TRANSPORT_TOKEN *TransportToken, OUT MANAGEABILITY_TRANSPORT_ADDITIONAL_STATUS *TransportAdditionalStatus OPTIONAL ) { return EFI_UNSUPPORTED; } /** This function transmit the request over target transport interface. The generic EFI_STATUS is returned to caller directly after reseting transport interface. The additional information of transport interface could be optionally returned in TransportAdditionalStatus to describes the status that can't be described obviously through EFI_STATUS. See the definition of MANAGEABILITY_TRANSPORT_ADDITIONAL_STATUS. @param [in] TransportToken The transport token acquired through AcquireTransportSession function. @param [in] TransferToken The transfer token, see the definition of MANAGEABILITY_TRANSFER_TOKEN. @retval The EFI status is returned in MANAGEABILITY_TRANSFER_TOKEN. **/ VOID EFIAPI KcsTransportTransmitReceive ( IN MANAGEABILITY_TRANSPORT_TOKEN *TransportToken, IN MANAGEABILITY_TRANSFER_TOKEN *TransferToken ) { EFI_STATUS Status; MANAGEABILITY_IPMI_TRANSPORT_HEADER *TransmitHeader; if (TransportToken == NULL || TransferToken == NULL) { DEBUG ((DEBUG_ERROR, "%a: Invalid transport token or transfer token.\n", __FUNCTION__)); return; } TransmitHeader = (MANAGEABILITY_IPMI_TRANSPORT_HEADER *)TransferToken->TransmitHeader; if (TransmitHeader == NULL) { TransferToken->TransferStatus = EFI_INVALID_PARAMETER; return; } Status = KcsTransportSendCommand ( TransmitHeader->NetFn, TransmitHeader->Command, TransferToken->TransmitPackage.TransmitPayload, TransferToken->TransmitPackage.TransmitSizeInByte, TransferToken->ReceivePackage.ReceiveBuffer, &TransferToken->ReceivePackage.ReceiveSizeInByte ); TransferToken->TransferStatus = Status; KcsTransportStatus (TransportToken, &TransferToken->TransportAdditionalStatus); } /** This function acquires to create a transport session to transmit manageability packet. A transport token is returned to caller for the follow up operations. @param [in] ManageabilityProtocolSpec The protocol spec the transport interface is acquired. @param [out] TransportToken The pointer to receive the transport token created by the target transport interface library. @retval EFI_SUCCESS Token is created successfully. @retval EFI_OUT_OF_RESOURCES Out of resource to create a new transport session. @retval EFI_UNSUPPORTED Protocol is not supported on this transport interface. @retval Otherwise Other errors. **/ EFI_STATUS AcquireTransportSession ( IN EFI_GUID *ManageabilityProtocolSpec, OUT MANAGEABILITY_TRANSPORT_TOKEN **TransportToken ) { EFI_STATUS Status; MANAGEABILITY_TRANSPORT_KCS *KcsTransportToken; if (ManageabilityProtocolSpec == NULL) { DEBUG ((DEBUG_ERROR, "%a: No Manageability protocol specification specified.\n", __FUNCTION__)); return EFI_INVALID_PARAMETER; } if (TransportToken == NULL) { DEBUG ((DEBUG_ERROR, "%a: TransportToken is NULL.\n", __FUNCTION__)); return EFI_INVALID_PARAMETER; } Status = HelperManageabilityCheckSupportedSpec ( &gManageabilityTransportKcsGuid, SupportedManageabilityProtocol, NumberOfSupportedProtocol, ManageabilityProtocolSpec ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "%a: Protocol is not supported on this transport interface.\n", __FUNCTION__)); return EFI_UNSUPPORTED; } if (mSingleSessionToken != NULL) { DEBUG ((DEBUG_ERROR, "%a: This manageability transport library only supports one session transport token.\n", __FUNCTION__)); return EFI_OUT_OF_RESOURCES; } KcsTransportToken = AllocateZeroPool (sizeof (MANAGEABILITY_TRANSPORT_KCS)); if (KcsTransportToken == NULL) { DEBUG ((DEBUG_ERROR, "%a: Fail to allocate memory for MANAGEABILITY_TRANSPORT_KCS\n", __FUNCTION__)); return EFI_OUT_OF_RESOURCES; } KcsTransportToken->Token.Transport = AllocateZeroPool (sizeof (MANAGEABILITY_TRANSPORT)); if (KcsTransportToken->Token.Transport == NULL) { FreePool (KcsTransportToken); DEBUG ((DEBUG_ERROR, "%a: Fail to allocate memory for MANAGEABILITY_TRANSPORT\n", __FUNCTION__)); return EFI_OUT_OF_RESOURCES; } KcsTransportToken->Signature = MANAGEABILITY_TRANSPORT_KCS_SIGNATURE; KcsTransportToken->Token.ManageabilityProtocolSpecification = ManageabilityProtocolSpec; KcsTransportToken->Token.Transport->TransportVersion = MANAGEABILITY_TRANSPORT_TOKEN_VERSION; KcsTransportToken->Token.Transport->ManageabilityTransportSpecification = &gManageabilityTransportKcsGuid; KcsTransportToken->Token.Transport->TransportName = L"KCS"; KcsTransportToken->Token.Transport->Function.Version1_0 = AllocateZeroPool (sizeof (MANAGEABILITY_TRANSPORT_FUNCTION_V1_0)); if (KcsTransportToken->Token.Transport->Function.Version1_0 == NULL) { DEBUG ((DEBUG_ERROR, "%a: Fail to allocate memory for MANAGEABILITY_TRANSPORT_FUNCTION_V1_0\n", __FUNCTION__)); FreePool (KcsTransportToken); FreePool (KcsTransportToken->Token.Transport); return EFI_OUT_OF_RESOURCES; } KcsTransportToken->Token.Transport->Function.Version1_0->TransportInit = KcsTransportInit; KcsTransportToken->Token.Transport->Function.Version1_0->TransportReset = KcsTransportReset; KcsTransportToken->Token.Transport->Function.Version1_0->TransportStatus = KcsTransportStatus; KcsTransportToken->Token.Transport->Function.Version1_0->TransportTransmitReceive = KcsTransportTransmitReceive; mSingleSessionToken = KcsTransportToken; *TransportToken = &KcsTransportToken->Token; return EFI_SUCCESS; } /** This function returns the transport capabilities. @param [out] TransportFeature Pointer to receive transport capabilities. See the definitions of MANAGEABILITY_TRANSPORT_CAPABILITY. **/ VOID GetTransportCapability ( OUT MANAGEABILITY_TRANSPORT_CAPABILITY *TransportCapability ) { if (TransportCapability != NULL) { *TransportCapability = 0; } } /** This function releases the manageability session. @param [in] TransportToken The transport token acquired through AcquireTransportSession. @retval EFI_SUCCESS Token is released successfully. @retval EFI_INVALID_PARAMETER Invalid TransportToken. @retval Otherwise Other errors. **/ EFI_STATUS ReleaseTransportSession ( IN MANAGEABILITY_TRANSPORT_TOKEN *TransportToken ) { EFI_STATUS Status; MANAGEABILITY_TRANSPORT_KCS *KcsTransportToken; if (TransportToken == NULL) { Status = EFI_INVALID_PARAMETER; } KcsTransportToken = MANAGEABILITY_TRANSPORT_KCS_FROM_LINK (TransportToken); if (mSingleSessionToken != KcsTransportToken) { Status = EFI_INVALID_PARAMETER; } if (KcsTransportToken != NULL) { FreePool (KcsTransportToken->Token.Transport->Function.Version1_0); FreePool (KcsTransportToken->Token.Transport); FreePool (KcsTransportToken); mSingleSessionToken = NULL; Status = EFI_SUCCESS; } if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "%a: Fail to release KCS transport token (%r).\n", __FUNCTION__, Status)); } return Status; }