/** @file
  IPMI Command - NetFnApp.

  Copyright (c) 2018 - 2021, Intel Corporation. All rights reserved.<BR>
  Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.<BR>

  SPDX-License-Identifier: BSD-2-Clause-Patent
**/

#include <PiPei.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/IpmiBaseLib.h>

#include <IndustryStandard/Ipmi.h>

EFI_STATUS
EFIAPI
IpmiGetDeviceId (
  OUT IPMI_GET_DEVICE_ID_RESPONSE  *DeviceId
  )
{
  EFI_STATUS                   Status;
  UINT32                       DataSize;

  DataSize = sizeof(*DeviceId);
  Status = IpmiSubmitCommand (
             IPMI_NETFN_APP,
             IPMI_APP_GET_DEVICE_ID,
             NULL,
             0,
             (VOID *)DeviceId,
             &DataSize
             );
  return Status;
}

EFI_STATUS
EFIAPI
IpmiGetSelfTestResult (
  OUT IPMI_SELF_TEST_RESULT_RESPONSE   *SelfTestResult
  )
{
  EFI_STATUS                   Status;
  UINT32                       DataSize;

  DataSize = sizeof(*SelfTestResult);
  Status = IpmiSubmitCommand (
             IPMI_NETFN_APP,
             IPMI_APP_GET_SELFTEST_RESULTS,
             NULL,
             0,
             (VOID *)SelfTestResult,
             &DataSize
             );
  return Status;
}

EFI_STATUS
EFIAPI
IpmiResetWatchdogTimer (
  OUT UINT8                            *CompletionCode
  )
{
  EFI_STATUS                   Status;
  UINT32                       DataSize;

  DataSize = sizeof(*CompletionCode);
  Status = IpmiSubmitCommand (
             IPMI_NETFN_APP,
             IPMI_APP_RESET_WATCHDOG_TIMER,
             NULL,
             0,
             (VOID *)CompletionCode,
             &DataSize
             );
  return Status;
}

EFI_STATUS
EFIAPI
IpmiSetWatchdogTimer (
  IN  IPMI_SET_WATCHDOG_TIMER_REQUEST  *SetWatchdogTimer,
  OUT UINT8                            *CompletionCode
  )
{
  EFI_STATUS                   Status;
  UINT32                       DataSize;

  DataSize = sizeof(*CompletionCode);
  Status = IpmiSubmitCommand (
             IPMI_NETFN_APP,
             IPMI_APP_SET_WATCHDOG_TIMER,
             (VOID *)SetWatchdogTimer,
             sizeof(*SetWatchdogTimer),
             (VOID *)CompletionCode,
             &DataSize
             );
  return Status;
}

EFI_STATUS
EFIAPI
IpmiGetWatchdogTimer (
  OUT IPMI_GET_WATCHDOG_TIMER_RESPONSE *GetWatchdogTimer
  )
{
  EFI_STATUS                   Status;
  UINT32                       DataSize;

  DataSize = sizeof(*GetWatchdogTimer);
  Status = IpmiSubmitCommand (
             IPMI_NETFN_APP,
             IPMI_APP_GET_WATCHDOG_TIMER,
             NULL,
             0,
             (VOID *)GetWatchdogTimer,
             &DataSize
             );
  return Status;
}

EFI_STATUS
EFIAPI
IpmiSetBmcGlobalEnables (
  IN  IPMI_SET_BMC_GLOBAL_ENABLES_REQUEST  *SetBmcGlobalEnables,
  OUT UINT8                                *CompletionCode
  )
{
  EFI_STATUS                   Status;
  UINT32                       DataSize;

  DataSize = sizeof(*CompletionCode);
  Status = IpmiSubmitCommand (
             IPMI_NETFN_APP,
             IPMI_APP_SET_BMC_GLOBAL_ENABLES,
             (VOID *)SetBmcGlobalEnables,
             sizeof(*SetBmcGlobalEnables),
             (VOID *)CompletionCode,
             &DataSize
             );
  return Status;
}

EFI_STATUS
EFIAPI
IpmiGetBmcGlobalEnables (
  OUT IPMI_GET_BMC_GLOBAL_ENABLES_RESPONSE *GetBmcGlobalEnables
  )
{
  EFI_STATUS                   Status;
  UINT32                       DataSize;

  DataSize = sizeof(*GetBmcGlobalEnables);
  Status = IpmiSubmitCommand (
             IPMI_NETFN_APP,
             IPMI_APP_GET_BMC_GLOBAL_ENABLES,
             NULL,
             0,
             (VOID *)GetBmcGlobalEnables,
             &DataSize
             );
  return Status;
}

EFI_STATUS
EFIAPI
IpmiClearMessageFlags (
  IN  IPMI_CLEAR_MESSAGE_FLAGS_REQUEST  *ClearMessageFlagsRequest,
  OUT UINT8                             *CompletionCode
  )
{
  EFI_STATUS                   Status;
  UINT32                       DataSize;

  DataSize = sizeof(*CompletionCode);
  Status = IpmiSubmitCommand (
             IPMI_NETFN_APP,
             IPMI_APP_CLEAR_MESSAGE_FLAGS,
             (VOID *)ClearMessageFlagsRequest,
             sizeof(*ClearMessageFlagsRequest),
             (VOID *)CompletionCode,
             &DataSize
             );
  return Status;
}

