public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Tinh Nguyen" <tinhnguyen@os.amperecomputing.com>
To: "Chang, Abner" <Abner.Chang@amd.com>,
	Nickle Wang <nicklew@nvidia.com>,
	"devel@edk2.groups.io" <devel@edk2.groups.io>
Cc: Isaac Oram <isaac.w.oram@intel.com>,
	"Attar, AbdulLateef (Abdul Lateef)" <AbdulLateef.Attar@amd.com>
Subject: Re: [edk2-platforms][PATCH] ManageabilityPkg: add support for the phosphor ipmi blob transfer protocol
Date: Mon, 17 Apr 2023 10:08:26 +0700	[thread overview]
Message-ID: <594581df-5fbf-a5e6-0521-962941f2ed90@amperemail.onmicrosoft.com> (raw)
In-Reply-To: <CH2PR12MB3957FD5E2F8716E00F949689EA9C9@CH2PR12MB3957.namprd12.prod.outlook.com>

Hi Abner,

On 17/04/2023 10:01, Chang, Abner wrote:
> [EXTERNAL EMAIL NOTICE: This email originated from an external sender. Please be mindful of safe email handling and proprietary information protection practices.]
>
>
> [AMD Official Use Only - General]
>
>
>
>> -----Original Message-----
>> From: Tinh Nguyen <tinhnguyen@amperemail.onmicrosoft.com>
>> Sent: Monday, April 17, 2023 10:25 AM
>> To: Chang, Abner <Abner.Chang@amd.com>; Nickle Wang
>> <nicklew@nvidia.com>; devel@edk2.groups.io
>> Cc: Isaac Oram <isaac.w.oram@intel.com>; Attar, AbdulLateef (Abdul Lateef)
>> <AbdulLateef.Attar@amd.com>
>> Subject: Re: [edk2-platforms][PATCH] 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.
>>
>>
>> On 4/16/2023 5:50 PM, Chang, Abner wrote:
>>> [EXTERNAL EMAIL NOTICE: This email originated from an external sender.
>> Please be mindful of safe email handling and proprietary information
>> protection practices.]
>>>
>>> [AMD Official Use Only - General]
>>>
>>> Tink and Nickle,
>>> Two feedbacks in below,
>>>
>>>> -----Original Message-----
>>>> From: Tinh Nguyen<tinhnguyen@amperemail.onmicrosoft.com>
>>>> Sent: Sunday, April 16, 2023 6:29 PM
>>>> To: Nickle Wang<nicklew@nvidia.com>;devel@edk2.groups.io
>>>> Cc: Chang, Abner<Abner.Chang@amd.com>; Isaac Oram
>>>> <isaac.w.oram@intel.com>; Attar, AbdulLateef (Abdul Lateef)
>>>> <AbdulLateef.Attar@amd.com>
>>>> Subject: Re: [edk2-platforms][PATCH] 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 find my inline comments below
>>>>
>>>> On 4/12/2023 10:17 AM, Nickle Wang wrote:
>>>>> [EXTERNAL EMAIL NOTICE: This email originated from an external sender.
>>>> Please be mindful of safe email handling and proprietary information
>>>> protection practices.]
>>>>> 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>
>>>>> Cc: Abner Chang<abner.chang@amd.com>
>>>>> Cc: Isaac Oram<isaac.w.oram@intel.com>
>>>>> Cc: Abdul Lateef Attar<AbdulLateef.Attar@amd.com>
>>>>> Cc: Nickle Wang<nicklew@nvidia.com>
>>>>> Cc: Tinh Nguyen<tinhnguyen@amperemail.onmicrosoft.com>
>>>>> ---
>>>>>     .../ManageabilityPkg/ManageabilityPkg.dec     |    6 +
>>>>>     .../Include/Dsc/Manageability.dsc             |    4 +-
>>>>>     .../IpmiBlobTransferDxe.inf                   |   39 +
>>>>>     .../IpmiBlobTransferTestUnitTestsHost.inf     |   40 +
>>>>>     .../Include/Protocol/IpmiBlobTransfer.h       |  136 ++
>>>>>     .../InternalIpmiBlobTransfer.h                |  363 ++++++
>>>>>     .../IpmiBlobTransferDxe/IpmiBlobTransferDxe.c |  799 ++++++++++++
>>>>>     .../UnitTest/IpmiBlobTransferTestUnitTests.c  | 1113
>>>> +++++++++++++++++
>>>>>     .../Universal/IpmiBlobTransferDxe/Readme.md   |   24 +
>>>>>     9 files changed, 2523 insertions(+), 1 deletion(-)
>>>>>     create mode 100644
>> Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransf
>>>> erDxe.inf
>>>>>     create mode 100644
>> Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBl
>>>> obTransferTestUnitTestsHost.inf
>>>>>     create mode 100644
>>>> Features/ManageabilityPkg/Include/Protocol/IpmiBlobTransfer.h
>>>>>     create mode 100644
>> Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiBlo
>>>> bTransfer.h
>>>>>     create mode 100644
>> Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransf
>>>> erDxe.c
>>>>>     create mode 100644
>> Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBl
>>>> obTransferTestUnitTests.c
>>>>>     create mode 100644
>>>> Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/Readme.md
>>>>> diff --git a/Features/ManageabilityPkg/ManageabilityPkg.dec
>>>> b/Features/ManageabilityPkg/ManageabilityPkg.dec
>>>>> index 9a930d3e4b..e2d6cccc50 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) 2023, NVIDIA CORPORATION & AFFILIATES. All rights
>>>> reserved.
>>>>>     # SPDX-License-Identifier: BSD-2-Clause-Patent
>>>>>     #
>>>>>     ##
>>>>> @@ -48,3 +49,8 @@
>>>>>       gManageabilityProtocolMctpGuid    = { 0x76FED8F1, 0x0BE5, 0x4269,
>>>> { 0xA3, 0x1A, 0x38, 0x0F, 0x54, 0xF1, 0xA1, 0x8A } }
>>>>>       # Manageability Protocol PLDM
>>>>>       gManageabilityProtocolPldmGuid    = { 0x3958090D, 0x69DD, 0x4868,
>>>> { 0x9C, 0x41, 0xC9, 0xAC, 0x31, 0xB5, 0x25, 0xC5 } }
>>>>> +
>>>>> +[Protocols]
>>>>> +
>>>>> +  ## Include/Protocol/IpmiBlobTransfer.h
>>>>> +  gEdkiiIpmiBlobTransferProtocolGuid = { 0x05837c75, 0x1d65, 0x468b,
>>>> { 0xb1, 0xc2, 0x81, 0xaf, 0x9a, 0x31, 0x5b, 0x2c } }
>>>>> diff --git a/Features/ManageabilityPkg/Include/Dsc/Manageability.dsc
>>>> b/Features/ManageabilityPkg/Include/Dsc/Manageability.dsc
>>>>> index 0d868fdf4a..111d6b91dc 100644
>>>>> --- a/Features/ManageabilityPkg/Include/Dsc/Manageability.dsc
>>>>> +++ b/Features/ManageabilityPkg/Include/Dsc/Manageability.dsc
>>>>> @@ -2,11 +2,13 @@
>>>>>     # Common libraries for Manageabilty Package
>>>>>     #
>>>>>     # Copyright (C) 2023 Advanced Micro Devices, Inc. All rights
>> reserved.<BR>
>>>>> +# Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights
>>>> reserved.
>>>>>     # SPDX-License-Identifier: BSD-2-Clause-Patent
>>>>>     #
>>>>>     ##
>>>>>     [LibraryClasses]
>>>>>
>> ManageabilityTransportHelperLib|ManageabilityPkg/Library/BaseManageabi
>>>> lityTransportHelperLib/BaseManageabilityTransportHelper.inf
>>>>> +
>> IpmiLib|MdeModulePkg/Library/DxeIpmiLibIpmiProtocol/DxeIpmiLibIpmiPr
>>>> otocol.inf
>>>>>     [LibraryClasses.ARM, LibraryClasses.AARCH64]
>>>>>       #
>>>>> @@ -22,4 +24,4 @@
>>>>>     [Components.X64]
>>>>>       ManageabilityPkg/Universal/IpmiProtocol/Dxe/IpmiProtocolDxe.inf
>>>>>       ManageabilityPkg/Universal/IpmiProtocol/Smm/IpmiProtocolSmm.inf
>>>>> -
>>>>> +
>> ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.inf
>>>>> diff --git
>> a/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTran
>>>> sferDxe.inf
>>>>
>> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTran
>>>> sferDxe.inf
>>>>> new file mode 100644
>>>>> index 0000000000..28e9d293c1
>>>>> --- /dev/null
>>>>> +++
>> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTran
>>>> sferDxe.inf
>>>>> @@ -0,0 +1,39 @@
>>>>> +## @file
>>>>> +# IPMI Blob Transfer Protocol DXE Driver.
>>>>> +#
>>>>> +#  Copyright (c) 2022-2023, 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/Ipmi
>>>> BlobTransferTestUnitTestsHost.inf
>>>>
>> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/Ipm
>>>> iBlobTransferTestUnitTestsHost.inf
>>>>> new file mode 100644
>>>>> index 0000000000..1f071bbadc
>>>>> --- /dev/null
>>>>> +++
>> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/Ipm
>>>> iBlobTransferTestUnitTestsHost.inf
>>>>> @@ -0,0 +1,40 @@
>>>>> +## @file
>>>>> +# Unit tests of the Ipmi blob transfer driver that are run from a host
>>>> environment.
>>>>> +#
>>>>> +# Copyright (c) 2020-2023, 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..8ea71d8816
>>>>> --- /dev/null
>>>>> +++ b/Features/ManageabilityPkg/Include/Protocol/IpmiBlobTransfer.h
>>>>> @@ -0,0 +1,136 @@
>>>>> +/** @file
>>>>> +
>>>>> +  IPMI Blob Transfer driver
>>>>> +
>>>>> +  Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All
>> rights
>>>> reserved.
>>>>> +
>>>>> +  SPDX-License-Identifier: BSD-2-Clause-Patent
>>>>> +
>>>>> +**/
>>>>> +#include <Library/IpmiLib.h>
>>>>> +#include <Library/UefiBootServicesTableLib.h>
>>>>> +#include <IndustryStandard/Ipmi.h>
>>>>> +
>>>>> +#define IPMI_NETFN_OEM                     0x2E
>>>>> +#define IPMI_OEM_BLOB_TRANSFER_CMD         0x80
>>>>> +#define IPMI_OEM_BLOB_MAX_DATA_PER_PACKET  64
>>>> It is better to avoid fixing the packet size here.
>>>>
>>>> - For ssif, get it from "get capabilities" command. If BMC supports only
>>>> single-part read/write, this size exceeds BMC capability
>>>>
>>>> - For kcs, I don't see the limitation
>>>>
>>>> I think limiting the size here is unsuitable, applications that use this
>>>> protocol should check the size themselves
>>> IPMI blob uses IpmiLib to submit the command and IPMI protocol is the
>> one that talks to transport interface. That would be IPMI protocol's
>> responsibility to know the exact maximum size of each transfer payload,
>> according to the transport interface.
>>>   From the ManageabilityPkg design, SSIF manageability transport library can
>> returns MTU and the capability of single/multi part read/write to caller (IPMI
>> protocol for example). IPMI protocol should determine having a single part
>> transfer or splitting the packet into multi transfers.
>>> I can help on SSIF manageability transport library as well if you have SSIF
>> sample code.
>>    yes I’m preparing the ssif driver, I’m sorry for being late.
> That's great, Tinh. I believe there are some missing considerations in the ManageabilityPkg and we need more use cases to find it out and improve it. I will definitely help on this.
>
>>>>> +
>>>>> +#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
>>>>> +
>>>>> +//
>>>>> +//  Blob Transfer Function Prototypes
>>>>> +//
>>>>> +typedef
>>>>> +EFI_STATUS
>>>>> +(EFIAPI *IPMI_BLOB_TRANSFER_PROTOCOL_GET_COUNT)(
>>>>> +  OUT UINT32 *Count
>>>>> +  );
>>>>> +
>>>>> +typedef
>>>>> +EFI_STATUS
>>>>> +(EFIAPI *IPMI_BLOB_TRANSFER_PROTOCOL_ENUMERATE)(
>>>>> +  IN  UINT32      BlobIndex,
>>>>> +  OUT CHAR8 *BlobId
>>>>> +  );
>>>>> +
>>>>> +typedef
>>>>> +EFI_STATUS
>>>>> +(EFIAPI *IPMI_BLOB_TRANSFER_PROTOCOL_OPEN)(
>>>>> +  IN  CHAR8 *BlobId,
>>>>> +  IN  UINT16      Flags,
>>>>> +  OUT UINT16 *SessionId
>>>>> +  );
>>>>> +
>>>>> +typedef
>>>>> +EFI_STATUS
>>>>> +(EFIAPI *IPMI_BLOB_TRANSFER_PROTOCOL_READ)(
>>>>> +  IN  UINT16      SessionId,
>>>>> +  IN  UINT32      Offset,
>>>>> +  IN  UINT32      RequestedSize,
>>>>> +  OUT UINT8 *Data
>>>>> +  );
>>>>> +
>>>>> +typedef
>>>>> +EFI_STATUS
>>>>> +(EFIAPI *IPMI_BLOB_TRANSFER_PROTOCOL_WRITE)(
>>>>> +  IN  UINT16      SessionId,
>>>>> +  IN  UINT32      Offset,
>>>>> +  IN  UINT8 *Data,
>>>>> +  IN  UINT32      WriteLength
>>>>> +  );
>>>>> +
>>>>> +typedef
>>>>> +EFI_STATUS
>>>>> +(EFIAPI *IPMI_BLOB_TRANSFER_PROTOCOL_COMMIT)(
>>>>> +  IN  UINT16      SessionId,
>>>>> +  IN  UINT8       CommitDataLength,
>>>>> +  IN  UINT8 *CommitData
>>>>> +  );
>>>>> +
>>>>> +typedef
>>>>> +EFI_STATUS
>>>>> +(EFIAPI *IPMI_BLOB_TRANSFER_PROTOCOL_CLOSE)(
>>>>> +  IN  UINT16      SessionId
>>>>> +  );
>>>>> +
>>>>> +typedef
>>>>> +EFI_STATUS
>>>>> +(EFIAPI *IPMI_BLOB_TRANSFER_PROTOCOL_DELETE)(
>>>>> +  IN  CHAR8 *BlobId
>>>>> +  );
>>>>> +
>>>>> +typedef
>>>>> +EFI_STATUS
>>>>> +(EFIAPI *IPMI_BLOB_TRANSFER_PROTOCOL_STAT)(
>>>>> +  IN  CHAR8 *BlobId,
>>>>> +  OUT UINT16 *BlobState,
>>>>> +  OUT UINT32 *Size,
>>>>> +  OUT UINT8 *MetadataLength,
>>>>> +  OUT UINT8 *Metadata
>>>>> +  );
>>>>> +
>>>>> +typedef
>>>>> +EFI_STATUS
>>>>> +(EFIAPI *IPMI_BLOB_TRANSFER_PROTOCOL_SESSION_STAT)(
>>>>> +  IN  UINT16      SessionId,
>>>>> +  OUT UINT16 *BlobState,
>>>>> +  OUT UINT32 *Size,
>>>>> +  OUT UINT8 *MetadataLength,
>>>>> +  OUT UINT8 *Metadata
>>>>> +  );
>>>>> +
>>>>> +typedef
>>>>> +EFI_STATUS
>>>>> +(EFIAPI *IPMI_BLOB_TRANSFER_PROTOCOL_WRITE_META)(
>>>>> +  IN  UINT16      SessionId,
>>>>> +  IN  UINT32      Offset,
>>>>> +  IN  UINT8 *Data,
>>>>> +  IN  UINT32      WriteLength
>>>>> +  );
>>>>> +
>>>>> +//
>>>>> +// Structure of IPMI_BLOB_TRANSFER_PROTOCOL
>>>>> +//
>>>>> +struct _IPMI_BLOB_TRANSFER_PROTOCOL {
>>>>> +  IPMI_BLOB_TRANSFER_PROTOCOL_GET_COUNT       BlobGetCount;
>>>>> +  IPMI_BLOB_TRANSFER_PROTOCOL_ENUMERATE       BlobEnumerate;
>>>>> +  IPMI_BLOB_TRANSFER_PROTOCOL_OPEN            BlobOpen;
>>>>> +  IPMI_BLOB_TRANSFER_PROTOCOL_READ            BlobRead;
>>>>> +  IPMI_BLOB_TRANSFER_PROTOCOL_WRITE           BlobWrite;
>>>>> +  IPMI_BLOB_TRANSFER_PROTOCOL_COMMIT          BlobCommit;
>>>>> +  IPMI_BLOB_TRANSFER_PROTOCOL_CLOSE           BlobClose;
>>>>> +  IPMI_BLOB_TRANSFER_PROTOCOL_DELETE          BlobDelete;
>>>>> +  IPMI_BLOB_TRANSFER_PROTOCOL_STAT            BlobStat;
>>>>> +  IPMI_BLOB_TRANSFER_PROTOCOL_SESSION_STAT    BlobSessionStat;
>>>>> +  IPMI_BLOB_TRANSFER_PROTOCOL_WRITE_META      BlobWriteMeta;
>>>>> +};
>>>>> +
>>>>> +typedef struct _IPMI_BLOB_TRANSFER_PROTOCOL
>>>> IPMI_BLOB_TRANSFER_PROTOCOL;
>>>>> +
>>>>> +extern EFI_GUID  gEdkiiIpmiBlobTransferProtocolGuid;
>>>>> diff --git
>> a/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiB
>>>> lobTransfer.h
>>>>
>> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiB
>>>> lobTransfer.h
>>>>> new file mode 100644
>>>>> index 0000000000..14f0dc02bc
>>>>> --- /dev/null
>>>>> +++
>> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiB
>>>> lobTransfer.h
>>>>> @@ -0,0 +1,363 @@
>>>>> +/** @file
>>>>> +
>>>>> +  Headers for IPMI Blob Transfer driver
>>>>> +
>>>>> +  Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All
>> rights
>>>> reserved.
>>>>> +
>>>>> +  SPDX-License-Identifier: BSD-2-Clause-Patent
>>>>> +
>>>>> +**/
>>>>> +
>>>>> +#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
>>>>> +
>>>>> +// 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[IPMI_OEM_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[IPMI_OEM_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[IPMI_OEM_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[IPMI_OEM_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[IPMI_OEM_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[IPMI_OEM_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[IPMI_OEM_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[IPMI_OEM_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[IPMI_OEM_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[IPMI_OEM_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
>>>>> +CalculateCrc16 (
>>>>> +  IN UINT8  *Data,
>>>>> +  IN UINTN  DataSize
>>>>> +  );
>>>>> +
>>>>> +EFI_STATUS
>>>>> +IpmiBlobTransferSendIpmi (
>>>>> +  IN  UINT8   SubCommand,
>>>>> +  IN  UINT8   *SendData,
>>>>> +  IN  UINT32  SendDataSize,
>>>>> +  OUT UINT8   *ResponseData,
>>>>> +  OUT UINT32  *ResponseDataSize
>>>>> +  );
>>>>> +
>>>>> +/**
>>>>> +  @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
>>>>> +  );
>>>>> +
>>>>> +/**
>>>>> +  @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
>>>>> +  );
>>>>> +
>>>>> +/**
>>>>> +  @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
>>>>> +  );
>>>>> +
>>>>> +/**
>>>>> +  @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
>>>>> +  );
>>>>> +
>>>>> +/**
>>>>> +  @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
>>>>> +
>>>>> +  @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
>>>>> +  );
>>>>> +
>>>>> +/**
>>>>> +  @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
>>>>> +  );
>>>>> +
>>>>> +/**
>>>>> +  @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
>>>>> +  );
>>>>> +
>>>>> +/**
>>>>> +  @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
>>>>> +  );
>>>>> +
>>>>> +/**
>>>>> +  @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
>>>>> +  );
>>>>> +
>>>>> +/**
>>>>> +  @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
>>>>> +  );
>>>>> +
>>>>> +/**
>>>>> +  @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
>>>>> +
>>>>> +  @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/IpmiBlobTran
>>>> sferDxe.c
>>>>
>> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTran
>>>> sferDxe.c
>>>>> new file mode 100644
>>>>> index 0000000000..9e663289d5
>>>>> --- /dev/null
>>>>> +++
>> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTran
>>>> sferDxe.c
>>>>> @@ -0,0 +1,799 @@
>>>>> +/** @file
>>>>> +
>>>>> +  IPMI Blob Transfer driver
>>>>> +
>>>>> +  Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All
>> rights
>>>> reserved.
>>>>> +
>>>>> +  SPDX-License-Identifier: BSD-2-Clause-Patent
>>>>> +
>>>>> +**/
>>>>> +#include <Protocol/IpmiBlobTransfer.h>
>>>>> +
>>>>> +#include "InternalIpmiBlobTransfer.h"
>>>>> +
>>>>> +#define BLOB_TRANSFER_DEBUG  0
>>>>> +
>>>>> +STATIC CONST IPMI_BLOB_TRANSFER_PROTOCOL  mIpmiBlobTransfer
>> = {
>>>>> +
>> (IPMI_BLOB_TRANSFER_PROTOCOL_GET_COUNT)*IpmiBlobTransferGetCou
>>>> nt,
>>>>> +
>> (IPMI_BLOB_TRANSFER_PROTOCOL_ENUMERATE)*IpmiBlobTransferEnume
>>>> rate,
>>>>> +  (IPMI_BLOB_TRANSFER_PROTOCOL_OPEN)*IpmiBlobTransferOpen,
>>>>> +  (IPMI_BLOB_TRANSFER_PROTOCOL_READ)*IpmiBlobTransferRead,
>>>>> +  (IPMI_BLOB_TRANSFER_PROTOCOL_WRITE)*IpmiBlobTransferWrite,
>>>>> +
>>>> (IPMI_BLOB_TRANSFER_PROTOCOL_COMMIT)*IpmiBlobTransferCommit,
>>>>> +  (IPMI_BLOB_TRANSFER_PROTOCOL_CLOSE)*IpmiBlobTransferClose,
>>>>> +
>> (IPMI_BLOB_TRANSFER_PROTOCOL_DELETE)*IpmiBlobTransferDelete,
>>>>> +  (IPMI_BLOB_TRANSFER_PROTOCOL_STAT)*IpmiBlobTransferStat,
>>>>> +
>> (IPMI_BLOB_TRANSFER_PROTOCOL_SESSION_STAT)*IpmiBlobTransferSessi
>>>> onStat,
>>>>> +
>> (IPMI_BLOB_TRANSFER_PROTOCOL_WRITE_META)*IpmiBlobTransferWrite
>>>> Meta
>>>>> +};
>>>>> +
>>>>> +const UINT8  OpenBmcOen[] = { 0xCF, 0xC2, 0x00 };          // OpenBMC
>> OEN
>>>> code in little endian format
>>>>
>>>> I don’t know what “Oen” means. Should it be “Oem” or “IANA” number?
>>> This is the OEM number defined by openbmc phosphor blob transfer
>> interface for openbmc.
>>> https://github.com/openbmc/phosphor-ipmi-blobs#phosphor-blob-
>> transfer-interface
>> so it is a short form of "OEM number", that is my mistake for not
>> reading the document carefully, thank you
>>>> And this number can be configured, other OEMs will have their own
>> number.
>>> Openbmc is already the OEM that uses this OEN number (49871). I consider
>> this is a industry standard for openbmc IPMI BLOB transfer and it is
>> unnecessary to be override by others, right? Any use case you can think of to
>> make this value configurable?
>>
>> The first thing that comes to my mind is that it is a part of a message.
>> It will have some meaning that helps BMC to know what exactly it needs
>> to do.
>>
>> If OEN is always fixed, why do we need it as a part of the message?
> That is defined in IPMI spec for OEM/Group req and response, the first three bytes is the OEM or non-IPMI group that specifies the functionality. The following bytes are defined by the openbmc IPMI commands, such as gpio, I2C, blob transfer and etc.

