public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [edk2-platforms][PATCH] ManageabilityPkg: add support for the phosphor ipmi blob transfer protocol
@ 2023-04-12  3:17 Nickle Wang
  2023-04-13  4:29 ` Chang, Abner
                   ` (3 more replies)
  0 siblings, 4 replies; 20+ messages in thread
From: Nickle Wang @ 2023-04-12  3:17 UTC (permalink / raw)
  To: devel; +Cc: Abner Chang, Isaac Oram, Abdul Lateef Attar, Tinh Nguyen

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/IpmiBlobTransferDxe.inf
 create mode 100644 Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTestsHost.inf
 create mode 100644 Features/ManageabilityPkg/Include/Protocol/IpmiBlobTransfer.h
 create mode 100644 Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiBlobTransfer.h
 create mode 100644 Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.c
 create mode 100644 Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTests.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/BaseManageabilityTransportHelperLib/BaseManageabilityTransportHelper.inf
+  IpmiLib|MdeModulePkg/Library/DxeIpmiLibIpmiProtocol/DxeIpmiLibIpmiProtocol.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/IpmiBlobTransferDxe.inf b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.inf
new file mode 100644
index 0000000000..28e9d293c1
--- /dev/null
+++ b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.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/IpmiBlobTransferTestUnitTestsHost.inf b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTestsHost.inf
new file mode 100644
index 0000000000..1f071bbadc
--- /dev/null
+++ b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTestsHost.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
+
+#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/InternalIpmiBlobTransfer.h b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiBlobTransfer.h
new file mode 100644
index 0000000000..14f0dc02bc
--- /dev/null
+++ b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiBlobTransfer.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/IpmiBlobTransferDxe.c b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.c
new file mode 100644
index 0000000000..9e663289d5
--- /dev/null
+++ b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.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)*IpmiBlobTransferGetCount,
+  (IPMI_BLOB_TRANSFER_PROTOCOL_ENUMERATE)*IpmiBlobTransferEnumerate,
+  (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)*IpmiBlobTransferSessionStat,
+  (IPMI_BLOB_TRANSFER_PROTOCOL_WRITE_META)*IpmiBlobTransferWriteMeta
+};
+
+const UINT8  OpenBmcOen[] = { 0xCF, 0xC2, 0x00 };          // OpenBMC OEN code in little endian format
+
+/**
+  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
+  )
+{
+  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);
+  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);
+    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/IpmiBlobTransferTestUnitTests.c b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTests.c
new file mode 100644
index 0000000000..f326467922
--- /dev/null
+++ b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTests.c
@@ -0,0 +1,1113 @@
+/** @file
+*
+*  Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
+*
+*  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


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: [edk2-platforms][PATCH] ManageabilityPkg: add support for the phosphor ipmi blob transfer protocol
  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
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 20+ messages in thread
From: Chang, Abner @ 2023-04-13  4:29 UTC (permalink / raw)
  To: Nickle Wang, devel@edk2.groups.io
  Cc: Isaac Oram, Attar, AbdulLateef (Abdul Lateef), Tinh Nguyen

[AMD Official Use Only - General]

Hi Nickle,

Could you please create a BZ ticket for this? Pease also run Uncristify on these files.

Feedback inline, 

> -----Original Message-----
> From: Nickle Wang <nicklew@nvidia.com>
> Sent: Wednesday, April 12, 2023 11:17 AM
> To: 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>; Tinh Nguyen
> <tinhnguyen@amperemail.onmicrosoft.com>
> Subject: [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.
> 
> 
> 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
Is 2022-2023 correct? This file will be added in 2023.


> 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
Please add @Par to https://github.com/openbmc/phosphor-ipmi-blobs/blob/master/README.md, as the reference of specification.

> +
> +**/
> +#include <Library/IpmiLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <IndustryStandard/Ipmi.h>
> +
> +#define IPMI_NETFN_OEM                     0x2E
Let's move this definition to under MdePkg/Incldue/IndustryStandard/IpmiNetFnOem.h, please refer to IpmiNetFnGroupExtension.h. This keeps the consistent implementation with the current IPMI header files under MdePkg, although there is only one line definition.


> +#define IPMI_OEM_BLOB_TRANSFER_CMD         0x80
> +#define IPMI_OEM_BLOB_MAX_DATA_PER_PACKET  64
> +
> +#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
We can create a C header file "IpmiOpenBmc.h" under ManageabilityPkg/Include/IndustryStandard.  Also relocate  OpenBmcOen from IpmiBloblTransfer.c to this header file. We can have this header file that accommodates the IPMI specs defined by OpenBMC.
Please also use OpenBmc instead of "Oem".

> +
> +//
> +//  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
> +  );
> +

You missed the function header for all function prototype here and above.

> +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;
> +};
Do you think EDKII_IPMI_BLOB_TRANSFER_PROTOCOL for protocol name is better? Although IPMI_PROTOCOL wasn't named as this way. That's fine to keep the naming of function member as it.


> +
> +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()

Above is defined in openbmc, we can remove it to the new C header file.