EFI_STATUS
EFIAPI
IpmiGetMessageFlags (
  OUT IPMI_GET_MESSAGE_FLAGS_RESPONSE *GetMessageFlagsResponse
  )
{
  EFI_STATUS                   Status;
  UINT32                       DataSize;

  DataSize = sizeof(*GetMessageFlagsResponse);
  Status = IpmiSubmitCommand (
             IPMI_NETFN_APP,
             IPMI_APP_GET_MESSAGE_FLAGS,
             NULL,
             0,
             (VOID *)GetMessageFlagsResponse,
             &DataSize
             );
  return Status;
}

EFI_STATUS
EFIAPI
IpmiGetMessage (
  OUT IPMI_GET_MESSAGE_RESPONSE *GetMessageResponse,
  IN OUT UINT32                 *GetMessageResponseSize
  )
{
  EFI_STATUS                   Status;

  Status = IpmiSubmitCommand (
             IPMI_NETFN_APP,
             IPMI_APP_GET_MESSAGE,
             NULL,
             0,
             (VOID *)GetMessageResponse,
             GetMessageResponseSize
             );
  return Status;
}

EFI_STATUS
EFIAPI
IpmiSendMessage (
  IN  IPMI_SEND_MESSAGE_REQUEST  *SendMessageRequest,
  IN  UINT32                     SendMessageRequestSize,
  OUT IPMI_SEND_MESSAGE_RESPONSE *SendMessageResponse,
  IN OUT UINT32                  *SendMessageResponseSize
  )
{
  EFI_STATUS                   Status;

  Status = IpmiSubmitCommand (
             IPMI_NETFN_APP,
             IPMI_APP_SEND_MESSAGE,
             (VOID *)SendMessageRequest,
             SendMessageRequestSize,
             (VOID *)SendMessageResponse,
             SendMessageResponseSize
             );
  return Status;
}

/**
  This function gets the system UUID.

  @param[out] SystemGuid   The pointer to retrieve system UUID.

  @retval EFI_SUCCESS               UUID is returned.
  @retval EFI_INVALID_PARAMETER     SystemGuid is a NULL pointer.
  @retval Others                    Other errors.

**/
EFI_STATUS
EFIAPI
IpmiGetSystemUuid (
  OUT EFI_GUID *SystemGuid
  )
{
  EFI_STATUS                    Status;
  UINT32                        RequestSize;
  UINT32                        ResponseSize;
  IPMI_GET_SYSTEM_UUID_RESPONSE GetSystemUuidResponse;

  if (SystemGuid == NULL) {
    return EFI_INVALID_PARAMETER;
  }
  RequestSize = 0;
  ResponseSize = sizeof (IPMI_GET_SYSTEM_UUID_RESPONSE);
  Status = IpmiSubmitCommand (
             IPMI_NETFN_APP,
             IPMI_APP_GET_SYSTEM_GUID,
             (VOID *)NULL,
             RequestSize,
             (VOID *)&GetSystemUuidResponse,
             &ResponseSize
             );
  if (!EFI_ERROR (Status) && GetSystemUuidResponse.CompletionCode == IPMI_COMP_CODE_NORMAL) {
    CopyMem (
      (VOID *)SystemGuid,
      (VOID *)&GetSystemUuidResponse.SystemUuid,
      sizeof (EFI_GUID)
      );
  }
  return Status;
}

/**
  This function gets the channel information.

  @param[in]  GetChannelInfoRequest          The get channel information request.
  @param[out] GetChannelInfoResponse         The get channel information response.
  @param[out] GetChannelInfoResponseSize     When input, the expected size of response.
                                             When output, the exact size of the returned
                                             response.

  @retval EFI_SUCCESS            Get channel information successfully.
  @retval EFI_INVALID_PARAMETER  One of the given input parameters is invalid.
  @retval Others                 Other errors.

**/
EFI_STATUS
EFIAPI
IpmiGetChannelInfo (
  IN  IPMI_GET_CHANNEL_INFO_REQUEST  *GetChannelInfoRequest,
  OUT IPMI_GET_CHANNEL_INFO_RESPONSE *GetChannelInfoResponse,
  OUT UINT32                         *GetChannelInfoResponseSize
  )
{
  EFI_STATUS Status;

  if (GetChannelInfoRequest == NULL ||
      GetChannelInfoResponse == NULL ||
      GetChannelInfoResponseSize == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  *GetChannelInfoResponseSize = sizeof (IPMI_GET_CHANNEL_INFO_RESPONSE);
  Status = IpmiSubmitCommand (
             IPMI_NETFN_APP,
             IPMI_APP_GET_CHANNEL_INFO,
             (UINT8 *)GetChannelInfoRequest,
             sizeof (IPMI_GET_CHANNEL_INFO_REQUEST),
             (UINT8 *)GetChannelInfoResponse,
             GetChannelInfoResponseSize
             );
  return Status;
}