oh, I got it.

Thanks,

-Tinh

>
> Thanks
> Abner
>
>> Hmm as you suggested, it is good to use it as an industry standard for
>> OpenBMC. Let's use fixed number (49871)
>>
>> If they support more OEN numbers, we will support later
>>
>>> Thanks
>>> Abner
>>>
>>>> This number should be provided by drivers that consume this protocol
>>>>
>>>>> +
>>>>> +/**
>>>>> +  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
>>>>> +CalculateCrc16 (
>>>>> +  IN UINT8  *Data,
>>>>> +  IN UINTN  DataSize
>>>>> +  )
>>>>> +{
>>>>> +  UINTN    Index;
>>>>> +  UINTN    BitIndex;
>>>>> +  UINT16   Crc     = 0xFFFF;
>>>>> +  UINT16   Poly    = 0x1021;
>>>>> +  BOOLEAN  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;
>>>>> +      }
>>>>> +    }
>>>>> +  }
>>>>> +
>>>>> + #if BLOB_TRANSFER_DEBUG
>>>>> +  DEBUG ((DEBUG_INFO, "%a: CRC-16-CCITT %x\n", __FUNCTION__,
>> Crc));
>>>>> + #endif
>>>>> +
>>>>> +  return Crc;
>>>>> +}
>>>>> +
>>>>> +EFI_STATUS
>>>>> +IpmiBlobTransferSendIpmi (
>>>>> +  IN  UINT8   SubCommand,
>>>>> +  IN  UINT8   *SendData,
>>>>> +  IN  UINT32  SendDataSize,
>>>>> +  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;
>>>>> +
>>>>> +  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) {
>>>>> +    //
>>>>> +    // Calculate the Crc of the send data
>>>>> +    //
>>>>> +    Crc = CalculateCrc16 (SendData, SendDataSize);
>>>>> +    CopyMem (IpmiSendData + sizeof (IPMI_BLOB_TRANSFER_HEADER),
>>>> &Crc, sizeof (UINT16));
>>>>> +    CopyMem (IpmiSendData + sizeof (IPMI_BLOB_TRANSFER_HEADER)
>> +
>>>> sizeof (UINT16), SendData, SendDataSize);
>>>>> +  }
>>>>> +
>>>>> + #if BLOB_TRANSFER_DEBUG
>>>>> +  DEBUG ((DEBUG_INFO, "%a: Inputs:\n", __FUNCTION__));
>>>>> +  DEBUG ((DEBUG_INFO, "%a: SendDataSize: %02x\nData: ",
>>>> __FUNCTION__, SendDataSize));
>>>>> +  UINT8  i;
>>>>> +  for (i = 0; i < SendDataSize; i++) {
>>>>> +    DEBUG ((DEBUG_INFO, "%02x", *((UINT8 *)SendData + i)));
>>>>> +  }
>>>>> +
>>>>> +  DEBUG ((DEBUG_INFO, "\n"));
>>>>> +  DEBUG ((DEBUG_INFO, "%a: IpmiSendDataSize: %02x\nData: ",
>>>> __FUNCTION__, IpmiSendDataSize));
>>>>> +  for (i = 0; i < IpmiSendDataSize; i++) {
>>>>> +    DEBUG ((DEBUG_INFO, "%02x", *((UINT8 *)IpmiSendData + i)));
>>>>> +  }
>>>>> +
>>>>> +  DEBUG ((DEBUG_INFO, "\n"));
>>>>> + #endif
>>>>> +
>>>>> +  IpmiResponseDataSize = (*ResponseDataSize +
>>>> PROTOCOL_RESPONSE_OVERHEAD);
>>>>> +  //
>>>>> +  // If expecting data to be returned, we have to also account for the 16
>> bit
>>>> CRC
>>>>> +  //
>>>>> +  if (*ResponseDataSize) {
>>>>> +    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;
>>>>> +
>>>>> + #if BLOB_TRANSFER_DEBUG
>>>>> +  DEBUG ((DEBUG_INFO, "%a: IPMI Response:\n", __FUNCTION__));
>>>>> +  DEBUG ((DEBUG_INFO, "%a: ResponseDataSize: %02x\nData: ",
>>>> __FUNCTION__, IpmiResponseDataSize));
>>>>> +  for (i = 0; i < IpmiResponseDataSize; i++) {
>>>>> +    DEBUG ((DEBUG_INFO, "%02x", *(ModifiedResponseData + i)));
>>>>> +  }
>>>>> +
>>>>> +  DEBUG ((DEBUG_INFO, "\n"));
>>>>> + #endif
>>>>> +
>>>>> +  if (EFI_ERROR (Status)) {
>>>>> +    return Status;
>>>>> +  }
>>>>> +
>>>>> +  CompletionCode = *ModifiedResponseData;
>>>>> +  if (CompletionCode != IPMI_COMP_CODE_NORMAL) {
>>>>> +    DEBUG ((DEBUG_ERROR, "%a: Returning because CompletionCode =
>>>> 0x%x\n", __FUNCTION__, 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 == CalculateCrc16 (ModifiedResponseData,
>>>> IpmiResponseDataSize)) {
>>>>> +      CopyMem (ResponseData, ModifiedResponseData,
>>>> IpmiResponseDataSize);
>>>>> +      CopyMem (ResponseDataSize, &IpmiResponseDataSize, sizeof
>>>> (IpmiResponseDataSize));
>>>>> +      FreePool (IpmiResponseData);
>>>>> +      return EFI_SUCCESS;
>>>>> +    } else {
>>>>> +      FreePool (IpmiResponseData);
>>>>> +      return EFI_CRC_ERROR;
>>>>> +    }
>>>>> +  }
>>>>> +}
>>>>> +
>>>>> +/**
>>>>> +  @param[out]        Count       The number of active blobs
>>>>> +
>>>>> +  @retval EFI_SUCCESS            The command byte stream was
>> successfully
>>>> submit to the device and a response was successfully received.
>>>>> +  @retval EFI_PROTOCOL_ERROR     The Ipmi command failed
>>>>> +  @retval EFI_CRC_ERROR          The Ipmi command returned a bad
>>>> checksum
>>>>> +**/
>>>>> +EFI_STATUS
>>>>> +IpmiBlobTransferGetCount (
>>>>> +  OUT UINT32  *Count
>>>>> +  )
>>>>> +{
>>>> Please add the argument validation for functions which expose for other
>>>> drivers
>>>>
>>>>
>>>>> +  EFI_STATUS  Status;
>>>>> +  UINT8       *ResponseData;
>>>>> +  UINT32      ResponseDataSize;
>>>>> +
>>>>> +  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;
>>>>> +}
>>>>> +
>>>>> +/**
>>>>> +  @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;
>>>>> +  }
>>>>> +
>>>>> +  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) {
>>>>> +    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;
>>>>> +}
>>>>> +
>>>>> +/**
>>>>> +  @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
>>>>> +  )
>>>>> +{
>>>>> +  EFI_STATUS  Status;
>>>>> +  UINT8       *SendData;
>>>>> +  UINT8       *ResponseData;
>>>>> +  UINT32      SendDataSize;
>>>>> +  UINT32      ResponseDataSize;
>>>>> +  CHAR8       *BlobSearch;
>>>>> +  UINT32      NumBlobs;
>>>>> +  UINT16      Index;
>>>>> +  BOOLEAN     BlobFound;
>>>>> +
>>>>> +  //
>>>>> +  // Before opening a blob, need to check if it exists
>>>>> +  //
>>>>> +  Status = IpmiBlobTransferGetCount (&NumBlobs);
>>>> I think it should be removed as that will duplicate work
>>>>
>>>> The drivers using IPMI blob protocol will  "get count" themselves.
>>>>
>>>>> +  if (EFI_ERROR (Status) || (NumBlobs == 0)) {
>>>>> +    if (Status == EFI_UNSUPPORTED) {
>>>>> +      return Status;
>>>>> +    }
>>>>> +
>>>>> +    DEBUG ((DEBUG_ERROR, "%a: Could not find any blobs: %r\n",
>>>> __FUNCTION__, Status));
>>>>> +    return EFI_NOT_FOUND;
>>>>> +  }
>>>>> +
>>>>> +  BlobSearch = AllocateZeroPool (sizeof (CHAR8) *
>>>> IPMI_OEM_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);
>>>> the same here
>>>>> +    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
>> %s\n",
>>>> __FUNCTION__, 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;
>>>>> +
>>>>> +  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;
>>>>> +}
>>>>> +
>>>>> +/**
>>>>> +  @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
>>>>> +  )
>>>>> +{
>>>>> +  EFI_STATUS  Status;
>>>>> +  UINT8       *SendData;
>>>>> +  UINT8       *ResponseData;
>>>>> +  UINT32      SendDataSize;
>>>>> +  UINT32      ResponseDataSize;
>>>>> +
>>>>> +  if (Data == NULL) {
>>>>> +    ASSERT (FALSE);
>>>>> +    return EFI_ABORTED;
>>>>> +  }
>>>>> +
>>>>> +  ResponseDataSize = RequestedSize * sizeof (UINT8);
>>>>> +  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) {
>>>>> +    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;
>>>>> +}
>>>>> +
>>>>> +/**
>>>>> +  @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
>>>>> +
>>>>> +  @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;
>>>>> +
>>>>> +  //
>>>>> +  // Format send data
>>>>> +  //
>>>>> +  SendDataSize = sizeof (SessionId) + sizeof (Offset) + WriteLength;
>>>>> +  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;
>>>>> +}
>>>>> +
>>>>> +/**
>>>>> +  @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;
>>>>> +
>>>>> +  //
>>>>> +  // 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;
>>>>> +}
>>>>> +
>>>>> +/**
>>>>> +  @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;
>>>>> +}
>>>>> +
>>>>> +/**
>>>>> +  @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;
>>>>> +
>>>>> +  //
>>>>> +  // 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;
>>>>> +}
>>>>> +
>>>>> +/**
>>>>> +  @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 (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, IPMI_OEM_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;
>>>>> +}
>>>>> +
>>>>> +/**
>>>>> +  @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;
>>>>> +}
>>>>> +
>>>>> +/**
>>>>> +  @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
>>>>> +
>>>>> +  @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
>>>>> +  )
>>>>> +{
>>>>> +  EFI_STATUS  Status;
>>>>> +  UINT8       *SendData;
>>>>> +  UINT32      SendDataSize;
>>>>> +  UINT32      ResponseDataSize;
>>>>> +
>>>>> +  //
>>>>> +  // 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,
>>>>> +                &gEdkiiIpmiBlobTransferProtocolGuid,
>>>>> +                (VOID *)&mIpmiBlobTransfer,
>>>>> +                NULL
>>>>> +                );
>>>>> +}
>>>>> diff --git
>> a/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/Ipmi
>>>> BlobTransferTestUnitTests.c
>>>>
>> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/Ipm
>>>> iBlobTransferTestUnitTests.c
>>>>> new file mode 100644
>>>>> index 0000000000..f326467922
>>>>> --- /dev/null
>>>>> +++
>> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/Ipm
>>>> iBlobTransferTestUnitTests.c
>>>>> @@ -0,0 +1,1113 @@
>>>>> +/** @file
>>>>> +*
>>>>> +*  Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
>>>> 2023
>>>>> +*
>>>>> +*  SPDX-FileCopyrightText: Copyright (c) 2022 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 = CalculateCrc16 (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 = CalculateCrc16 (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) *
>>>> IPMI_OEM_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;
>>>>> +  }
>>>>> +
>>>>> +  // CalculateCrc16
>>>>> +  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..47800f5801
>>>>> --- /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
>>>>> +
>>>>> +## NVIDIA's 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 1
>>>>> --
>>>>> 2.17.1
>>>>>

  reply	other threads:[~2023-04-17  3:08 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-04-12  3:17 [edk2-platforms][PATCH] ManageabilityPkg: add support for the phosphor ipmi blob transfer protocol Nickle Wang
2023-04-13  4:29 ` Chang, Abner
2023-04-16 10:28 ` Tinh Nguyen
2023-04-16 10:50   ` Chang, Abner
2023-04-17  2:24     ` Tinh Nguyen
2023-04-17  3:01       ` Chang, Abner
2023-04-17  3:08         ` Tinh Nguyen [this message]
2023-04-17  2:20   ` [edk2-devel] " Thang Nguyen OS
2023-04-17 11:38 ` Mike Maslenkin
2024-02-08 23:52 ` Rebecca Cran
2024-02-09 13:34   ` Nickle Wang via groups.io
2024-02-09 16:37     ` Chang, Abner via groups.io
2024-05-13  9:02       ` Nhi Pham via groups.io
2024-05-14  1:56         ` Nickle Wang via groups.io
2024-05-14  2:25           ` Nhi Pham via groups.io
2024-05-15 15:14             ` Nickle Wang via groups.io
2024-05-16  8:39               ` Nhi Pham via groups.io
2024-05-16  8:44                 ` Chang, Abner via groups.io
2024-05-16  8:49                   ` Nhi Pham via groups.io
2024-05-16  8:53                     ` Chang, Abner 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=594581df-5fbf-a5e6-0521-962941f2ed90@amperemail.onmicrosoft.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