> +
> +/**
> +  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
> +  );
No function header.

> +
> +/**
> +  @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
> +
> +/**
> +  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;
I remember we don't do local variable initialization here.  We give it a initial value in a separate line.

> +
> +  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
Do you mind if we remove the macros those  are used through entire file, the definition of BLOB_TRANSFER_DEBUG as well. We can just output the message with DEBUG_INFO for now. We can use DEBUG_MANAGEABILITY_INFO once Manageabilty Part II patch set is reviewed and merged.
Also, I am proposing to have new debug print error level.

> +
> +  return Crc;
> +}
> +
Missed function header. 

> +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;
> +    }
> +  }
> +}
> +
> +/**
Could we have short description for function in this files? We can copy it from openbmc spec.


> +  @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
> +  )
> +{
> +  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);
> +  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);
> +    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.
> +*
> +*  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.
We should remove NVIDIA and use edk2 instead. 

Thanks
Abner

> +
> +### 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

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [edk2-platforms][PATCH] ManageabilityPkg: add support for the phosphor ipmi blob transfer protocol
  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:20   ` [edk2-devel] " Thang Nguyen OS
  2023-04-17 11:38 ` Mike Maslenkin
  2024-02-08 23:52 ` Rebecca Cran
  3 siblings, 2 replies; 20+ messages in thread
From: Tinh Nguyen @ 2023-04-16 10:28 UTC (permalink / raw)
  To: Nickle Wang, devel; +Cc: Abner Chang, Isaac Oram, Abdul Lateef Attar

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/IpmiBlobTransferDxe.inf
>   create mode 100644 Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTestsHost.inf
>   create mode 100644 Features/ManageabilityPkg/Include/Protocol/IpmiBlobTransfer.h
>   create mode 100644 Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiBlobTransfer.h
>   create mode 100644 Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.c
>   create mode 100644 Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTests.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/BaseManageabilityTransportHelperLib/BaseManageabilityTransportHelper.inf
> +  IpmiLib|MdeModulePkg/Library/DxeIpmiLibIpmiProtocol/DxeIpmiLibIpmiProtocol.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/IpmiBlobTransferDxe.inf b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.inf
> new file mode 100644
> index 0000000000..28e9d293c1
> --- /dev/null
> +++ b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.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/IpmiBlobTransferTestUnitTestsHost.inf b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTestsHost.inf
> new file mode 100644
> index 0000000000..1f071bbadc
> --- /dev/null
> +++ b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTestsHost.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

> +
> +#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/InternalIpmiBlobTransfer.h b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiBlobTransfer.h
> new file mode 100644
> index 0000000000..14f0dc02bc
> --- /dev/null
> +++ b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiBlobTransfer.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/IpmiBlobTransferDxe.c b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.c
> new file mode 100644
> index 0000000000..9e663289d5
> --- /dev/null
> +++ b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.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)*IpmiBlobTransferGetCount,
> +  (IPMI_BLOB_TRANSFER_PROTOCOL_ENUMERATE)*IpmiBlobTransferEnumerate,
> +  (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)*IpmiBlobTransferSessionStat,
> +  (IPMI_BLOB_TRANSFER_PROTOCOL_WRITE_META)*IpmiBlobTransferWriteMeta
> +};
> +
> +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?

And this number can be configured, other OEMs will have their own number.

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/IpmiBlobTransferTestUnitTests.c b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTests.c
> new file mode 100644
> index 0000000000..f326467922
> --- /dev/null
> +++ b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTests.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
>

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [edk2-platforms][PATCH] ManageabilityPkg: add support for the phosphor ipmi blob transfer protocol
  2023-04-16 10:28 ` Tinh Nguyen
@ 2023-04-16 10:50   ` Chang, Abner
  2023-04-17  2:24     ` Tinh Nguyen
  2023-04-17  2:20   ` [edk2-devel] " Thang Nguyen OS
  1 sibling, 1 reply; 20+ messages in thread
From: Chang, Abner @ 2023-04-16 10:50 UTC (permalink / raw)
  To: Tinh Nguyen, Nickle Wang, devel@edk2.groups.io
  Cc: Isaac Oram, Attar, AbdulLateef (Abdul Lateef)

[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.

> 
> > +
> > +#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 

> 
> 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?

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
> >

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [edk2-devel] [edk2-platforms][PATCH] ManageabilityPkg: add support for the phosphor ipmi blob transfer protocol
  2023-04-16 10:28 ` Tinh Nguyen
  2023-04-16 10:50   ` Chang, Abner
@ 2023-04-17  2:20   ` Thang Nguyen OS
  1 sibling, 0 replies; 20+ messages in thread
From: Thang Nguyen OS @ 2023-04-17  2:20 UTC (permalink / raw)
  To: devel@edk2.groups.io, Tinh Nguyen OS
  Cc: Nickle Wang, Abner Chang, Isaac Oram, Abdul Lateef Attar

[-- Attachment #1: Type: text/plain, Size: 96572 bytes --]



On 16 Apr 2023, at 17:28, Tinh Nguyen via groups.io <tinhnguyen=os.amperecomputing.com@groups.io> wrote:

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/IpmiBlobTransferDxe.inf
 create mode 100644 Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTestsHost.inf
 create mode 100644 Features/ManageabilityPkg/Include/Protocol/IpmiBlobTransfer.h
 create mode 100644 Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiBlobTransfer.h
 create mode 100644 Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.c
 create mode 100644 Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTests.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/BaseManageabilityTransportHelperLib/BaseManageabilityTransportHelper.inf
+  IpmiLib|MdeModulePkg/Library/DxeIpmiLibIpmiProtocol/DxeIpmiLibIpmiProtocol.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/IpmiBlobTransferDxe.inf b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.inf
new file mode 100644
index 0000000000..28e9d293c1
--- /dev/null
+++ b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.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/IpmiBlobTransferTestUnitTestsHost.inf b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTestsHost.inf
new file mode 100644
index 0000000000..1f071bbadc
--- /dev/null
+++ b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTestsHost.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

+
+#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/InternalIpmiBlobTransfer.h b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiBlobTransfer.h
new file mode 100644
index 0000000000..14f0dc02bc
--- /dev/null
+++ b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiBlobTransfer.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/IpmiBlobTransferDxe.c b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.c
new file mode 100644
index 0000000000..9e663289d5
--- /dev/null
+++ b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.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)*IpmiBlobTransferGetCount,
+  (IPMI_BLOB_TRANSFER_PROTOCOL_ENUMERATE)*IpmiBlobTransferEnumerate,
+  (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)*IpmiBlobTransferSessionStat,
+  (IPMI_BLOB_TRANSFER_PROTOCOL_WRITE_META)*IpmiBlobTransferWriteMeta
+};
+
+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?

And this number can be configured, other OEMs will have their own number.

This number should be provided by drivers that consume this protocol
This commit uses OpenBMC IPMI blob commands defined in https://github.com/openbmc/phosphor-ipmi-blobs which are fixed numbers. So, no problem to have fixed definition.

+
+/**
+  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/IpmiBlobTransferTestUnitTests.c b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTests.c
new file mode 100644
index 0000000000..f326467922
--- /dev/null
+++ b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTests.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






[-- Attachment #2: Type: text/html, Size: 180923 bytes --]

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: [edk2-platforms][PATCH] ManageabilityPkg: add support for the phosphor ipmi blob transfer protocol
  2023-04-16 10:50   ` Chang, Abner
@ 2023-04-17  2:24     ` Tinh Nguyen
  2023-04-17  3:01       ` Chang, Abner
  0 siblings, 1 reply; 20+ messages in thread
From: Tinh Nguyen @ 2023-04-17  2:24 UTC (permalink / raw)
  To: Chang, Abner, Nickle Wang, devel@edk2.groups.io
  Cc: Isaac Oram, Attar, AbdulLateef (Abdul Lateef)


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.
>>> +
>>> +#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?

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
>>>

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [edk2-platforms][PATCH] ManageabilityPkg: add support for the phosphor ipmi blob transfer protocol
  2023-04-17  2:24     ` Tinh Nguyen
@ 2023-04-17  3:01       ` Chang, Abner
  2023-04-17  3:08         ` Tinh Nguyen
  0 siblings, 1 reply; 20+ messages in thread
From: Chang, Abner @ 2023-04-17  3:01 UTC (permalink / raw)
  To: Tinh Nguyen, Nickle Wang, devel@edk2.groups.io
  Cc: Isaac Oram, Attar, AbdulLateef (Abdul Lateef)

[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.

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
> >>>

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [edk2-platforms][PATCH] ManageabilityPkg: add support for the phosphor ipmi blob transfer protocol
  2023-04-17  3:01       ` Chang, Abner
@ 2023-04-17  3:08         ` Tinh Nguyen
  0 siblings, 0 replies; 20+ messages in thread
From: Tinh Nguyen @ 2023-04-17  3:08 UTC (permalink / raw)
  To: Chang, Abner, Nickle Wang, devel@edk2.groups.io
  Cc: Isaac Oram, Attar, AbdulLateef (Abdul Lateef)

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
>>>>>

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [edk2-devel] [edk2-platforms][PATCH] ManageabilityPkg: add support for the phosphor ipmi blob transfer protocol
  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-17 11:38 ` Mike Maslenkin
  2024-02-08 23:52 ` Rebecca Cran
  3 siblings, 0 replies; 20+ messages in thread
From: Mike Maslenkin @ 2023-04-17 11:38 UTC (permalink / raw)
  To: devel, nicklew; +Cc: Abner Chang, Isaac Oram, Abdul Lateef Attar, Tinh Nguyen

Hello Nick,

CalculateCrc16 function has already defined in
edk2-platforms/Platform/Intel/WhitleyOpenBoardPkg/Include/Library/CrcLib.h
and edk2/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugAgent.c.
This patch adds another CalculateCrc16 declaration.
There was an attempt to unify Crc16 calculation [*], but it left
implementations mentioned above untouched.
I would suggest to rename CalculateCrc16 provided by this path to
something like CalculateCrc16Ccitt.
It could be easy moved to MdePkg later.

[*] https://bugzilla.tianocore.org/show_bug.cgi?id=3871

On Wed, Apr 12, 2023 at 6:17 AM Nickle Wang via groups.io
<nicklew=nvidia.com@groups.io> wrote:
>
> 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/IpmiBlobTransferDxe.inf
>  create mode 100644 Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTestsHost.inf
>  create mode 100644 Features/ManageabilityPkg/Include/Protocol/IpmiBlobTransfer.h
>  create mode 100644 Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiBlobTransfer.h
>  create mode 100644 Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.c
>  create mode 100644 Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTests.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/BaseManageabilityTransportHelperLib/BaseManageabilityTransportHelper.inf
> +  IpmiLib|MdeModulePkg/Library/DxeIpmiLibIpmiProtocol/DxeIpmiLibIpmiProtocol.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/IpmiBlobTransferDxe.inf b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.inf
> new file mode 100644
> index 0000000000..28e9d293c1
> --- /dev/null
> +++ b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.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/IpmiBlobTransferTestUnitTestsHost.inf b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTestsHost.inf
> new file mode 100644
> index 0000000000..1f071bbadc
> --- /dev/null
> +++ b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTestsHost.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
> +
> +#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/InternalIpmiBlobTransfer.h b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiBlobTransfer.h
> new file mode 100644
> index 0000000000..14f0dc02bc
> --- /dev/null
> +++ b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiBlobTransfer.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/IpmiBlobTransferDxe.c b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.c
> new file mode 100644
> index 0000000000..9e663289d5
> --- /dev/null
> +++ b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.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)*IpmiBlobTransferGetCount,
> +  (IPMI_BLOB_TRANSFER_PROTOCOL_ENUMERATE)*IpmiBlobTransferEnumerate,
> +  (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)*IpmiBlobTransferSessionStat,
> +  (IPMI_BLOB_TRANSFER_PROTOCOL_WRITE_META)*IpmiBlobTransferWriteMeta
> +};
> +
> +const UINT8  OpenBmcOen[] = { 0xCF, 0xC2, 0x00 };          // OpenBMC OEN code in little endian format
> +
> +/**
> +  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
> +  )
> +{
> +  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);
> +  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);
> +    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/IpmiBlobTransferTestUnitTests.c b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTests.c
> new file mode 100644
> index 0000000000..f326467922
> --- /dev/null
> +++ b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTests.c
> @@ -0,0 +1,1113 @@
> +/** @file
> +*
> +*  Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
> +*
> +*  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
>
>
>
> 
>
>

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [edk2-devel] [edk2-platforms][PATCH] ManageabilityPkg: add support for the phosphor ipmi blob transfer protocol
  2023-04-12  3:17 [edk2-platforms][PATCH] ManageabilityPkg: add support for the phosphor ipmi blob transfer protocol Nickle Wang
                   ` (2 preceding siblings ...)
  2023-04-17 11:38 ` Mike Maslenkin
@ 2024-02-08 23:52 ` Rebecca Cran
  2024-02-09 13:34   ` Nickle Wang via groups.io
  3 siblings, 1 reply; 20+ messages in thread
From: Rebecca Cran @ 2024-02-08 23:52 UTC (permalink / raw)
  To: devel, nicklew; +Cc: Abner Chang, Isaac Oram, Abdul Lateef Attar, Tinh Nguyen

Was this change abandoned?

I've realized it would be useful to have in the firmware I'm working on, 
and was wondering if there's a newer revision of this patch somewhere?


-- 
Rebecca Cran


On 4/11/23 21:17, Nickle Wang via groups.io wrote:
> 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/IpmiBlobTransferDxe.inf
>   create mode 100644 Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTestsHost.inf
>   create mode 100644 Features/ManageabilityPkg/Include/Protocol/IpmiBlobTransfer.h
>   create mode 100644 Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiBlobTransfer.h
>   create mode 100644 Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.c
>   create mode 100644 Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTests.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/BaseManageabilityTransportHelperLib/BaseManageabilityTransportHelper.inf
> +  IpmiLib|MdeModulePkg/Library/DxeIpmiLibIpmiProtocol/DxeIpmiLibIpmiProtocol.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/IpmiBlobTransferDxe.inf b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.inf
> new file mode 100644
> index 0000000000..28e9d293c1
> --- /dev/null
> +++ b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.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/IpmiBlobTransferTestUnitTestsHost.inf b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTestsHost.inf
> new file mode 100644
> index 0000000000..1f071bbadc
> --- /dev/null
> +++ b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTestsHost.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
> +
> +#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/InternalIpmiBlobTransfer.h b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiBlobTransfer.h
> new file mode 100644
> index 0000000000..14f0dc02bc
> --- /dev/null
> +++ b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiBlobTransfer.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/IpmiBlobTransferDxe.c b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.c
> new file mode 100644
> index 0000000000..9e663289d5
> --- /dev/null
> +++ b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.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)*IpmiBlobTransferGetCount,
> +  (IPMI_BLOB_TRANSFER_PROTOCOL_ENUMERATE)*IpmiBlobTransferEnumerate,
> +  (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)*IpmiBlobTransferSessionStat,
> +  (IPMI_BLOB_TRANSFER_PROTOCOL_WRITE_META)*IpmiBlobTransferWriteMeta
> +};
> +
> +const UINT8  OpenBmcOen[] = { 0xCF, 0xC2, 0x00 };          // OpenBMC OEN code in little endian format
> +
> +/**
> +  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
> +  )
> +{
> +  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);
> +  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);
> +    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/IpmiBlobTransferTestUnitTests.c b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTests.c
> new file mode 100644
> index 0000000000..f326467922
> --- /dev/null
> +++ b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTests.c
> @@ -0,0 +1,1113 @@
> +/** @file
> +*
> +*  Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
> +*
> +*  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


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



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [edk2-devel] [edk2-platforms][PATCH] ManageabilityPkg: add support for the phosphor ipmi blob transfer protocol
  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
  0 siblings, 1 reply; 20+ messages in thread
From: Nickle Wang via groups.io @ 2024-02-09 13:34 UTC (permalink / raw)
  To: Rebecca Cran, devel@edk2.groups.io
  Cc: Abner Chang, Isaac Oram, Abdul Lateef Attar, Tinh Nguyen

Hi Rebecca,

There is change to this driver on NVIDIA GitHub here: https://github.com/NVIDIA/edk2-nvidia/tree/main/Silicon/NVIDIA/Drivers/IpmiBlobTransferDxe

Regards,
Nickle

> -----Original Message-----
> From: Rebecca Cran <rebecca@bsdio.com>
> Sent: Friday, February 9, 2024 7:53 AM
> To: devel@edk2.groups.io; Nickle Wang <nicklew@nvidia.com>
> Cc: Abner Chang <abner.chang@amd.com>; Isaac Oram
> <isaac.w.oram@intel.com>; Abdul Lateef Attar
> <AbdulLateef.Attar@amd.com>; Tinh Nguyen
> <tinhnguyen@amperemail.onmicrosoft.com>
> Subject: Re: [edk2-devel] [edk2-platforms][PATCH] ManageabilityPkg: add
> support for the phosphor ipmi blob transfer protocol
> 
> External email: Use caution opening links or attachments
> 
> 
> Was this change abandoned?
> 
> I've realized it would be useful to have in the firmware I'm working on,
> and was wondering if there's a newer revision of this patch somewhere?
> 
> 
> --
> Rebecca Cran
> 
> 
> On 4/11/23 21:17, Nickle Wang via groups.io wrote:
> > This change implements the blob transfer protocol used in OpenBmc
> > documented here:
> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.
> com%2Fopenbmc%2Fphosphor-ipmi-
> blobs&data=05%7C02%7Cnicklew%40nvidia.com%7Cb327966e84624368765
> 208dc29010a98%7C43083d15727340c1b7db39efd9ccc17a%7C0%7C0%7C63
> 8430331675542376%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMD
> AiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%7C%7C&sda
> ta=esHFGSAc5TGBvPUWAOKd22p7DRMZ9UbnBU1jNAh%2Fsb0%3D&reserved
> =0
> >
> > 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/IpmiBlobTransferD
> xe.inf
> >   create mode 100644
> Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlob
> TransferTestUnitTestsHost.inf
> >   create mode 100644
> Features/ManageabilityPkg/Include/Protocol/IpmiBlobTransfer.h
> >   create mode 100644
> Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiBlobTr
> ansfer.h
> >   create mode 100644
> Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferD
> xe.c
> >   create mode 100644
> Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlob
> TransferTestUnitTests.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/BaseManageabili
> tyTransportHelperLib/BaseManageabilityTransportHelper.inf
> > +
> IpmiLib|MdeModulePkg/Library/DxeIpmiLibIpmiProtocol/DxeIpmiLibIpmiProt
> ocol.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/IpmiBlobTransfe
> rDxe.inf
> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransfe
> rDxe.inf
> > new file mode 100644
> > index 0000000000..28e9d293c1
> > --- /dev/null
> > +++
> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransfe
> rDxe.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/IpmiBl
> obTransferTestUnitTestsHost.inf
> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBl
> obTransferTestUnitTestsHost.inf
> > new file mode 100644
> > index 0000000000..1f071bbadc
> > --- /dev/null
> > +++
> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBl
> obTransferTestUnitTestsHost.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
> > +
> > +#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/InternalIpmiBlo
> bTransfer.h
> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiBlo
> bTransfer.h
> > new file mode 100644
> > index 0000000000..14f0dc02bc
> > --- /dev/null
> > +++
> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiBlo
> bTransfer.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/IpmiBlobTransfe
> rDxe.c
> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransfe
> rDxe.c
> > new file mode 100644
> > index 0000000000..9e663289d5
> > --- /dev/null
> > +++
> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransfe
> rDxe.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)*IpmiBlobTransferGetCount,
> > +
> (IPMI_BLOB_TRANSFER_PROTOCOL_ENUMERATE)*IpmiBlobTransferEnumerat
> e,
> > +  (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)*IpmiBlobTransferSessionS
> tat,
> > +
> (IPMI_BLOB_TRANSFER_PROTOCOL_WRITE_META)*IpmiBlobTransferWriteMe
> ta
> > +};
> > +
> > +const UINT8  OpenBmcOen[] = { 0xCF, 0xC2, 0x00 };          // OpenBMC OEN
> code in little endian format
> > +
> > +/**
> > +  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
> > +  )
> > +{
> > +  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);
> > +  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);
> > +    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/IpmiBl
> obTransferTestUnitTests.c
> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBl
> obTransferTestUnitTests.c
> > new file mode 100644
> > index 0000000000..f326467922
> > --- /dev/null
> > +++
> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBl
> obTransferTestUnitTests.c
> > @@ -0,0 +1,1113 @@
> > +/** @file
> > +*
> > +*  Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
> > +*
> > +*  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://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithu
> b.com%2Fopenbmc%2Fphosphor-ipmi-
> blobs&data=05%7C02%7Cnicklew%40nvidia.com%7Cb327966e84624368765
> 208dc29010a98%7C43083d15727340c1b7db39efd9ccc17a%7C0%7C0%7C63
> 8430331675551644%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMD
> AiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%7C%7C&sda
> ta=WdwXQUKvHs3bv4KI9rbvvvQ3jJOFlWRhBczJAke9vL0%3D&reserved=0
> > +
> > +## 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


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



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [edk2-devel] [edk2-platforms][PATCH] ManageabilityPkg: add support for the phosphor ipmi blob transfer protocol
  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
  0 siblings, 1 reply; 20+ messages in thread
From: Chang, Abner via groups.io @ 2024-02-09 16:37 UTC (permalink / raw)
  To: Nickle Wang, Rebecca Cran, devel@edk2.groups.io
  Cc: Isaac Oram, Attar, AbdulLateef (Abdul Lateef), Tinh Nguyen

[AMD Official Use Only - General]

Yeah, I forget this patch set and seems we don't have any follow up conversation after below feedbacks from community.

https://edk2.groups.io/g/devel/message/103116
https://edk2.groups.io/g/devel/message/103087

So Nickle, does NV still has the plan to upstream IPMI blob edk2 implementation? We should keep driving upstream the implementation as industry needs it to incorporate with OpenBMC.

Hi Rebessa,
As we are on Chinese New Year holidays now, please expect the delay response.
Thanks
Abner

> -----Original Message-----
> From: Nickle Wang <nicklew@nvidia.com>
> Sent: Friday, February 9, 2024 9:34 PM
> To: Rebecca Cran <rebecca@bsdio.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>; Tinh Nguyen
> <tinhnguyen@amperemail.onmicrosoft.com>
> Subject: RE: [edk2-devel] [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 Rebecca,
>
> There is change to this driver on NVIDIA GitHub here:
> https://github.com/NVIDIA/edk2-
> nvidia/tree/main/Silicon/NVIDIA/Drivers/IpmiBlobTransferDxe
>
> Regards,
> Nickle
>
> > -----Original Message-----
> > From: Rebecca Cran <rebecca@bsdio.com>
> > Sent: Friday, February 9, 2024 7:53 AM
> > To: devel@edk2.groups.io; Nickle Wang <nicklew@nvidia.com>
> > Cc: Abner Chang <abner.chang@amd.com>; Isaac Oram
> > <isaac.w.oram@intel.com>; Abdul Lateef Attar
> > <AbdulLateef.Attar@amd.com>; Tinh Nguyen
> > <tinhnguyen@amperemail.onmicrosoft.com>
> > Subject: Re: [edk2-devel] [edk2-platforms][PATCH] ManageabilityPkg: add
> > support for the phosphor ipmi blob transfer protocol
> >
> > External email: Use caution opening links or attachments
> >
> >
> > Was this change abandoned?
> >
> > I've realized it would be useful to have in the firmware I'm working on,
> > and was wondering if there's a newer revision of this patch somewhere?
> >
> >
> > --
> > Rebecca Cran
> >
> >
> > On 4/11/23 21:17, Nickle Wang via groups.io wrote:
> > > This change implements the blob transfer protocol used in OpenBmc
> > > documented here:
> >
> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgith
> ub.
> > com%2Fopenbmc%2Fphosphor-ipmi-
> >
> blobs&data=05%7C02%7Cnicklew%40nvidia.com%7Cb327966e846243687
> 65
> >
> 208dc29010a98%7C43083d15727340c1b7db39efd9ccc17a%7C0%7C0%7C
> 63
> >
> 8430331675542376%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAw
> MD
> >
> AiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%7C%7C&s
> da
> >
> ta=esHFGSAc5TGBvPUWAOKd22p7DRMZ9UbnBU1jNAh%2Fsb0%3D&reserv
> ed
> > =0
> > >
> > > 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/IpmiBlobTransfer
> D
> > xe.inf
> > >   create mode 100644
> >
> Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlo
> b
> > TransferTestUnitTestsHost.inf
> > >   create mode 100644
> > Features/ManageabilityPkg/Include/Protocol/IpmiBlobTransfer.h
> > >   create mode 100644
> >
> Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiBlob
> Tr
> > ansfer.h
> > >   create mode 100644
> >
> Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransfer
> D
> > xe.c
> > >   create mode 100644
> >
> Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlo
> b
> > TransferTestUnitTests.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/BaseManageabili
> > tyTransportHelperLib/BaseManageabilityTransportHelper.inf
> > > +
> >
> IpmiLib|MdeModulePkg/Library/DxeIpmiLibIpmiProtocol/DxeIpmiLibIpmiPro
> t
> > ocol.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/IpmiBlobTransf
> e
> > rDxe.inf
> >
> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransf
> e
> > rDxe.inf
> > > new file mode 100644
> > > index 0000000000..28e9d293c1
> > > --- /dev/null
> > > +++
> >
> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransf
> e
> > rDxe.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/IpmiB
> l
> > obTransferTestUnitTestsHost.inf
> >
> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiB
> l
> > obTransferTestUnitTestsHost.inf
> > > new file mode 100644
> > > index 0000000000..1f071bbadc
> > > --- /dev/null
> > > +++
> >
> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiB
> l
> > obTransferTestUnitTestsHost.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
> > > +
> > > +#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/InternalIpmiBlo
> > bTransfer.h
> >
> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiBl
> o
> > bTransfer.h
> > > new file mode 100644
> > > index 0000000000..14f0dc02bc
> > > --- /dev/null
> > > +++
> >
> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiBl
> o
> > bTransfer.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/IpmiBlobTransf
> e
> > rDxe.c
> >
> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransf
> e
> > rDxe.c
> > > new file mode 100644
> > > index 0000000000..9e663289d5
> > > --- /dev/null
> > > +++
> >
> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransf
> e
> > rDxe.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)*IpmiBlobTransferGetCoun
> t,
> > > +
> >
> (IPMI_BLOB_TRANSFER_PROTOCOL_ENUMERATE)*IpmiBlobTransferEnumera
> t
> > e,
> > > +  (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)*IpmiBlobTransferSession
> S
> > tat,
> > > +
> >
> (IPMI_BLOB_TRANSFER_PROTOCOL_WRITE_META)*IpmiBlobTransferWriteM
> e
> > ta
> > > +};
> > > +
> > > +const UINT8  OpenBmcOen[] = { 0xCF, 0xC2, 0x00 };          // OpenBMC
> OEN
> > code in little endian format
> > > +
> > > +/**
> > > +  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
> > > +  )
> > > +{
> > > +  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);
> > > +  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);
> > > +    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/IpmiB
> l
> > obTransferTestUnitTests.c
> >
> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiB
> l
> > obTransferTestUnitTests.c
> > > new file mode 100644
> > > index 0000000000..f326467922
> > > --- /dev/null
> > > +++
> >
> b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiB
> l
> > obTransferTestUnitTests.c
> > > @@ -0,0 +1,1113 @@
> > > +/** @file
> > > +*
> > > +*  Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
> > > +*
> > > +*  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://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit
> hu
> > b.com%2Fopenbmc%2Fphosphor-ipmi-
> >
> blobs&data=05%7C02%7Cnicklew%40nvidia.com%7Cb327966e846243687
> 65
> >
> 208dc29010a98%7C43083d15727340c1b7db39efd9ccc17a%7C0%7C0%7C
> 63
> >
> 8430331675551644%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAw
> MD
> >
> AiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%7C%7C&s
> da
> > ta=WdwXQUKvHs3bv4KI9rbvvvQ3jJOFlWRhBczJAke9vL0%3D&reserved=0
> > > +
> > > +## 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


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



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [edk2-devel] [edk2-platforms][PATCH] ManageabilityPkg: add support for the phosphor ipmi blob transfer protocol
  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
  0 siblings, 1 reply; 20+ messages in thread
From: Nhi Pham via groups.io @ 2024-05-13  9:02 UTC (permalink / raw)
  To: devel, abner.chang, Nickle Wang, Rebecca Cran
  Cc: Isaac Oram, Attar, AbdulLateef (Abdul Lateef), Tinh Nguyen

On 2/9/2024 11:37 PM, Chang, Abner via groups.io wrote:
> [AMD Official Use Only - General]
> 
> Yeah, I forget this patch set and seems we don't have any follow up conversation after below feedbacks from community.
> 
> https://edk2.groups.io/g/devel/message/103116
> https://edk2.groups.io/g/devel/message/103087
> 
> So Nickle, does NV still has the plan to upstream IPMI blob edk2 implementation? We should keep driving upstream the implementation as industry needs it to incorporate with OpenBMC.
> 
> Hi Rebessa,
> As we are on Chinese New Year holidays now, please expect the delay response.
> Thanks
> Abner
> 

Hi Nickle and Abner,

May I know the status of upstreaming the IPMI Blob Transfer Protocol? 
I'm planning to upstream the SMBIOS transfer to OpenBMC by leveraging 
this protocol.

Thanks,
Nhi


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



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [edk2-devel] [edk2-platforms][PATCH] ManageabilityPkg: add support for the phosphor ipmi blob transfer protocol
  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
  0 siblings, 1 reply; 20+ messages in thread
From: Nickle Wang via groups.io @ 2024-05-14  1:56 UTC (permalink / raw)
  To: Nhi Pham, devel@edk2.groups.io, abner.chang@amd.com, Rebecca Cran
  Cc: Isaac Oram, Attar, AbdulLateef (Abdul Lateef), Tinh Nguyen

Hi Nhi,

This task is on my list but with lower priority. I will try to provide version 2 patch for review here by the end of this week. 

Thanks,
Nickle

> -----Original Message-----
> From: Nhi Pham <nhi@os.amperecomputing.com>
> Sent: Monday, May 13, 2024 5:02 PM
> To: devel@edk2.groups.io; abner.chang@amd.com; Nickle Wang
> <nicklew@nvidia.com>; Rebecca Cran <rebecca@bsdio.com>
> Cc: Isaac Oram <isaac.w.oram@intel.com>; Attar, AbdulLateef (Abdul Lateef)
> <AbdulLateef.Attar@amd.com>; Tinh Nguyen
> <tinhnguyen@amperemail.onmicrosoft.com>
> Subject: Re: [edk2-devel] [edk2-platforms][PATCH] ManageabilityPkg: add
> support for the phosphor ipmi blob transfer protocol
> 
> External email: Use caution opening links or attachments
> 
> 
> On 2/9/2024 11:37 PM, Chang, Abner via groups.io wrote:
> > [AMD Official Use Only - General]
> >
> > Yeah, I forget this patch set and seems we don't have any follow up conversation
> after below feedbacks from community.
> >
> > https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fedk2
> > .groups.io%2Fg%2Fdevel%2Fmessage%2F103116&data=05%7C02%7Cnicklew
> %40nvi
> >
> dia.com%7C8b9e1a8a8d044208f8d608dc732b678d%7C43083d15727340c1b7db
> 39efd
> >
> 9ccc17a%7C0%7C0%7C638511877469561600%7CUnknown%7CTWFpbGZsb3d8
> eyJWIjoiM
> >
> C4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%7
> C%7C
> > &sdata=N4eDH668lBSFxq9r81QrhMgpULvht8isrrEI9lipVKc%3D&reserved=0
> > https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fedk2
> > .groups.io%2Fg%2Fdevel%2Fmessage%2F103087&data=05%7C02%7Cnicklew
> %40nvi
> >
> dia.com%7C8b9e1a8a8d044208f8d608dc732b678d%7C43083d15727340c1b7db
> 39efd
> >
> 9ccc17a%7C0%7C0%7C638511877469569817%7CUnknown%7CTWFpbGZsb3d8
> eyJWIjoiM
> >
> C4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%7
> C%7C
> >
> &sdata=7p0BHb8RFRapFyygr35u0hQBK2bQwKPSypBaUi6cMIQ%3D&reserved=0
> >
> > So Nickle, does NV still has the plan to upstream IPMI blob edk2
> implementation? We should keep driving upstream the implementation as
> industry needs it to incorporate with OpenBMC.
> >
> > Hi Rebessa,
> > As we are on Chinese New Year holidays now, please expect the delay response.
> > Thanks
> > Abner
> >
> 
> Hi Nickle and Abner,
> 
> May I know the status of upstreaming the IPMI Blob Transfer Protocol?
> I'm planning to upstream the SMBIOS transfer to OpenBMC by leveraging this
> protocol.
> 
> Thanks,
> Nhi


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



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [edk2-devel] [edk2-platforms][PATCH] ManageabilityPkg: add support for the phosphor ipmi blob transfer protocol
  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
  0 siblings, 1 reply; 20+ messages in thread
From: Nhi Pham via groups.io @ 2024-05-14  2:25 UTC (permalink / raw)
  To: Nickle Wang, devel@edk2.groups.io, abner.chang@amd.com,
	Rebecca Cran
  Cc: Isaac Oram, Attar, AbdulLateef (Abdul Lateef), Tinh Nguyen

Thanks Nickle. I will help review and verify your patch.

On 5/14/2024 8:56 AM, Nickle Wang wrote:
> Hi Nhi,
> 
> This task is on my list but with lower priority. I will try to provide version 2 patch for review here by the end of this week.
> 
> Thanks,
> Nickle
> 
>> -----Original Message-----
>> From: Nhi Pham <nhi@os.amperecomputing.com>
>> Sent: Monday, May 13, 2024 5:02 PM
>> To: devel@edk2.groups.io; abner.chang@amd.com; Nickle Wang
>> <nicklew@nvidia.com>; Rebecca Cran <rebecca@bsdio.com>
>> Cc: Isaac Oram <isaac.w.oram@intel.com>; Attar, AbdulLateef (Abdul Lateef)
>> <AbdulLateef.Attar@amd.com>; Tinh Nguyen
>> <tinhnguyen@amperemail.onmicrosoft.com>
>> Subject: Re: [edk2-devel] [edk2-platforms][PATCH] ManageabilityPkg: add
>> support for the phosphor ipmi blob transfer protocol
>>
>> External email: Use caution opening links or attachments
>>
>>
>> On 2/9/2024 11:37 PM, Chang, Abner via groups.io wrote:
>>> [AMD Official Use Only - General]
>>>
>>> Yeah, I forget this patch set and seems we don't have any follow up conversation
>> after below feedbacks from community.
>>>
>>> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fedk2
>>> .groups.io%2Fg%2Fdevel%2Fmessage%2F103116&data=05%7C02%7Cnicklew
>> %40nvi
>>>
>> dia.com%7C8b9e1a8a8d044208f8d608dc732b678d%7C43083d15727340c1b7db
>> 39efd
>>>
>> 9ccc17a%7C0%7C0%7C638511877469561600%7CUnknown%7CTWFpbGZsb3d8
>> eyJWIjoiM
>>>
>> C4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%7
>> C%7C
>>> &sdata=N4eDH668lBSFxq9r81QrhMgpULvht8isrrEI9lipVKc%3D&reserved=0
>>> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fedk2
>>> .groups.io%2Fg%2Fdevel%2Fmessage%2F103087&data=05%7C02%7Cnicklew
>> %40nvi
>>>
>> dia.com%7C8b9e1a8a8d044208f8d608dc732b678d%7C43083d15727340c1b7db
>> 39efd
>>>
>> 9ccc17a%7C0%7C0%7C638511877469569817%7CUnknown%7CTWFpbGZsb3d8
>> eyJWIjoiM
>>>
>> C4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%7
>> C%7C
>>>
>> &sdata=7p0BHb8RFRapFyygr35u0hQBK2bQwKPSypBaUi6cMIQ%3D&reserved=0
>>>
>>> So Nickle, does NV still has the plan to upstream IPMI blob edk2
>> implementation? We should keep driving upstream the implementation as
>> industry needs it to incorporate with OpenBMC.
>>>
>>> Hi Rebessa,
>>> As we are on Chinese New Year holidays now, please expect the delay response.
>>> Thanks
>>> Abner
>>>
>>
>> Hi Nickle and Abner,
>>
>> May I know the status of upstreaming the IPMI Blob Transfer Protocol?
>> I'm planning to upstream the SMBIOS transfer to OpenBMC by leveraging this
>> protocol.
>>
>> Thanks,
>> Nhi


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



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [edk2-devel] [edk2-platforms][PATCH] ManageabilityPkg: add support for the phosphor ipmi blob transfer protocol
  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
  0 siblings, 1 reply; 20+ messages in thread
From: Nickle Wang via groups.io @ 2024-05-15 15:14 UTC (permalink / raw)
  To: Nhi Pham, devel@edk2.groups.io, abner.chang@amd.com, Rebecca Cran
  Cc: Isaac Oram, Attar, AbdulLateef (Abdul Lateef), Tinh Nguyen

Hi Nhi,

Version 2 patch files are sent for review here: https://edk2.groups.io/g/devel/message/118914 and https://edk2.groups.io/g/devel/message/118922

For your convenience, below are two pull requests if you would like to test them.

1) https://github.com/tianocore/edk2/pull/5660
2) https://github.com/tianocore/edk2-platforms/pull/76

I had tried to address review comments as much as I can. Please feel free to let me know if you see any issue in this version of patch set.

Thanks,
Nickle

> -----Original Message-----
> From: Nhi Pham <nhi@os.amperecomputing.com>
> Sent: Tuesday, May 14, 2024 10:26 AM
> To: Nickle Wang <nicklew@nvidia.com>; devel@edk2.groups.io;
> abner.chang@amd.com; Rebecca Cran <rebecca@bsdio.com>
> Cc: Isaac Oram <isaac.w.oram@intel.com>; Attar, AbdulLateef (Abdul Lateef)
> <AbdulLateef.Attar@amd.com>; Tinh Nguyen
> <tinhnguyen@amperemail.onmicrosoft.com>
> Subject: Re: [edk2-devel] [edk2-platforms][PATCH] ManageabilityPkg: add
> support for the phosphor ipmi blob transfer protocol
> 
> External email: Use caution opening links or attachments
> 
> 
> Thanks Nickle. I will help review and verify your patch.
> 
> On 5/14/2024 8:56 AM, Nickle Wang wrote:
> > Hi Nhi,
> >
> > This task is on my list but with lower priority. I will try to provide version 2 patch
> for review here by the end of this week.
> >
> > Thanks,
> > Nickle
> >
> >> -----Original Message-----
> >> From: Nhi Pham <nhi@os.amperecomputing.com>
> >> Sent: Monday, May 13, 2024 5:02 PM
> >> To: devel@edk2.groups.io; abner.chang@amd.com; Nickle Wang
> >> <nicklew@nvidia.com>; Rebecca Cran <rebecca@bsdio.com>
> >> Cc: Isaac Oram <isaac.w.oram@intel.com>; Attar, AbdulLateef (Abdul
> >> Lateef) <AbdulLateef.Attar@amd.com>; Tinh Nguyen
> >> <tinhnguyen@amperemail.onmicrosoft.com>
> >> Subject: Re: [edk2-devel] [edk2-platforms][PATCH] ManageabilityPkg:
> >> add support for the phosphor ipmi blob transfer protocol
> >>
> >> External email: Use caution opening links or attachments
> >>
> >>
> >> On 2/9/2024 11:37 PM, Chang, Abner via groups.io wrote:
> >>> [AMD Official Use Only - General]
> >>>
> >>> Yeah, I forget this patch set and seems we don't have any follow up
> >>> conversation
> >> after below feedbacks from community.
> >>>
> >>> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fed
> >>>
> k2%2F&data=05%7C02%7Cnicklew%40nvidia.com%7Cdc53be8f0cf24ccfd35108d
> c
> >>>
> 73bd2d45%7C43083d15727340c1b7db39efd9ccc17a%7C0%7C0%7C6385125035
> 6068
> >>>
> 8708%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIi
> LCJ
> >>>
> BTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%7C%7C&sdata=%2BCkaU%2FcdG1v
> r6uPsA
> >>> 7fqrvhvxg%2FX5FqcmJ6fizaa9fA%3D&reserved=0
> >>> .groups.io%2Fg%2Fdevel%2Fmessage%2F103116&data=05%7C02%7Cnickle
> w
> >> %40nvi
> >>>
> >>
> dia.com%7C8b9e1a8a8d044208f8d608dc732b678d%7C43083d15727340c1b7db
> >> 39efd
> >>>
> >>
> 9ccc17a%7C0%7C0%7C638511877469561600%7CUnknown%7CTWFpbGZsb3d8
> >> eyJWIjoiM
> >>>
> >>
> C4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%7
> >> C%7C
> >>> &sdata=N4eDH668lBSFxq9r81QrhMgpULvht8isrrEI9lipVKc%3D&reserved=0
> >>> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fed
> >>>
> k2%2F&data=05%7C02%7Cnicklew%40nvidia.com%7Cdc53be8f0cf24ccfd35108d
> c
> >>>
> 73bd2d45%7C43083d15727340c1b7db39efd9ccc17a%7C0%7C0%7C6385125035
> 6070
> >>>
> 0897%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIi
> LCJ
> >>>
> BTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%7C%7C&sdata=KFd86NhmrQeGqEB
> 8%2FJy
> >>> 0qnbMkb%2Furpo8YCsVbVsOxNk%3D&reserved=0
> >>> .groups.io%2Fg%2Fdevel%2Fmessage%2F103087&data=05%7C02%7Cnickle
> w
> >> %40nvi
> >>>
> >>
> dia.com%7C8b9e1a8a8d044208f8d608dc732b678d%7C43083d15727340c1b7db
> >> 39efd
> >>>
> >>
> 9ccc17a%7C0%7C0%7C638511877469569817%7CUnknown%7CTWFpbGZsb3d8
> >> eyJWIjoiM
> >>>
> >>
> C4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%7
> >> C%7C
> >>>
> >>
> &sdata=7p0BHb8RFRapFyygr35u0hQBK2bQwKPSypBaUi6cMIQ%3D&reserved=0
> >>>
> >>> So Nickle, does NV still has the plan to upstream IPMI blob edk2
> >> implementation? We should keep driving upstream the implementation as
> >> industry needs it to incorporate with OpenBMC.
> >>>
> >>> Hi Rebessa,
> >>> As we are on Chinese New Year holidays now, please expect the delay
> response.
> >>> Thanks
> >>> Abner
> >>>
> >>
> >> Hi Nickle and Abner,
> >>
> >> May I know the status of upstreaming the IPMI Blob Transfer Protocol?
> >> I'm planning to upstream the SMBIOS transfer to OpenBMC by leveraging
> >> this protocol.
> >>
> >> Thanks,
> >> Nhi


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



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [edk2-devel] [edk2-platforms][PATCH] ManageabilityPkg: add support for the phosphor ipmi blob transfer protocol
  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
  0 siblings, 1 reply; 20+ messages in thread
From: Nhi Pham via groups.io @ 2024-05-16  8:39 UTC (permalink / raw)
  To: devel, nicklew, abner.chang@amd.com, Rebecca Cran
  Cc: Isaac Oram, Attar, AbdulLateef (Abdul Lateef), Tinh Nguyen

Thanks Nickle. I'm reviewing and testing it. Will get back to you soon.

On 5/15/2024 10:14 PM, Nickle Wang via groups.io wrote:
> Hi Nhi,
> 
> Version 2 patch files are sent for review here: https://edk2.groups.io/g/devel/message/118914 and https://edk2.groups.io/g/devel/message/118922
> 
> For your convenience, below are two pull requests if you would like to test them.
> 
> 1) https://github.com/tianocore/edk2/pull/5660
> 2) https://github.com/tianocore/edk2-platforms/pull/76
> 
> I had tried to address review comments as much as I can. Please feel free to let me know if you see any issue in this version of patch set.
> 
> Thanks,
> Nickle
> 
>> -----Original Message-----
>> From: Nhi Pham <nhi@os.amperecomputing.com>
>> Sent: Tuesday, May 14, 2024 10:26 AM
>> To: Nickle Wang <nicklew@nvidia.com>; devel@edk2.groups.io;
>> abner.chang@amd.com; Rebecca Cran <rebecca@bsdio.com>
>> Cc: Isaac Oram <isaac.w.oram@intel.com>; Attar, AbdulLateef (Abdul Lateef)
>> <AbdulLateef.Attar@amd.com>; Tinh Nguyen
>> <tinhnguyen@amperemail.onmicrosoft.com>
>> Subject: Re: [edk2-devel] [edk2-platforms][PATCH] ManageabilityPkg: add
>> support for the phosphor ipmi blob transfer protocol
>>
>> External email: Use caution opening links or attachments
>>
>>
>> Thanks Nickle. I will help review and verify your patch.
>>
>> On 5/14/2024 8:56 AM, Nickle Wang wrote:
>>> Hi Nhi,
>>>
>>> This task is on my list but with lower priority. I will try to provide version 2 patch
>> for review here by the end of this week.
>>>
>>> Thanks,
>>> Nickle
>>>
>>>> -----Original Message-----
>>>> From: Nhi Pham <nhi@os.amperecomputing.com>
>>>> Sent: Monday, May 13, 2024 5:02 PM
>>>> To: devel@edk2.groups.io; abner.chang@amd.com; Nickle Wang
>>>> <nicklew@nvidia.com>; Rebecca Cran <rebecca@bsdio.com>
>>>> Cc: Isaac Oram <isaac.w.oram@intel.com>; Attar, AbdulLateef (Abdul
>>>> Lateef) <AbdulLateef.Attar@amd.com>; Tinh Nguyen
>>>> <tinhnguyen@amperemail.onmicrosoft.com>
>>>> Subject: Re: [edk2-devel] [edk2-platforms][PATCH] ManageabilityPkg:
>>>> add support for the phosphor ipmi blob transfer protocol
>>>>
>>>> External email: Use caution opening links or attachments
>>>>
>>>>
>>>> On 2/9/2024 11:37 PM, Chang, Abner via groups.io wrote:
>>>>> [AMD Official Use Only - General]
>>>>>
>>>>> Yeah, I forget this patch set and seems we don't have any follow up
>>>>> conversation
>>>> after below feedbacks from community.
>>>>>
>>>>> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fed
>>>>>
>> k2%2F&data=05%7C02%7Cnicklew%40nvidia.com%7Cdc53be8f0cf24ccfd35108d
>> c
>>>>>
>> 73bd2d45%7C43083d15727340c1b7db39efd9ccc17a%7C0%7C0%7C6385125035
>> 6068
>>>>>
>> 8708%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIi
>> LCJ
>>>>>
>> BTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%7C%7C&sdata=%2BCkaU%2FcdG1v
>> r6uPsA
>>>>> 7fqrvhvxg%2FX5FqcmJ6fizaa9fA%3D&reserved=0
>>>>> .groups.io%2Fg%2Fdevel%2Fmessage%2F103116&data=05%7C02%7Cnickle
>> w
>>>> %40nvi
>>>>>
>>>>
>> dia.com%7C8b9e1a8a8d044208f8d608dc732b678d%7C43083d15727340c1b7db
>>>> 39efd
>>>>>
>>>>
>> 9ccc17a%7C0%7C0%7C638511877469561600%7CUnknown%7CTWFpbGZsb3d8
>>>> eyJWIjoiM
>>>>>
>>>>
>> C4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%7
>>>> C%7C
>>>>> &sdata=N4eDH668lBSFxq9r81QrhMgpULvht8isrrEI9lipVKc%3D&reserved=0
>>>>> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fed
>>>>>
>> k2%2F&data=05%7C02%7Cnicklew%40nvidia.com%7Cdc53be8f0cf24ccfd35108d
>> c
>>>>>
>> 73bd2d45%7C43083d15727340c1b7db39efd9ccc17a%7C0%7C0%7C6385125035
>> 6070
>>>>>
>> 0897%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIi
>> LCJ
>>>>>
>> BTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%7C%7C&sdata=KFd86NhmrQeGqEB
>> 8%2FJy
>>>>> 0qnbMkb%2Furpo8YCsVbVsOxNk%3D&reserved=0
>>>>> .groups.io%2Fg%2Fdevel%2Fmessage%2F103087&data=05%7C02%7Cnickle
>> w
>>>> %40nvi
>>>>>
>>>>
>> dia.com%7C8b9e1a8a8d044208f8d608dc732b678d%7C43083d15727340c1b7db
>>>> 39efd
>>>>>
>>>>
>> 9ccc17a%7C0%7C0%7C638511877469569817%7CUnknown%7CTWFpbGZsb3d8
>>>> eyJWIjoiM
>>>>>
>>>>
>> C4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%7
>>>> C%7C
>>>>>
>>>>
>> &sdata=7p0BHb8RFRapFyygr35u0hQBK2bQwKPSypBaUi6cMIQ%3D&reserved=0
>>>>>
>>>>> So Nickle, does NV still has the plan to upstream IPMI blob edk2
>>>> implementation? We should keep driving upstream the implementation as
>>>> industry needs it to incorporate with OpenBMC.
>>>>>
>>>>> Hi Rebessa,
>>>>> As we are on Chinese New Year holidays now, please expect the delay
>> response.
>>>>> Thanks
>>>>> Abner
>>>>>
>>>>
>>>> Hi Nickle and Abner,
>>>>
>>>> May I know the status of upstreaming the IPMI Blob Transfer Protocol?
>>>> I'm planning to upstream the SMBIOS transfer to OpenBMC by leveraging
>>>> this protocol.
>>>>
>>>> Thanks,
>>>> Nhi
> 
> 
> 
> 
> 


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



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [edk2-devel] [edk2-platforms][PATCH] ManageabilityPkg: add support for the phosphor ipmi blob transfer protocol
  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
  0 siblings, 1 reply; 20+ messages in thread
From: Chang, Abner via groups.io @ 2024-05-16  8:44 UTC (permalink / raw)
  To: Nhi Pham, devel@edk2.groups.io, nicklew@nvidia.com, Rebecca Cran
  Cc: Isaac Oram, Attar, AbdulLateef (Abdul Lateef), Tinh Nguyen

[AMD Official Use Only - AMD Internal Distribution Only]

Hi Nhi,
Are you using SSIF as the transport interface based on the ManabeabilityPkg framework? If yes, will you contribute that driver?

Thanks
Abner

> -----Original Message-----
> From: Nhi Pham <nhi@os.amperecomputing.com>
> Sent: Thursday, May 16, 2024 4:40 PM
> To: devel@edk2.groups.io; nicklew@nvidia.com; Chang, Abner
> <Abner.Chang@amd.com>; Rebecca Cran <rebecca@bsdio.com>
> Cc: Isaac Oram <isaac.w.oram@intel.com>; Attar, AbdulLateef (Abdul Lateef)
> <AbdulLateef.Attar@amd.com>; Tinh Nguyen
> <tinhnguyen@amperemail.onmicrosoft.com>
> Subject: Re: [edk2-devel] [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.
>
>
> Thanks Nickle. I'm reviewing and testing it. Will get back to you soon.
>
> On 5/15/2024 10:14 PM, Nickle Wang via groups.io wrote:
> > Hi Nhi,
> >
> > Version 2 patch files are sent for review here:
> https://edk2.groups.io/g/devel/message/118914 and
> https://edk2.groups.io/g/devel/message/118922
> >
> > For your convenience, below are two pull requests if you would like to test
> them.
> >
> > 1) https://github.com/tianocore/edk2/pull/5660
> > 2) https://github.com/tianocore/edk2-platforms/pull/76
> >
> > I had tried to address review comments as much as I can. Please feel free to
> let me know if you see any issue in this version of patch set.
> >
> > Thanks,
> > Nickle
> >
> >> -----Original Message-----
> >> From: Nhi Pham <nhi@os.amperecomputing.com>
> >> Sent: Tuesday, May 14, 2024 10:26 AM
> >> To: Nickle Wang <nicklew@nvidia.com>; devel@edk2.groups.io;
> >> abner.chang@amd.com; Rebecca Cran <rebecca@bsdio.com>
> >> Cc: Isaac Oram <isaac.w.oram@intel.com>; Attar, AbdulLateef (Abdul
> Lateef)
> >> <AbdulLateef.Attar@amd.com>; Tinh Nguyen
> >> <tinhnguyen@amperemail.onmicrosoft.com>
> >> Subject: Re: [edk2-devel] [edk2-platforms][PATCH] ManageabilityPkg: add
> >> support for the phosphor ipmi blob transfer protocol
> >>
> >> External email: Use caution opening links or attachments
> >>
> >>
> >> Thanks Nickle. I will help review and verify your patch.
> >>
> >> On 5/14/2024 8:56 AM, Nickle Wang wrote:
> >>> Hi Nhi,
> >>>
> >>> This task is on my list but with lower priority. I will try to provide version 2
> patch
> >> for review here by the end of this week.
> >>>
> >>> Thanks,
> >>> Nickle
> >>>
> >>>> -----Original Message-----
> >>>> From: Nhi Pham <nhi@os.amperecomputing.com>
> >>>> Sent: Monday, May 13, 2024 5:02 PM
> >>>> To: devel@edk2.groups.io; abner.chang@amd.com; Nickle Wang
> >>>> <nicklew@nvidia.com>; Rebecca Cran <rebecca@bsdio.com>
> >>>> Cc: Isaac Oram <isaac.w.oram@intel.com>; Attar, AbdulLateef (Abdul
> >>>> Lateef) <AbdulLateef.Attar@amd.com>; Tinh Nguyen
> >>>> <tinhnguyen@amperemail.onmicrosoft.com>
> >>>> Subject: Re: [edk2-devel] [edk2-platforms][PATCH] ManageabilityPkg:
> >>>> add support for the phosphor ipmi blob transfer protocol
> >>>>
> >>>> External email: Use caution opening links or attachments
> >>>>
> >>>>
> >>>> On 2/9/2024 11:37 PM, Chang, Abner via groups.io wrote:
> >>>>> [AMD Official Use Only - General]
> >>>>>
> >>>>> Yeah, I forget this patch set and seems we don't have any follow up
> >>>>> conversation
> >>>> after below feedbacks from community.
> >>>>>
> >>>>>
> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fed
> >>>>>
> >>
> k2%2F&data=05%7C02%7Cnicklew%40nvidia.com%7Cdc53be8f0cf24ccfd35
> 108d
> >> c
> >>>>>
> >>
> 73bd2d45%7C43083d15727340c1b7db39efd9ccc17a%7C0%7C0%7C63851
> 25035
> >> 6068
> >>>>>
> >>
> 8708%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2l
> uMzIi
> >> LCJ
> >>>>>
> >>
> BTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%7C%7C&sdata=%2BCkaU%2Fcd
> G1v
> >> r6uPsA
> >>>>> 7fqrvhvxg%2FX5FqcmJ6fizaa9fA%3D&reserved=0
> >>>>> .groups.io%2Fg%2Fdevel%2Fmessage%2F103116&data=05%7C02%7
> Cnickle
> >> w
> >>>> %40nvi
> >>>>>
> >>>>
> >>
> dia.com%7C8b9e1a8a8d044208f8d608dc732b678d%7C43083d15727340c
> 1b7db
> >>>> 39efd
> >>>>>
> >>>>
> >>
> 9ccc17a%7C0%7C0%7C638511877469561600%7CUnknown%7CTWFpbGZs
> b3d8
> >>>> eyJWIjoiM
> >>>>>
> >>>>
> >>
> C4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7
> C%7
> >>>> C%7C
> >>>>>
> &sdata=N4eDH668lBSFxq9r81QrhMgpULvht8isrrEI9lipVKc%3D&reserved=0
> >>>>>
> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fed
> >>>>>
> >>
> k2%2F&data=05%7C02%7Cnicklew%40nvidia.com%7Cdc53be8f0cf24ccfd35
> 108d
> >> c
> >>>>>
> >>
> 73bd2d45%7C43083d15727340c1b7db39efd9ccc17a%7C0%7C0%7C63851
> 25035
> >> 6070
> >>>>>
> >>
> 0897%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2l
> uMzIi
> >> LCJ
> >>>>>
> >>
> BTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%7C%7C&sdata=KFd86NhmrQeG
> qEB
> >> 8%2FJy
> >>>>> 0qnbMkb%2Furpo8YCsVbVsOxNk%3D&reserved=0
> >>>>> .groups.io%2Fg%2Fdevel%2Fmessage%2F103087&data=05%7C02%7
> Cnickle
> >> w
> >>>> %40nvi
> >>>>>
> >>>>
> >>
> dia.com%7C8b9e1a8a8d044208f8d608dc732b678d%7C43083d15727340c
> 1b7db
> >>>> 39efd
> >>>>>
> >>>>
> >>
> 9ccc17a%7C0%7C0%7C638511877469569817%7CUnknown%7CTWFpbGZs
> b3d8
> >>>> eyJWIjoiM
> >>>>>
> >>>>
> >>
> C4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7
> C%7
> >>>> C%7C
> >>>>>
> >>>>
> >>
> &sdata=7p0BHb8RFRapFyygr35u0hQBK2bQwKPSypBaUi6cMIQ%3D&reserve
> d=0
> >>>>>
> >>>>> So Nickle, does NV still has the plan to upstream IPMI blob edk2
> >>>> implementation? We should keep driving upstream the implementation
> as
> >>>> industry needs it to incorporate with OpenBMC.
> >>>>>
> >>>>> Hi Rebessa,
> >>>>> As we are on Chinese New Year holidays now, please expect the delay
> >> response.
> >>>>> Thanks
> >>>>> Abner
> >>>>>
> >>>>
> >>>> Hi Nickle and Abner,
> >>>>
> >>>> May I know the status of upstreaming the IPMI Blob Transfer Protocol?
> >>>> I'm planning to upstream the SMBIOS transfer to OpenBMC by leveraging
> >>>> this protocol.
> >>>>
> >>>> Thanks,
> >>>> Nhi
> >
> >
> > 
> >
> >


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



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [edk2-devel] [edk2-platforms][PATCH] ManageabilityPkg: add support for the phosphor ipmi blob transfer protocol
  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
  0 siblings, 1 reply; 20+ messages in thread
From: Nhi Pham via groups.io @ 2024-05-16  8:49 UTC (permalink / raw)
  To: Chang, Abner, devel@edk2.groups.io, nicklew@nvidia.com,
	Rebecca Cran
  Cc: Isaac Oram, Attar, AbdulLateef (Abdul Lateef), Tinh Nguyen

On 5/16/2024 3:44 PM, Chang, Abner wrote:
> [AMD Official Use Only - AMD Internal Distribution Only]
> 
> Hi Nhi,
> Are you using SSIF as the transport interface based on the ManabeabilityPkg framework? If yes, will you contribute that driver?
> 

yes, we are. I will need to update the SSIF driver to be compatible with 
the ManabeabilityPkg and upstream it.

Regards,
Nhi


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



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [edk2-devel] [edk2-platforms][PATCH] ManageabilityPkg: add support for the phosphor ipmi blob transfer protocol
  2024-05-16  8:49                   ` Nhi Pham via groups.io
@ 2024-05-16  8:53                     ` Chang, Abner via groups.io
  0 siblings, 0 replies; 20+ messages in thread
From: Chang, Abner via groups.io @ 2024-05-16  8:53 UTC (permalink / raw)
  To: Nhi Pham, devel@edk2.groups.io, nicklew@nvidia.com, Rebecca Cran
  Cc: Isaac Oram, Attar, AbdulLateef (Abdul Lateef), Tinh Nguyen

[AMD Official Use Only - AMD Internal Distribution Only]

That is awesome!  Thank you!

Abner

> -----Original Message-----
> From: Nhi Pham <nhi@os.amperecomputing.com>
> Sent: Thursday, May 16, 2024 4:50 PM
> To: Chang, Abner <Abner.Chang@amd.com>; devel@edk2.groups.io;
> nicklew@nvidia.com; Rebecca Cran <rebecca@bsdio.com>
> Cc: Isaac Oram <isaac.w.oram@intel.com>; Attar, AbdulLateef (Abdul Lateef)
> <AbdulLateef.Attar@amd.com>; Tinh Nguyen
> <tinhnguyen@amperemail.onmicrosoft.com>
> Subject: Re: [edk2-devel] [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 5/16/2024 3:44 PM, Chang, Abner wrote:
> > [AMD Official Use Only - AMD Internal Distribution Only]
> >
> > Hi Nhi,
> > Are you using SSIF as the transport interface based on the ManabeabilityPkg
> framework? If yes, will you contribute that driver?
> >
>
> yes, we are. I will need to update the SSIF driver to be compatible with
> the ManabeabilityPkg and upstream it.
>
> Regards,
> Nhi


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



^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2024-05-16  8:53 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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
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

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox