public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Nhi Pham via groups.io" <nhi=os.amperecomputing.com@groups.io>
To: "Chang, Abner" <Abner.Chang@amd.com>,
	Nickle Wang <nicklew@nvidia.com>,
	"devel@edk2.groups.io" <devel@edk2.groups.io>
Cc: "Attar, AbdulLateef (Abdul Lateef)" <AbdulLateef.Attar@amd.com>,
	Tinh Nguyen <tinhnguyen@amperemail.onmicrosoft.com>,
	Thang Nguyen OS <thang@amperemail.onmicrosoft.com>,
	Mike Maslenkin <mike.maslenkin@gmail.com>
Subject: Re: [edk2-devel] [edk2-platforms][PATCH v2] ManageabilityPkg: add support for the phosphor ipmi blob transfer protocol
Date: Fri, 17 May 2024 15:34:32 +0700	[thread overview]
Message-ID: <fbeca374-7027-4a44-9192-5424abf51844@os.amperecomputing.com> (raw)
In-Reply-To: <LV8PR12MB9452984005EA3BA16CF328A9EAEE2@LV8PR12MB9452.namprd12.prod.outlook.com>

Hi Abner,

It' hard to say actually. I don't spend full-time for open-source work. 
But I will try to complete it within 2 weeks or sooner.

Most of Ampere Altra drivers including IPMI SSIF are living at 
https://github.com/AmpereComputing/edk2-platforms. The effort now is to 
port to be compatible with ManageabilityPkg.

Regards,
Nhi

On 5/17/2024 3:16 PM, Chang, Abner wrote:
> [AMD Official Use Only - AMD Internal Distribution Only]
> 
> Hi Nhi,
> How much effort you think to have the SSIF ManageabilityPkg port?
> 
> Regards,
> Abner
> 
>> -----Original Message-----
>> From: Nhi Pham <nhi@os.amperecomputing.com>
>> Sent: Friday, May 17, 2024 3:49 PM
>> To: Nickle Wang <nicklew@nvidia.com>; devel@edk2.groups.io
>> Cc: Chang, Abner <Abner.Chang@amd.com>; Attar, AbdulLateef (Abdul
>> Lateef) <AbdulLateef.Attar@amd.com>; Tinh Nguyen
>> <tinhnguyen@amperemail.onmicrosoft.com>; Thang Nguyen OS
>> <thang@amperemail.onmicrosoft.com>; Mike Maslenkin
>> <mike.maslenkin@gmail.com>
>> Subject: Re: [edk2-platforms][PATCH v2] ManageabilityPkg: add support for
>> the phosphor ipmi blob transfer protocol
>>
>> Caution: This message originated from an External Source. Use proper caution
>> when opening attachments, clicking links, or responding.
>>
>>
>> Hi Nickle,
>>
>> Please see my comments inline...
>>
>> P/s: I just realized that I can not test this protocol without IPMI SSIF
>> to be compatible with ManageabilityPkg framework.
>>
>> On 5/15/2024 10:06 PM, Nickle Wang wrote:
>>> REF:https://bugzilla.tianocore.org/show_bug.cgi?id=4773
>>>
>>> This change implements the blob transfer protocol used in OpenBmc
>>> documented here: https://github.com/openbmc/phosphor-ipmi-blobs
>>>
>>> Signed-off-by: Nick Ramirez <nramirez@nvidia.com>
>>> Co-authored-by: Nickle Wang <nicklew@nvidia.com>
>>> Cc: Abner Chang <abner.chang@amd.com>
>>> Cc: Abdul Lateef Attar <AbdulLateef.Attar@amd.com>
>>> Cc: Tinh Nguyen <tinhnguyen@amperemail.onmicrosoft.com>
>>> Cc: Nhi Pham <nhi@os.amperecomputing.com>
>>> Cc: Thang Nguyen OS <thang@amperemail.onmicrosoft.com>
>>> Cc: Mike Maslenkin <mike.maslenkin@gmail.com>
>>> ---
>>>    .../ManageabilityPkg/ManageabilityPkg.dec     |    3 +
>>>    .../Include/Manageability.dsc                 |    2 +
>>>    .../IpmiBlobTransferDxe.inf                   |   39 +
>>>    .../IpmiBlobTransferTestUnitTestsHost.inf     |   40 +
>>>    .../Include/Protocol/IpmiBlobTransfer.h       |  253 ++++
>>>    .../InternalIpmiBlobTransfer.h                |  407 ++++++
>>>    .../IpmiBlobTransferDxe/IpmiBlobTransferDxe.c |  872 +++++++++++++
>>>    .../UnitTest/IpmiBlobTransferTestUnitTests.c  | 1113 +++++++++++++++++
>>>    .../Universal/IpmiBlobTransferDxe/Readme.md   |   24 +
>>>    9 files changed, 2753 insertions(+)
>>>    create mode 100644
>> Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransfer
>> Dxe.inf
>>>    create mode 100644
>> Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlo
>> bTransferTestUnitTestsHost.inf
>>>    create mode 100644
>> Features/ManageabilityPkg/Include/Protocol/IpmiBlobTransfer.h
>>>    create mode 100644
>> Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiBlob
>> Transfer.h
>>>    create mode 100644
>> Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransfer
>> Dxe.c
>>>    create mode 100644
>> Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlo
>> bTransferTestUnitTests.c
>>>    create mode 100644
>> Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/Readme.md
>>>
>>> diff --git a/Features/ManageabilityPkg/ManageabilityPkg.dec
>> b/Features/ManageabilityPkg/ManageabilityPkg.dec
>>> index eb0ee67cba..dc1d00162c 100644
>>> --- a/Features/ManageabilityPkg/ManageabilityPkg.dec
>>> +++ b/Features/ManageabilityPkg/ManageabilityPkg.dec
>>> @@ -4,6 +4,7 @@
>>>    # those are related to the platform management.
>>>    #
>>>    # Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.<BR>
>>> +# Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights
>> reserved.
>>>    # SPDX-License-Identifier: BSD-2-Clause-Patent
>>>    #
>>>    ##
>>> @@ -58,6 +59,8 @@
>>>      gEdkiiPldmProtocolGuid                = { 0x60997616, 0xDB70, 0x4B5F, { 0x86,
>> 0xA4, 0x09, 0x58, 0xA3, 0x71, 0x47, 0xB4 } }
>>>      gEdkiiPldmSmbiosTransferProtocolGuid  = { 0xFA431C3C, 0x816B, 0x4B32,
>> { 0xA3, 0xE0, 0xAD, 0x9B, 0x7F, 0x64, 0x27, 0x2E } }
>>>      gEdkiiMctpProtocolGuid                = { 0xE93465C1, 0x9A31, 0x4C96, { 0x92,
>> 0x56, 0x22, 0x0A, 0xE1, 0x80, 0xB4, 0x1B } }
>>> +  ## Include/Protocol/IpmiBlobTransfer.h
>>> +  gEdkiiIpmiBlobTransferProtocolGuid    = { 0x05837c75, 0x1d65, 0x468b,
>> { 0xb1, 0xc2, 0x81, 0xaf, 0x9a, 0x31, 0x5b, 0x2c } }
>>>
>>>    [PcdsFixedAtBuild]
>>>      ## This value is the MCTP Interface source and destination endpoint ID for
>> transmiting MCTP message.
>>> diff --git a/Features/ManageabilityPkg/Include/Manageability.dsc
>> b/Features/ManageabilityPkg/Include/Manageability.dsc
>>> index 2e410df9ba..aae343a733 100644
>>> --- a/Features/ManageabilityPkg/Include/Manageability.dsc
>>> +++ b/Features/ManageabilityPkg/Include/Manageability.dsc
>>> @@ -2,6 +2,7 @@
>>>    # Common libraries for Manageabilty Package
>>>    #
>>>    # Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.<BR>
>>> +# Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights
>> reserved.
>>>    # SPDX-License-Identifier: BSD-2-Clause-Patent
>>>    #
>>>    ##
>>> @@ -37,6 +38,7 @@
>>>    [Components.X64, Components.AARCH64]
>>>    !if gManageabilityPkgTokenSpaceGuid.PcdManageabilityDxeIpmiEnable ==
>> TRUE
>>>      ManageabilityPkg/Universal/IpmiProtocol/Dxe/IpmiProtocolDxe.inf
>>> +
>> ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.inf
>>>    !endif
>>>
>>>    [Components.X64]
>>> diff --git
>> a/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransf
>> erDxe.inf
>> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransf
>> erDxe.inf
>>> new file mode 100644
>>> index 0000000000..108f4bb5f8
>>> --- /dev/null
>>> +++
>> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransf
>> erDxe.inf
>>> @@ -0,0 +1,39 @@
>>> +## @file
>>> +# IPMI Blob Transfer Protocol DXE Driver.
>>> +#
>>> +#  Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights
>> reserved.
>>> +#
>>> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
>>> +#
>>> +
>>> +[Defines]
>>> +  INF_VERSION                    = 0x00010005
>>> +  BASE_NAME                      = IpmiBlobTransferDxe
>>> +  FILE_GUID                      = 6357c804-78bb-4b0c-abdf-c75df942f319
>>> +  MODULE_TYPE                    = DXE_DRIVER
>>> +  VERSION_STRING                 = 1.0
>>> +  ENTRY_POINT                    = IpmiBlobTransferDxeDriverEntryPoint
>>> +
>>> +[Sources.common]
>>> +  IpmiBlobTransferDxe.c
>>> +
>>> +[LibraryClasses]
>>> +  BaseLib
>>> +  BaseMemoryLib
>>> +  DebugLib
>>> +  IpmiLib
>>> +  MemoryAllocationLib
>>> +  PcdLib
>>> +  UefiBootServicesTableLib
>>> +  UefiDriverEntryPoint
>>> +
>>> +[Packages]
>>> +  MdePkg/MdePkg.dec
>>> +  MdeModulePkg/MdeModulePkg.dec
>>> +  ManageabilityPkg/ManageabilityPkg.dec
>>> +
>>> +[Protocols]
>>> +  gEdkiiIpmiBlobTransferProtocolGuid
>>> +
>>> +[Depex]
>>> +  TRUE
>>> diff --git
>> a/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiB
>> lobTransferTestUnitTestsHost.inf
>> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiB
>> lobTransferTestUnitTestsHost.inf
>>> new file mode 100644
>>> index 0000000000..dab6858f09
>>> --- /dev/null
>>> +++
>> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiB
>> lobTransferTestUnitTestsHost.inf
>>> @@ -0,0 +1,40 @@
>>> +## @file
>>> +# Unit tests of the Ipmi blob transfer driver that are run from a host
>> environment.
>>> +#
>>> +# Copyright (c) 2020-2024, NVIDIA CORPORATION & AFFILIATES. All rights
>> reserved.
>>> +#
>>> +# SPDX-License-Identifier: BSD-2-Clause-Patent
>>> +##
>>> +
>>> +[Defines]
>>> +  INF_VERSION                    = 0x00010006
>>> +  BASE_NAME                      = IpmiBlobTransferDxeUnitTestsHost
>>> +  FILE_GUID                      = 1f5d4095-ea52-432c-b078-86097fef6004
>>> +  MODULE_TYPE                    = HOST_APPLICATION
>>> +  VERSION_STRING                 = 1.0
>>> +
>>> +#
>>> +# The following information is for reference only
>>> +# and not required by the build tools.
>>> +#
>>> +#  VALID_ARCHITECTURES           = X64
>>> +#
>>> +
>>> +[Sources]
>>> +  IpmiBlobTransferTestUnitTests.c
>>> +
>>> +[Packages]
>>> +  MdePkg/MdePkg.dec
>>> +  MdeModulePkg/MdeModulePkg.dec
>>> +  ManageabilityPkg/ManageabilityPkg.dec
>>> +  UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec
>>> +
>>> +[LibraryClasses]
>>> +  BaseLib
>>> +  BaseMemoryLib
>>> +  DebugLib
>>> +  UnitTestLib
>>> +  IpmiLib
>>> +
>>> +[Protocols]
>>> +  gEdkiiIpmiBlobTransferProtocolGuid
>>> diff --git a/Features/ManageabilityPkg/Include/Protocol/IpmiBlobTransfer.h
>> b/Features/ManageabilityPkg/Include/Protocol/IpmiBlobTransfer.h
>>> new file mode 100644
>>> index 0000000000..14b5294314
>>> --- /dev/null
>>> +++ b/Features/ManageabilityPkg/Include/Protocol/IpmiBlobTransfer.h
>>> @@ -0,0 +1,253 @@
>>> +/** @file
>>> +
>>> +  IPMI Blob Transfer driver
>>> +
>>> +  Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights
>> reserved.
>>> +
>>> +  SPDX-License-Identifier: BSD-2-Clause-Patent
>>> +
>>> +  @Par: https://github.com/openbmc/phosphor-ipmi-
>> blobs/blob/master/README.md
>>> +**/
>>
>> Lack of header guard
>> #ifndef IPMI_BLOB_TRANSFER_H_
>>
>>> +#include <Library/IpmiLib.h>
>>> +#include <Library/UefiBootServicesTableLib.h>
>>> +#include <IndustryStandard/Ipmi.h>
>>> +#include <IndustryStandard/IpmiNetFnOem.h>
>>> +
>>> +#define IPMI_OEM_BLOB_TRANSFER_CMD  0x80
>>> +
>>> +#define BLOB_TRANSFER_STAT_OPEN_R        BIT0
>>> +#define BLOB_TRANSFER_STAT_OPEN_W        BIT1
>>> +#define BLOB_TRANSFER_STAT_COMMITING     BIT2
>>> +#define BLOB_TRANSFER_STAT_COMMITTED     BIT3
>>> +#define BLOB_TRANSFER_STAT_COMMIT_ERROR  BIT4
>>> +// Bits 5-7 are reserved
>>> +// Bits 8-15 are blob-specific definitions
>>> +
>>> +//
>>> +// OpenBMC OEN code in little endian format
>>> +//
>>> +const UINT8  OpenBmcOen[] = { 0xCF, 0xC2, 0x00 };
>>
>> const -> CONST
>>
>> Should we add a PCD for the OEN to be configured by platform specific
>> BMC? Or this protocol is only to support OpenBMC.
>>
>>> +
>>> +//
>>> +//  Blob Transfer Function Prototypes
>>> +//
>>> +
>>> +/**
>>> +  This function retrieves the count of blob transfers available through the
>> IPMI.
>>> +
>>> +  @param[out]        Count       The number of active blobs
>>> +
>>> +  @retval EFI_SUCCESS            Successfully retrieved the number of active
>> blobs.
>>> +  @retval Other                  An error occurred
>>> +**/
>>> +typedef
>>> +EFI_STATUS
>>> +(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_GET_COUNT)(
>>> +  OUT UINT32 *Count
>>> +  );
>>> +
>>> +/**
>>> +  This function enumerates blob transfers available through the IPMI.
>>> +
>>> +  @param[in]         BlobIndex       The 0-based Index of the blob to enumerate
>>> +  @param[out]        BlobId          The ID of the blob
>>> +
>>> +  @retval EFI_SUCCESS                Successfully enumerated the blob.
>>> +  @retval Other                      An error occurred
>>> +**/
>>> +typedef
>>> +EFI_STATUS
>>> +(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_ENUMERATE)(
>>> +  IN  UINT32  BlobIndex,
>>> +  OUT CHAR8   *BlobId
>>> +  );
>>> +
>>> +/**
>>> +  This function is designed to open a session for a specific blob
>>> +  identified by its ID, using the IPMI.
>>> +
>>> +  @param[in]         BlobId          The ID of the blob to open
>>> +  @param[in]         Flags           Flags to control how the blob is opened
>>> +  @param[out]        SessionId       A unique session identifier
>>> +
>>> +  @retval EFI_SUCCESS                Successfully opened the blob.
>>> +  @retval Other                      An error occurred
>>> +**/
>>> +typedef
>>> +EFI_STATUS
>>> +(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_OPEN)(
>>> +  IN  CHAR8  *BlobId,
>>> +  IN  UINT16 Flags,
>>> +  OUT UINT16 *SessionId
>>> +  );
>>> +
>>> +/**
>>> +  This function reads data from a blob over the IPMI.
>>> +
>>> +  @param[in]         SessionId       The session ID returned from a call to
>> BlobOpen
>>> +  @param[in]         Offset          The offset of the blob from which to start
>> reading
>>> +  @param[in]         RequestedSize   The length of data to read
>>> +  @param[out]        Data            Data read from the blob
>>> +
>>> +  @retval EFI_SUCCESS                Successfully read from the blob.
>>> +  @retval Other                      An error occurred
>>> +**/
>>> +typedef
>>> +EFI_STATUS
>>> +(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_READ)(
>>> +  IN  UINT16      SessionId,
>>> +  IN  UINT32      Offset,
>>> +  IN  UINT32      RequestedSize,
>>> +  OUT UINT8       *Data
>>> +  );
>>> +
>>> +/**
>>> +  This function writes data to a blob over the IPMI.
>>> +
>>> +  @param[in]         SessionId       The session ID returned from a call to
>> BlobOpen
>>> +  @param[in]         Offset          The offset of the blob from which to start
>> writing
>>> +  @param[in]         Data            A pointer to the data to write
>>> +  @param[in]         WriteLength     The length to write
>>> +
>>> +  @retval EFI_SUCCESS                Successfully wrote to the blob.
>>> +  @retval Other                      An error occurred
>>> +**/
>>> +typedef
>>> +EFI_STATUS
>>> +(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_WRITE)(
>>> +  IN  UINT16      SessionId,
>>> +  IN  UINT32      Offset,
>>> +  IN  UINT8       *Data,
>>> +  IN  UINT32      WriteLength
>>> +  );
>>> +
>>> +/**
>>> +  This function commits data to a blob over the IPMI.
>>> +
>>> +  @param[in]         SessionId        The session ID returned from a call to
>> BlobOpen
>>> +  @param[in]         CommitDataLength The length of data to commit to the
>> blob
>>> +  @param[in]         CommitData       A pointer to the data to commit
>>> +
>>> +  @retval EFI_SUCCESS                Successful commit to the blob.
>>> +  @retval Other                      An error occurred
>>> +**/
>>> +typedef
>>> +EFI_STATUS
>>> +(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_COMMIT)(
>>> +  IN  UINT16      SessionId,
>>> +  IN  UINT8       CommitDataLength,
>>> +  IN  UINT8       *CommitData
>>> +  );
>>> +
>>> +/**
>>> +  This function close a session associated with a blob transfer over the IPMI.
>>> +
>>> +  @param[in]         SessionId       The session ID returned from a call to
>> BlobOpen
>>> +
>>> +  @retval EFI_SUCCESS                The blob was closed.
>>> +  @retval Other                      An error occurred
>>> +**/
>>> +typedef
>>> +EFI_STATUS
>>> +(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_CLOSE)(
>>> +  IN  UINT16      SessionId
>>> +  );
>>> +
>>> +/**
>>> +  This function deletes a specific blob identified by its ID over the IPMI.
>>> +
>>> +  @param[in]         BlobId          The BlobId to be deleted
>>> +
>>> +  @retval EFI_SUCCESS                The blob was deleted.
>>> +  @retval Other                      An error occurred
>>> +**/
>>> +typedef
>>> +EFI_STATUS
>>> +(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_DELETE)(
>>> +  IN  CHAR8 *BlobId
>>> +  );
>>> +
>>> +/**
>>> +  This function retrieve the status of a specific blob identified by BlobId from
>> an IPMI.
>>> +
>>> +  @param[in]         BlobId          The Blob ID to gather statistics for
>>> +  @param[out]        BlobState       The current state of the blob
>>> +  @param[out]        Size            Size in bytes of the blob
>>> +  @param[out]        MetadataLength  Length of the optional metadata
>>> +  @param[out]        Metadata        Optional blob-specific metadata
>>> +
>>> +  @retval EFI_SUCCESS                The blob statistics were successfully
>> gathered.
>>> +  @retval Other                      An error occurred
>>> +**/
>>> +typedef
>>> +EFI_STATUS
>>> +(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_STAT)(
>>> +  IN  CHAR8  *BlobId,
>>> +  OUT UINT16 *BlobState,
>>> +  OUT UINT32 *Size,
>>> +  OUT UINT8  *MetadataLength,
>>> +  OUT UINT8  *Metadata
>>> +  );
>>> +
>>> +/**
>>> +  This function query the status of a blob transfer session in an IPMI.
>>> +
>>> +  @param[in]         SessionId       The ID of the session to gather statistics for
>>> +  @param[out]        BlobState       The current state of the blob
>>> +  @param[out]        Size            Size in bytes of the blob
>>> +  @param[out]        MetadataLength  Length of the optional metadata
>>> +  @param[out]        Metadata        Optional blob-specific metadata
>>> +
>>> +  @retval EFI_SUCCESS                The blob statistics were successfully
>> gathered.
>>> +  @retval Other                      An error occurred
>>> +**/
>>> +typedef
>>> +EFI_STATUS
>>> +(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_SESSION_STAT)(
>>> +  IN  UINT16 SessionId,
>>> +  OUT UINT16 *BlobState,
>>> +  OUT UINT32 *Size,
>>> +  OUT UINT8  *MetadataLength,
>>> +  OUT UINT8  *Metadata
>>> +  );
>>> +
>>> +/**
>>> +  This function writes metadata to a blob associated with a session in an
>> IPMI.
>>> +
>>> +  @param[in]         SessionId       The ID of the session to write metadata for
>>> +  @param[in]         Offset          The offset of the metadata to write to
>>> +  @param[in]         Data            The data to write to the metadata
>>> +  @param[in]         WriteLength     The length to write
>>> +
>>> +  @retval EFI_SUCCESS                The blob metadata was successfully written.
>>> +  @retval Other                      An error occurred
>>> +**/
>>> +typedef
>>> +EFI_STATUS
>>> +(EFIAPI *EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_WRITE_META)(
>>> +  IN  UINT16      SessionId,
>>> +  IN  UINT32      Offset,
>>> +  IN  UINT8       *Data,
>>> +  IN  UINT32      WriteLength
>>> +  );
>>> +
>>> +//
>>> +// Structure of EDKII_IPMI_BLOB_TRANSFER_PROTOCOL
>>> +//
>>> +struct _EDKII_IPMI_BLOB_TRANSFER_PROTOCOL {
>>> +  EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_GET_COUNT       BlobGetCount;
>>> +  EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_ENUMERATE
>> BlobEnumerate;
>>> +  EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_OPEN            BlobOpen;
>>> +  EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_READ            BlobRead;
>>> +  EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_WRITE           BlobWrite;
>>> +  EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_COMMIT          BlobCommit;
>>> +  EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_CLOSE           BlobClose;
>>> +  EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_DELETE          BlobDelete;
>>> +  EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_STAT            BlobStat;
>>> +  EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_SESSION_STAT
>> BlobSessionStat;
>>> +  EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_WRITE_META
>> BlobWriteMeta;
>>> +};
>>> +
>>> +typedef struct _EDKII_IPMI_BLOB_TRANSFER_PROTOCOL
>> EDKII_IPMI_BLOB_TRANSFER_PROTOCOL;
>>> +
>>> +extern EFI_GUID  gEdkiiIpmiBlobTransferProtocolGuid;
>>> diff --git
>> a/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiBlo
>> bTransfer.h
>> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiBl
>> obTransfer.h
>>> new file mode 100644
>>> index 0000000000..3e90dc6871
>>> --- /dev/null
>>> +++
>> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiBl
>> obTransfer.h
>>> @@ -0,0 +1,407 @@
>>> +/** @file
>>> +
>>> +  Headers for IPMI Blob Transfer driver
>>> +
>>> +  Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights
>> reserved.
>>> +
>>> +  SPDX-License-Identifier: BSD-2-Clause-Patent
>>> +
>>> +**/
>>> +
>>
>> Lack of header guard
>> #ifndef INTERNAL_IPMI_BLOB_TRANSFER_H_
>>
>>> +#include <Library/BaseLib.h>
>>> +#include <Library/BaseMemoryLib.h>
>>> +#include <Library/DebugLib.h>
>>> +#include <Library/IpmiLib.h>
>>> +#include <Library/MemoryAllocationLib.h>
>>> +#include <Library/PcdLib.h>
>>> +
>>> +#define PROTOCOL_RESPONSE_OVERHEAD  (4 * sizeof(UINT8))       // 1
>> byte completion code + 3 bytes OEN
>>
>> Nit: Add a space after sizeof
>>
>>> +#define BLOB_MAX_DATA_PER_PACKET    64
>>
>> Should it be moved to Include/Protocol/IpmiBlobTransfer.h? The caller
>> could need to be aware the max length of the package.
>>
>>> +
>>> +// Subcommands for this protocol
>>> +typedef enum {
>>> +  IpmiBlobTransferSubcommandGetCount = 0,
>>> +  IpmiBlobTransferSubcommandEnumerate,
>>> +  IpmiBlobTransferSubcommandOpen,
>>> +  IpmiBlobTransferSubcommandRead,
>>> +  IpmiBlobTransferSubcommandWrite,
>>> +  IpmiBlobTransferSubcommandCommit,
>>> +  IpmiBlobTransferSubcommandClose,
>>> +  IpmiBlobTransferSubcommandDelete,
>>> +  IpmiBlobTransferSubcommandStat,
>>> +  IpmiBlobTransferSubcommandSessionStat,
>>> +  IpmiBlobTransferSubcommandWriteMeta,
>>> +} IPMI_BLOB_TRANSFER_SUBCOMMANDS;
>>> +
>>> +#pragma pack(1)
>>> +
>>> +typedef struct {
>>> +  UINT8    OEN[3];
>>> +  UINT8    SubCommand;
>>> +} IPMI_BLOB_TRANSFER_HEADER;
>>> +
>>> +//
>>> +// Command 0 - BmcBlobGetCount
>>> +// The BmcBlobGetCount command expects to receive an empty body.
>>> +// The BMC will return the number of enumerable blobs
>>> +//
>>> +typedef struct {
>>> +  UINT32    BlobCount;
>>> +} IPMI_BLOB_TRANSFER_GET_COUNT_RESPONSE;
>>> +
>>> +//
>>> +// Command 1 - BmcBlobEnumerate
>>> +// The BmcBlobEnumerate command expects to receive a body of:
>>> +//
>>> +typedef struct {
>>> +  UINT32    BlobIndex; // 0-based index of blob to receive
>>> +} IPMI_BLOB_TRANSFER_BLOB_ENUMERATE_SEND_DATA;
>>> +
>>> +typedef struct {
>>> +  CHAR8    BlobId[BLOB_MAX_DATA_PER_PACKET];
>>> +} IPMI_BLOB_TRANSFER_BLOB_ENUMERATE_RESPONSE;
>>> +
>>> +//
>>> +// Command 2 - BmcBlobOpen
>>> +// The BmcBlobOpen command expects to receive a body of:
>>> +//
>>> +typedef struct {
>>> +  UINT16    Flags;
>>> +  CHAR8     BlobId[BLOB_MAX_DATA_PER_PACKET];
>>> +} IPMI_BLOB_TRANSFER_BLOB_OPEN_SEND_DATA;
>>> +
>>> +#define BLOB_OPEN_FLAG_READ   0
>>> +#define BLOB_OPEN_FLAG_WRITE  1
>>> +// Bits 2-7 are reserved
>>> +// Bits 8-15 are blob-specific definitions
>>> +
>>> +typedef struct {
>>> +  UINT16    SessionId;
>>> +} IPMI_BLOB_TRANSFER_BLOB_OPEN_RESPONSE;
>>> +
>>> +//
>>> +// Command 3 - BmcBlobRead
>>> +// The BmcBlobRead command expects to receive a body of:
>>> +//
>>> +typedef struct {
>>> +  UINT16    SessionId; // Returned from BlobOpen
>>> +  UINT32    Offset;
>>> +  UINT32    RequestedSize;
>>> +} IPMI_BLOB_TRANSFER_BLOB_READ_SEND_DATA;
>>> +
>>> +typedef struct {
>>> +  UINT8    Data[BLOB_MAX_DATA_PER_PACKET];
>>> +} IPMI_BLOB_TRANSFER_BLOB_READ_RESPONSE;
>>> +
>>> +//
>>> +// Command 4 - BmcBlobWrite
>>> +// The BmcBlobWrite command expects to receive a body of:
>>> +//
>>> +typedef struct {
>>> +  UINT16    SessionId; // Returned from BlobOpen
>>> +  UINT32    Offset;
>>> +  UINT8     Data[BLOB_MAX_DATA_PER_PACKET];
>>> +} IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_DATA;
>>> +
>>> +//
>>> +// Command 5 - BmcBlobCommit
>>> +// The BmcBlobCommit command expects to receive a body of:
>>> +//
>>> +typedef struct {
>>> +  UINT16    SessionId; // Returned from BlobOpen
>>> +  UINT8     CommitDataLength;
>>> +  UINT8     CommitData[BLOB_MAX_DATA_PER_PACKET];
>>> +} IPMI_BLOB_TRANSFER_BLOB_COMMIT_SEND_DATA;
>>> +
>>> +//
>>> +// Command 6 - BmcBlobClose
>>> +// The BmcBlobClose command expects to receive a body of:
>>> +//
>>> +typedef struct {
>>> +  UINT16    SessionId; // Returned from BlobOpen
>>> +} IPMI_BLOB_TRANSFER_BLOB_CLOSE_SEND_DATA;
>>> +
>>> +//
>>> +// Command 7 - BmcBlobDelete
>>> +// NOTE: This command will fail if there are open sessions for this blob
>>> +// The BmcBlobDelete command expects to receive a body of:
>>> +//
>>> +typedef struct {
>>> +  CHAR8    BlobId[BLOB_MAX_DATA_PER_PACKET];
>>> +} IPMI_BLOB_TRANSFER_BLOB_DELETE_SEND_DATA;
>>> +
>>> +//
>>> +// Command 8 - BmcBlobStat
>>> +// This command returns statistics about a blob.
>>> +// This command expects to receive a body of:
>>> +//
>>> +typedef struct {
>>> +  CHAR8    BlobId[BLOB_MAX_DATA_PER_PACKET];
>>> +} IPMI_BLOB_TRANSFER_BLOB_STAT_SEND_DATA;
>>> +
>>> +typedef struct {
>>> +  UINT16    BlobState;
>>> +  UINT32    Size; // Size in bytes of the blob
>>> +  UINT8     MetaDataLen;
>>> +  UINT8     MetaData[BLOB_MAX_DATA_PER_PACKET];
>>> +} IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE;
>>> +
>>> +//
>>> +// Command 9 - BmcBlobSessionStat
>>> +// Returns same data as BmcBlobState expect for a session, not a blob
>>> +// This command expects to receive a body of:
>>> +//
>>> +typedef struct {
>>> +  UINT16    SessionId;
>>> +} IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_SEND_DATA;
>>> +
>>> +typedef struct {
>>> +  UINT16    BlobState;
>>> +  UINT32    Size; // Size in bytes of the blob
>>> +  UINT8     MetaDataLen;
>>> +  UINT8     MetaData[BLOB_MAX_DATA_PER_PACKET];
>>> +} IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_RESPONSE;
>>> +
>>> +//
>>> +// Command 10 - BmcBlobWriteMeta
>>> +// The BmcBlobWriteMeta command expects to receive a body of:
>>> +//
>>> +typedef struct {
>>> +  UINT16    SessionId;
>>> +  UINT32    Offset;
>>> +  UINT8     Data[BLOB_MAX_DATA_PER_PACKET];
>>> +} IPMI_BLOB_TRANSFER_BLOB_WRITE_META_SEND_DATA;
>>> +
>>> +#define IPMI_BLOB_TRANSFER_BLOB_WRITE_META_RESPONSE  NULL
>>> +
>>> +#pragma pack()
>>> +
>>> +/**
>>> +  Calculate CRC-16-CCITT with poly of 0x1021
>>> +
>>> +  @param[in]  Data              The target data.
>>> +  @param[in]  DataSize          The target data size.
>>> +
>>> +  @return UINT16     The CRC16 value.
>>> +
>>> +**/
>>> +UINT16
>>> +CalculateCrc16Ccitt (
>>> +  IN UINT8  *Data,
>>> +  IN UINTN  DataSize
>>> +  );
>>> +
>>> +/**
>>> +  This function does blob transfer over IPMI command.
>>> +
>>> +  @param[in]  SubCommand        The specific sub-command to be executed
>> as part of
>>> +                                the blob transfer operation.
>>> +  @param[in]  SendData          A pointer to the data buffer that contains the
>> data to be sent.
>>> +  @param[in]  SendDataSize      The size of the data to be sent, in bytes.
>>> +  @param[out] ResponseData      A pointer to the buffer where the response
>> data will be stored.
>>> +  @param[out] ResponseDataSize  A pointer to a variable that will hold the
>> size of the response
>>> +                                data received.
>>> +
>>> +  @retval EFI_SUCCESS            Successfully sends blob data.
>>> +  @retval EFI_OUT_OF_RESOURCES   Memory allocation fails.
>>> +  @retval EFI_PROTOCOL_ERROR     Communication errors.
>>> +  @retval EFI_CRC_ERROR          Data integrity checks fail.
>>> +  @retval Other                  An error occurred
>>> +
>>> +**/
>>> +EFI_STATUS
>>> +IpmiBlobTransferSendIpmi (
>>> +  IN  UINT8   SubCommand,
>>> +  IN  UINT8   *SendData,
>>> +  IN  UINT32  SendDataSize,
>>> +  OUT UINT8   *ResponseData,
>>> +  OUT UINT32  *ResponseDataSize
>>> +  );
>>> +
>>> +/**
>>> +  This function retrieves the count of blob transfers available through the
>> IPMI.
>>> +
>>> +  @param[out]        Count       The number of active blobs
>>> +
>>> +  @retval EFI_SUCCESS            Successfully retrieved the number of active
>> blobs.
>>> +  @retval Other                  An error occurred
>>> +**/
>>> +EFI_STATUS
>>> +IpmiBlobTransferGetCount (
>>> +  OUT UINT32  *Count
>>> +  );
>>> +
>>> +/**
>>> +  This function enumerates blob transfers available through the IPMI.
>>> +
>>> +  @param[in]         BlobIndex       The 0-based Index of the blob to enumerate
>>> +  @param[out]        BlobId          The ID of the blob
>>> +
>>> +  @retval EFI_SUCCESS                Successfully enumerated the blob.
>>> +  @retval Other                      An error occurred
>>> +**/
>>> +EFI_STATUS
>>> +IpmiBlobTransferEnumerate (
>>> +  IN  UINT32  BlobIndex,
>>> +  OUT CHAR8   *BlobId
>>> +  );
>>> +
>>> +/**
>>> +  This function is designed to open a session for a specific blob
>>> +  identified by its ID, using the IPMI.
>>> +
>>> +  @param[in]         BlobId          The ID of the blob to open
>>> +  @param[in]         Flags           Flags to control how the blob is opened
>>> +  @param[out]        SessionId       A unique session identifier
>>> +
>>> +  @retval EFI_SUCCESS                Successfully opened the blob.
>>> +  @retval Other                      An error occurred
>>> +**/
>>> +EFI_STATUS
>>> +IpmiBlobTransferOpen (
>>> +  IN  CHAR8   *BlobId,
>>> +  IN  UINT16  Flags,
>>> +  OUT UINT16  *SessionId
>>> +  );
>>> +
>>> +/**
>>> +  This function reads data from a blob over the IPMI.
>>> +
>>> +  @param[in]         SessionId       The session ID returned from a call to
>> BlobOpen
>>> +  @param[in]         Offset          The offset of the blob from which to start
>> reading
>>> +  @param[in]         RequestedSize   The length of data to read
>>> +  @param[out]        Data            Data read from the blob
>>> +
>>> +  @retval EFI_SUCCESS                Successfully read from the blob.
>>> +  @retval Other                      An error occurred
>>> +**/
>>> +EFI_STATUS
>>> +IpmiBlobTransferRead (
>>> +  IN  UINT16  SessionId,
>>> +  IN  UINT32  Offset,
>>> +  IN  UINT32  RequestedSize,
>>> +  OUT UINT8   *Data
>>> +  );
>>> +
>>> +/**
>>> +  This function writes data to a blob over the IPMI.
>>> +
>>> +  @param[in]         SessionId       The session ID returned from a call to
>> BlobOpen
>>> +  @param[in]         Offset          The offset of the blob from which to start
>> writing
>>> +  @param[in]         Data            A pointer to the data to write
>>> +  @param[in]         WriteLength     The length to write
>>> +
>>> +  @retval EFI_SUCCESS                Successfully wrote to the blob.
>>> +  @retval Other                      An error occurred
>>> +**/
>>> +EFI_STATUS
>>> +IpmiBlobTransferWrite (
>>> +  IN  UINT16  SessionId,
>>> +  IN  UINT32  Offset,
>>> +  IN  UINT8   *Data,
>>> +  IN  UINT32  WriteLength
>>> +  );
>>> +
>>> +/**
>>> +  This function commits data to a blob over the IPMI.
>>> +
>>> +  @param[in]         SessionId        The session ID returned from a call to
>> BlobOpen
>>> +  @param[in]         CommitDataLength The length of data to commit to the
>> blob
>>> +  @param[in]         CommitData       A pointer to the data to commit
>>> +
>>> +  @retval EFI_SUCCESS                Successful commit to the blob.
>>> +  @retval Other                      An error occurred
>>> +**/
>>> +EFI_STATUS
>>> +IpmiBlobTransferCommit (
>>> +  IN  UINT16  SessionId,
>>> +  IN  UINT8   CommitDataLength,
>>> +  IN  UINT8   *CommitData
>>> +  );
>>> +
>>> +/**
>>> +  This function close a session associated with a blob transfer over the IPMI.
>>> +
>>> +  @param[in]         SessionId       The session ID returned from a call to
>> BlobOpen
>>> +
>>> +  @retval EFI_SUCCESS                The blob was closed.
>>> +  @retval Other                      An error occurred
>>> +**/
>>> +EFI_STATUS
>>> +IpmiBlobTransferClose (
>>> +  IN  UINT16  SessionId
>>> +  );
>>> +
>>> +/**
>>> +  This function deletes a specific blob identified by its ID over the IPMI.
>>> +
>>> +  @param[in]         BlobId          The BlobId to be deleted
>>> +
>>> +  @retval EFI_SUCCESS                The blob was deleted.
>>> +  @retval Other                      An error occurred
>>> +**/
>>> +EFI_STATUS
>>> +IpmiBlobTransferDelete (
>>> +  IN  CHAR8  *BlobId
>>> +  );
>>> +
>>> +/**
>>> +  This function retrieve the status of a specific blob identified by BlobId from
>> an IPMI.
>>> +
>>> +  @param[in]         BlobId          The Blob ID to gather statistics for
>>> +  @param[out]        BlobState       The current state of the blob
>>> +  @param[out]        Size            Size in bytes of the blob
>>> +  @param[out]        MetadataLength  Length of the optional metadata
>>> +  @param[out]        Metadata        Optional blob-specific metadata
>>> +
>>> +  @retval EFI_SUCCESS                The blob statistics were successfully
>> gathered.
>>> +  @retval Other                      An error occurred
>>> +**/
>>> +EFI_STATUS
>>> +IpmiBlobTransferStat (
>>> +  IN  CHAR8   *BlobId,
>>> +  OUT UINT16  *BlobState,
>>> +  OUT UINT32  *Size,
>>> +  OUT UINT8   *MetadataLength,
>>> +  OUT UINT8   *Metadata
>>> +  );
>>> +
>>> +/**
>>> +  This function query the status of a blob transfer session in an IPMI.
>>> +
>>> +  @param[in]         SessionId       The ID of the session to gather statistics for
>>> +  @param[out]        BlobState       The current state of the blob
>>> +  @param[out]        Size            Size in bytes of the blob
>>> +  @param[out]        MetadataLength  Length of the optional metadata
>>> +  @param[out]        Metadata        Optional blob-specific metadata
>>> +
>>> +  @retval EFI_SUCCESS                The blob statistics were successfully
>> gathered.
>>> +  @retval Other                      An error occurred
>>> +**/
>>> +EFI_STATUS
>>> +IpmiBlobTransferSessionStat (
>>> +  IN  UINT16  SessionId,
>>> +  OUT UINT16  *BlobState,
>>> +  OUT UINT32  *Size,
>>> +  OUT UINT8   *MetadataLength,
>>> +  OUT UINT8   *Metadata
>>> +  );
>>> +
>>> +/**
>>> +  This function writes metadata to a blob associated with a session in an
>> IPMI.
>>> +
>>> +  @param[in]         SessionId       The ID of the session to write metadata for
>>> +  @param[in]         Offset          The offset of the metadata to write to
>>> +  @param[in]         Data            The data to write to the metadata
>>> +  @param[in]         WriteLength     The length to write
>>> +
>>> +  @retval EFI_SUCCESS                The blob metadata was successfully written.
>>> +  @retval Other                      An error occurred
>>> +**/
>>> +EFI_STATUS
>>> +IpmiBlobTransferWriteMeta (
>>> +  IN  UINT16  SessionId,
>>> +  IN  UINT32  Offset,
>>> +  IN  UINT8   *Data,
>>> +  IN  UINT32  WriteLength
>>> +  );
>>> diff --git
>> a/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransf
>> erDxe.c
>> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransf
>> erDxe.c
>>> new file mode 100644
>>> index 0000000000..b8a2db193b
>>> --- /dev/null
>>> +++
>> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransf
>> erDxe.c
>>> @@ -0,0 +1,872 @@
>>> +/** @file
>>> +
>>> +  IPMI Blob Transfer driver
>>> +
>>> +  Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights
>> reserved.
>>> +
>>> +  SPDX-License-Identifier: BSD-2-Clause-Patent
>>> +
>>> +**/
>>> +#include <Protocol/IpmiBlobTransfer.h>
>>> +
>>> +#include "InternalIpmiBlobTransfer.h"
>>> +
>>> +#define BLOB_TRANSFER_DEBUG  DEBUG_MANAGEABILITY
>>> +
>>> +STATIC CONST EDKII_IPMI_BLOB_TRANSFER_PROTOCOL
>> mIpmiBlobTransfer = {
>>> +
>> (EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_GET_COUNT)*IpmiBlobTransferGe
>> tCount,
>>> +
>> (EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_ENUMERATE)*IpmiBlobTransferEn
>> umerate,
>>> +
>> (EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_OPEN)*IpmiBlobTransferOpen,
>>> +  (EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_READ)*IpmiBlobTransferRead,
>>> +
>> (EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_WRITE)*IpmiBlobTransferWrite,
>>> +
>> (EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_COMMIT)*IpmiBlobTransferCom
>> mit,
>>> +
>> (EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_CLOSE)*IpmiBlobTransferClose,
>>> +
>> (EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_DELETE)*IpmiBlobTransferDelete,
>>> +  (EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_STAT)*IpmiBlobTransferStat,
>>> +
>> (EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_SESSION_STAT)*IpmiBlobTransfer
>> SessionStat,
>>> +
>> (EDKII_IPMI_BLOB_TRANSFER_PROTOCOL_WRITE_META)*IpmiBlobTransfer
>> WriteMeta
>>> +};
>>> +
>>> +/**
>>> +  Calculate CRC-16-CCITT with poly of 0x1021
>>> +
>>> +  @param[in]  Data              The target data.
>>> +  @param[in]  DataSize          The target data size.
>>> +
>>> +  @return UINT16     The CRC16 value.
>>> +
>>> +**/
>>> +UINT16
>>> +CalculateCrc16Ccitt (
>>> +  IN UINT8  *Data,
>>> +  IN UINTN  DataSize
>>> +  )
>>> +{
>>> +  UINTN    Index;
>>> +  UINTN    BitIndex;
>>> +  UINT16   Crc;
>>> +  UINT16   Poly;
>>> +  BOOLEAN  XorFlag;
>>> +
>>> +  Crc     = 0xFFFF;
>>> +  Poly    = 0x1021;
>>> +  XorFlag = FALSE;
>>> +
>>> +  for (Index = 0; Index < (DataSize + 2); ++Index) {
>>> +    for (BitIndex = 0; BitIndex < 8; ++BitIndex) {
>>> +      XorFlag = (Crc & 0x8000) ? TRUE : FALSE;
>>> +      Crc   <<= 1;
>>> +      if ((Index < DataSize) && (Data[Index] & (1 << (7 - BitIndex)))) {
>>> +        Crc++;
>>> +      }
>>> +
>>> +      if (XorFlag == TRUE) {
>>> +        Crc ^= Poly;
>>> +      }
>>> +    }
>>> +  }
>>> +
>>> +  DEBUG ((BLOB_TRANSFER_DEBUG, "%a: CRC-16-CCITT %x\n", __func__,
>> Crc));
>>> +
>>> +  return Crc;
>>> +}
>>> +
>>> +/**
>>> +  This function does blob transfer over IPMI command.
>>> +
>>> +  @param[in]  SubCommand        The specific sub-command to be executed
>> as part of
>>> +                                the blob transfer operation.
>>> +  @param[in]  SendData          A pointer to the data buffer that contains the
>> data to be sent.
>>> +  @param[in]  SendDataSize      The size of the data to be sent, in bytes.
>>> +  @param[out] ResponseData      A pointer to the buffer where the response
>> data will be stored.
>>> +  @param[out] ResponseDataSize  A pointer to a variable that will hold the
>> size of the response
>>> +                                data received.
>>> +
>>> +  @retval EFI_SUCCESS            Successfully sends blob data.
>>> +  @retval EFI_OUT_OF_RESOURCES   Memory allocation fails.
>>> +  @retval EFI_PROTOCOL_ERROR     Communication errors.
>>> +  @retval EFI_CRC_ERROR          Data integrity checks fail.
>>> +  @retval Other                  An error occurred
>>> +
>>> +**/
>>> +EFI_STATUS
>>> +IpmiBlobTransferSendIpmi (
>>> +  IN  UINT8   SubCommand,
>>> +  IN  UINT8   *SendData,
>>> +  IN  UINT32  SendDataSize,
>>
>> Should describe SendData and SendDataSize as OPTIONAL
>>
>>> +  OUT UINT8   *ResponseData,
>>> +  OUT UINT32  *ResponseDataSize
>>> +  )
>>> +{
>>> +  EFI_STATUS                 Status;
>>> +  UINT8                      CompletionCode;
>>> +  UINT16                     Crc;
>>> +  UINT8                      Oen[3];
>>> +  UINT8                      *IpmiSendData;
>>> +  UINT32                     IpmiSendDataSize;
>>> +  UINT8                      *IpmiResponseData;
>>> +  UINT8                      *ModifiedResponseData;
>>> +  UINT32                     IpmiResponseDataSize;
>>> +  IPMI_BLOB_TRANSFER_HEADER  Header;
>>> +
>>
>> Should validate the pointer of input arguments: SendData, ResponseData,
>> ResponseDataSize.
>>
>>> +  Crc = 0;
>>> +
>>> +  //
>>> +  // Prepend the proper header to the SendData
>>> +  //
>>> +  IpmiSendDataSize = (sizeof (IPMI_BLOB_TRANSFER_HEADER));
>>> +  if (SendDataSize) {
>>> +    IpmiSendDataSize += sizeof (Crc) + (sizeof (UINT8) * SendDataSize);
>>> +  }
>>> +
>>> +  IpmiSendData = AllocateZeroPool (IpmiSendDataSize);
>>> +  if (IpmiSendData == NULL) {
>>> +    return EFI_OUT_OF_RESOURCES;
>>> +  }
>>> +
>>> +  Header.OEN[0]     = OpenBmcOen[0];
>>> +  Header.OEN[1]     = OpenBmcOen[1];
>>> +  Header.OEN[2]     = OpenBmcOen[2];
>>> +  Header.SubCommand = SubCommand;
>>> +  CopyMem (IpmiSendData, &Header, sizeof
>> (IPMI_BLOB_TRANSFER_HEADER));
>>> +  if (SendDataSize) {
>>
>> if (SendDataSize != 0)
>>
>>> +    //
>>> +    // Calculate the Crc of the send data
>>> +    //
>>> +    Crc = CalculateCrc16Ccitt (SendData, SendDataSize);
>>> +    CopyMem (IpmiSendData + sizeof (IPMI_BLOB_TRANSFER_HEADER),
>> &Crc, sizeof (UINT16));
>>> +    CopyMem (IpmiSendData + sizeof (IPMI_BLOB_TRANSFER_HEADER) +
>> sizeof (UINT16), SendData, SendDataSize);
>>> +  }
>>> +
>>> +  DEBUG_CODE_BEGIN ();
>>> +  DEBUG ((BLOB_TRANSFER_DEBUG, "%a: Inputs:\n", __func__));
>>> +  DEBUG ((BLOB_TRANSFER_DEBUG, "%a: SendDataSize: %02x\nData: ",
>> __func__, SendDataSize));
>>> +  UINT8  i;
>>> +
>>> +  for (i = 0; i < SendDataSize; i++) {
>>> +    DEBUG ((BLOB_TRANSFER_DEBUG, "%02x", *((UINT8 *)SendData + i)));
>>> +  }
>>> +
>>> +  DEBUG ((BLOB_TRANSFER_DEBUG, "\n"));
>>> +  DEBUG ((BLOB_TRANSFER_DEBUG, "%a: IpmiSendDataSize: %02x\nData:
>> ", __func__, IpmiSendDataSize));
>>> +  for (i = 0; i < IpmiSendDataSize; i++) {
>>> +    DEBUG ((BLOB_TRANSFER_DEBUG, "%02x", *((UINT8 *)IpmiSendData +
>> i)));
>>> +  }
>>> +
>>> +  DEBUG ((BLOB_TRANSFER_DEBUG, "\n"));
>>> +  DEBUG_CODE_END ();
>>> +
>>> +  IpmiResponseDataSize = (*ResponseDataSize +
>> PROTOCOL_RESPONSE_OVERHEAD);
>>> +  //
>>> +  // If expecting data to be returned, we have to also account for the 16 bit
>> CRC
>>> +  //
>>> +  if (*ResponseDataSize) {
>>
>> if (*ResponseDataSize != 0)
>>
>>> +    IpmiResponseDataSize += sizeof (Crc);
>>> +  }
>>> +
>>> +  IpmiResponseData = AllocateZeroPool (IpmiResponseDataSize);
>>> +  if (IpmiResponseData == NULL) {
>>> +    return EFI_OUT_OF_RESOURCES;
>>> +  }
>>> +
>>> +  Status = IpmiSubmitCommand (
>>> +             IPMI_NETFN_OEM,
>>> +             IPMI_OEM_BLOB_TRANSFER_CMD,
>>> +             (VOID *)IpmiSendData,
>>> +             IpmiSendDataSize,
>>> +             (VOID *)IpmiResponseData,
>>> +             &IpmiResponseDataSize
>>> +             );
>>> +
>>> +  FreePool (IpmiSendData);
>>> +  ModifiedResponseData = IpmiResponseData;
>>> +
>>> +  DEBUG_CODE_BEGIN ();
>>> +  DEBUG ((BLOB_TRANSFER_DEBUG, "%a: IPMI Response:\n", __func__));
>>> +  DEBUG ((BLOB_TRANSFER_DEBUG, "%a: ResponseDataSize: %02x\nData:
>> ", __func__, IpmiResponseDataSize));
>>> +  UINT8  i;
>>> +
>>> +  for (i = 0; i < IpmiResponseDataSize; i++) {
>>> +    DEBUG ((BLOB_TRANSFER_DEBUG, "%02x", *(ModifiedResponseData +
>> i)));
>>> +  }
>>> +
>>> +  DEBUG ((BLOB_TRANSFER_DEBUG, "\n"));
>>> +  DEBUG_CODE_END ();
>>> +
>>> +  if (EFI_ERROR (Status)) {
>>> +    return Status;
>>> +  }
>>> +
>>> +  CompletionCode = *ModifiedResponseData;
>>> +  if (CompletionCode != IPMI_COMP_CODE_NORMAL) {
>>> +    DEBUG ((DEBUG_ERROR, "%a: Returning because CompletionCode =
>> 0x%x\n", __func__, CompletionCode));
>>> +    FreePool (IpmiResponseData);
>>> +    return EFI_PROTOCOL_ERROR;
>>> +  }
>>> +
>>> +  // Strip completion code, we are done with it
>>> +  ModifiedResponseData  = ModifiedResponseData + sizeof
>> (CompletionCode);
>>> +  IpmiResponseDataSize -= sizeof (CompletionCode);
>>> +
>>> +  // Check OEN code and verify it matches the OpenBMC OEN
>>> +  CopyMem (Oen, ModifiedResponseData, sizeof (OpenBmcOen));
>>> +  if (CompareMem (Oen, OpenBmcOen, sizeof (OpenBmcOen)) != 0) {
>>> +    FreePool (IpmiResponseData);
>>> +    return EFI_PROTOCOL_ERROR;
>>> +  }
>>> +
>>> +  if (IpmiResponseDataSize == sizeof (OpenBmcOen)) {
>>> +    //
>>> +    // In this case, there was no response data sent. This is not an error.
>>> +    // Some messages do not require a response.
>>> +    //
>>> +    *ResponseDataSize = 0;
>>> +    FreePool (IpmiResponseData);
>>> +    return Status;
>>> +    // Now we need to validate the CRC then send the Response body back
>>> +  } else {
>>> +    // Strip the OEN, we are done with it now
>>> +    ModifiedResponseData  = ModifiedResponseData + sizeof (Oen);
>>> +    IpmiResponseDataSize -= sizeof (Oen);
>>> +    // Then validate the Crc
>>> +    CopyMem (&Crc, ModifiedResponseData, sizeof (Crc));
>>> +    ModifiedResponseData  = ModifiedResponseData + sizeof (Crc);
>>> +    IpmiResponseDataSize -= sizeof (Crc);
>>> +
>>> +    if (Crc == CalculateCrc16Ccitt (ModifiedResponseData,
>> IpmiResponseDataSize)) {
>>> +      CopyMem (ResponseData, ModifiedResponseData,
>> IpmiResponseDataSize);
>>> +      CopyMem (ResponseDataSize, &IpmiResponseDataSize, sizeof
>> (IpmiResponseDataSize));
>>> +      FreePool (IpmiResponseData);
>>> +      return EFI_SUCCESS;
>>> +    } else {
>>> +      FreePool (IpmiResponseData);
>>> +      return EFI_CRC_ERROR;
>>> +    }
>>> +  }
>>> +}
>>> +
>>> +/**
>>> +  This function retrieves the count of blob transfers available through the
>> IPMI.
>>> +
>>> +  @param[out]        Count       The number of active blobs
>>> +
>>> +  @retval EFI_SUCCESS            Successfully retrieved the number of active
>> blobs.
>>> +  @retval Other                  An error occurred
>>> +**/
>>> +EFI_STATUS
>>> +IpmiBlobTransferGetCount (
>>> +  OUT UINT32  *Count
>>> +  )
>>> +{
>>> +  EFI_STATUS  Status;
>>> +  UINT8       *ResponseData;
>>> +  UINT32      ResponseDataSize;
>>> +
>>> +  if (Count == NULL) {
>>> +    return EFI_INVALID_PARAMETER;
>>> +  }
>>> +
>>> +  ResponseDataSize = sizeof
>> (IPMI_BLOB_TRANSFER_GET_COUNT_RESPONSE);
>>> +  ResponseData     = AllocateZeroPool (ResponseDataSize);
>>> +  if (ResponseData == NULL) {
>>> +    return EFI_OUT_OF_RESOURCES;
>>> +  }
>>> +
>>> +  Status = IpmiBlobTransferSendIpmi
>> (IpmiBlobTransferSubcommandGetCount, NULL, 0, (UINT8 *)ResponseData,
>> &ResponseDataSize);
>>> +  if (!EFI_ERROR (Status)) {
>>> +    *Count = ((IPMI_BLOB_TRANSFER_GET_COUNT_RESPONSE
>> *)ResponseData)->BlobCount;
>>> +  }
>>> +
>>> +  FreePool (ResponseData);
>>> +  return Status;
>>> +}
>>> +
>>> +/**
>>> +  This function enumerates blob transfers available through the IPMI.
>>> +
>>> +  @param[in]         BlobIndex       The 0-based Index of the blob to enumerate
>>> +  @param[out]        BlobId          The ID of the blob
>>> +
>>> +  @retval EFI_SUCCESS                Successfully enumerated the blob.
>>> +  @retval Other                      An error occurred
>>> +**/
>>> +EFI_STATUS
>>> +IpmiBlobTransferEnumerate (
>>> +  IN  UINT32  BlobIndex,
>>> +  OUT CHAR8   *BlobId
>>> +  )
>>> +{
>>> +  EFI_STATUS  Status;
>>> +
>>> +  UINT8   *SendData;
>>> +  UINT8   *ResponseData;
>>> +  UINT32  SendDataSize;
>>> +  UINT32  ResponseDataSize;
>>> +
>>> +  if (BlobId == NULL) {
>>> +    ASSERT (FALSE);
>>> +    return EFI_ABORTED;
>>
>> Should return EFI_INVALID_PARAMETER for input validation?
>>
>>> +  }
>>> +
>>> +  ResponseDataSize = sizeof
>> (IPMI_BLOB_TRANSFER_BLOB_ENUMERATE_RESPONSE);
>>> +  ResponseData     = AllocateZeroPool (ResponseDataSize);
>>> +  if (ResponseData == NULL) {
>>> +    return EFI_OUT_OF_RESOURCES;
>>> +  }
>>> +
>>> +  //
>>> +  // Format send data
>>> +  //
>>> +  SendDataSize = sizeof
>> (IPMI_BLOB_TRANSFER_BLOB_ENUMERATE_SEND_DATA);
>>> +  SendData     = AllocateZeroPool (SendDataSize);
>>> +  if (SendData == NULL) {
>>
>> FreePool (ResponseData);
>>
>>> +    return EFI_OUT_OF_RESOURCES;
>>> +  }
>>> +
>>> +  ((IPMI_BLOB_TRANSFER_BLOB_ENUMERATE_SEND_DATA *)SendData)-
>>> BlobIndex = BlobIndex;
>>> +
>>> +  Status = IpmiBlobTransferSendIpmi
>> (IpmiBlobTransferSubcommandEnumerate, SendData, SendDataSize, (UINT8
>> *)ResponseData, &ResponseDataSize);
>>> +  if (!EFI_ERROR (Status)) {
>>> +    AsciiStrCpyS (BlobId, ResponseDataSize, (CHAR8 *)ResponseData);
>>> +  }
>>> +
>>> +  FreePool (ResponseData);
>>> +  return Status;
>>> +}
>>> +
>>> +/**
>>> +  This function is designed to open a session for a specific blob
>>> +  identified by its ID, using the IPMI.
>>> +
>>> +  @param[in]         BlobId          The ID of the blob to open
>>> +  @param[in]         Flags           Flags to control how the blob is opened
>>
>> It would be good if we can list out all flag definitions here. Actually,
>> I don't know how to input for this argument.
>>
>> Are they BLOB_OPEN_FLAG_READ and BLOB_OPEN_FLAG_WRITE in the
>> private
>> include header?
>>
>>> +  @param[out]        SessionId       A unique session identifier
>>> +
>>> +  @retval EFI_SUCCESS                Successfully opened the blob.
>>> +  @retval Other                      An error occurred
>>> +**/
>>> +EFI_STATUS
>>> +IpmiBlobTransferOpen (
>>> +  IN  CHAR8   *BlobId,
>>> +  IN  UINT16  Flags,
>>> +  OUT UINT16  *SessionId
>>> +  )
>>> +{
>>> +  EFI_STATUS  Status;
>>> +  UINT8       *SendData;
>>> +  UINT8       *ResponseData;
>>> +  UINT32      SendDataSize;
>>> +  UINT32      ResponseDataSize;
>>> +  CHAR8       *BlobSearch;
>>> +  UINT32      NumBlobs;
>>> +  UINT16      Index;
>>> +  BOOLEAN     BlobFound;
>>> +
>>> +  if ((BlobId == NULL) || (SessionId == NULL)) {
>>> +    return EFI_INVALID_PARAMETER;
>>> +  }
>>> +
>>> +  //
>>> +  // Before opening a blob, need to check if it exists
>>
>> I'm thinking the caller sequence here. Typically, the caller might check
>> the presence of a blob by calling GetCount () and Enumerate () before
>> opening a blob session. This check here could waste time. Or, do we call
>> open direction the blob session without pre-checking?
>>
>>> +  //
>>> +  Status = IpmiBlobTransferGetCount (&NumBlobs);
>>> +  if (EFI_ERROR (Status) || (NumBlobs == 0)) {
>>> +    if (Status == EFI_UNSUPPORTED) {
>>> +      return Status;
>>> +    }
>>> +
>>> +    DEBUG ((DEBUG_ERROR, "%a: Could not find any blobs: %r\n", __func__,
>> Status));
>>> +    return EFI_NOT_FOUND;
>>> +  }
>>> +
>>> +  BlobSearch = AllocateZeroPool (sizeof (CHAR8) *
>> BLOB_MAX_DATA_PER_PACKET);
>>> +  if (BlobSearch == NULL) {
>>> +    return EFI_OUT_OF_RESOURCES;
>>> +  }
>>> +
>>> +  BlobFound = FALSE;
>>> +  for (Index = 0; Index < NumBlobs; Index++) {
>>> +    Status = IpmiBlobTransferEnumerate (Index, BlobSearch);
>>> +    if ((!EFI_ERROR (Status)) && (AsciiStrCmp (BlobSearch, BlobId) == 0)) {
>>> +      BlobFound = TRUE;
>>> +      break;
>>> +    } else {
>>> +      continue;
>>> +    }
>>> +  }
>>> +
>>> +  if (!BlobFound) {
>>> +    DEBUG ((DEBUG_ERROR, "%a: Could not find a blob that matches %a\n",
>> __func__, BlobId));
>>> +    FreePool (BlobSearch);
>>> +    return EFI_NOT_FOUND;
>>> +  }
>>> +
>>> +  ResponseDataSize = sizeof
>> (IPMI_BLOB_TRANSFER_BLOB_OPEN_RESPONSE);
>>> +  ResponseData     = AllocateZeroPool (ResponseDataSize);
>>> +  if (ResponseData == NULL) {
>>> +    return EFI_OUT_OF_RESOURCES;
>>> +  }
>>> +
>>> +  //
>>> +  // Format send data
>>> +  //
>>> +  SendDataSize = sizeof (((IPMI_BLOB_TRANSFER_BLOB_OPEN_SEND_DATA
>> *)SendData)->Flags) + ((AsciiStrLen (BlobId)) * sizeof (CHAR8)) + sizeof
>> (CHAR8);
>>> +  SendData     = AllocateZeroPool (SendDataSize);
>>> +  if (SendData == NULL) {
>>> +    return EFI_OUT_OF_RESOURCES;
>>> +  }
>>> +
>>> +  AsciiStrCpyS (((IPMI_BLOB_TRANSFER_BLOB_OPEN_SEND_DATA
>> *)SendData)->BlobId, AsciiStrSize (BlobId) / sizeof (CHAR8), BlobId);
>>> +  ((IPMI_BLOB_TRANSFER_BLOB_OPEN_SEND_DATA *)SendData)->Flags =
>> Flags;
>>> +  // append null char to SendData
>>> +  SendData[SendDataSize-1] = 0;
>>
>> Nit: add spaces around minus (-) for readability.
>>
>>> +
>>> +  Status = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandOpen,
>> SendData, SendDataSize, (UINT8 *)ResponseData, &ResponseDataSize);
>>> +  if (!EFI_ERROR (Status)) {
>>> +    *SessionId = ((IPMI_BLOB_TRANSFER_BLOB_OPEN_RESPONSE
>> *)ResponseData)->SessionId;
>>> +  }
>>> +
>>> +  FreePool (ResponseData);
>>> +  FreePool (SendData);
>>> +  FreePool (BlobSearch);
>>> +  return Status;
>>> +}
>>> +
>>> +/**
>>> +  This function reads data from a blob over the IPMI.
>>> +
>>> +  @param[in]         SessionId       The session ID returned from a call to
>> BlobOpen
>>> +  @param[in]         Offset          The offset of the blob from which to start
>> reading
>>> +  @param[in]         RequestedSize   The length of data to read
>>> +  @param[out]        Data            Data read from the blob
>>> +
>>> +  @retval EFI_SUCCESS                Successfully read from the blob.
>>> +  @retval Other                      An error occurred
>>> +**/
>>> +EFI_STATUS
>>> +IpmiBlobTransferRead (
>>> +  IN  UINT16  SessionId,
>>
>> There might be developer mistake when executing the transfer before
>> opening the session. How do we handle this failure path? Do we need to
>> maintain a state machine for that?
>>
>> This comment applies to other functions as well.
>>
>>> +  IN  UINT32  Offset,
>>> +  IN  UINT32  RequestedSize,
>>> +  OUT UINT8   *Data
>>> +  )
>>> +{
>>> +  EFI_STATUS  Status;
>>> +  UINT8       *SendData;
>>> +  UINT8       *ResponseData;
>>> +  UINT32      SendDataSize;
>>> +  UINT32      ResponseDataSize;
>>> +
>>> +  if (Data == NULL) {
>>> +    ASSERT (FALSE);
>>> +    return EFI_ABORTED;
>>
>> Should return EFI_INVALID_PARAMETER?
>>
>>> +  }
>>> +
>>> +  ResponseDataSize = RequestedSize * sizeof (UINT8);
>>
>> Should check the RequestedSize against BLOB_MAX_DATA_PER_PACKET?
>>
>>> +  ResponseData     = AllocateZeroPool (ResponseDataSize);
>>> +  if (ResponseData == NULL) {
>>> +    return EFI_OUT_OF_RESOURCES;
>>> +  }
>>> +
>>> +  //
>>> +  // Format send data
>>> +  //
>>> +  SendDataSize = sizeof (IPMI_BLOB_TRANSFER_BLOB_READ_SEND_DATA);
>>> +  SendData     = AllocateZeroPool (SendDataSize);
>>> +  if (SendData == NULL) {
>>
>> FreePool (ResponseData);
>>
>>> +    return EFI_OUT_OF_RESOURCES;
>>> +  }
>>> +
>>> +  ((IPMI_BLOB_TRANSFER_BLOB_READ_SEND_DATA *)SendData)-
>>> SessionId     = SessionId;
>>> +  ((IPMI_BLOB_TRANSFER_BLOB_READ_SEND_DATA *)SendData)->Offset
>> = Offset;
>>> +  ((IPMI_BLOB_TRANSFER_BLOB_READ_SEND_DATA *)SendData)-
>>> RequestedSize = RequestedSize;
>>> +
>>> +  Status = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandRead,
>> SendData, SendDataSize, (UINT8 *)ResponseData, &ResponseDataSize);
>>> +  if (!EFI_ERROR (Status)) {
>>> +    CopyMem (Data, ((IPMI_BLOB_TRANSFER_BLOB_READ_RESPONSE
>> *)ResponseData)->Data, ResponseDataSize * sizeof (UINT8));
>>> +  }
>>> +
>>> +  FreePool (ResponseData);
>>> +  FreePool (SendData);
>>> +  return Status;
>>> +}
>>> +
>>> +/**
>>> +  This function writes data to a blob over the IPMI.
>>> +
>>> +  @param[in]         SessionId       The session ID returned from a call to
>> BlobOpen
>>> +  @param[in]         Offset          The offset of the blob from which to start
>> writing
>>> +  @param[in]         Data            A pointer to the data to write
>>> +  @param[in]         WriteLength     The length to write
>>> +
>>> +  @retval EFI_SUCCESS                Successfully wrote to the blob.
>>> +  @retval Other                      An error occurred
>>> +**/
>>> +EFI_STATUS
>>> +IpmiBlobTransferWrite (
>>> +  IN  UINT16  SessionId,
>>> +  IN  UINT32  Offset,
>>> +  IN  UINT8   *Data,
>>> +  IN  UINT32  WriteLength
>>> +  )
>>> +{
>>> +  EFI_STATUS  Status;
>>> +  UINT8       *SendData;
>>> +  UINT32      SendDataSize;
>>> +  UINT32      ResponseDataSize;
>>> +
>>> +  if (Data == NULL) {
>>> +    return EFI_INVALID_PARAMETER;
>>> +  }
>>> +
>>> +  //
>>> +  // Format send data
>>> +  //
>>> +  SendDataSize = sizeof (SessionId) + sizeof (Offset) + WriteLength;
>>
>> Should we check whether or not the WriteLength is equal to or less than
>> BLOB_MAX_DATA_PER_PACKET?
>>
>>> +  SendData     = AllocateZeroPool (SendDataSize);
>>> +  if (SendData == NULL) {
>>> +    return EFI_OUT_OF_RESOURCES;
>>> +  }
>>> +
>>> +  ((IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_DATA *)SendData)-
>>> SessionId = SessionId;
>>> +  ((IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_DATA *)SendData)->Offset
>> = Offset;
>>> +  CopyMem (((IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_DATA
>> *)SendData)->Data, Data, sizeof (UINT8) * WriteLength);
>>> +
>>> +  ResponseDataSize = 0;
>>> +  Status           = IpmiBlobTransferSendIpmi
>> (IpmiBlobTransferSubcommandWrite, SendData, SendDataSize, NULL,
>> &ResponseDataSize);
>>> +
>>> +  FreePool (SendData);
>>> +  return Status;
>>> +}
>>> +
>>> +/**
>>> +  This function commits data to a blob over the IPMI.
>>> +
>>> +  @param[in]         SessionId        The session ID returned from a call to
>> BlobOpen
>>> +  @param[in]         CommitDataLength The length of data to commit to the
>> blob
>>> +  @param[in]         CommitData       A pointer to the data to commit
>>> +
>>> +  @retval EFI_SUCCESS                Successful commit to the blob.
>>> +  @retval Other                      An error occurred
>>> +**/
>>> +EFI_STATUS
>>> +IpmiBlobTransferCommit (
>>> +  IN  UINT16  SessionId,
>>> +  IN  UINT8   CommitDataLength,
>>> +  IN  UINT8   *CommitData
>>> +  )
>>> +{
>>> +  EFI_STATUS  Status;
>>> +  UINT8       *SendData;
>>> +  UINT32      SendDataSize;
>>> +  UINT32      ResponseDataSize;
>>> +
>>> +  if (CommitData == NULL) {
>>
>> According to the spec https://github.com/openbmc/phosphor-ipmi-blobs,
>> the commit data is block-specific optional.
>>
>> For instance, the commit data is optional for SMBIOS blob transfer. Look
>> at https://github.com/openbmc/smbios-mdr
>>
>>> +    return EFI_INVALID_PARAMETER;
>>> +  }
>>> +
>>> +  //
>>> +  // Format send data
>>> +  //
>>> +  SendDataSize = sizeof (SessionId) + sizeof (CommitDataLength) +
>> CommitDataLength;
>>> +  SendData     = AllocateZeroPool (SendDataSize);
>>> +  if (SendData == NULL) {
>>> +    return EFI_OUT_OF_RESOURCES;
>>> +  }
>>> +
>>> +  ((IPMI_BLOB_TRANSFER_BLOB_COMMIT_SEND_DATA *)SendData)-
>>> SessionId        = SessionId;
>>> +  ((IPMI_BLOB_TRANSFER_BLOB_COMMIT_SEND_DATA *)SendData)-
>>> CommitDataLength = CommitDataLength;
>>> +  CopyMem (((IPMI_BLOB_TRANSFER_BLOB_COMMIT_SEND_DATA
>> *)SendData)->CommitData, CommitData, sizeof (UINT8) *
>> CommitDataLength);
>>> +
>>> +  ResponseDataSize = 0;
>>> +
>>> +  Status = IpmiBlobTransferSendIpmi
>> (IpmiBlobTransferSubcommandCommit, SendData, SendDataSize, NULL,
>> &ResponseDataSize);
>>> +
>>> +  FreePool (SendData);
>>> +  return Status;
>>> +}
>>> +
>>> +/**
>>> +  This function close a session associated with a blob transfer over the IPMI.
>>> +
>>> +  @param[in]         SessionId       The session ID returned from a call to
>> BlobOpen
>>> +
>>> +  @retval EFI_SUCCESS                The blob was closed.
>>> +  @retval Other                      An error occurred
>>> +**/
>>> +EFI_STATUS
>>> +IpmiBlobTransferClose (
>>> +  IN  UINT16  SessionId
>>> +  )
>>> +{
>>> +  EFI_STATUS  Status;
>>> +  UINT8       *SendData;
>>> +  UINT32      SendDataSize;
>>> +  UINT32      ResponseDataSize;
>>> +
>>> +  //
>>> +  // Format send data
>>> +  //
>>> +  SendDataSize = sizeof (IPMI_BLOB_TRANSFER_BLOB_CLOSE_SEND_DATA);
>>> +  SendData     = AllocateZeroPool (SendDataSize);
>>> +  if (SendData == NULL) {
>>> +    return EFI_OUT_OF_RESOURCES;
>>> +  }
>>> +
>>> +  ((IPMI_BLOB_TRANSFER_BLOB_CLOSE_SEND_DATA *)SendData)-
>>> SessionId = SessionId;
>>> +
>>> +  ResponseDataSize = 0;
>>> +
>>> +  Status = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandClose,
>> SendData, SendDataSize, NULL, &ResponseDataSize);
>>> +
>>> +  FreePool (SendData);
>>> +  return Status;
>>> +}
>>> +
>>> +/**
>>> +  This function deletes a specific blob identified by its ID over the IPMI.
>>> +
>>> +  @param[in]         BlobId          The BlobId to be deleted
>>> +
>>> +  @retval EFI_SUCCESS                The blob was deleted.
>>> +  @retval Other                      An error occurred
>>> +**/
>>> +EFI_STATUS
>>> +IpmiBlobTransferDelete (
>>> +  IN  CHAR8  *BlobId
>>> +  )
>>> +{
>>> +  EFI_STATUS  Status;
>>> +  UINT8       *SendData;
>>> +  UINT32      SendDataSize;
>>> +  UINT32      ResponseDataSize;
>>> +
>>> +  if (BlobId == NULL) {
>>> +    return EFI_INVALID_PARAMETER;
>>> +  }
>>> +
>>> +  //
>>> +  // Format send data
>>> +  //
>>> +  SendDataSize = sizeof
>> (IPMI_BLOB_TRANSFER_BLOB_DELETE_SEND_DATA);
>>> +  SendData     = AllocateZeroPool (SendDataSize);
>>> +  if (SendData == NULL) {
>>> +    return EFI_OUT_OF_RESOURCES;
>>> +  }
>>> +
>>> +  AsciiStrCpyS (((IPMI_BLOB_TRANSFER_BLOB_DELETE_SEND_DATA
>> *)SendData)->BlobId, AsciiStrLen (BlobId), BlobId);
>>> +
>>> +  ResponseDataSize = 0;
>>> +
>>> +  Status = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandDelete,
>> SendData, SendDataSize, NULL, &ResponseDataSize);
>>> +
>>> +  FreePool (SendData);
>>> +  return Status;
>>> +}
>>> +
>>> +/**
>>> +  This function retrieve the status of a specific blob identified by BlobId from
>> an IPMI.
>>> +
>>> +  @param[in]         BlobId          The Blob ID to gather statistics for
>>> +  @param[out]        BlobState       The current state of the blob
>>> +  @param[out]        Size            Size in bytes of the blob
>>> +  @param[out]        MetadataLength  Length of the optional metadata
>>> +  @param[out]        Metadata        Optional blob-specific metadata
>>> +
>>> +  @retval EFI_SUCCESS                The blob statistics were successfully
>> gathered.
>>> +  @retval Other                      An error occurred
>>> +**/
>>> +EFI_STATUS
>>> +IpmiBlobTransferStat (
>>> +  IN  CHAR8   *BlobId,
>>> +  OUT UINT16  *BlobState,
>>> +  OUT UINT32  *Size,
>>> +  OUT UINT8   *MetadataLength,
>>> +  OUT UINT8   *Metadata
>>> +  )
>>> +{
>>> +  EFI_STATUS  Status;
>>> +  UINT8       *SendData;
>>> +  UINT8       *ResponseData;
>>> +  UINT32      SendDataSize;
>>> +  UINT32      ResponseDataSize;
>>> +
>>> +  if ((BlobId == NULL) || (BlobState == NULL) || (Size == NULL) ||
>> (MetadataLength == NULL)) {
>>
>> Could we make Metadata **per spec**, MetadataLength, and Size optional?
>> We could not care them rather than BlobState.
>>
>> This comment applies to IpmiBlobTransferSessionStat () as well.
>>
>>> +    return EFI_INVALID_PARAMETER;
>>> +  }
>>> +
>>> +  if (Metadata == NULL) {
>>> +    ASSERT (FALSE);
>>> +    return EFI_ABORTED;
>>> +  }
>>> +
>>> +  ResponseDataSize = sizeof
>> (IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE);
>>> +  ResponseData     = AllocateZeroPool (ResponseDataSize);
>>> +  if (ResponseData == NULL) {
>>> +    return EFI_OUT_OF_RESOURCES;
>>> +  }
>>> +
>>> +  //
>>> +  // Format send data
>>> +  //
>>> +  SendDataSize = sizeof (IPMI_BLOB_TRANSFER_BLOB_STAT_SEND_DATA);
>>> +  SendData     = AllocateZeroPool (SendDataSize);
>>> +  if (SendData == NULL) {
>>> +    return EFI_OUT_OF_RESOURCES;
>>> +  }
>>> +
>>> +  AsciiStrCpyS (((IPMI_BLOB_TRANSFER_BLOB_STAT_SEND_DATA
>> *)SendData)->BlobId, BLOB_MAX_DATA_PER_PACKET, BlobId);
>>> +
>>> +  Status = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandStat,
>> SendData, SendDataSize, (UINT8 *)ResponseData, &ResponseDataSize);
>>> +  if (!EFI_ERROR (Status)) {
>>> +    *BlobState      = ((IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE
>> *)ResponseData)->BlobState;
>>> +    *Size           = ((IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE
>> *)ResponseData)->Size;
>>> +    *MetadataLength = ((IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE
>> *)ResponseData)->MetaDataLen;
>>> +
>>> +    CopyMem (&Metadata,
>> &((IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE *)ResponseData)-
>>> MetaData, sizeof (((IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE
>> *)ResponseData)->MetaData));
>>> +  }
>>> +
>>> +  FreePool (ResponseData);
>>> +  FreePool (SendData);
>>> +  return Status;
>>> +}
>>> +
>>> +/**
>>> +  This function query the status of a blob transfer session in an IPMI.
>>> +
>>> +  @param[in]         SessionId       The ID of the session to gather statistics for
>>> +  @param[out]        BlobState       The current state of the blob
>>> +  @param[out]        Size            Size in bytes of the blob
>>> +  @param[out]        MetadataLength  Length of the optional metadata
>>> +  @param[out]        Metadata        Optional blob-specific metadata
>>> +
>>> +  @retval EFI_SUCCESS                The blob statistics were successfully
>> gathered.
>>> +  @retval Other                      An error occurred
>>> +**/
>>> +EFI_STATUS
>>> +IpmiBlobTransferSessionStat (
>>> +  IN  UINT16  SessionId,
>>> +  OUT UINT16  *BlobState,
>>> +  OUT UINT32  *Size,
>>> +  OUT UINT8   *MetadataLength,
>>> +  OUT UINT8   *Metadata
>>> +  )
>>> +{
>>> +  EFI_STATUS  Status;
>>> +  UINT8       *SendData;
>>> +  UINT8       *ResponseData;
>>> +  UINT32      SendDataSize;
>>> +  UINT32      ResponseDataSize;
>>> +
>>> +  if ((BlobState == NULL) || (Size == NULL) || (MetadataLength == NULL) ||
>> (Metadata == NULL)) {
>>> +    ASSERT (FALSE);
>>> +    return EFI_ABORTED;
>>> +  }
>>> +
>>> +  ResponseDataSize = sizeof
>> (IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE);
>>> +  ResponseData     = AllocateZeroPool (ResponseDataSize);
>>> +  if (ResponseData == NULL) {
>>> +    return EFI_OUT_OF_RESOURCES;
>>> +  }
>>> +
>>> +  //
>>> +  // Format send data
>>> +  //
>>> +  SendDataSize = sizeof
>> (IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_SEND_DATA);
>>> +  SendData     = AllocateZeroPool (SendDataSize);
>>> +  if (SendData == NULL) {
>>> +    return EFI_OUT_OF_RESOURCES;
>>> +  }
>>> +
>>> +  ((IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_SEND_DATA *)SendData)-
>>> SessionId = SessionId;
>>> +
>>> +  Status = IpmiBlobTransferSendIpmi
>> (IpmiBlobTransferSubcommandSessionStat, SendData, SendDataSize, (UINT8
>> *)ResponseData, &ResponseDataSize);
>>> +
>>> +  if (!EFI_ERROR (Status)) {
>>> +    *BlobState      =
>> ((IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_RESPONSE *)ResponseData)-
>>> BlobState;
>>> +    *Size           = ((IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_RESPONSE
>> *)ResponseData)->Size;
>>> +    *MetadataLength =
>> ((IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_RESPONSE *)ResponseData)-
>>> MetaDataLen;
>>> +
>>> +    CopyMem (&Metadata,
>> &((IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_RESPONSE
>> *)ResponseData)->MetaData, sizeof
>> (((IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_RESPONSE *)ResponseData)-
>>> MetaData));
>>> +  }
>>> +
>>> +  FreePool (ResponseData);
>>> +  FreePool (SendData);
>>> +  return Status;
>>> +}
>>> +
>>> +/**
>>> +  This function writes metadata to a blob associated with a session in an
>> IPMI.
>>> +
>>> +  @param[in]         SessionId       The ID of the session to write metadata for
>>> +  @param[in]         Offset          The offset of the metadata to write to
>>> +  @param[in]         Data            The data to write to the metadata
>>> +  @param[in]         WriteLength     The length to write
>>> +
>>> +  @retval EFI_SUCCESS                The blob metadata was successfully written.
>>> +  @retval Other                      An error occurred
>>> +**/
>>> +EFI_STATUS
>>> +IpmiBlobTransferWriteMeta (
>>> +  IN  UINT16  SessionId,
>>> +  IN  UINT32  Offset,
>>> +  IN  UINT8   *Data,
>>
>> How do callers know the data format of metadata for writing correctly?
>>
>>> +  IN  UINT32  WriteLength
>>
>> Should check with BLOB_MAX_DATA_PER_PACKET
>>
>>> +  )
>>> +{
>>> +  EFI_STATUS  Status;
>>> +  UINT8       *SendData;
>>> +  UINT32      SendDataSize;
>>> +  UINT32      ResponseDataSize;
>>> +
>>> +  if (Data == NULL) {
>>> +    return EFI_INVALID_PARAMETER;
>>> +  }
>>> +
>>> +  //
>>> +  // Format send data
>>> +  //
>>> +  SendDataSize = sizeof
>> (IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_DATA);
>>> +  SendData     = AllocateZeroPool (SendDataSize);
>>> +  if (SendData == NULL) {
>>> +    return EFI_OUT_OF_RESOURCES;
>>> +  }
>>> +
>>> +  ((IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_DATA *)SendData)-
>>> SessionId = SessionId;
>>> +  ((IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_DATA *)SendData)->Offset
>> = Offset;
>>> +  CopyMem (((IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_DATA
>> *)SendData)->Data, Data, sizeof (UINT8) * WriteLength);
>>> +
>>> +  ResponseDataSize = 0;
>>> +
>>> +  Status = IpmiBlobTransferSendIpmi
>> (IpmiBlobTransferSubcommandWriteMeta, SendData, SendDataSize, NULL,
>> &ResponseDataSize);
>>> +
>>> +  FreePool (SendData);
>>> +  return Status;
>>> +}
>>> +
>>> +/**
>>> +  This is the declaration of an EFI image entry point. This entry point is
>>> +  the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers
>> including
>>> +  both device drivers and bus drivers.
>>> +
>>> +  @param[in]  ImageHandle       The firmware allocated handle for the UEFI
>> image.
>>> +  @param[in]  SystemTable       A pointer to the EFI System Table.
>>> +
>>> +  @retval EFI_SUCCESS           The operation completed successfully.
>>> +  @retval Others                An unexpected error occurred.
>>> +
>>> +**/
>>> +EFI_STATUS
>>> +EFIAPI
>>> +IpmiBlobTransferDxeDriverEntryPoint (
>>> +  IN EFI_HANDLE        ImageHandle,
>>> +  IN EFI_SYSTEM_TABLE  *SystemTable
>>> +  )
>>> +{
>>> +  return gBS->InstallMultipleProtocolInterfaces (
>>> +                &ImageHandle,
>>
>> Nit: Typically, we could also use gImageHandle instead.
>>
>>> +                &gEdkiiIpmiBlobTransferProtocolGuid,
>>> +                (VOID *)&mIpmiBlobTransfer,
>>> +                NULL
>>> +                );
>>> +}
>>> diff --git
>> a/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiB
>> lobTransferTestUnitTests.c
>> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiB
>> lobTransferTestUnitTests.c
>>> new file mode 100644
>>> index 0000000000..0f728527b8
>>> --- /dev/null
>>> +++
>> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiB
>> lobTransferTestUnitTests.c
>>> @@ -0,0 +1,1113 @@
>>> +/** @file
>>> +*
>>> +*  Copyright (c) 2022-2024, NVIDIA CORPORATION. All rights reserved.
>>> +*
>>> +*  SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION
>> & AFFILIATES
>>> +*  SPDX-License-Identifier: BSD-2-Clause-Patent
>>> +*
>>> +**/
>>> +#include <stdarg.h>
>>> +#include <stddef.h>
>>> +#include <setjmp.h>
>>> +#include <stdint.h>
>>> +#include <cmocka.h>
>>> +
>>> +#include <Uefi.h>
>>> +#include <Library/BaseMemoryLib.h>
>>> +#include <Library/DebugLib.h>
>>> +#include <Library/MemoryAllocationLib.h>
>>> +#include <Library/HostBasedTestStubLib/IpmiStubLib.h>
>>> +
>>> +#include <Library/UnitTestLib.h>
>>> +#include <Protocol/IpmiBlobTransfer.h>
>>> +#include "../InternalIpmiBlobTransfer.h"
>>> +
>>> +#define UNIT_TEST_NAME     "IPMI Blob Transfer Unit Tests"
>>> +#define UNIT_TEST_VERSION  "1.0"
>>> +
>>> +UINT8  InvalidCompletion[] = {
>>> +  0xC0,             // CompletionCode
>>> +  0xCF, 0xC2, 0x00, // OpenBMC OEN
>>> +};
>>> +#define INVALID_COMPLETION_SIZE  4 * sizeof(UINT8)
>>> +
>>> +UINT8  NoDataResponse[] = {
>>> +  0x00,             // CompletionCode
>>> +  0xCF, 0xC2, 0x00, // OpenBMC OEN
>>> +};
>>> +#define NO_DATA_RESPONSE_SIZE  4 * sizeof(UINT8)
>>> +
>>> +UINT8  BadOenResponse[] = {
>>> +  0x00,             // CompletionCode
>>> +  0xFF, 0xC2, 0x00, // Wrong OEN
>>> +};
>>> +#define BAD_OEN_RESPONSE_SIZE  4 * sizeof(UINT8)
>>> +
>>> +UINT8  BadCrcResponse[] = {
>>> +  0x00,                   // CompletionCode
>>> +  0xCF, 0xC2, 0x00,       // OpenBMC OEN
>>> +  0x00, 0x00,             // CRC
>>> +  0x01, 0x00, 0x00, 0x00, // Data
>>> +};
>>> +#define BAD_CRC_RESPONSE_SIZE  10 * sizeof(UINT8)
>>> +
>>> +UINT8  ValidNoDataResponse[] = {
>>> +  0x00,             // CompletionCode
>>> +  0xCF, 0xC2, 0x00, // OpenBMC OEN
>>> +};
>>> +
>>> +#define VALID_NODATA_RESPONSE_SIZE  4 * sizeof(UINT8)
>>> +
>>> +/**
>>> +  @param[in]  Context    [Optional] An optional parameter that enables:
>>> +                         1) test-case reuse with varied parameters and
>>> +                         2) test-case re-entry for Target tests that need a
>>> +                         reboot.  This parameter is a VOID* and it is the
>>> +                         responsibility of the test author to ensure that the
>>> +                         contents are well understood by all test cases that may
>>> +                         consume it.
>>> +  @retval  UNIT_TEST_PASSED             The Unit test has completed and the
>> test
>>> +                                        case was successful.
>>> +  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.
>>> +**/
>>> +UNIT_TEST_STATUS
>>> +EFIAPI
>>> +GoodCrc (
>>> +  IN UNIT_TEST_CONTEXT  Context
>>> +  )
>>> +{
>>> +  UINT8   Data[5] = { 0x12, 0x34, 0x56, 0x78, 0x90 };
>>> +  UINTN   DataSize;
>>> +  UINT16  Crc;
>>> +
>>> +  DataSize = sizeof (Data);
>>> +
>>> +  Crc = CalculateCrc16Ccitt (Data, DataSize);
>>> +
>>> +  UT_ASSERT_EQUAL (Crc, 0xB928);
>>> +  return UNIT_TEST_PASSED;
>>> +}
>>> +
>>> +/**
>>> +  @param[in]  Context    [Optional] An optional parameter that enables:
>>> +                         1) test-case reuse with varied parameters and
>>> +                         2) test-case re-entry for Target tests that need a
>>> +                         reboot.  This parameter is a VOID* and it is the
>>> +                         responsibility of the test author to ensure that the
>>> +                         contents are well understood by all test cases that may
>>> +                         consume it.
>>> +  @retval  UNIT_TEST_PASSED             The Unit test has completed and the
>> test
>>> +                                        case was successful.
>>> +  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.
>>> +**/
>>> +UNIT_TEST_STATUS
>>> +EFIAPI
>>> +BadCrc (
>>> +  IN UNIT_TEST_CONTEXT  Context
>>> +  )
>>> +{
>>> +  UINT8   Data[5] = { 0x12, 0x34, 0x56, 0x78, 0x90 };
>>> +  UINTN   DataSize;
>>> +  UINT16  Crc;
>>> +
>>> +  DataSize = sizeof (Data);
>>> +
>>> +  Crc = CalculateCrc16Ccitt (Data, DataSize);
>>> +
>>> +  UT_ASSERT_NOT_EQUAL (Crc, 0x3409);
>>> +  return UNIT_TEST_PASSED;
>>> +}
>>> +
>>> +/**
>>> +  @param[in]  Context    [Optional] An optional parameter that enables:
>>> +                         1) test-case reuse with varied parameters and
>>> +                         2) test-case re-entry for Target tests that need a
>>> +                         reboot.  This parameter is a VOID* and it is the
>>> +                         responsibility of the test author to ensure that the
>>> +                         contents are well understood by all test cases that may
>>> +                         consume it.
>>> +  @retval  UNIT_TEST_PASSED             The Unit test has completed and the
>> test
>>> +                                        case was successful.
>>> +  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.
>>> +**/
>>> +UNIT_TEST_STATUS
>>> +EFIAPI
>>> +SendIpmiBadCompletion (
>>> +  IN UNIT_TEST_CONTEXT  Context
>>> +  )
>>> +{
>>> +  VOID        *ResponseData;
>>> +  UINT32      *ResponseDataSize;
>>> +  EFI_STATUS  Status;
>>> +  VOID        *MockResponseResults = NULL;
>>> +
>>> +  MockResponseResults = (UINT8 *)AllocateZeroPool
>> (INVALID_COMPLETION_SIZE);
>>> +  ResponseDataSize    = (UINT32 *)AllocateZeroPool (sizeof (UINT32));
>>> +  CopyMem (MockResponseResults, &InvalidCompletion,
>> INVALID_COMPLETION_SIZE);
>>> +
>>> +  MockIpmiSubmitCommand ((UINT8 *)MockResponseResults,
>> INVALID_COMPLETION_SIZE, EFI_SUCCESS);
>>> +
>>> +  ResponseData = (UINT8 *)AllocateZeroPool (*ResponseDataSize);
>>> +  Status       = IpmiBlobTransferSendIpmi
>> (IpmiBlobTransferSubcommandGetCount, NULL, 0, ResponseData,
>> ResponseDataSize);
>>> +
>>> +  UT_ASSERT_STATUS_EQUAL (Status, EFI_PROTOCOL_ERROR);
>>> +  FreePool (MockResponseResults);
>>> +  FreePool (ResponseDataSize);
>>> +  FreePool (ResponseData);
>>> +  return UNIT_TEST_PASSED;
>>> +}
>>> +
>>> +/**
>>> +  @param[in]  Context    [Optional] An optional parameter that enables:
>>> +                         1) test-case reuse with varied parameters and
>>> +                         2) test-case re-entry for Target tests that need a
>>> +                         reboot.  This parameter is a VOID* and it is the
>>> +                         responsibility of the test author to ensure that the
>>> +                         contents are well understood by all test cases that may
>>> +                         consume it.
>>> +  @retval  UNIT_TEST_PASSED             The Unit test has completed and the
>> test
>>> +                                        case was successful.
>>> +  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.
>>> +**/
>>> +UNIT_TEST_STATUS
>>> +EFIAPI
>>> +SendIpmiNoDataResponse (
>>> +  IN UNIT_TEST_CONTEXT  Context
>>> +  )
>>> +{
>>> +  VOID        *ResponseData;
>>> +  UINT32      *ResponseDataSize;
>>> +  EFI_STATUS  Status;
>>> +  VOID        *MockResponseResults = NULL;
>>> +
>>> +  MockResponseResults = (UINT8 *)AllocateZeroPool
>> (NO_DATA_RESPONSE_SIZE);
>>> +  ResponseDataSize    = (UINT32 *)AllocateZeroPool (sizeof (UINT32));
>>> +  CopyMem (MockResponseResults, &NoDataResponse,
>> NO_DATA_RESPONSE_SIZE);
>>> +
>>> +  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults,
>> NO_DATA_RESPONSE_SIZE, EFI_SUCCESS);
>>> +  if (EFI_ERROR (Status)) {
>>> +    return UNIT_TEST_ERROR_TEST_FAILED;
>>> +  }
>>> +
>>> +  ResponseData = (UINT8 *)AllocateZeroPool (sizeof (NoDataResponse));
>>> +  Status       = IpmiBlobTransferSendIpmi
>> (IpmiBlobTransferSubcommandGetCount, NULL, 0, ResponseData,
>> ResponseDataSize);
>>> +
>>> +  UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);
>>> +  UT_ASSERT_EQUAL (*ResponseDataSize, 0);
>>> +  FreePool (MockResponseResults);
>>> +  FreePool (ResponseDataSize);
>>> +  FreePool (ResponseData);
>>> +  return UNIT_TEST_PASSED;
>>> +}
>>> +
>>> +/**
>>> +  @param[in]  Context    [Optional] An optional parameter that enables:
>>> +                         1) test-case reuse with varied parameters and
>>> +                         2) test-case re-entry for Target tests that need a
>>> +                         reboot.  This parameter is a VOID* and it is the
>>> +                         responsibility of the test author to ensure that the
>>> +                         contents are well understood by all test cases that may
>>> +                         consume it.
>>> +  @retval  UNIT_TEST_PASSED             The Unit test has completed and the
>> test
>>> +                                        case was successful.
>>> +  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.
>>> +**/
>>> +UNIT_TEST_STATUS
>>> +EFIAPI
>>> +SendIpmiBadOenResponse (
>>> +  IN UNIT_TEST_CONTEXT  Context
>>> +  )
>>> +{
>>> +  VOID        *ResponseData;
>>> +  UINT32      *ResponseDataSize;
>>> +  EFI_STATUS  Status;
>>> +  VOID        *MockResponseResults = NULL;
>>> +
>>> +  MockResponseResults = (UINT8 *)AllocateZeroPool
>> (BAD_OEN_RESPONSE_SIZE);
>>> +  ResponseDataSize    = (UINT32 *)AllocateZeroPool (sizeof (UINT32));
>>> +  CopyMem (MockResponseResults, &BadOenResponse,
>> BAD_OEN_RESPONSE_SIZE);
>>> +
>>> +  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults,
>> BAD_OEN_RESPONSE_SIZE, EFI_SUCCESS);
>>> +  if (EFI_ERROR (Status)) {
>>> +    return UNIT_TEST_ERROR_TEST_FAILED;
>>> +  }
>>> +
>>> +  ResponseData = (UINT8 *)AllocateZeroPool (sizeof (BadOenResponse));
>>> +  Status       = IpmiBlobTransferSendIpmi
>> (IpmiBlobTransferSubcommandGetCount, NULL, 0, ResponseData,
>> ResponseDataSize);
>>> +
>>> +  UT_ASSERT_STATUS_EQUAL (Status, EFI_PROTOCOL_ERROR);
>>> +  FreePool (MockResponseResults);
>>> +  FreePool (ResponseDataSize);
>>> +  FreePool (ResponseData);
>>> +  return UNIT_TEST_PASSED;
>>> +}
>>> +
>>> +/**
>>> +  @param[in]  Context    [Optional] An optional parameter that enables:
>>> +                         1) test-case reuse with varied parameters and
>>> +                         2) test-case re-entry for Target tests that need a
>>> +                         reboot.  This parameter is a VOID* and it is the
>>> +                         responsibility of the test author to ensure that the
>>> +                         contents are well understood by all test cases that may
>>> +                         consume it.
>>> +  @retval  UNIT_TEST_PASSED             The Unit test has completed and the
>> test
>>> +                                        case was successful.
>>> +  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.
>>> +**/
>>> +UNIT_TEST_STATUS
>>> +EFIAPI
>>> +SendIpmiBadCrcResponse (
>>> +  IN UNIT_TEST_CONTEXT  Context
>>> +  )
>>> +{
>>> +  VOID        *ResponseData;
>>> +  UINT32      *ResponseDataSize;
>>> +  EFI_STATUS  Status;
>>> +  VOID        *MockResponseResults = NULL;
>>> +
>>> +  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof
>> (BAD_CRC_RESPONSE_SIZE));
>>> +  ResponseDataSize    = (UINT32 *)AllocateZeroPool (sizeof (UINT32));
>>> +  CopyMem (MockResponseResults, &BadCrcResponse,
>> BAD_CRC_RESPONSE_SIZE);
>>> +
>>> +  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults,
>> BAD_CRC_RESPONSE_SIZE, EFI_SUCCESS);
>>> +  if (EFI_ERROR (Status)) {
>>> +    return UNIT_TEST_ERROR_TEST_FAILED;
>>> +  }
>>> +
>>> +  ResponseData = (UINT8 *)AllocateZeroPool (sizeof (BadCrcResponse));
>>> +  Status       = IpmiBlobTransferSendIpmi
>> (IpmiBlobTransferSubcommandGetCount, NULL, 0, ResponseData,
>> ResponseDataSize);
>>> +
>>> +  UT_ASSERT_STATUS_EQUAL (Status, EFI_CRC_ERROR);
>>> +  FreePool (MockResponseResults);
>>> +  FreePool (ResponseDataSize);
>>> +  FreePool (ResponseData);
>>> +  return UNIT_TEST_PASSED;
>>> +}
>>> +
>>> +UINT8  ValidGetCountResponse[] = {
>>> +  0x00,                   // CompletionCode
>>> +  0xCF, 0xC2, 0x00,       // OpenBMC OEN
>>> +  0xA4, 0x78,             // CRC
>>> +  0x01, 0x00, 0x00, 0x00, // Data
>>> +};
>>> +#define VALID_GET_COUNT_RESPONSE_SIZE  10 * sizeof(UINT8)
>>> +
>>> +/**
>>> +  @param[in]  Context    [Optional] An optional parameter that enables:
>>> +                         1) test-case reuse with varied parameters and
>>> +                         2) test-case re-entry for Target tests that need a
>>> +                         reboot.  This parameter is a VOID* and it is the
>>> +                         responsibility of the test author to ensure that the
>>> +                         contents are well understood by all test cases that may
>>> +                         consume it.
>>> +  @retval  UNIT_TEST_PASSED             The Unit test has completed and the
>> test
>>> +                                        case was successful.
>>> +  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.
>>> +**/
>>> +UNIT_TEST_STATUS
>>> +EFIAPI
>>> +SendIpmiValidCountResponse (
>>> +  IN UNIT_TEST_CONTEXT  Context
>>> +  )
>>> +{
>>> +  UINT8       *ResponseData;
>>> +  UINT32      *ResponseDataSize;
>>> +  EFI_STATUS  Status;
>>> +  VOID        *MockResponseResults = NULL;
>>> +
>>> +  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof
>> (VALID_GET_COUNT_RESPONSE_SIZE));
>>> +  ResponseDataSize    = (UINT32 *)AllocateZeroPool (sizeof (UINT32));
>>> +  CopyMem (MockResponseResults, &ValidGetCountResponse,
>> VALID_GET_COUNT_RESPONSE_SIZE);
>>> +
>>> +  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults,
>> VALID_GET_COUNT_RESPONSE_SIZE, EFI_SUCCESS);
>>> +  if (EFI_ERROR (Status)) {
>>> +    return UNIT_TEST_ERROR_TEST_FAILED;
>>> +  }
>>> +
>>> +  ResponseData = AllocateZeroPool (sizeof (ValidGetCountResponse));
>>> +  Status       = IpmiBlobTransferSendIpmi
>> (IpmiBlobTransferSubcommandGetCount, NULL, 0, ResponseData,
>> ResponseDataSize);
>>> +
>>> +  UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);
>>> +  FreePool (MockResponseResults);
>>> +  FreePool (ResponseDataSize);
>>> +  FreePool (ResponseData);
>>> +  return UNIT_TEST_PASSED;
>>> +}
>>> +
>>> +/**
>>> +  @param[in]  Context    [Optional] An optional parameter that enables:
>>> +                         1) test-case reuse with varied parameters and
>>> +                         2) test-case re-entry for Target tests that need a
>>> +                         reboot.  This parameter is a VOID* and it is the
>>> +                         responsibility of the test author to ensure that the
>>> +                         contents are well understood by all test cases that may
>>> +                         consume it.
>>> +  @retval  UNIT_TEST_PASSED             The Unit test has completed and the
>> test
>>> +                                        case was successful.
>>> +  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.
>>> +**/
>>> +UNIT_TEST_STATUS
>>> +EFIAPI
>>> +GetCountValidCountResponse (
>>> +  IN UNIT_TEST_CONTEXT  Context
>>> +  )
>>> +{
>>> +  EFI_STATUS  Status;
>>> +  UINT32      Count;
>>> +  VOID        *MockResponseResults = NULL;
>>> +
>>> +  Count = 0;
>>> +
>>> +  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof
>> (VALID_GET_COUNT_RESPONSE_SIZE));
>>> +  CopyMem (MockResponseResults, &ValidGetCountResponse,
>> VALID_GET_COUNT_RESPONSE_SIZE);
>>> +
>>> +  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults,
>> VALID_GET_COUNT_RESPONSE_SIZE, EFI_SUCCESS);
>>> +  if (EFI_ERROR (Status)) {
>>> +    return UNIT_TEST_ERROR_TEST_FAILED;
>>> +  }
>>> +
>>> +  Status = IpmiBlobTransferGetCount (&Count);
>>> +
>>> +  UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);
>>> +  UT_ASSERT_EQUAL (Count, 1);
>>> +  FreePool (MockResponseResults);
>>> +  return UNIT_TEST_PASSED;
>>> +}
>>> +
>>> +UINT8  ValidEnumerateResponse[] = {
>>> +  0x00,                   // CompletionCode
>>> +  0xCF, 0xC2, 0x00,       // OpenBMC OEN
>>> +  0x81, 0x13,             // CRC
>>> +  0x2F, 0x73, 0x6D, 0x62, // Data = "/smbios"
>>> +  0x69, 0x6F, 0x73, 0x00,
>>> +};
>>> +#define VALID_ENUMERATE_RESPONSE_SIZE  14 * sizeof(UINT8)
>>> +
>>> +/**
>>> +  @param[in]  Context    [Optional] An optional parameter that enables:
>>> +                         1) test-case reuse with varied parameters and
>>> +                         2) test-case re-entry for Target tests that need a
>>> +                         reboot.  This parameter is a VOID* and it is the
>>> +                         responsibility of the test author to ensure that the
>>> +                         contents are well understood by all test cases that may
>>> +                         consume it.
>>> +  @retval  UNIT_TEST_PASSED             The Unit test has completed and the
>> test
>>> +                                        case was successful.
>>> +  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.
>>> +**/
>>> +UNIT_TEST_STATUS
>>> +EFIAPI
>>> +EnumerateValidResponse (
>>> +  IN UNIT_TEST_CONTEXT  Context
>>> +  )
>>> +{
>>> +  EFI_STATUS  Status;
>>> +  CHAR8       *BlobId;
>>> +  VOID        *MockResponseResults = NULL;
>>> +
>>> +  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof
>> (VALID_ENUMERATE_RESPONSE_SIZE));
>>> +  CopyMem (MockResponseResults, &ValidEnumerateResponse,
>> VALID_ENUMERATE_RESPONSE_SIZE);
>>> +
>>> +  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults,
>> VALID_ENUMERATE_RESPONSE_SIZE, EFI_SUCCESS);
>>> +  if (EFI_ERROR (Status)) {
>>> +    return UNIT_TEST_ERROR_TEST_FAILED;
>>> +  }
>>> +
>>> +  BlobId = AllocateZeroPool (sizeof (CHAR8) *
>> BLOB_MAX_DATA_PER_PACKET);
>>> +
>>> +  Status = IpmiBlobTransferEnumerate (0, BlobId);
>>> +
>>> +  UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);
>>> +  UT_ASSERT_MEM_EQUAL (BlobId, "/smbios", 7);
>>> +  FreePool (MockResponseResults);
>>> +  FreePool (BlobId);
>>> +  return UNIT_TEST_PASSED;
>>> +}
>>> +
>>> +/**
>>> +  @param[in]  Context    [Optional] An optional parameter that enables:
>>> +                         1) test-case reuse with varied parameters and
>>> +                         2) test-case re-entry for Target tests that need a
>>> +                         reboot.  This parameter is a VOID* and it is the
>>> +                         responsibility of the test author to ensure that the
>>> +                         contents are well understood by all test cases that may
>>> +                         consume it.
>>> +  @retval  UNIT_TEST_PASSED             The Unit test has completed and the
>> test
>>> +                                        case was successful.
>>> +  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.
>>> +**/
>>> +UNIT_TEST_STATUS
>>> +EFIAPI
>>> +EnumerateInvalidBuffer (
>>> +  IN UNIT_TEST_CONTEXT  Context
>>> +  )
>>> +{
>>> +  CHAR8       *BlobId;
>>> +  EFI_STATUS  Status;
>>> +  VOID        *MockResponseResults = NULL;
>>> +
>>> +  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof
>> (VALID_ENUMERATE_RESPONSE_SIZE));
>>> +  CopyMem (MockResponseResults, &ValidEnumerateResponse,
>> VALID_ENUMERATE_RESPONSE_SIZE);
>>> +
>>> +  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults,
>> VALID_ENUMERATE_RESPONSE_SIZE, EFI_SUCCESS);
>>> +  if (EFI_ERROR (Status)) {
>>> +    return UNIT_TEST_ERROR_TEST_FAILED;
>>> +  }
>>> +
>>> +  BlobId = NULL;
>>> +
>>> +  UT_EXPECT_ASSERT_FAILURE (IpmiBlobTransferEnumerate (0, BlobId),
>> NULL);
>>> +
>>> +  FreePool (MockResponseResults);
>>> +  return UNIT_TEST_PASSED;
>>> +}
>>> +
>>> +UINT8  ValidOpenResponse[] = {
>>> +  0x00,             // CompletionCode
>>> +  0xCF, 0xC2, 0x00, // OpenBMC OEN
>>> +  0x93, 0xD1,       // CRC
>>> +  0x03, 0x00,       // SessionId = 3
>>> +};
>>> +#define VALID_OPEN_RESPONSE_SIZE  8 * sizeof(UINT8)
>>> +
>>> +/**
>>> +  @param[in]  Context    [Optional] An optional parameter that enables:
>>> +                         1) test-case reuse with varied parameters and
>>> +                         2) test-case re-entry for Target tests that need a
>>> +                         reboot.  This parameter is a VOID* and it is the
>>> +                         responsibility of the test author to ensure that the
>>> +                         contents are well understood by all test cases that may
>>> +                         consume it.
>>> +  @retval  UNIT_TEST_PASSED             The Unit test has completed and the
>> test
>>> +                                        case was successful.
>>> +  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.
>>> +**/
>>> +UNIT_TEST_STATUS
>>> +EFIAPI
>>> +OpenValidResponse (
>>> +  IN UNIT_TEST_CONTEXT  Context
>>> +  )
>>> +{
>>> +  EFI_STATUS  Status;
>>> +  CHAR8       *BlobId;
>>> +  UINT16      Flags;
>>> +  UINT16      SessionId;
>>> +  VOID        *MockResponseResults  = NULL;
>>> +  VOID        *MockResponseResults2 = NULL;
>>> +  VOID        *MockResponseResults3 = NULL;
>>> +
>>> +  Flags = BLOB_TRANSFER_STAT_OPEN_W;
>>> +
>>> +  //
>>> +  // An open call effectively leads to three IPMI commands
>>> +  // 1. GetCount of blobs
>>> +  // 2. Enumerate the requested blob
>>> +  // 3. Open the requested blob
>>> +  //
>>> +  // So we'll push three Ipmi responses in this case
>>> +  //
>>> +
>>> +  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof
>> (VALID_OPEN_RESPONSE_SIZE));
>>> +
>>> +  CopyMem (MockResponseResults, &ValidOpenResponse,
>> VALID_OPEN_RESPONSE_SIZE);
>>> +  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults,
>> VALID_OPEN_RESPONSE_SIZE, EFI_SUCCESS);
>>> +  if (EFI_ERROR (Status)) {
>>> +    return UNIT_TEST_ERROR_TEST_FAILED;
>>> +  }
>>> +
>>> +  MockResponseResults2 = (UINT8 *)AllocateZeroPool (sizeof
>> (VALID_ENUMERATE_RESPONSE_SIZE));
>>> +  CopyMem (MockResponseResults2, &ValidEnumerateResponse,
>> VALID_ENUMERATE_RESPONSE_SIZE);
>>> +  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults2,
>> VALID_ENUMERATE_RESPONSE_SIZE, EFI_SUCCESS);
>>> +  if (EFI_ERROR (Status)) {
>>> +    return UNIT_TEST_ERROR_TEST_FAILED;
>>> +  }
>>> +
>>> +  MockResponseResults3 = (UINT8 *)AllocateZeroPool (sizeof
>> (VALID_GET_COUNT_RESPONSE_SIZE));
>>> +  CopyMem (MockResponseResults3, &ValidGetCountResponse,
>> VALID_GET_COUNT_RESPONSE_SIZE);
>>> +  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults3,
>> VALID_GET_COUNT_RESPONSE_SIZE, EFI_SUCCESS);
>>> +  if (EFI_ERROR (Status)) {
>>> +    return UNIT_TEST_ERROR_TEST_FAILED;
>>> +  }
>>> +
>>> +  BlobId = "/smbios";
>>> +
>>> +  Status = IpmiBlobTransferOpen (BlobId, Flags, &SessionId);
>>> +
>>> +  UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);
>>> +  UT_ASSERT_EQUAL (SessionId, 3);
>>> +  FreePool (MockResponseResults);
>>> +  return UNIT_TEST_PASSED;
>>> +}
>>> +
>>> +UINT8  ValidReadResponse[] = {
>>> +  0x00,                   // CompletionCode
>>> +  0xCF, 0xC2, 0x00,       // OpenBMC OEN
>>> +  0x21, 0x6F,             // CRC
>>> +  0x00, 0x01, 0x02, 0x03, // Data to read
>>> +};
>>> +
>>> +#define VALID_READ_RESPONSE_SIZE  10 * sizeof(UINT8)
>>> +
>>> +/**
>>> +  @param[in]  Context    [Optional] An optional parameter that enables:
>>> +                         1) test-case reuse with varied parameters and
>>> +                         2) test-case re-entry for Target tests that need a
>>> +                         reboot.  This parameter is a VOID* and it is the
>>> +                         responsibility of the test author to ensure that the
>>> +                         contents are well understood by all test cases that may
>>> +                         consume it.
>>> +  @retval  UNIT_TEST_PASSED             The Unit test has completed and the
>> test
>>> +                                        case was successful.
>>> +  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.
>>> +**/
>>> +UNIT_TEST_STATUS
>>> +EFIAPI
>>> +ReadValidResponse (
>>> +  IN UNIT_TEST_CONTEXT  Context
>>> +  )
>>> +{
>>> +  EFI_STATUS  Status;
>>> +  UINT8       *ResponseData;
>>> +  UINT8       ExpectedDataResponse[4] = { 0x00, 0x01, 0x02, 0x03 };
>>> +  VOID        *MockResponseResults    = NULL;
>>> +
>>> +  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof
>> (VALID_READ_RESPONSE_SIZE));
>>> +  CopyMem (MockResponseResults, &ValidReadResponse,
>> VALID_READ_RESPONSE_SIZE);
>>> +  ResponseData = AllocateZeroPool (sizeof (ValidReadResponse));
>>> +
>>> +  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults,
>> VALID_READ_RESPONSE_SIZE, EFI_SUCCESS);
>>> +  if (EFI_ERROR (Status)) {
>>> +    return UNIT_TEST_ERROR_TEST_FAILED;
>>> +  }
>>> +
>>> +  Status = IpmiBlobTransferRead (0, 0, 4, ResponseData);
>>> +
>>> +  UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);
>>> +  UT_ASSERT_MEM_EQUAL (ResponseData, ExpectedDataResponse, 4);
>>> +  FreePool (MockResponseResults);
>>> +  FreePool (ResponseData);
>>> +  return UNIT_TEST_PASSED;
>>> +}
>>> +
>>> +/**
>>> +  @param[in]  Context    [Optional] An optional parameter that enables:
>>> +                         1) test-case reuse with varied parameters and
>>> +                         2) test-case re-entry for Target tests that need a
>>> +                         reboot.  This parameter is a VOID* and it is the
>>> +                         responsibility of the test author to ensure that the
>>> +                         contents are well understood by all test cases that may
>>> +                         consume it.
>>> +  @retval  UNIT_TEST_PASSED             The Unit test has completed and the
>> test
>>> +                                        case was successful.
>>> +  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.
>>> +**/
>>> +UNIT_TEST_STATUS
>>> +EFIAPI
>>> +ReadInvalidBuffer (
>>> +  IN UNIT_TEST_CONTEXT  Context
>>> +  )
>>> +{
>>> +  UINT8       *ResponseData;
>>> +  EFI_STATUS  Status;
>>> +  VOID        *MockResponseResults = NULL;
>>> +
>>> +  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof
>> (VALID_READ_RESPONSE_SIZE));
>>> +  CopyMem (MockResponseResults, &ValidReadResponse,
>> VALID_READ_RESPONSE_SIZE);
>>> +  ResponseData = NULL;
>>> +
>>> +  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults,
>> VALID_READ_RESPONSE_SIZE, EFI_SUCCESS);
>>> +  if (EFI_ERROR (Status)) {
>>> +    return UNIT_TEST_ERROR_TEST_FAILED;
>>> +  }
>>> +
>>> +  UT_EXPECT_ASSERT_FAILURE (IpmiBlobTransferRead (0, 0, 4,
>> ResponseData), NULL);
>>> +
>>> +  FreePool (MockResponseResults);
>>> +  return UNIT_TEST_PASSED;
>>> +}
>>> +
>>> +/**
>>> +  @param[in]  Context    [Optional] An optional parameter that enables:
>>> +                         1) test-case reuse with varied parameters and
>>> +                         2) test-case re-entry for Target tests that need a
>>> +                         reboot.  This parameter is a VOID* and it is the
>>> +                         responsibility of the test author to ensure that the
>>> +                         contents are well understood by all test cases that may
>>> +                         consume it.
>>> +  @retval  UNIT_TEST_PASSED             The Unit test has completed and the
>> test
>>> +                                        case was successful.
>>> +  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.
>>> +**/
>>> +UNIT_TEST_STATUS
>>> +EFIAPI
>>> +WriteValidResponse (
>>> +  IN UNIT_TEST_CONTEXT  Context
>>> +  )
>>> +{
>>> +  EFI_STATUS  Status;
>>> +  UINT8       SendData[4]          = { 0x00, 0x01, 0x02, 0x03 };
>>> +  VOID        *MockResponseResults = NULL;
>>> +
>>> +  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof
>> (VALID_NODATA_RESPONSE_SIZE));
>>> +  CopyMem (MockResponseResults, &ValidNoDataResponse,
>> VALID_NODATA_RESPONSE_SIZE);
>>> +
>>> +  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults,
>> VALID_NODATA_RESPONSE_SIZE, EFI_SUCCESS);
>>> +  if (EFI_ERROR (Status)) {
>>> +    return UNIT_TEST_ERROR_TEST_FAILED;
>>> +  }
>>> +
>>> +  Status = IpmiBlobTransferWrite (0, 0, SendData, 4);
>>> +
>>> +  UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);
>>> +  FreePool (MockResponseResults);
>>> +  return UNIT_TEST_PASSED;
>>> +}
>>> +
>>> +/**
>>> +  @param[in]  Context    [Optional] An optional parameter that enables:
>>> +                         1) test-case reuse with varied parameters and
>>> +                         2) test-case re-entry for Target tests that need a
>>> +                         reboot.  This parameter is a VOID* and it is the
>>> +                         responsibility of the test author to ensure that the
>>> +                         contents are well understood by all test cases that may
>>> +                         consume it.
>>> +  @retval  UNIT_TEST_PASSED             The Unit test has completed and the
>> test
>>> +                                        case was successful.
>>> +  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.
>>> +**/
>>> +UNIT_TEST_STATUS
>>> +EFIAPI
>>> +CommitValidResponse (
>>> +  IN UNIT_TEST_CONTEXT  Context
>>> +  )
>>> +{
>>> +  EFI_STATUS  Status;
>>> +  UINT8       SendData[4]          = { 0x00, 0x01, 0x02, 0x03 };
>>> +  VOID        *MockResponseResults = NULL;
>>> +
>>> +  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof
>> (VALID_NODATA_RESPONSE_SIZE));
>>> +  CopyMem (MockResponseResults, &ValidNoDataResponse,
>> VALID_NODATA_RESPONSE_SIZE);
>>> +
>>> +  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults,
>> VALID_NODATA_RESPONSE_SIZE, EFI_SUCCESS);
>>> +  if (EFI_ERROR (Status)) {
>>> +    return UNIT_TEST_ERROR_TEST_FAILED;
>>> +  }
>>> +
>>> +  Status = IpmiBlobTransferCommit (0, 4, SendData);
>>> +
>>> +  UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);
>>> +  FreePool (MockResponseResults);
>>> +  return UNIT_TEST_PASSED;
>>> +}
>>> +
>>> +/**
>>> +  @param[in]  Context    [Optional] An optional parameter that enables:
>>> +                         1) test-case reuse with varied parameters and
>>> +                         2) test-case re-entry for Target tests that need a
>>> +                         reboot.  This parameter is a VOID* and it is the
>>> +                         responsibility of the test author to ensure that the
>>> +                         contents are well understood by all test cases that may
>>> +                         consume it.
>>> +  @retval  UNIT_TEST_PASSED             The Unit test has completed and the
>> test
>>> +                                        case was successful.
>>> +  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.
>>> +**/
>>> +UNIT_TEST_STATUS
>>> +EFIAPI
>>> +CloseValidResponse (
>>> +  IN UNIT_TEST_CONTEXT  Context
>>> +  )
>>> +{
>>> +  EFI_STATUS  Status;
>>> +  VOID        *MockResponseResults = NULL;
>>> +
>>> +  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof
>> (VALID_NODATA_RESPONSE_SIZE));
>>> +  CopyMem (MockResponseResults, &ValidNoDataResponse,
>> VALID_NODATA_RESPONSE_SIZE);
>>> +
>>> +  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults,
>> VALID_NODATA_RESPONSE_SIZE, EFI_SUCCESS);
>>> +  if (EFI_ERROR (Status)) {
>>> +    return UNIT_TEST_ERROR_TEST_FAILED;
>>> +  }
>>> +
>>> +  Status = IpmiBlobTransferClose (1);
>>> +
>>> +  UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);
>>> +  FreePool (MockResponseResults);
>>> +  return UNIT_TEST_PASSED;
>>> +}
>>> +
>>> +/**
>>> +  @param[in]  Context    [Optional] An optional parameter that enables:
>>> +                         1) test-case reuse with varied parameters and
>>> +                         2) test-case re-entry for Target tests that need a
>>> +                         reboot.  This parameter is a VOID* and it is the
>>> +                         responsibility of the test author to ensure that the
>>> +                         contents are well understood by all test cases that may
>>> +                         consume it.
>>> +  @retval  UNIT_TEST_PASSED             The Unit test has completed and the
>> test
>>> +                                        case was successful.
>>> +  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.
>>> +**/
>>> +UNIT_TEST_STATUS
>>> +EFIAPI
>>> +DeleteValidResponse (
>>> +  IN UNIT_TEST_CONTEXT  Context
>>> +  )
>>> +{
>>> +  EFI_STATUS  Status;
>>> +  VOID        *MockResponseResults = NULL;
>>> +
>>> +  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof
>> (VALID_NODATA_RESPONSE_SIZE));
>>> +  CopyMem (MockResponseResults, &ValidNoDataResponse,
>> VALID_NODATA_RESPONSE_SIZE);
>>> +
>>> +  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults,
>> VALID_NODATA_RESPONSE_SIZE, EFI_SUCCESS);
>>> +  if (EFI_ERROR (Status)) {
>>> +    return UNIT_TEST_ERROR_TEST_FAILED;
>>> +  }
>>> +
>>> +  Status = IpmiBlobTransferDelete ("/smbios");
>>> +
>>> +  UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);
>>> +  FreePool (MockResponseResults);
>>> +  return UNIT_TEST_PASSED;
>>> +}
>>> +
>>> +UINT8  ValidBlobStatResponse[] = {
>>> +  0x00,                   // CompletionCode
>>> +  0xCF, 0xC2, 0x00,       // OpenBMC OEN
>>> +  0x1F, 0x4F,             // Crc
>>> +  0x01, 0x00,             // BlobState
>>> +  0x02, 0x03, 0x04, 0x05, // BlobSize
>>> +  0x04,                   // MetaDataLen
>>> +  0x06, 0x07, 0x08, 0x09, // MetaData
>>> +};
>>> +
>>> +#define VALID_BLOB_STAT_RESPONSE_SIZE  17 * sizeof(UINT8)
>>> +
>>> +/**
>>> +  @param[in]  Context    [Optional] An optional parameter that enables:
>>> +                         1) test-case reuse with varied parameters and
>>> +                         2) test-case re-entry for Target tests that need a
>>> +                         reboot.  This parameter is a VOID* and it is the
>>> +                         responsibility of the test author to ensure that the
>>> +                         contents are well understood by all test cases that may
>>> +                         consume it.
>>> +  @retval  UNIT_TEST_PASSED             The Unit test has completed and the
>> test
>>> +                                        case was successful.
>>> +  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.
>>> +**/
>>> +UNIT_TEST_STATUS
>>> +EFIAPI
>>> +BlobStatValidResponse (
>>> +  IN UNIT_TEST_CONTEXT  Context
>>> +  )
>>> +{
>>> +  EFI_STATUS  Status;
>>> +  UINT16      *BlobState;
>>> +  UINT32      *Size;
>>> +  UINT8       *MetadataLength;
>>> +  UINT8       *Metadata;
>>> +  UINT8       *ExpectedMetadata;
>>> +  CHAR8       *BlobId;
>>> +  VOID        *MockResponseResults = NULL;
>>> +
>>> +  BlobState        = AllocateZeroPool (sizeof (UINT16));
>>> +  Size             = AllocateZeroPool (sizeof (UINT32));
>>> +  BlobId           = "BlobId";
>>> +  MetadataLength   = AllocateZeroPool (sizeof (UINT8));
>>> +  Metadata         = AllocateZeroPool (4 * sizeof (UINT8));
>>> +  ExpectedMetadata = AllocateZeroPool (4 * sizeof (UINT8));
>>> +
>>> +  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof
>> (VALID_BLOB_STAT_RESPONSE_SIZE));
>>> +  CopyMem (MockResponseResults, &ValidBlobStatResponse,
>> VALID_BLOB_STAT_RESPONSE_SIZE);
>>> +
>>> +  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults,
>> VALID_BLOB_STAT_RESPONSE_SIZE, EFI_SUCCESS);
>>> +  if (EFI_ERROR (Status)) {
>>> +    return UNIT_TEST_ERROR_TEST_FAILED;
>>> +  }
>>> +
>>> +  Status = IpmiBlobTransferStat (BlobId, BlobState, Size, MetadataLength,
>> Metadata);
>>> +
>>> +  UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);
>>> +  UT_ASSERT_EQUAL (*BlobState, 1);
>>> +  UT_ASSERT_EQUAL (*Size, 0x05040302);
>>> +  UT_ASSERT_EQUAL (*MetadataLength, 4);
>>> +  UT_ASSERT_MEM_EQUAL (Metadata, ExpectedMetadata, 4);
>>> +  FreePool (MockResponseResults);
>>> +  FreePool (BlobState);
>>> +  FreePool (Size);
>>> +  FreePool (MetadataLength);
>>> +  FreePool (Metadata);
>>> +  return UNIT_TEST_PASSED;
>>> +}
>>> +
>>> +/**
>>> +  @param[in]  Context    [Optional] An optional parameter that enables:
>>> +                         1) test-case reuse with varied parameters and
>>> +                         2) test-case re-entry for Target tests that need a
>>> +                         reboot.  This parameter is a VOID* and it is the
>>> +                         responsibility of the test author to ensure that the
>>> +                         contents are well understood by all test cases that may
>>> +                         consume it.
>>> +  @retval  UNIT_TEST_PASSED             The Unit test has completed and the
>> test
>>> +                                        case was successful.
>>> +  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.
>>> +**/
>>> +UNIT_TEST_STATUS
>>> +EFIAPI
>>> +BlobStatInvalidBuffer (
>>> +  IN UNIT_TEST_CONTEXT  Context
>>> +  )
>>> +{
>>> +  UINT8       *Metadata;
>>> +  EFI_STATUS  Status;
>>> +  VOID        *MockResponseResults = NULL;
>>> +
>>> +  Metadata = NULL;
>>> +
>>> +  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof
>> (VALID_BLOB_STAT_RESPONSE_SIZE));
>>> +  CopyMem (MockResponseResults, &ValidBlobStatResponse,
>> VALID_BLOB_STAT_RESPONSE_SIZE);
>>> +
>>> +  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults,
>> VALID_BLOB_STAT_RESPONSE_SIZE, EFI_SUCCESS);
>>> +  if (EFI_ERROR (Status)) {
>>> +    return UNIT_TEST_ERROR_TEST_FAILED;
>>> +  }
>>> +
>>> +  UT_EXPECT_ASSERT_FAILURE (IpmiBlobTransferStat (NULL, 0, 0, 0,
>> Metadata), NULL);
>>> +
>>> +  FreePool (MockResponseResults);
>>> +  return UNIT_TEST_PASSED;
>>> +}
>>> +
>>> +/**
>>> +  @param[in]  Context    [Optional] An optional parameter that enables:
>>> +                         1) test-case reuse with varied parameters and
>>> +                         2) test-case re-entry for Target tests that need a
>>> +                         reboot.  This parameter is a VOID* and it is the
>>> +                         responsibility of the test author to ensure that the
>>> +                         contents are well understood by all test cases that may
>>> +                         consume it.
>>> +  @retval  UNIT_TEST_PASSED             The Unit test has completed and the
>> test
>>> +                                        case was successful.
>>> +  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.
>>> +**/
>>> +UNIT_TEST_STATUS
>>> +EFIAPI
>>> +SessionStatValidResponse (
>>> +  IN UNIT_TEST_CONTEXT  Context
>>> +  )
>>> +{
>>> +  EFI_STATUS  Status;
>>> +  UINT16      *BlobState;
>>> +  UINT32      *Size;
>>> +  UINT8       *MetadataLength;
>>> +  UINT8       *Metadata;
>>> +  UINT8       *ExpectedMetadata;
>>> +  VOID        *MockResponseResults = NULL;
>>> +
>>> +  BlobState        = AllocateZeroPool (sizeof (UINT16));
>>> +  Size             = AllocateZeroPool (sizeof (UINT32));
>>> +  MetadataLength   = AllocateZeroPool (sizeof (UINT8));
>>> +  Metadata         = AllocateZeroPool (4 * sizeof (UINT8));
>>> +  ExpectedMetadata = AllocateZeroPool (4 * sizeof (UINT8));
>>> +
>>> +  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof
>> (VALID_BLOB_STAT_RESPONSE_SIZE));
>>> +  CopyMem (MockResponseResults, &ValidBlobStatResponse,
>> VALID_BLOB_STAT_RESPONSE_SIZE);
>>> +
>>> +  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults,
>> VALID_BLOB_STAT_RESPONSE_SIZE, EFI_SUCCESS);
>>> +  if (EFI_ERROR (Status)) {
>>> +    return UNIT_TEST_ERROR_TEST_FAILED;
>>> +  }
>>> +
>>> +  Status = IpmiBlobTransferSessionStat (0, BlobState, Size, MetadataLength,
>> Metadata);
>>> +
>>> +  UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);
>>> +  UT_ASSERT_EQUAL (*BlobState, 1);
>>> +  UT_ASSERT_EQUAL (*Size, 0x05040302);
>>> +  UT_ASSERT_EQUAL (*MetadataLength, 4);
>>> +  UT_ASSERT_MEM_EQUAL (Metadata, ExpectedMetadata, 4);
>>> +  FreePool (MockResponseResults);
>>> +  FreePool (BlobState);
>>> +  FreePool (Size);
>>> +  FreePool (MetadataLength);
>>> +  FreePool (Metadata);
>>> +  return UNIT_TEST_PASSED;
>>> +}
>>> +
>>> +/**
>>> +  @param[in]  Context    [Optional] An optional parameter that enables:
>>> +                         1) test-case reuse with varied parameters and
>>> +                         2) test-case re-entry for Target tests that need a
>>> +                         reboot.  This parameter is a VOID* and it is the
>>> +                         responsibility of the test author to ensure that the
>>> +                         contents are well understood by all test cases that may
>>> +                         consume it.
>>> +  @retval  UNIT_TEST_PASSED             The Unit test has completed and the
>> test
>>> +                                        case was successful.
>>> +  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.
>>> +**/
>>> +UNIT_TEST_STATUS
>>> +EFIAPI
>>> +SessionStatInvalidBuffer (
>>> +  IN UNIT_TEST_CONTEXT  Context
>>> +  )
>>> +{
>>> +  UINT8       *Metadata;
>>> +  EFI_STATUS  Status;
>>> +  VOID        *MockResponseResults = NULL;
>>> +
>>> +  Metadata = NULL;
>>> +
>>> +  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof
>> (VALID_BLOB_STAT_RESPONSE_SIZE));
>>> +  CopyMem (MockResponseResults, &ValidBlobStatResponse,
>> VALID_BLOB_STAT_RESPONSE_SIZE);
>>> +
>>> +  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults,
>> VALID_BLOB_STAT_RESPONSE_SIZE, EFI_SUCCESS);
>>> +  if (EFI_ERROR (Status)) {
>>> +    return UNIT_TEST_ERROR_TEST_FAILED;
>>> +  }
>>> +
>>> +  UT_EXPECT_ASSERT_FAILURE (IpmiBlobTransferSessionStat (0, 0, 0, 0,
>> Metadata), NULL);
>>> +
>>> +  FreePool (MockResponseResults);
>>> +  return UNIT_TEST_PASSED;
>>> +}
>>> +
>>> +/**
>>> +  @param[in]  Context    [Optional] An optional parameter that enables:
>>> +                         1) test-case reuse with varied parameters and
>>> +                         2) test-case re-entry for Target tests that need a
>>> +                         reboot.  This parameter is a VOID* and it is the
>>> +                         responsibility of the test author to ensure that the
>>> +                         contents are well understood by all test cases that may
>>> +                         consume it.
>>> +  @retval  UNIT_TEST_PASSED             The Unit test has completed and the
>> test
>>> +                                        case was successful.
>>> +  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.
>>> +**/
>>> +UNIT_TEST_STATUS
>>> +EFIAPI
>>> +WriteMetaValidResponse (
>>> +  IN UNIT_TEST_CONTEXT  Context
>>> +  )
>>> +{
>>> +  EFI_STATUS  Status;
>>> +  VOID        *MockResponseResults = NULL;
>>> +
>>> +  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof
>> (VALID_NODATA_RESPONSE_SIZE));
>>> +  CopyMem (MockResponseResults, &ValidNoDataResponse,
>> VALID_NODATA_RESPONSE_SIZE);
>>> +
>>> +  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults,
>> VALID_NODATA_RESPONSE_SIZE, EFI_SUCCESS);
>>> +  if (EFI_ERROR (Status)) {
>>> +    return UNIT_TEST_ERROR_TEST_FAILED;
>>> +  }
>>> +
>>> +  Status = IpmiBlobTransferWriteMeta (0, 0, NULL, 0);
>>> +
>>> +  UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);
>>> +  FreePool (MockResponseResults);
>>> +  return UNIT_TEST_PASSED;
>>> +}
>>> +
>>> +/**
>>> +  Initialize the unit test framework, suite, and unit tests for the
>>> +  sample unit tests and run the unit tests.
>>> +  @retval  EFI_SUCCESS           All test cases were dispatched.
>>> +  @retval  EFI_OUT_OF_RESOURCES  There are not enough resources
>> available to
>>> +                                 initialize the unit tests.
>>> +**/
>>> +EFI_STATUS
>>> +EFIAPI
>>> +SetupAndRunUnitTests (
>>> +  VOID
>>> +  )
>>> +{
>>> +  EFI_STATUS                  Status;
>>> +  UNIT_TEST_FRAMEWORK_HANDLE  Framework;
>>> +  UNIT_TEST_SUITE_HANDLE      IpmiBlobTransfer;
>>> +
>>> +  Framework = NULL;
>>> +  DEBUG ((DEBUG_INFO, "%a: v%a\n", UNIT_TEST_NAME,
>> UNIT_TEST_VERSION));
>>> +
>>> +  Status = InitUnitTestFramework (&Framework, UNIT_TEST_NAME,
>> gEfiCallerBaseName, UNIT_TEST_VERSION);
>>> +  if (EFI_ERROR (Status)) {
>>> +    DEBUG ((DEBUG_ERROR, "Failed to setup Test Framework. Exiting with
>> status = %r\n", Status));
>>> +    ASSERT (FALSE);
>>> +    return Status;
>>> +  }
>>> +
>>> +  //
>>> +  // Populate the Unit Test Suite.
>>> +  //
>>> +  Status = CreateUnitTestSuite (&IpmiBlobTransfer, Framework, "IPMI Blob
>> Transfer Tests", "UnitTest.IpmiBlobTransferCB", NULL, NULL);
>>> +  if (EFI_ERROR (Status)) {
>>> +    DEBUG ((DEBUG_ERROR, "Failed in CreateUnitTestSuite for IPMI Blob
>> Transfer Tests\n"));
>>> +    Status = EFI_OUT_OF_RESOURCES;
>>> +    return Status;
>>> +  }
>>> +
>>> +  // CalculateCrc16Ccitt
>>> +  Status = AddTestCase (IpmiBlobTransfer, "Test CRC Calculation",
>> "GoodCrc", GoodCrc, NULL, NULL, NULL);
>>> +  Status = AddTestCase (IpmiBlobTransfer, "Test Bad CRC Calculation",
>> "BadCrc", BadCrc, NULL, NULL, NULL);
>>> +  // IpmiBlobTransferSendIpmi
>>> +  Status = AddTestCase (IpmiBlobTransfer, "Send IPMI returns bad
>> completion", "SendIpmiBadCompletion", SendIpmiBadCompletion, NULL,
>> NULL, NULL);
>>> +  Status = AddTestCase (IpmiBlobTransfer, "Send IPMI returns successfully
>> with no data", "SendIpmiNoDataResponse", SendIpmiNoDataResponse,
>> NULL, NULL, NULL);
>>> +  Status = AddTestCase (IpmiBlobTransfer, "Send IPMI returns successfully
>> with bad OEN", "SendIpmiBadOenResponse", SendIpmiBadOenResponse,
>> NULL, NULL, NULL);
>>> +  Status = AddTestCase (IpmiBlobTransfer, "Send IPMI returns successfully
>> with bad CRC", "SendIpmiBadCrcResponse", SendIpmiBadCrcResponse, NULL,
>> NULL, NULL);
>>> +  Status = AddTestCase (IpmiBlobTransfer, "Send IPMI returns with valid
>> GetCount data", "SendIpmiValidCountResponse",
>> SendIpmiValidCountResponse, NULL, NULL, NULL);
>>> +  // IpmiBlobTransferGetCount
>>> +  Status = AddTestCase (IpmiBlobTransfer, "GetCount call with valid data",
>> "GetCountValidCountResponse", GetCountValidCountResponse, NULL, NULL,
>> NULL);
>>> +  // IpmiBlobTransferEnumerate
>>> +  Status = AddTestCase (IpmiBlobTransfer, "Enumerate call with valid data",
>> "EnumerateValidResponse", EnumerateValidResponse, NULL, NULL, NULL);
>>> +  Status = AddTestCase (IpmiBlobTransfer, "Enumerate call with invalid
>> output buffer", "EnumerateInvalidBuffer", EnumerateInvalidBuffer, NULL,
>> NULL, NULL);
>>> +  // IpmiBlobTransferOpen
>>> +  Status = AddTestCase (IpmiBlobTransfer, "Open call with valid data",
>> "OpenValidResponse", OpenValidResponse, NULL, NULL, NULL);
>>> +  // IpmiBlobTransferRead
>>> +  Status = AddTestCase (IpmiBlobTransfer, "Read call with valid data",
>> "ReadValidResponse", ReadValidResponse, NULL, NULL, NULL);
>>> +  Status = AddTestCase (IpmiBlobTransfer, "Read call with invalid buffer",
>> "ReadInvalidBuffer", ReadInvalidBuffer, NULL, NULL, NULL);
>>> +  // IpmiBlobTransferWrite
>>> +  Status = AddTestCase (IpmiBlobTransfer, "Write call with valid data",
>> "WriteValidResponse", WriteValidResponse, NULL, NULL, NULL);
>>> +  // IpmiBlobTransferCommit
>>> +  Status = AddTestCase (IpmiBlobTransfer, "Commit call with valid data",
>> "CommitValidResponse", CommitValidResponse, NULL, NULL, NULL);
>>> +  // IpmiBlobTransferClose
>>> +  Status = AddTestCase (IpmiBlobTransfer, "Close call with valid data",
>> "CloseValidResponse", CloseValidResponse, NULL, NULL, NULL);
>>> +  // IpmiBlobTransferDelete
>>> +  Status = AddTestCase (IpmiBlobTransfer, "Delete call with valid data",
>> "DeleteValidResponse", DeleteValidResponse, NULL, NULL, NULL);
>>> +  // IpmiBlobTransferStat
>>> +  Status = AddTestCase (IpmiBlobTransfer, "Blob Stat call with valid data",
>> "BlobStatValidResponse", BlobStatValidResponse, NULL, NULL, NULL);
>>> +  Status = AddTestCase (IpmiBlobTransfer, "Blob Stat call with invalid buffer",
>> "BlobStatInvalidBuffer", BlobStatInvalidBuffer, NULL, NULL, NULL);
>>> +  // IpmiBlobTransferSessionStat
>>> +  Status = AddTestCase (IpmiBlobTransfer, "Session Stat call with valid data",
>> "SessionStatValidResponse", SessionStatValidResponse, NULL, NULL, NULL);
>>> +  Status = AddTestCase (IpmiBlobTransfer, "Session Stat call with invalid
>> buffer", "SessionStatInvalidBuffer", SessionStatInvalidBuffer, NULL, NULL,
>> NULL);
>>> +  // IpmiBlobTransferWriteMeta
>>> +  Status = AddTestCase (IpmiBlobTransfer, "WriteMeta call with valid data",
>> "WriteMetaValidResponse", WriteMetaValidResponse, NULL, NULL, NULL);
>>> +
>>> +  // Execute the tests.
>>> +  Status = RunAllTestSuites (Framework);
>>> +  return Status;
>>> +}
>>> +
>>> +/**
>>> +  Standard UEFI entry point for target based
>>> +  unit test execution from UEFI Shell.
>>> +**/
>>> +EFI_STATUS
>>> +EFIAPI
>>> +BaseLibUnitTestAppEntry (
>>> +  IN EFI_HANDLE        ImageHandle,
>>> +  IN EFI_SYSTEM_TABLE  *SystemTable
>>> +  )
>>> +{
>>> +  return SetupAndRunUnitTests ();
>>> +}
>>> +
>>> +/**
>>> +  Standard POSIX C entry point for host based unit test execution.
>>> +**/
>>> +int
>>> +main (
>>> +  int   argc,
>>> +  char  *argv[]
>>> +  )
>>> +{
>>> +  return SetupAndRunUnitTests ();
>>> +}
>>> diff --git
>> a/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/Readme.md
>> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/Readme.md
>>> new file mode 100644
>>> index 0000000000..9eed5d3728
>>> --- /dev/null
>>> +++
>> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/Readme.md
>>> @@ -0,0 +1,24 @@
>>> +# IPMI Blob Transfer Interface Driver
>>> +
>>> +This DXE module is a UEFI implementation of the Phorphor Blob Transfer
>> Interface defined in OpenBMC
>>> +https://github.com/openbmc/phosphor-ipmi-blobs
>>> +
>>> +## OpenBMC implements this interface as a protocol, allowing UEFI and
>> BMC to transfer blobs over IPMI.
>>> +
>>> +### Usage:
>>> +Any DXE module that wishes to use this protocol should do the following:
>>> +1) The module should have a dependency on
>> gEdkiiIpmiBlobTransferProtocolGuid in its inf "Depex" section
>>> +2) The module should list gEdkiiIpmiBlobTransferProtocolGuid in its inf
>> "Protocol" section
>>> +3) The module's entry point should do a LocateProtocol on
>> gEdkiiIpmiBlobTransferProtocolGuid
>>> +
>>> +### A sample flow of protocol usage is as follows:
>>> +1) A call to IpmiBlobTransferOpen ()
>>> +2) Iterative calls to IpmiBlobTransferWrite
>>> +3) A call to IpmiBlobTransferClose ()
>>> +
>>> +### Unit Tests:
>>> +IpmiBlobTransferDxe/UnitTest/ contains host based unit tests of this
>> implementation.
>>> +Any changes to IpmiBlobTransferDxe should include proof of successful unit
>> tests.
>>> +
>>> +### Debugging
>>> +To assist in debugging any issues, change BLOB_TRANSFER_DEBUG to
>> desired debug level, such as DEBUG_ERROR or DEBUG_INFO.


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#118995): https://edk2.groups.io/g/devel/message/118995
Mute This Topic: https://groups.io/mt/106115743/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



  reply	other threads:[~2024-05-17  8:34 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-05-15 15:06 [edk2-devel] [edk2-platforms][PATCH v2] ManageabilityPkg: add support for the phosphor ipmi blob transfer protocol Nickle Wang via groups.io
2024-05-17  7:49 ` Nhi Pham via groups.io
2024-05-17  8:16   ` Chang, Abner via groups.io
2024-05-17  8:34     ` Nhi Pham via groups.io [this message]
2024-07-10 15:12   ` Nickle Wang via groups.io
2024-07-11  1:58     ` Nhi Pham via groups.io

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=fbeca374-7027-4a44-9192-5424abf51844@os.amperecomputing.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox