<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body style="overflow-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;">
<br>
<div><br>
<blockquote type="cite">
<div>On 16 Apr 2023, at 17:28, Tinh Nguyen via groups.io <tinhnguyen=os.amperecomputing.com@groups.io> wrote:</div>
<br class="Apple-interchange-newline">
<div><span style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;">Hi
 Nickle,</span><br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;">
<br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;">
<span style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;">Please
 find my inline comments below</span><br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;">
<br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;">
<span style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;">On
 4/12/2023 10:17 AM, Nickle Wang wrote:</span><br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;">
<blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;">
[EXTERNAL EMAIL NOTICE: This email originated from an external sender. Please be mindful of safe email handling and proprietary information protection practices.]<br>
<br>
<br>
This change implements the blob transfer protocol used in OpenBmc<br>
documented here: https://github.com/openbmc/phosphor-ipmi-blobs<br>
<br>
Signed-off-by: Nick Ramirez <nramirez@nvidia.com><br>
Cc: Abner Chang <abner.chang@amd.com><br>
Cc: Isaac Oram <isaac.w.oram@intel.com><br>
Cc: Abdul Lateef Attar <AbdulLateef.Attar@amd.com><br>
Cc: Nickle Wang <nicklew@nvidia.com><br>
Cc: Tinh Nguyen <tinhnguyen@amperemail.onmicrosoft.com><br>
---<br>
 .../ManageabilityPkg/ManageabilityPkg.dec     |    6 +<br>
 .../Include/Dsc/Manageability.dsc             |    4 +-<br>
 .../IpmiBlobTransferDxe.inf                   |   39 +<br>
 .../IpmiBlobTransferTestUnitTestsHost.inf     |   40 +<br>
 .../Include/Protocol/IpmiBlobTransfer.h       |  136 ++<br>
 .../InternalIpmiBlobTransfer.h                |  363 ++++++<br>
 .../IpmiBlobTransferDxe/IpmiBlobTransferDxe.c |  799 ++++++++++++<br>
 .../UnitTest/IpmiBlobTransferTestUnitTests.c  | 1113 +++++++++++++++++<br>
 .../Universal/IpmiBlobTransferDxe/Readme.md   |   24 +<br>
 9 files changed, 2523 insertions(+), 1 deletion(-)<br>
 create mode 100644 Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.inf<br>
 create mode 100644 Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTestsHost.inf<br>
 create mode 100644 Features/ManageabilityPkg/Include/Protocol/IpmiBlobTransfer.h<br>
 create mode 100644 Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiBlobTransfer.h<br>
 create mode 100644 Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.c<br>
 create mode 100644 Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTests.c<br>
 create mode 100644 Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/Readme.md<br>
<br>
diff --git a/Features/ManageabilityPkg/ManageabilityPkg.dec b/Features/ManageabilityPkg/ManageabilityPkg.dec<br>
index 9a930d3e4b..e2d6cccc50 100644<br>
--- a/Features/ManageabilityPkg/ManageabilityPkg.dec<br>
+++ b/Features/ManageabilityPkg/ManageabilityPkg.dec<br>
@@ -4,6 +4,7 @@<br>
 # those are related to the platform management.<br>
 #<br>
 # Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.<BR><br>
+# Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.<br>
 # SPDX-License-Identifier: BSD-2-Clause-Patent<br>
 #<br>
 ##<br>
@@ -48,3 +49,8 @@<br>
   gManageabilityProtocolMctpGuid    = { 0x76FED8F1, 0x0BE5, 0x4269, { 0xA3, 0x1A, 0x38, 0x0F, 0x54, 0xF1, 0xA1, 0x8A } }<br>
   # Manageability Protocol PLDM<br>
   gManageabilityProtocolPldmGuid    = { 0x3958090D, 0x69DD, 0x4868, { 0x9C, 0x41, 0xC9, 0xAC, 0x31, 0xB5, 0x25, 0xC5 } }<br>
+<br>
+[Protocols]<br>
+<br>
+  ## Include/Protocol/IpmiBlobTransfer.h<br>
+  gEdkiiIpmiBlobTransferProtocolGuid = { 0x05837c75, 0x1d65, 0x468b, { 0xb1, 0xc2, 0x81, 0xaf, 0x9a, 0x31, 0x5b, 0x2c } }<br>
diff --git a/Features/ManageabilityPkg/Include/Dsc/Manageability.dsc b/Features/ManageabilityPkg/Include/Dsc/Manageability.dsc<br>
index 0d868fdf4a..111d6b91dc 100644<br>
--- a/Features/ManageabilityPkg/Include/Dsc/Manageability.dsc<br>
+++ b/Features/ManageabilityPkg/Include/Dsc/Manageability.dsc<br>
@@ -2,11 +2,13 @@<br>
 # Common libraries for Manageabilty Package<br>
 #<br>
 # Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.<BR><br>
+# Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.<br>
 # SPDX-License-Identifier: BSD-2-Clause-Patent<br>
 #<br>
 ##<br>
 [LibraryClasses]<br>
   ManageabilityTransportHelperLib|ManageabilityPkg/Library/BaseManageabilityTransportHelperLib/BaseManageabilityTransportHelper.inf<br>
+  IpmiLib|MdeModulePkg/Library/DxeIpmiLibIpmiProtocol/DxeIpmiLibIpmiProtocol.inf<br>
<br>
 [LibraryClasses.ARM, LibraryClasses.AARCH64]<br>
   #<br>
@@ -22,4 +24,4 @@<br>
 [Components.X64]<br>
   ManageabilityPkg/Universal/IpmiProtocol/Dxe/IpmiProtocolDxe.inf<br>
   ManageabilityPkg/Universal/IpmiProtocol/Smm/IpmiProtocolSmm.inf<br>
-<br>
+  ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.inf<br>
diff --git a/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.inf b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.inf<br>
new file mode 100644<br>
index 0000000000..28e9d293c1<br>
--- /dev/null<br>
+++ b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.inf<br>
@@ -0,0 +1,39 @@<br>
+## @file<br>
+# IPMI Blob Transfer Protocol DXE Driver.<br>
+#<br>
+#  Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.<br>
+#<br>
+#  SPDX-License-Identifier: BSD-2-Clause-Patent<br>
+#<br>
+<br>
+[Defines]<br>
+  INF_VERSION                    = 0x00010005<br>
+  BASE_NAME                      = IpmiBlobTransferDxe<br>
+  FILE_GUID                      = 6357c804-78bb-4b0c-abdf-c75df942f319<br>
+  MODULE_TYPE                    = DXE_DRIVER<br>
+  VERSION_STRING                 = 1.0<br>
+  ENTRY_POINT                    = IpmiBlobTransferDxeDriverEntryPoint<br>
+<br>
+[Sources.common]<br>
+  IpmiBlobTransferDxe.c<br>
+<br>
+[LibraryClasses]<br>
+  BaseLib<br>
+  BaseMemoryLib<br>
+  DebugLib<br>
+  IpmiLib<br>
+  MemoryAllocationLib<br>
+  PcdLib<br>
+  UefiBootServicesTableLib<br>
+  UefiDriverEntryPoint<br>
+<br>
+[Packages]<br>
+  MdePkg/MdePkg.dec<br>
+  MdeModulePkg/MdeModulePkg.dec<br>
+  ManageabilityPkg/ManageabilityPkg.dec<br>
+<br>
+[Protocols]<br>
+  gEdkiiIpmiBlobTransferProtocolGuid<br>
+<br>
+[Depex]<br>
+  TRUE<br>
diff --git a/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTestsHost.inf b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTestsHost.inf<br>
new file mode 100644<br>
index 0000000000..1f071bbadc<br>
--- /dev/null<br>
+++ b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTestsHost.inf<br>
@@ -0,0 +1,40 @@<br>
+## @file<br>
+# Unit tests of the Ipmi blob transfer driver that are run from a host environment.<br>
+#<br>
+# Copyright (c) 2020-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.<br>
+#<br>
+# SPDX-License-Identifier: BSD-2-Clause-Patent<br>
+##<br>
+<br>
+[Defines]<br>
+  INF_VERSION                    = 0x00010006<br>
+  BASE_NAME                      = IpmiBlobTransferDxeUnitTestsHost<br>
+  FILE_GUID                      = 1f5d4095-ea52-432c-b078-86097fef6004<br>
+  MODULE_TYPE                    = HOST_APPLICATION<br>
+  VERSION_STRING                 = 1.0<br>
+<br>
+#<br>
+# The following information is for reference only<br>
+# and not required by the build tools.<br>
+#<br>
+#  VALID_ARCHITECTURES           = X64<br>
+#<br>
+<br>
+[Sources]<br>
+  IpmiBlobTransferTestUnitTests.c<br>
+<br>
+[Packages]<br>
+  MdePkg/MdePkg.dec<br>
+  MdeModulePkg/MdeModulePkg.dec<br>
+  ManageabilityPkg/ManageabilityPkg.dec<br>
+  UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec<br>
+<br>
+[LibraryClasses]<br>
+  BaseLib<br>
+  BaseMemoryLib<br>
+  DebugLib<br>
+  UnitTestLib<br>
+  IpmiLib<br>
+<br>
+[Protocols]<br>
+  gEdkiiIpmiBlobTransferProtocolGuid<br>
diff --git a/Features/ManageabilityPkg/Include/Protocol/IpmiBlobTransfer.h b/Features/ManageabilityPkg/Include/Protocol/IpmiBlobTransfer.h<br>
new file mode 100644<br>
index 0000000000..8ea71d8816<br>
--- /dev/null<br>
+++ b/Features/ManageabilityPkg/Include/Protocol/IpmiBlobTransfer.h<br>
@@ -0,0 +1,136 @@<br>
+/** @file<br>
+<br>
+  IPMI Blob Transfer driver<br>
+<br>
+  Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.<br>
+<br>
+  SPDX-License-Identifier: BSD-2-Clause-Patent<br>
+<br>
+**/<br>
+#include <Library/IpmiLib.h><br>
+#include <Library/UefiBootServicesTableLib.h><br>
+#include <IndustryStandard/Ipmi.h><br>
+<br>
+#define IPMI_NETFN_OEM                     0x2E<br>
+#define IPMI_OEM_BLOB_TRANSFER_CMD         0x80<br>
+#define IPMI_OEM_BLOB_MAX_DATA_PER_PACKET  64<br>
</blockquote>
<br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;">
<span style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;">It
 is better to avoid fixing the packet size here.</span><br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;">
<br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;">
<span style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;">-
 For ssif, get it from "get capabilities" command. If BMC supports only single-part read/write, this size exceeds BMC capability</span><br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;">
<br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;">
<span style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;">-
 For kcs, I don't see the limitation</span><br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;">
<br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;">
<span style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;">I
 think limiting the size here is unsuitable, applications that use this protocol should check the size themselves</span><br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;">
<br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;">
<blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;">
+<br>
+#define BLOB_TRANSFER_STAT_OPEN_R        BIT0<br>
+#define BLOB_TRANSFER_STAT_OPEN_W        BIT1<br>
+#define BLOB_TRANSFER_STAT_COMMITING     BIT2<br>
+#define BLOB_TRANSFER_STAT_COMMITTED     BIT3<br>
+#define BLOB_TRANSFER_STAT_COMMIT_ERROR  BIT4<br>
+// Bits 5-7 are reserved<br>
+// Bits 8-15 are blob-specific definitions<br>
+<br>
+//<br>
+//  Blob Transfer Function Prototypes<br>
+//<br>
+typedef<br>
+EFI_STATUS<br>
+(EFIAPI *IPMI_BLOB_TRANSFER_PROTOCOL_GET_COUNT)(<br>
+  OUT UINT32 *Count<br>
+  );<br>
+<br>
+typedef<br>
+EFI_STATUS<br>
+(EFIAPI *IPMI_BLOB_TRANSFER_PROTOCOL_ENUMERATE)(<br>
+  IN  UINT32      BlobIndex,<br>
+  OUT CHAR8 *BlobId<br>
+  );<br>
+<br>
+typedef<br>
+EFI_STATUS<br>
+(EFIAPI *IPMI_BLOB_TRANSFER_PROTOCOL_OPEN)(<br>
+  IN  CHAR8 *BlobId,<br>
+  IN  UINT16      Flags,<br>
+  OUT UINT16 *SessionId<br>
+  );<br>
+<br>
+typedef<br>
+EFI_STATUS<br>
+(EFIAPI *IPMI_BLOB_TRANSFER_PROTOCOL_READ)(<br>
+  IN  UINT16      SessionId,<br>
+  IN  UINT32      Offset,<br>
+  IN  UINT32      RequestedSize,<br>
+  OUT UINT8 *Data<br>
+  );<br>
+<br>
+typedef<br>
+EFI_STATUS<br>
+(EFIAPI *IPMI_BLOB_TRANSFER_PROTOCOL_WRITE)(<br>
+  IN  UINT16      SessionId,<br>
+  IN  UINT32      Offset,<br>
+  IN  UINT8 *Data,<br>
+  IN  UINT32      WriteLength<br>
+  );<br>
+<br>
+typedef<br>
+EFI_STATUS<br>
+(EFIAPI *IPMI_BLOB_TRANSFER_PROTOCOL_COMMIT)(<br>
+  IN  UINT16      SessionId,<br>
+  IN  UINT8       CommitDataLength,<br>
+  IN  UINT8 *CommitData<br>
+  );<br>
+<br>
+typedef<br>
+EFI_STATUS<br>
+(EFIAPI *IPMI_BLOB_TRANSFER_PROTOCOL_CLOSE)(<br>
+  IN  UINT16      SessionId<br>
+  );<br>
+<br>
+typedef<br>
+EFI_STATUS<br>
+(EFIAPI *IPMI_BLOB_TRANSFER_PROTOCOL_DELETE)(<br>
+  IN  CHAR8 *BlobId<br>
+  );<br>
+<br>
+typedef<br>
+EFI_STATUS<br>
+(EFIAPI *IPMI_BLOB_TRANSFER_PROTOCOL_STAT)(<br>
+  IN  CHAR8 *BlobId,<br>
+  OUT UINT16 *BlobState,<br>
+  OUT UINT32 *Size,<br>
+  OUT UINT8 *MetadataLength,<br>
+  OUT UINT8 *Metadata<br>
+  );<br>
+<br>
+typedef<br>
+EFI_STATUS<br>
+(EFIAPI *IPMI_BLOB_TRANSFER_PROTOCOL_SESSION_STAT)(<br>
+  IN  UINT16      SessionId,<br>
+  OUT UINT16 *BlobState,<br>
+  OUT UINT32 *Size,<br>
+  OUT UINT8 *MetadataLength,<br>
+  OUT UINT8 *Metadata<br>
+  );<br>
+<br>
+typedef<br>
+EFI_STATUS<br>
+(EFIAPI *IPMI_BLOB_TRANSFER_PROTOCOL_WRITE_META)(<br>
+  IN  UINT16      SessionId,<br>
+  IN  UINT32      Offset,<br>
+  IN  UINT8 *Data,<br>
+  IN  UINT32      WriteLength<br>
+  );<br>
+<br>
+//<br>
+// Structure of IPMI_BLOB_TRANSFER_PROTOCOL<br>
+//<br>
+struct _IPMI_BLOB_TRANSFER_PROTOCOL {<br>
+  IPMI_BLOB_TRANSFER_PROTOCOL_GET_COUNT       BlobGetCount;<br>
+  IPMI_BLOB_TRANSFER_PROTOCOL_ENUMERATE       BlobEnumerate;<br>
+  IPMI_BLOB_TRANSFER_PROTOCOL_OPEN            BlobOpen;<br>
+  IPMI_BLOB_TRANSFER_PROTOCOL_READ            BlobRead;<br>
+  IPMI_BLOB_TRANSFER_PROTOCOL_WRITE           BlobWrite;<br>
+  IPMI_BLOB_TRANSFER_PROTOCOL_COMMIT          BlobCommit;<br>
+  IPMI_BLOB_TRANSFER_PROTOCOL_CLOSE           BlobClose;<br>
+  IPMI_BLOB_TRANSFER_PROTOCOL_DELETE          BlobDelete;<br>
+  IPMI_BLOB_TRANSFER_PROTOCOL_STAT            BlobStat;<br>
+  IPMI_BLOB_TRANSFER_PROTOCOL_SESSION_STAT    BlobSessionStat;<br>
+  IPMI_BLOB_TRANSFER_PROTOCOL_WRITE_META      BlobWriteMeta;<br>
+};<br>
+<br>
+typedef struct _IPMI_BLOB_TRANSFER_PROTOCOL IPMI_BLOB_TRANSFER_PROTOCOL;<br>
+<br>
+extern EFI_GUID  gEdkiiIpmiBlobTransferProtocolGuid;<br>
diff --git a/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiBlobTransfer.h b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiBlobTransfer.h<br>
new file mode 100644<br>
index 0000000000..14f0dc02bc<br>
--- /dev/null<br>
+++ b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/InternalIpmiBlobTransfer.h<br>
@@ -0,0 +1,363 @@<br>
+/** @file<br>
+<br>
+  Headers for IPMI Blob Transfer driver<br>
+<br>
+  Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.<br>
+<br>
+  SPDX-License-Identifier: BSD-2-Clause-Patent<br>
+<br>
+**/<br>
+<br>
+#include <Library/BaseLib.h><br>
+#include <Library/BaseMemoryLib.h><br>
+#include <Library/DebugLib.h><br>
+#include <Library/IpmiLib.h><br>
+#include <Library/MemoryAllocationLib.h><br>
+#include <Library/PcdLib.h><br>
+<br>
+#define PROTOCOL_RESPONSE_OVERHEAD  (4 * sizeof(UINT8))     // 1 byte completion code + 3 bytes OEN<br>
+<br>
+// Subcommands for this protocol<br>
+typedef enum {<br>
+  IpmiBlobTransferSubcommandGetCount = 0,<br>
+  IpmiBlobTransferSubcommandEnumerate,<br>
+  IpmiBlobTransferSubcommandOpen,<br>
+  IpmiBlobTransferSubcommandRead,<br>
+  IpmiBlobTransferSubcommandWrite,<br>
+  IpmiBlobTransferSubcommandCommit,<br>
+  IpmiBlobTransferSubcommandClose,<br>
+  IpmiBlobTransferSubcommandDelete,<br>
+  IpmiBlobTransferSubcommandStat,<br>
+  IpmiBlobTransferSubcommandSessionStat,<br>
+  IpmiBlobTransferSubcommandWriteMeta,<br>
+} IPMI_BLOB_TRANSFER_SUBCOMMANDS;<br>
+<br>
+#pragma pack(1)<br>
+<br>
+typedef struct {<br>
+  UINT8    OEN[3];<br>
+  UINT8    SubCommand;<br>
+} IPMI_BLOB_TRANSFER_HEADER;<br>
+<br>
+//<br>
+// Command 0 - BmcBlobGetCount<br>
+// The BmcBlobGetCount command expects to receive an empty body.<br>
+// The BMC will return the number of enumerable blobs<br>
+//<br>
+typedef struct {<br>
+  UINT32    BlobCount;<br>
+} IPMI_BLOB_TRANSFER_GET_COUNT_RESPONSE;<br>
+<br>
+//<br>
+// Command 1 - BmcBlobEnumerate<br>
+// The BmcBlobEnumerate command expects to receive a body of:<br>
+//<br>
+typedef struct {<br>
+  UINT32    BlobIndex; // 0-based index of blob to receive<br>
+} IPMI_BLOB_TRANSFER_BLOB_ENUMERATE_SEND_DATA;<br>
+<br>
+typedef struct {<br>
+  CHAR8    BlobId[IPMI_OEM_BLOB_MAX_DATA_PER_PACKET];<br>
+} IPMI_BLOB_TRANSFER_BLOB_ENUMERATE_RESPONSE;<br>
+<br>
+//<br>
+// Command 2 - BmcBlobOpen<br>
+// The BmcBlobOpen command expects to receive a body of:<br>
+//<br>
+typedef struct {<br>
+  UINT16    Flags;<br>
+  CHAR8     BlobId[IPMI_OEM_BLOB_MAX_DATA_PER_PACKET];<br>
+} IPMI_BLOB_TRANSFER_BLOB_OPEN_SEND_DATA;<br>
+<br>
+#define BLOB_OPEN_FLAG_READ   0<br>
+#define BLOB_OPEN_FLAG_WRITE  1<br>
+// Bits 2-7 are reserved<br>
+// Bits 8-15 are blob-specific definitions<br>
+<br>
+typedef struct {<br>
+  UINT16    SessionId;<br>
+} IPMI_BLOB_TRANSFER_BLOB_OPEN_RESPONSE;<br>
+<br>
+//<br>
+// Command 3 - BmcBlobRead<br>
+// The BmcBlobRead command expects to receive a body of:<br>
+//<br>
+typedef struct {<br>
+  UINT16    SessionId; // Returned from BlobOpen<br>
+  UINT32    Offset;<br>
+  UINT32    RequestedSize;<br>
+} IPMI_BLOB_TRANSFER_BLOB_READ_SEND_DATA;<br>
+<br>
+typedef struct {<br>
+  UINT8    Data[IPMI_OEM_BLOB_MAX_DATA_PER_PACKET];<br>
+} IPMI_BLOB_TRANSFER_BLOB_READ_RESPONSE;<br>
+<br>
+//<br>
+// Command 4 - BmcBlobWrite<br>
+// The BmcBlobWrite command expects to receive a body of:<br>
+//<br>
+typedef struct {<br>
+  UINT16    SessionId; // Returned from BlobOpen<br>
+  UINT32    Offset;<br>
+  UINT8     Data[IPMI_OEM_BLOB_MAX_DATA_PER_PACKET];<br>
+} IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_DATA;<br>
+<br>
+//<br>
+// Command 5 - BmcBlobCommit<br>
+// The BmcBlobCommit command expects to receive a body of:<br>
+//<br>
+typedef struct {<br>
+  UINT16    SessionId; // Returned from BlobOpen<br>
+  UINT8     CommitDataLength;<br>
+  UINT8     CommitData[IPMI_OEM_BLOB_MAX_DATA_PER_PACKET];<br>
+} IPMI_BLOB_TRANSFER_BLOB_COMMIT_SEND_DATA;<br>
+<br>
+//<br>
+// Command 6 - BmcBlobClose<br>
+// The BmcBlobClose command expects to receive a body of:<br>
+//<br>
+typedef struct {<br>
+  UINT16    SessionId; // Returned from BlobOpen<br>
+} IPMI_BLOB_TRANSFER_BLOB_CLOSE_SEND_DATA;<br>
+<br>
+//<br>
+// Command 7 - BmcBlobDelete<br>
+// NOTE: This command will fail if there are open sessions for this blob<br>
+// The BmcBlobDelete command expects to receive a body of:<br>
+//<br>
+typedef struct {<br>
+  CHAR8    BlobId[IPMI_OEM_BLOB_MAX_DATA_PER_PACKET];<br>
+} IPMI_BLOB_TRANSFER_BLOB_DELETE_SEND_DATA;<br>
+<br>
+//<br>
+// Command 8 - BmcBlobStat<br>
+// This command returns statistics about a blob.<br>
+// This command expects to receive a body of:<br>
+//<br>
+typedef struct {<br>
+  CHAR8    BlobId[IPMI_OEM_BLOB_MAX_DATA_PER_PACKET];<br>
+} IPMI_BLOB_TRANSFER_BLOB_STAT_SEND_DATA;<br>
+<br>
+typedef struct {<br>
+  UINT16    BlobState;<br>
+  UINT32    Size; // Size in bytes of the blob<br>
+  UINT8     MetaDataLen;<br>
+  UINT8     MetaData[IPMI_OEM_BLOB_MAX_DATA_PER_PACKET];<br>
+} IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE;<br>
+<br>
+//<br>
+// Command 9 - BmcBlobSessionStat<br>
+// Returns same data as BmcBlobState expect for a session, not a blob<br>
+// This command expects to receive a body of:<br>
+//<br>
+typedef struct {<br>
+  UINT16    SessionId;<br>
+} IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_SEND_DATA;<br>
+<br>
+typedef struct {<br>
+  UINT16    BlobState;<br>
+  UINT32    Size; // Size in bytes of the blob<br>
+  UINT8     MetaDataLen;<br>
+  UINT8     MetaData[IPMI_OEM_BLOB_MAX_DATA_PER_PACKET];<br>
+} IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_RESPONSE;<br>
+<br>
+//<br>
+// Command 10 - BmcBlobWriteMeta<br>
+// The BmcBlobWriteMeta command expects to receive a body of:<br>
+//<br>
+typedef struct {<br>
+  UINT16    SessionId;<br>
+  UINT32    Offset;<br>
+  UINT8     Data[IPMI_OEM_BLOB_MAX_DATA_PER_PACKET];<br>
+} IPMI_BLOB_TRANSFER_BLOB_WRITE_META_SEND_DATA;<br>
+<br>
+#define IPMI_BLOB_TRANSFER_BLOB_WRITE_META_RESPONSE  NULL<br>
+<br>
+#pragma pack()<br>
+<br>
+/**<br>
+  Calculate CRC-16-CCITT with poly of 0x1021<br>
+<br>
+  @param[in]  Data              The target data.<br>
+  @param[in]  DataSize          The target data size.<br>
+<br>
+  @return UINT16     The CRC16 value.<br>
+<br>
+**/<br>
+UINT16<br>
+CalculateCrc16 (<br>
+  IN UINT8  *Data,<br>
+  IN UINTN  DataSize<br>
+  );<br>
+<br>
+EFI_STATUS<br>
+IpmiBlobTransferSendIpmi (<br>
+  IN  UINT8   SubCommand,<br>
+  IN  UINT8   *SendData,<br>
+  IN  UINT32  SendDataSize,<br>
+  OUT UINT8   *ResponseData,<br>
+  OUT UINT32  *ResponseDataSize<br>
+  );<br>
+<br>
+/**<br>
+  @param[out]        Count       The number of active blobs<br>
+<br>
+  @retval EFI_SUCCESS            Successfully retrieved the number of active blobs.<br>
+  @retval Other                  An error occurred<br>
+**/<br>
+EFI_STATUS<br>
+IpmiBlobTransferGetCount (<br>
+  OUT UINT32  *Count<br>
+  );<br>
+<br>
+/**<br>
+  @param[in]         BlobIndex       The 0-based Index of the blob to enumerate<br>
+  @param[out]        BlobId          The ID of the blob<br>
+<br>
+  @retval EFI_SUCCESS                Successfully enumerated the blob.<br>
+  @retval Other                      An error occurred<br>
+**/<br>
+EFI_STATUS<br>
+IpmiBlobTransferEnumerate (<br>
+  IN  UINT32  BlobIndex,<br>
+  OUT CHAR8   *BlobId<br>
+  );<br>
+<br>
+/**<br>
+  @param[in]         BlobId          The ID of the blob to open<br>
+  @param[in]         Flags           Flags to control how the blob is opened<br>
+  @param[out]        SessionId       A unique session identifier<br>
+<br>
+  @retval EFI_SUCCESS                Successfully opened the blob.<br>
+  @retval Other                      An error occurred<br>
+**/<br>
+EFI_STATUS<br>
+IpmiBlobTransferOpen (<br>
+  IN  CHAR8   *BlobId,<br>
+  IN  UINT16  Flags,<br>
+  OUT UINT16  *SessionId<br>
+  );<br>
+<br>
+/**<br>
+  @param[in]         SessionId       The session ID returned from a call to BlobOpen<br>
+  @param[in]         Offset          The offset of the blob from which to start reading<br>
+  @param[in]         RequestedSize   The length of data to read<br>
+  @param[out]        Data            Data read from the blob<br>
+<br>
+  @retval EFI_SUCCESS                Successfully read from the blob.<br>
+  @retval Other                      An error occurred<br>
+**/<br>
+EFI_STATUS<br>
+IpmiBlobTransferRead (<br>
+  IN  UINT16  SessionId,<br>
+  IN  UINT32  Offset,<br>
+  IN  UINT32  RequestedSize,<br>
+  OUT UINT8   *Data<br>
+  );<br>
+<br>
+/**<br>
+  @param[in]         SessionId       The session ID returned from a call to BlobOpen<br>
+  @param[in]         Offset          The offset of the blob from which to start writing<br>
+  @param[in]         Data            A pointer to the data to write<br>
+<br>
+  @retval EFI_SUCCESS                Successfully wrote to the blob.<br>
+  @retval Other                      An error occurred<br>
+**/<br>
+EFI_STATUS<br>
+IpmiBlobTransferWrite (<br>
+  IN  UINT16  SessionId,<br>
+  IN  UINT32  Offset,<br>
+  IN  UINT8   *Data,<br>
+  IN  UINT32  WriteLength<br>
+  );<br>
+<br>
+/**<br>
+  @param[in]         SessionId        The session ID returned from a call to BlobOpen<br>
+  @param[in]         CommitDataLength The length of data to commit to the blob<br>
+  @param[in]         CommitData       A pointer to the data to commit<br>
+<br>
+  @retval EFI_SUCCESS                Successful commit to the blob.<br>
+  @retval Other                      An error occurred<br>
+**/<br>
+EFI_STATUS<br>
+IpmiBlobTransferCommit (<br>
+  IN  UINT16  SessionId,<br>
+  IN  UINT8   CommitDataLength,<br>
+  IN  UINT8   *CommitData<br>
+  );<br>
+<br>
+/**<br>
+  @param[in]         SessionId       The session ID returned from a call to BlobOpen<br>
+<br>
+  @retval EFI_SUCCESS                The blob was closed.<br>
+  @retval Other                      An error occurred<br>
+**/<br>
+EFI_STATUS<br>
+IpmiBlobTransferClose (<br>
+  IN  UINT16  SessionId<br>
+  );<br>
+<br>
+/**<br>
+  @param[in]         BlobId          The BlobId to be deleted<br>
+<br>
+  @retval EFI_SUCCESS                The blob was deleted.<br>
+  @retval Other                      An error occurred<br>
+**/<br>
+EFI_STATUS<br>
+IpmiBlobTransferDelete (<br>
+  IN  CHAR8  *BlobId<br>
+  );<br>
+<br>
+/**<br>
+  @param[in]         BlobId          The Blob ID to gather statistics for<br>
+  @param[out]        BlobState       The current state of the blob<br>
+  @param[out]        Size            Size in bytes of the blob<br>
+  @param[out]        MetadataLength  Length of the optional metadata<br>
+  @param[out]        Metadata        Optional blob-specific metadata<br>
+<br>
+  @retval EFI_SUCCESS                The blob statistics were successfully gathered.<br>
+  @retval Other                      An error occurred<br>
+**/<br>
+EFI_STATUS<br>
+IpmiBlobTransferStat (<br>
+  IN  CHAR8   *BlobId,<br>
+  OUT UINT16  *BlobState,<br>
+  OUT UINT32  *Size,<br>
+  OUT UINT8   *MetadataLength,<br>
+  OUT UINT8   *Metadata<br>
+  );<br>
+<br>
+/**<br>
+  @param[in]         SessionId       The ID of the session to gather statistics for<br>
+  @param[out]        BlobState       The current state of the blob<br>
+  @param[out]        Size            Size in bytes of the blob<br>
+  @param[out]        MetadataLength  Length of the optional metadata<br>
+  @param[out]        Metadata        Optional blob-specific metadata<br>
+<br>
+  @retval EFI_SUCCESS                The blob statistics were successfully gathered.<br>
+  @retval Other                      An error occurred<br>
+**/<br>
+EFI_STATUS<br>
+IpmiBlobTransferSessionStat (<br>
+  IN  UINT16  SessionId,<br>
+  OUT UINT16  *BlobState,<br>
+  OUT UINT32  *Size,<br>
+  OUT UINT8   *MetadataLength,<br>
+  OUT UINT8   *Metadata<br>
+  );<br>
+<br>
+/**<br>
+  @param[in]         SessionId       The ID of the session to write metadata for<br>
+  @param[in]         Offset          The offset of the metadata to write to<br>
+  @param[in]         Data            The data to write to the metadata<br>
+<br>
+  @retval EFI_SUCCESS                The blob metadata was successfully written.<br>
+  @retval Other                      An error occurred<br>
+**/<br>
+EFI_STATUS<br>
+IpmiBlobTransferWriteMeta (<br>
+  IN  UINT16  SessionId,<br>
+  IN  UINT32  Offset,<br>
+  IN  UINT8   *Data,<br>
+  IN  UINT32  WriteLength<br>
+  );<br>
diff --git a/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.c b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.c<br>
new file mode 100644<br>
index 0000000000..9e663289d5<br>
--- /dev/null<br>
+++ b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/IpmiBlobTransferDxe.c<br>
@@ -0,0 +1,799 @@<br>
+/** @file<br>
+<br>
+  IPMI Blob Transfer driver<br>
+<br>
+  Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.<br>
+<br>
+  SPDX-License-Identifier: BSD-2-Clause-Patent<br>
+<br>
+**/<br>
+#include <Protocol/IpmiBlobTransfer.h><br>
+<br>
+#include "InternalIpmiBlobTransfer.h"<br>
+<br>
+#define BLOB_TRANSFER_DEBUG  0<br>
+<br>
+STATIC CONST IPMI_BLOB_TRANSFER_PROTOCOL  mIpmiBlobTransfer = {<br>
+  (IPMI_BLOB_TRANSFER_PROTOCOL_GET_COUNT)*IpmiBlobTransferGetCount,<br>
+  (IPMI_BLOB_TRANSFER_PROTOCOL_ENUMERATE)*IpmiBlobTransferEnumerate,<br>
+  (IPMI_BLOB_TRANSFER_PROTOCOL_OPEN)*IpmiBlobTransferOpen,<br>
+  (IPMI_BLOB_TRANSFER_PROTOCOL_READ)*IpmiBlobTransferRead,<br>
+  (IPMI_BLOB_TRANSFER_PROTOCOL_WRITE)*IpmiBlobTransferWrite,<br>
+  (IPMI_BLOB_TRANSFER_PROTOCOL_COMMIT)*IpmiBlobTransferCommit,<br>
+  (IPMI_BLOB_TRANSFER_PROTOCOL_CLOSE)*IpmiBlobTransferClose,<br>
+  (IPMI_BLOB_TRANSFER_PROTOCOL_DELETE)*IpmiBlobTransferDelete,<br>
+  (IPMI_BLOB_TRANSFER_PROTOCOL_STAT)*IpmiBlobTransferStat,<br>
+  (IPMI_BLOB_TRANSFER_PROTOCOL_SESSION_STAT)*IpmiBlobTransferSessionStat,<br>
+  (IPMI_BLOB_TRANSFER_PROTOCOL_WRITE_META)*IpmiBlobTransferWriteMeta<br>
+};<br>
+<br>
+const UINT8  OpenBmcOen[] = { 0xCF, 0xC2, 0x00 };          // OpenBMC OEN code in little endian format<br>
</blockquote>
<br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;">
<span style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;">I
 don’t know what “Oen” means. Should it be “Oem” or “IANA” number?</span><br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;">
<br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;">
<span style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;">And
 this number can be configured, other OEMs will have their own number.</span><br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;">
<br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;">
<span style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;">This
 number should be provided by drivers that consume this protocol</span><br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;">
</div>
</blockquote>
This commit uses OpenBMC IPMI blob commands defined in <a href="https://github.com/openbmc/phosphor-ipmi-blobs">https://github.com/openbmc/phosphor-ipmi-blobs</a> which are fixed numbers. So, no problem to have fixed definition.<br>
<blockquote type="cite">
<div><br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;">
<blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;">
+<br>
+/**<br>
+  Calculate CRC-16-CCITT with poly of 0x1021<br>
+<br>
+  @param[in]  Data              The target data.<br>
+  @param[in]  DataSize          The target data size.<br>
+<br>
+  @return UINT16     The CRC16 value.<br>
+<br>
+**/<br>
+UINT16<br>
+CalculateCrc16 (<br>
+  IN UINT8  *Data,<br>
+  IN UINTN  DataSize<br>
+  )<br>
+{<br>
+  UINTN    Index;<br>
+  UINTN    BitIndex;<br>
+  UINT16   Crc     = 0xFFFF;<br>
+  UINT16   Poly    = 0x1021;<br>
+  BOOLEAN  XorFlag = FALSE;<br>
+<br>
+  for (Index = 0; Index < (DataSize + 2); ++Index) {<br>
+    for (BitIndex = 0; BitIndex < 8; ++BitIndex) {<br>
+      XorFlag = (Crc & 0x8000) ? TRUE : FALSE;<br>
+      Crc   <<= 1;<br>
+      if ((Index < DataSize) && (Data[Index] & (1 << (7 - BitIndex)))) {<br>
+        Crc++;<br>
+      }<br>
+<br>
+      if (XorFlag == TRUE) {<br>
+        Crc ^= Poly;<br>
+      }<br>
+    }<br>
+  }<br>
+<br>
+ #if BLOB_TRANSFER_DEBUG<br>
+  DEBUG ((DEBUG_INFO, "%a: CRC-16-CCITT %x\n", __FUNCTION__, Crc));<br>
+ #endif<br>
+<br>
+  return Crc;<br>
+}<br>
+<br>
+EFI_STATUS<br>
+IpmiBlobTransferSendIpmi (<br>
+  IN  UINT8   SubCommand,<br>
+  IN  UINT8   *SendData,<br>
+  IN  UINT32  SendDataSize,<br>
+  OUT UINT8   *ResponseData,<br>
+  OUT UINT32  *ResponseDataSize<br>
+  )<br>
+{<br>
+  EFI_STATUS                 Status;<br>
+  UINT8                      CompletionCode;<br>
+  UINT16                     Crc;<br>
+  UINT8                      Oen[3];<br>
+  UINT8                      *IpmiSendData;<br>
+  UINT32                     IpmiSendDataSize;<br>
+  UINT8                      *IpmiResponseData;<br>
+  UINT8                      *ModifiedResponseData;<br>
+  UINT32                     IpmiResponseDataSize;<br>
+  IPMI_BLOB_TRANSFER_HEADER  Header;<br>
+<br>
+  Crc = 0;<br>
+<br>
+  //<br>
+  // Prepend the proper header to the SendData<br>
+  //<br>
+  IpmiSendDataSize = (sizeof (IPMI_BLOB_TRANSFER_HEADER));<br>
+  if (SendDataSize) {<br>
+    IpmiSendDataSize += sizeof (Crc) + (sizeof (UINT8) * SendDataSize);<br>
+  }<br>
+<br>
+  IpmiSendData = AllocateZeroPool (IpmiSendDataSize);<br>
+  if (IpmiSendData == NULL) {<br>
+    return EFI_OUT_OF_RESOURCES;<br>
+  }<br>
+<br>
+  Header.OEN[0]     = OpenBmcOen[0];<br>
+  Header.OEN[1]     = OpenBmcOen[1];<br>
+  Header.OEN[2]     = OpenBmcOen[2];<br>
+  Header.SubCommand = SubCommand;<br>
+  CopyMem (IpmiSendData, &Header, sizeof (IPMI_BLOB_TRANSFER_HEADER));<br>
+  if (SendDataSize) {<br>
+    //<br>
+    // Calculate the Crc of the send data<br>
+    //<br>
+    Crc = CalculateCrc16 (SendData, SendDataSize);<br>
+    CopyMem (IpmiSendData + sizeof (IPMI_BLOB_TRANSFER_HEADER), &Crc, sizeof (UINT16));<br>
+    CopyMem (IpmiSendData + sizeof (IPMI_BLOB_TRANSFER_HEADER) + sizeof (UINT16), SendData, SendDataSize);<br>
+  }<br>
+<br>
+ #if BLOB_TRANSFER_DEBUG<br>
+  DEBUG ((DEBUG_INFO, "%a: Inputs:\n", __FUNCTION__));<br>
+  DEBUG ((DEBUG_INFO, "%a: SendDataSize: %02x\nData: ", __FUNCTION__, SendDataSize));<br>
+  UINT8  i;<br>
+  for (i = 0; i < SendDataSize; i++) {<br>
+    DEBUG ((DEBUG_INFO, "%02x", *((UINT8 *)SendData + i)));<br>
+  }<br>
+<br>
+  DEBUG ((DEBUG_INFO, "\n"));<br>
+  DEBUG ((DEBUG_INFO, "%a: IpmiSendDataSize: %02x\nData: ", __FUNCTION__, IpmiSendDataSize));<br>
+  for (i = 0; i < IpmiSendDataSize; i++) {<br>
+    DEBUG ((DEBUG_INFO, "%02x", *((UINT8 *)IpmiSendData + i)));<br>
+  }<br>
+<br>
+  DEBUG ((DEBUG_INFO, "\n"));<br>
+ #endif<br>
+<br>
+  IpmiResponseDataSize = (*ResponseDataSize + PROTOCOL_RESPONSE_OVERHEAD);<br>
+  //<br>
+  // If expecting data to be returned, we have to also account for the 16 bit CRC<br>
+  //<br>
+  if (*ResponseDataSize) {<br>
+    IpmiResponseDataSize += sizeof (Crc);<br>
+  }<br>
+<br>
+  IpmiResponseData = AllocateZeroPool (IpmiResponseDataSize);<br>
+  if (IpmiResponseData == NULL) {<br>
+    return EFI_OUT_OF_RESOURCES;<br>
+  }<br>
+<br>
+  Status = IpmiSubmitCommand (<br>
+             IPMI_NETFN_OEM,<br>
+             IPMI_OEM_BLOB_TRANSFER_CMD,<br>
+             (VOID *)IpmiSendData,<br>
+             IpmiSendDataSize,<br>
+             (VOID *)IpmiResponseData,<br>
+             &IpmiResponseDataSize<br>
+             );<br>
+<br>
+  FreePool (IpmiSendData);<br>
+  ModifiedResponseData = IpmiResponseData;<br>
+<br>
+ #if BLOB_TRANSFER_DEBUG<br>
+  DEBUG ((DEBUG_INFO, "%a: IPMI Response:\n", __FUNCTION__));<br>
+  DEBUG ((DEBUG_INFO, "%a: ResponseDataSize: %02x\nData: ", __FUNCTION__, IpmiResponseDataSize));<br>
+  for (i = 0; i < IpmiResponseDataSize; i++) {<br>
+    DEBUG ((DEBUG_INFO, "%02x", *(ModifiedResponseData + i)));<br>
+  }<br>
+<br>
+  DEBUG ((DEBUG_INFO, "\n"));<br>
+ #endif<br>
+<br>
+  if (EFI_ERROR (Status)) {<br>
+    return Status;<br>
+  }<br>
+<br>
+  CompletionCode = *ModifiedResponseData;<br>
+  if (CompletionCode != IPMI_COMP_CODE_NORMAL) {<br>
+    DEBUG ((DEBUG_ERROR, "%a: Returning because CompletionCode = 0x%x\n", __FUNCTION__, CompletionCode));<br>
+    FreePool (IpmiResponseData);<br>
+    return EFI_PROTOCOL_ERROR;<br>
+  }<br>
+<br>
+  // Strip completion code, we are done with it<br>
+  ModifiedResponseData  = ModifiedResponseData + sizeof (CompletionCode);<br>
+  IpmiResponseDataSize -= sizeof (CompletionCode);<br>
+<br>
+  // Check OEN code and verify it matches the OpenBMC OEN<br>
+  CopyMem (Oen, ModifiedResponseData, sizeof (OpenBmcOen));<br>
+  if (CompareMem (Oen, OpenBmcOen, sizeof (OpenBmcOen)) != 0) {<br>
+    FreePool (IpmiResponseData);<br>
+    return EFI_PROTOCOL_ERROR;<br>
+  }<br>
+<br>
+  if (IpmiResponseDataSize == sizeof (OpenBmcOen)) {<br>
+    //<br>
+    // In this case, there was no response data sent. This is not an error.<br>
+    // Some messages do not require a response.<br>
+    //<br>
+    *ResponseDataSize = 0;<br>
+    FreePool (IpmiResponseData);<br>
+    return Status;<br>
+    // Now we need to validate the CRC then send the Response body back<br>
+  } else {<br>
+    // Strip the OEN, we are done with it now<br>
+    ModifiedResponseData  = ModifiedResponseData + sizeof (Oen);<br>
+    IpmiResponseDataSize -= sizeof (Oen);<br>
+    // Then validate the Crc<br>
+    CopyMem (&Crc, ModifiedResponseData, sizeof (Crc));<br>
+    ModifiedResponseData  = ModifiedResponseData + sizeof (Crc);<br>
+    IpmiResponseDataSize -= sizeof (Crc);<br>
+<br>
+    if (Crc == CalculateCrc16 (ModifiedResponseData, IpmiResponseDataSize)) {<br>
+      CopyMem (ResponseData, ModifiedResponseData, IpmiResponseDataSize);<br>
+      CopyMem (ResponseDataSize, &IpmiResponseDataSize, sizeof (IpmiResponseDataSize));<br>
+      FreePool (IpmiResponseData);<br>
+      return EFI_SUCCESS;<br>
+    } else {<br>
+      FreePool (IpmiResponseData);<br>
+      return EFI_CRC_ERROR;<br>
+    }<br>
+  }<br>
+}<br>
+<br>
+/**<br>
+  @param[out]        Count       The number of active blobs<br>
+<br>
+  @retval EFI_SUCCESS            The command byte stream was successfully submit to the device and a response was successfully received.<br>
+  @retval EFI_PROTOCOL_ERROR     The Ipmi command failed<br>
+  @retval EFI_CRC_ERROR          The Ipmi command returned a bad checksum<br>
+**/<br>
+EFI_STATUS<br>
+IpmiBlobTransferGetCount (<br>
+  OUT UINT32  *Count<br>
+  )<br>
+{<br>
</blockquote>
<br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;">
<span style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;">Please
 add the argument validation for functions which expose for other drivers</span><br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;">
<br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;">
<br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;">
<blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;">
+  EFI_STATUS  Status;<br>
+  UINT8       *ResponseData;<br>
+  UINT32      ResponseDataSize;<br>
+<br>
+  ResponseDataSize = sizeof (IPMI_BLOB_TRANSFER_GET_COUNT_RESPONSE);<br>
+  ResponseData     = AllocateZeroPool (ResponseDataSize);<br>
+  if (ResponseData == NULL) {<br>
+    return EFI_OUT_OF_RESOURCES;<br>
+  }<br>
+<br>
+  Status = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandGetCount, NULL, 0, (UINT8 *)ResponseData, &ResponseDataSize);<br>
+  if (!EFI_ERROR (Status)) {<br>
+    *Count = ((IPMI_BLOB_TRANSFER_GET_COUNT_RESPONSE *)ResponseData)->BlobCount;<br>
+  }<br>
+<br>
+  FreePool (ResponseData);<br>
+  return Status;<br>
+}<br>
+<br>
+/**<br>
+  @param[in]         BlobIndex       The 0-based Index of the blob to enumerate<br>
+  @param[out]        BlobId          The ID of the blob<br>
+<br>
+  @retval EFI_SUCCESS                Successfully enumerated the blob.<br>
+  @retval Other                      An error occurred<br>
+**/<br>
+EFI_STATUS<br>
+IpmiBlobTransferEnumerate (<br>
+  IN  UINT32  BlobIndex,<br>
+  OUT CHAR8   *BlobId<br>
+  )<br>
+{<br>
+  EFI_STATUS  Status;<br>
+<br>
+  UINT8   *SendData;<br>
+  UINT8   *ResponseData;<br>
+  UINT32  SendDataSize;<br>
+  UINT32  ResponseDataSize;<br>
+<br>
+  if (BlobId == NULL) {<br>
+    ASSERT (FALSE);<br>
+    return EFI_ABORTED;<br>
+  }<br>
+<br>
+  ResponseDataSize = sizeof (IPMI_BLOB_TRANSFER_BLOB_ENUMERATE_RESPONSE);<br>
+  ResponseData     = AllocateZeroPool (ResponseDataSize);<br>
+  if (ResponseData == NULL) {<br>
+    return EFI_OUT_OF_RESOURCES;<br>
+  }<br>
+<br>
+  //<br>
+  // Format send data<br>
+  //<br>
+  SendDataSize = sizeof (IPMI_BLOB_TRANSFER_BLOB_ENUMERATE_SEND_DATA);<br>
+  SendData     = AllocateZeroPool (SendDataSize);<br>
+  if (SendData == NULL) {<br>
+    return EFI_OUT_OF_RESOURCES;<br>
+  }<br>
+<br>
+  ((IPMI_BLOB_TRANSFER_BLOB_ENUMERATE_SEND_DATA *)SendData)->BlobIndex = BlobIndex;<br>
+<br>
+  Status = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandEnumerate, SendData, SendDataSize, (UINT8 *)ResponseData, &ResponseDataSize);<br>
+  if (!EFI_ERROR (Status)) {<br>
+    AsciiStrCpyS (BlobId, ResponseDataSize, (CHAR8 *)ResponseData);<br>
+  }<br>
+<br>
+  FreePool (ResponseData);<br>
+  return Status;<br>
+}<br>
+<br>
+/**<br>
+  @param[in]         BlobId          The ID of the blob to open<br>
+  @param[in]         Flags           Flags to control how the blob is opened<br>
+  @param[out]        SessionId       A unique session identifier<br>
+<br>
+  @retval EFI_SUCCESS                Successfully opened the blob.<br>
+  @retval Other                      An error occurred<br>
+**/<br>
+EFI_STATUS<br>
+IpmiBlobTransferOpen (<br>
+  IN  CHAR8   *BlobId,<br>
+  IN  UINT16  Flags,<br>
+  OUT UINT16  *SessionId<br>
+  )<br>
+{<br>
+  EFI_STATUS  Status;<br>
+  UINT8       *SendData;<br>
+  UINT8       *ResponseData;<br>
+  UINT32      SendDataSize;<br>
+  UINT32      ResponseDataSize;<br>
+  CHAR8       *BlobSearch;<br>
+  UINT32      NumBlobs;<br>
+  UINT16      Index;<br>
+  BOOLEAN     BlobFound;<br>
+<br>
+  //<br>
+  // Before opening a blob, need to check if it exists<br>
+  //<br>
+  Status = IpmiBlobTransferGetCount (&NumBlobs);<br>
</blockquote>
<br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;">
<span style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;">I
 think it should be removed as that will duplicate work</span><br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;">
<br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;">
<span style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;">The
 drivers using IPMI blob protocol will  "get count" themselves.</span><br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;">
<br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;">
<blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;">
+  if (EFI_ERROR (Status) || (NumBlobs == 0)) {<br>
+    if (Status == EFI_UNSUPPORTED) {<br>
+      return Status;<br>
+    }<br>
+<br>
+    DEBUG ((DEBUG_ERROR, "%a: Could not find any blobs: %r\n", __FUNCTION__, Status));<br>
+    return EFI_NOT_FOUND;<br>
+  }<br>
+<br>
+  BlobSearch = AllocateZeroPool (sizeof (CHAR8) * IPMI_OEM_BLOB_MAX_DATA_PER_PACKET);<br>
+  if (BlobSearch == NULL) {<br>
+    return EFI_OUT_OF_RESOURCES;<br>
+  }<br>
+<br>
+  BlobFound = FALSE;<br>
+  for (Index = 0; Index < NumBlobs; Index++) {<br>
+    Status = IpmiBlobTransferEnumerate (Index, BlobSearch);<br>
</blockquote>
<span style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;">the
 same here</span><br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;">
<blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;">
+    if ((!EFI_ERROR (Status)) && (AsciiStrCmp (BlobSearch, BlobId) == 0)) {<br>
+      BlobFound = TRUE;<br>
+      break;<br>
+    } else {<br>
+      continue;<br>
+    }<br>
+  }<br>
+<br>
+  if (!BlobFound) {<br>
+    DEBUG ((DEBUG_ERROR, "%a: Could not find a blob that matches %s\n", __FUNCTION__, BlobId));<br>
+    FreePool (BlobSearch);<br>
+    return EFI_NOT_FOUND;<br>
+  }<br>
+<br>
+  ResponseDataSize = sizeof (IPMI_BLOB_TRANSFER_BLOB_OPEN_RESPONSE);<br>
+  ResponseData     = AllocateZeroPool (ResponseDataSize);<br>
+  if (ResponseData == NULL) {<br>
+    return EFI_OUT_OF_RESOURCES;<br>
+  }<br>
+<br>
+  //<br>
+  // Format send data<br>
+  //<br>
+  SendDataSize = sizeof (((IPMI_BLOB_TRANSFER_BLOB_OPEN_SEND_DATA *)SendData)->Flags) + ((AsciiStrLen (BlobId)) * sizeof (CHAR8)) + sizeof (CHAR8);<br>
+  SendData     = AllocateZeroPool (SendDataSize);<br>
+  if (SendData == NULL) {<br>
+    return EFI_OUT_OF_RESOURCES;<br>
+  }<br>
+<br>
+  AsciiStrCpyS (((IPMI_BLOB_TRANSFER_BLOB_OPEN_SEND_DATA *)SendData)->BlobId, AsciiStrSize (BlobId) / sizeof (CHAR8), BlobId);<br>
+  ((IPMI_BLOB_TRANSFER_BLOB_OPEN_SEND_DATA *)SendData)->Flags = Flags;<br>
+  // append null char to SendData<br>
+  SendData[SendDataSize-1] = 0;<br>
+<br>
+  Status = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandOpen, SendData, SendDataSize, (UINT8 *)ResponseData, &ResponseDataSize);<br>
+  if (!EFI_ERROR (Status)) {<br>
+    *SessionId = ((IPMI_BLOB_TRANSFER_BLOB_OPEN_RESPONSE *)ResponseData)->SessionId;<br>
+  }<br>
+<br>
+  FreePool (ResponseData);<br>
+  FreePool (SendData);<br>
+  FreePool (BlobSearch);<br>
+  return Status;<br>
+}<br>
+<br>
+/**<br>
+  @param[in]         SessionId       The session ID returned from a call to BlobOpen<br>
+  @param[in]         Offset          The offset of the blob from which to start reading<br>
+  @param[in]         RequestedSize   The length of data to read<br>
+  @param[out]        Data            Data read from the blob<br>
+<br>
+  @retval EFI_SUCCESS                Successfully read from the blob.<br>
+  @retval Other                      An error occurred<br>
+**/<br>
+EFI_STATUS<br>
+IpmiBlobTransferRead (<br>
+  IN  UINT16  SessionId,<br>
+  IN  UINT32  Offset,<br>
+  IN  UINT32  RequestedSize,<br>
+  OUT UINT8   *Data<br>
+  )<br>
+{<br>
+  EFI_STATUS  Status;<br>
+  UINT8       *SendData;<br>
+  UINT8       *ResponseData;<br>
+  UINT32      SendDataSize;<br>
+  UINT32      ResponseDataSize;<br>
+<br>
+  if (Data == NULL) {<br>
+    ASSERT (FALSE);<br>
+    return EFI_ABORTED;<br>
+  }<br>
+<br>
+  ResponseDataSize = RequestedSize * sizeof (UINT8);<br>
+  ResponseData     = AllocateZeroPool (ResponseDataSize);<br>
+  if (ResponseData == NULL) {<br>
+    return EFI_OUT_OF_RESOURCES;<br>
+  }<br>
+<br>
+  //<br>
+  // Format send data<br>
+  //<br>
+  SendDataSize = sizeof (IPMI_BLOB_TRANSFER_BLOB_READ_SEND_DATA);<br>
+  SendData     = AllocateZeroPool (SendDataSize);<br>
+  if (SendData == NULL) {<br>
+    return EFI_OUT_OF_RESOURCES;<br>
+  }<br>
+<br>
+  ((IPMI_BLOB_TRANSFER_BLOB_READ_SEND_DATA *)SendData)->SessionId     = SessionId;<br>
+  ((IPMI_BLOB_TRANSFER_BLOB_READ_SEND_DATA *)SendData)->Offset        = Offset;<br>
+  ((IPMI_BLOB_TRANSFER_BLOB_READ_SEND_DATA *)SendData)->RequestedSize = RequestedSize;<br>
+<br>
+  Status = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandRead, SendData, SendDataSize, (UINT8 *)ResponseData, &ResponseDataSize);<br>
+  if (!EFI_ERROR (Status)) {<br>
+    CopyMem (Data, ((IPMI_BLOB_TRANSFER_BLOB_READ_RESPONSE *)ResponseData)->Data, ResponseDataSize * sizeof (UINT8));<br>
+  }<br>
+<br>
+  FreePool (ResponseData);<br>
+  FreePool (SendData);<br>
+  return Status;<br>
+}<br>
+<br>
+/**<br>
+  @param[in]         SessionId       The session ID returned from a call to BlobOpen<br>
+  @param[in]         Offset          The offset of the blob from which to start writing<br>
+  @param[in]         Data            A pointer to the data to write<br>
+<br>
+  @retval EFI_SUCCESS                Successfully wrote to the blob.<br>
+  @retval Other                      An error occurred<br>
+**/<br>
+EFI_STATUS<br>
+IpmiBlobTransferWrite (<br>
+  IN  UINT16  SessionId,<br>
+  IN  UINT32  Offset,<br>
+  IN  UINT8   *Data,<br>
+  IN  UINT32  WriteLength<br>
+  )<br>
+{<br>
+  EFI_STATUS  Status;<br>
+  UINT8       *SendData;<br>
+  UINT32      SendDataSize;<br>
+  UINT32      ResponseDataSize;<br>
+<br>
+  //<br>
+  // Format send data<br>
+  //<br>
+  SendDataSize = sizeof (SessionId) + sizeof (Offset) + WriteLength;<br>
+  SendData     = AllocateZeroPool (SendDataSize);<br>
+  if (SendData == NULL) {<br>
+    return EFI_OUT_OF_RESOURCES;<br>
+  }<br>
+<br>
+  ((IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_DATA *)SendData)->SessionId = SessionId;<br>
+  ((IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_DATA *)SendData)->Offset    = Offset;<br>
+  CopyMem (((IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_DATA *)SendData)->Data, Data, sizeof (UINT8) * WriteLength);<br>
+<br>
+  ResponseDataSize = 0;<br>
+  Status           = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandWrite, SendData, SendDataSize, NULL, &ResponseDataSize);<br>
+<br>
+  FreePool (SendData);<br>
+  return Status;<br>
+}<br>
+<br>
+/**<br>
+  @param[in]         SessionId        The session ID returned from a call to BlobOpen<br>
+  @param[in]         CommitDataLength The length of data to commit to the blob<br>
+  @param[in]         CommitData       A pointer to the data to commit<br>
+<br>
+  @retval EFI_SUCCESS                Successful commit to the blob.<br>
+  @retval Other                      An error occurred<br>
+**/<br>
+EFI_STATUS<br>
+IpmiBlobTransferCommit (<br>
+  IN  UINT16  SessionId,<br>
+  IN  UINT8   CommitDataLength,<br>
+  IN  UINT8   *CommitData<br>
+  )<br>
+{<br>
+  EFI_STATUS  Status;<br>
+  UINT8       *SendData;<br>
+  UINT32      SendDataSize;<br>
+  UINT32      ResponseDataSize;<br>
+<br>
+  //<br>
+  // Format send data<br>
+  //<br>
+  SendDataSize = sizeof (SessionId) + sizeof (CommitDataLength) + CommitDataLength;<br>
+  SendData     = AllocateZeroPool (SendDataSize);<br>
+  if (SendData == NULL) {<br>
+    return EFI_OUT_OF_RESOURCES;<br>
+  }<br>
+<br>
+  ((IPMI_BLOB_TRANSFER_BLOB_COMMIT_SEND_DATA *)SendData)->SessionId        = SessionId;<br>
+  ((IPMI_BLOB_TRANSFER_BLOB_COMMIT_SEND_DATA *)SendData)->CommitDataLength = CommitDataLength;<br>
+  CopyMem (((IPMI_BLOB_TRANSFER_BLOB_COMMIT_SEND_DATA *)SendData)->CommitData, CommitData, sizeof (UINT8) * CommitDataLength);<br>
+<br>
+  ResponseDataSize = 0;<br>
+<br>
+  Status = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandCommit, SendData, SendDataSize, NULL, &ResponseDataSize);<br>
+<br>
+  FreePool (SendData);<br>
+  return Status;<br>
+}<br>
+<br>
+/**<br>
+  @param[in]         SessionId       The session ID returned from a call to BlobOpen<br>
+<br>
+  @retval EFI_SUCCESS                The blob was closed.<br>
+  @retval Other                      An error occurred<br>
+**/<br>
+EFI_STATUS<br>
+IpmiBlobTransferClose (<br>
+  IN  UINT16  SessionId<br>
+  )<br>
+{<br>
+  EFI_STATUS  Status;<br>
+  UINT8       *SendData;<br>
+  UINT32      SendDataSize;<br>
+  UINT32      ResponseDataSize;<br>
+<br>
+  //<br>
+  // Format send data<br>
+  //<br>
+  SendDataSize = sizeof (IPMI_BLOB_TRANSFER_BLOB_CLOSE_SEND_DATA);<br>
+  SendData     = AllocateZeroPool (SendDataSize);<br>
+  if (SendData == NULL) {<br>
+    return EFI_OUT_OF_RESOURCES;<br>
+  }<br>
+<br>
+  ((IPMI_BLOB_TRANSFER_BLOB_CLOSE_SEND_DATA *)SendData)->SessionId = SessionId;<br>
+<br>
+  ResponseDataSize = 0;<br>
+<br>
+  Status = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandClose, SendData, SendDataSize, NULL, &ResponseDataSize);<br>
+<br>
+  FreePool (SendData);<br>
+  return Status;<br>
+}<br>
+<br>
+/**<br>
+  @param[in]         BlobId          The BlobId to be deleted<br>
+<br>
+  @retval EFI_SUCCESS                The blob was deleted.<br>
+  @retval Other                      An error occurred<br>
+**/<br>
+EFI_STATUS<br>
+IpmiBlobTransferDelete (<br>
+  IN  CHAR8  *BlobId<br>
+  )<br>
+{<br>
+  EFI_STATUS  Status;<br>
+  UINT8       *SendData;<br>
+  UINT32      SendDataSize;<br>
+  UINT32      ResponseDataSize;<br>
+<br>
+  //<br>
+  // Format send data<br>
+  //<br>
+  SendDataSize = sizeof (IPMI_BLOB_TRANSFER_BLOB_DELETE_SEND_DATA);<br>
+  SendData     = AllocateZeroPool (SendDataSize);<br>
+  if (SendData == NULL) {<br>
+    return EFI_OUT_OF_RESOURCES;<br>
+  }<br>
+<br>
+  AsciiStrCpyS (((IPMI_BLOB_TRANSFER_BLOB_DELETE_SEND_DATA *)SendData)->BlobId, AsciiStrLen (BlobId), BlobId);<br>
+<br>
+  ResponseDataSize = 0;<br>
+<br>
+  Status = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandDelete, SendData, SendDataSize, NULL, &ResponseDataSize);<br>
+<br>
+  FreePool (SendData);<br>
+  return Status;<br>
+}<br>
+<br>
+/**<br>
+  @param[in]         BlobId          The Blob ID to gather statistics for<br>
+  @param[out]        BlobState       The current state of the blob<br>
+  @param[out]        Size            Size in bytes of the blob<br>
+  @param[out]        MetadataLength  Length of the optional metadata<br>
+  @param[out]        Metadata        Optional blob-specific metadata<br>
+<br>
+  @retval EFI_SUCCESS                The blob statistics were successfully gathered.<br>
+  @retval Other                      An error occurred<br>
+**/<br>
+EFI_STATUS<br>
+IpmiBlobTransferStat (<br>
+  IN  CHAR8   *BlobId,<br>
+  OUT UINT16  *BlobState,<br>
+  OUT UINT32  *Size,<br>
+  OUT UINT8   *MetadataLength,<br>
+  OUT UINT8   *Metadata<br>
+  )<br>
+{<br>
+  EFI_STATUS  Status;<br>
+  UINT8       *SendData;<br>
+  UINT8       *ResponseData;<br>
+  UINT32      SendDataSize;<br>
+  UINT32      ResponseDataSize;<br>
+<br>
+  if (Metadata == NULL) {<br>
+    ASSERT (FALSE);<br>
+    return EFI_ABORTED;<br>
+  }<br>
+<br>
+  ResponseDataSize = sizeof (IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE);<br>
+  ResponseData     = AllocateZeroPool (ResponseDataSize);<br>
+  if (ResponseData == NULL) {<br>
+    return EFI_OUT_OF_RESOURCES;<br>
+  }<br>
+<br>
+  //<br>
+  // Format send data<br>
+  //<br>
+  SendDataSize = sizeof (IPMI_BLOB_TRANSFER_BLOB_STAT_SEND_DATA);<br>
+  SendData     = AllocateZeroPool (SendDataSize);<br>
+  if (SendData == NULL) {<br>
+    return EFI_OUT_OF_RESOURCES;<br>
+  }<br>
+<br>
+  AsciiStrCpyS (((IPMI_BLOB_TRANSFER_BLOB_STAT_SEND_DATA *)SendData)->BlobId, IPMI_OEM_BLOB_MAX_DATA_PER_PACKET, BlobId);<br>
+<br>
+  Status = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandStat, SendData, SendDataSize, (UINT8 *)ResponseData, &ResponseDataSize);<br>
+  if (!EFI_ERROR (Status)) {<br>
+    *BlobState      = ((IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE *)ResponseData)->BlobState;<br>
+    *Size           = ((IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE *)ResponseData)->Size;<br>
+    *MetadataLength = ((IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE *)ResponseData)->MetaDataLen;<br>
+<br>
+    CopyMem (&Metadata, &((IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE *)ResponseData)->MetaData, sizeof (((IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE *)ResponseData)->MetaData));<br>
+  }<br>
+<br>
+  FreePool (ResponseData);<br>
+  FreePool (SendData);<br>
+  return Status;<br>
+}<br>
+<br>
+/**<br>
+  @param[in]         SessionId       The ID of the session to gather statistics for<br>
+  @param[out]        BlobState       The current state of the blob<br>
+  @param[out]        Size            Size in bytes of the blob<br>
+  @param[out]        MetadataLength  Length of the optional metadata<br>
+  @param[out]        Metadata        Optional blob-specific metadata<br>
+<br>
+  @retval EFI_SUCCESS                The blob statistics were successfully gathered.<br>
+  @retval Other                      An error occurred<br>
+**/<br>
+EFI_STATUS<br>
+IpmiBlobTransferSessionStat (<br>
+  IN  UINT16  SessionId,<br>
+  OUT UINT16  *BlobState,<br>
+  OUT UINT32  *Size,<br>
+  OUT UINT8   *MetadataLength,<br>
+  OUT UINT8   *Metadata<br>
+  )<br>
+{<br>
+  EFI_STATUS  Status;<br>
+  UINT8       *SendData;<br>
+  UINT8       *ResponseData;<br>
+  UINT32      SendDataSize;<br>
+  UINT32      ResponseDataSize;<br>
+<br>
+  if ((BlobState == NULL) || (Size == NULL) || (MetadataLength == NULL) || (Metadata == NULL)) {<br>
+    ASSERT (FALSE);<br>
+    return EFI_ABORTED;<br>
+  }<br>
+<br>
+  ResponseDataSize = sizeof (IPMI_BLOB_TRANSFER_BLOB_STAT_RESPONSE);<br>
+  ResponseData     = AllocateZeroPool (ResponseDataSize);<br>
+  if (ResponseData == NULL) {<br>
+    return EFI_OUT_OF_RESOURCES;<br>
+  }<br>
+<br>
+  //<br>
+  // Format send data<br>
+  //<br>
+  SendDataSize = sizeof (IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_SEND_DATA);<br>
+  SendData     = AllocateZeroPool (SendDataSize);<br>
+  if (SendData == NULL) {<br>
+    return EFI_OUT_OF_RESOURCES;<br>
+  }<br>
+<br>
+  ((IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_SEND_DATA *)SendData)->SessionId = SessionId;<br>
+<br>
+  Status = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandSessionStat, SendData, SendDataSize, (UINT8 *)ResponseData, &ResponseDataSize);<br>
+<br>
+  if (!EFI_ERROR (Status)) {<br>
+    *BlobState      = ((IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_RESPONSE *)ResponseData)->BlobState;<br>
+    *Size           = ((IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_RESPONSE *)ResponseData)->Size;<br>
+    *MetadataLength = ((IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_RESPONSE *)ResponseData)->MetaDataLen;<br>
+<br>
+    CopyMem (&Metadata, &((IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_RESPONSE *)ResponseData)->MetaData, sizeof (((IPMI_BLOB_TRANSFER_BLOB_SESSION_STAT_RESPONSE *)ResponseData)->MetaData));<br>
+  }<br>
+<br>
+  FreePool (ResponseData);<br>
+  FreePool (SendData);<br>
+  return Status;<br>
+}<br>
+<br>
+/**<br>
+  @param[in]         SessionId       The ID of the session to write metadata for<br>
+  @param[in]         Offset          The offset of the metadata to write to<br>
+  @param[in]         Data            The data to write to the metadata<br>
+<br>
+  @retval EFI_SUCCESS                The blob metadata was successfully written.<br>
+  @retval Other                      An error occurred<br>
+**/<br>
+EFI_STATUS<br>
+IpmiBlobTransferWriteMeta (<br>
+  IN  UINT16  SessionId,<br>
+  IN  UINT32  Offset,<br>
+  IN  UINT8   *Data,<br>
+  IN  UINT32  WriteLength<br>
+  )<br>
+{<br>
+  EFI_STATUS  Status;<br>
+  UINT8       *SendData;<br>
+  UINT32      SendDataSize;<br>
+  UINT32      ResponseDataSize;<br>
+<br>
+  //<br>
+  // Format send data<br>
+  //<br>
+  SendDataSize = sizeof (IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_DATA);<br>
+  SendData     = AllocateZeroPool (SendDataSize);<br>
+  if (SendData == NULL) {<br>
+    return EFI_OUT_OF_RESOURCES;<br>
+  }<br>
+<br>
+  ((IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_DATA *)SendData)->SessionId = SessionId;<br>
+  ((IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_DATA *)SendData)->Offset    = Offset;<br>
+  CopyMem (((IPMI_BLOB_TRANSFER_BLOB_WRITE_SEND_DATA *)SendData)->Data, Data, sizeof (UINT8) * WriteLength);<br>
+<br>
+  ResponseDataSize = 0;<br>
+<br>
+  Status = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandWriteMeta, SendData, SendDataSize, NULL, &ResponseDataSize);<br>
+<br>
+  FreePool (SendData);<br>
+  return Status;<br>
+}<br>
+<br>
+/**<br>
+  This is the declaration of an EFI image entry point. This entry point is<br>
+  the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including<br>
+  both device drivers and bus drivers.<br>
+<br>
+  @param[in]  ImageHandle       The firmware allocated handle for the UEFI image.<br>
+  @param[in]  SystemTable       A pointer to the EFI System Table.<br>
+<br>
+  @retval EFI_SUCCESS           The operation completed successfully.<br>
+  @retval Others                An unexpected error occurred.<br>
+<br>
+**/<br>
+EFI_STATUS<br>
+EFIAPI<br>
+IpmiBlobTransferDxeDriverEntryPoint (<br>
+  IN EFI_HANDLE        ImageHandle,<br>
+  IN EFI_SYSTEM_TABLE  *SystemTable<br>
+  )<br>
+{<br>
+  return gBS->InstallMultipleProtocolInterfaces (<br>
+                &ImageHandle,<br>
+                &gEdkiiIpmiBlobTransferProtocolGuid,<br>
+                (VOID *)&mIpmiBlobTransfer,<br>
+                NULL<br>
+                );<br>
+}<br>
diff --git a/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTests.c b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTests.c<br>
new file mode 100644<br>
index 0000000000..f326467922<br>
--- /dev/null<br>
+++ b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/UnitTest/IpmiBlobTransferTestUnitTests.c<br>
@@ -0,0 +1,1113 @@<br>
+/** @file<br>
+*<br>
+*  Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.<br>
</blockquote>
<span style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;">2023</span><br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;">
<blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;">
+*<br>
+*  SPDX-FileCopyrightText: Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES<br>
+*  SPDX-License-Identifier: BSD-2-Clause-Patent<br>
+*<br>
+**/<br>
+#include <stdarg.h><br>
+#include <stddef.h><br>
+#include <setjmp.h><br>
+#include <stdint.h><br>
+#include <cmocka.h><br>
+<br>
+#include <Uefi.h><br>
+#include <Library/BaseMemoryLib.h><br>
+#include <Library/DebugLib.h><br>
+#include <Library/MemoryAllocationLib.h><br>
+#include <Library/HostBasedTestStubLib/IpmiStubLib.h><br>
+<br>
+#include <Library/UnitTestLib.h><br>
+#include <Protocol/IpmiBlobTransfer.h><br>
+#include "../InternalIpmiBlobTransfer.h"<br>
+<br>
+#define UNIT_TEST_NAME     "IPMI Blob Transfer Unit Tests"<br>
+#define UNIT_TEST_VERSION  "1.0"<br>
+<br>
+UINT8  InvalidCompletion[] = {<br>
+  0xC0,             // CompletionCode<br>
+  0xCF, 0xC2, 0x00, // OpenBMC OEN<br>
+};<br>
+#define INVALID_COMPLETION_SIZE  4 * sizeof(UINT8)<br>
+<br>
+UINT8  NoDataResponse[] = {<br>
+  0x00,             // CompletionCode<br>
+  0xCF, 0xC2, 0x00, // OpenBMC OEN<br>
+};<br>
+#define NO_DATA_RESPONSE_SIZE  4 * sizeof(UINT8)<br>
+<br>
+UINT8  BadOenResponse[] = {<br>
+  0x00,             // CompletionCode<br>
+  0xFF, 0xC2, 0x00, // Wrong OEN<br>
+};<br>
+#define BAD_OEN_RESPONSE_SIZE  4 * sizeof(UINT8)<br>
+<br>
+UINT8  BadCrcResponse[] = {<br>
+  0x00,                   // CompletionCode<br>
+  0xCF, 0xC2, 0x00,       // OpenBMC OEN<br>
+  0x00, 0x00,             // CRC<br>
+  0x01, 0x00, 0x00, 0x00, // Data<br>
+};<br>
+#define BAD_CRC_RESPONSE_SIZE  10 * sizeof(UINT8)<br>
+<br>
+UINT8  ValidNoDataResponse[] = {<br>
+  0x00,             // CompletionCode<br>
+  0xCF, 0xC2, 0x00, // OpenBMC OEN<br>
+};<br>
+<br>
+#define VALID_NODATA_RESPONSE_SIZE  4 * sizeof(UINT8)<br>
+<br>
+/**<br>
+  @param[in]  Context    [Optional] An optional parameter that enables:<br>
+                         1) test-case reuse with varied parameters and<br>
+                         2) test-case re-entry for Target tests that need a<br>
+                         reboot.  This parameter is a VOID* and it is the<br>
+                         responsibility of the test author to ensure that the<br>
+                         contents are well understood by all test cases that may<br>
+                         consume it.<br>
+  @retval  UNIT_TEST_PASSED             The Unit test has completed and the test<br>
+                                        case was successful.<br>
+  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.<br>
+**/<br>
+UNIT_TEST_STATUS<br>
+EFIAPI<br>
+GoodCrc (<br>
+  IN UNIT_TEST_CONTEXT  Context<br>
+  )<br>
+{<br>
+  UINT8   Data[5] = { 0x12, 0x34, 0x56, 0x78, 0x90 };<br>
+  UINTN   DataSize;<br>
+  UINT16  Crc;<br>
+<br>
+  DataSize = sizeof (Data);<br>
+<br>
+  Crc = CalculateCrc16 (Data, DataSize);<br>
+<br>
+  UT_ASSERT_EQUAL (Crc, 0xB928);<br>
+  return UNIT_TEST_PASSED;<br>
+}<br>
+<br>
+/**<br>
+  @param[in]  Context    [Optional] An optional parameter that enables:<br>
+                         1) test-case reuse with varied parameters and<br>
+                         2) test-case re-entry for Target tests that need a<br>
+                         reboot.  This parameter is a VOID* and it is the<br>
+                         responsibility of the test author to ensure that the<br>
+                         contents are well understood by all test cases that may<br>
+                         consume it.<br>
+  @retval  UNIT_TEST_PASSED             The Unit test has completed and the test<br>
+                                        case was successful.<br>
+  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.<br>
+**/<br>
+UNIT_TEST_STATUS<br>
+EFIAPI<br>
+BadCrc (<br>
+  IN UNIT_TEST_CONTEXT  Context<br>
+  )<br>
+{<br>
+  UINT8   Data[5] = { 0x12, 0x34, 0x56, 0x78, 0x90 };<br>
+  UINTN   DataSize;<br>
+  UINT16  Crc;<br>
+<br>
+  DataSize = sizeof (Data);<br>
+<br>
+  Crc = CalculateCrc16 (Data, DataSize);<br>
+<br>
+  UT_ASSERT_NOT_EQUAL (Crc, 0x3409);<br>
+  return UNIT_TEST_PASSED;<br>
+}<br>
+<br>
+/**<br>
+  @param[in]  Context    [Optional] An optional parameter that enables:<br>
+                         1) test-case reuse with varied parameters and<br>
+                         2) test-case re-entry for Target tests that need a<br>
+                         reboot.  This parameter is a VOID* and it is the<br>
+                         responsibility of the test author to ensure that the<br>
+                         contents are well understood by all test cases that may<br>
+                         consume it.<br>
+  @retval  UNIT_TEST_PASSED             The Unit test has completed and the test<br>
+                                        case was successful.<br>
+  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.<br>
+**/<br>
+UNIT_TEST_STATUS<br>
+EFIAPI<br>
+SendIpmiBadCompletion (<br>
+  IN UNIT_TEST_CONTEXT  Context<br>
+  )<br>
+{<br>
+  VOID        *ResponseData;<br>
+  UINT32      *ResponseDataSize;<br>
+  EFI_STATUS  Status;<br>
+  VOID        *MockResponseResults = NULL;<br>
+<br>
+  MockResponseResults = (UINT8 *)AllocateZeroPool (INVALID_COMPLETION_SIZE);<br>
+  ResponseDataSize    = (UINT32 *)AllocateZeroPool (sizeof (UINT32));<br>
+  CopyMem (MockResponseResults, &InvalidCompletion, INVALID_COMPLETION_SIZE);<br>
+<br>
+  MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, INVALID_COMPLETION_SIZE, EFI_SUCCESS);<br>
+<br>
+  ResponseData = (UINT8 *)AllocateZeroPool (*ResponseDataSize);<br>
+  Status       = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandGetCount, NULL, 0, ResponseData, ResponseDataSize);<br>
+<br>
+  UT_ASSERT_STATUS_EQUAL (Status, EFI_PROTOCOL_ERROR);<br>
+  FreePool (MockResponseResults);<br>
+  FreePool (ResponseDataSize);<br>
+  FreePool (ResponseData);<br>
+  return UNIT_TEST_PASSED;<br>
+}<br>
+<br>
+/**<br>
+  @param[in]  Context    [Optional] An optional parameter that enables:<br>
+                         1) test-case reuse with varied parameters and<br>
+                         2) test-case re-entry for Target tests that need a<br>
+                         reboot.  This parameter is a VOID* and it is the<br>
+                         responsibility of the test author to ensure that the<br>
+                         contents are well understood by all test cases that may<br>
+                         consume it.<br>
+  @retval  UNIT_TEST_PASSED             The Unit test has completed and the test<br>
+                                        case was successful.<br>
+  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.<br>
+**/<br>
+UNIT_TEST_STATUS<br>
+EFIAPI<br>
+SendIpmiNoDataResponse (<br>
+  IN UNIT_TEST_CONTEXT  Context<br>
+  )<br>
+{<br>
+  VOID        *ResponseData;<br>
+  UINT32      *ResponseDataSize;<br>
+  EFI_STATUS  Status;<br>
+  VOID        *MockResponseResults = NULL;<br>
+<br>
+  MockResponseResults = (UINT8 *)AllocateZeroPool (NO_DATA_RESPONSE_SIZE);<br>
+  ResponseDataSize    = (UINT32 *)AllocateZeroPool (sizeof (UINT32));<br>
+  CopyMem (MockResponseResults, &NoDataResponse, NO_DATA_RESPONSE_SIZE);<br>
+<br>
+  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, NO_DATA_RESPONSE_SIZE, EFI_SUCCESS);<br>
+  if (EFI_ERROR (Status)) {<br>
+    return UNIT_TEST_ERROR_TEST_FAILED;<br>
+  }<br>
+<br>
+  ResponseData = (UINT8 *)AllocateZeroPool (sizeof (NoDataResponse));<br>
+  Status       = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandGetCount, NULL, 0, ResponseData, ResponseDataSize);<br>
+<br>
+  UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);<br>
+  UT_ASSERT_EQUAL (*ResponseDataSize, 0);<br>
+  FreePool (MockResponseResults);<br>
+  FreePool (ResponseDataSize);<br>
+  FreePool (ResponseData);<br>
+  return UNIT_TEST_PASSED;<br>
+}<br>
+<br>
+/**<br>
+  @param[in]  Context    [Optional] An optional parameter that enables:<br>
+                         1) test-case reuse with varied parameters and<br>
+                         2) test-case re-entry for Target tests that need a<br>
+                         reboot.  This parameter is a VOID* and it is the<br>
+                         responsibility of the test author to ensure that the<br>
+                         contents are well understood by all test cases that may<br>
+                         consume it.<br>
+  @retval  UNIT_TEST_PASSED             The Unit test has completed and the test<br>
+                                        case was successful.<br>
+  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.<br>
+**/<br>
+UNIT_TEST_STATUS<br>
+EFIAPI<br>
+SendIpmiBadOenResponse (<br>
+  IN UNIT_TEST_CONTEXT  Context<br>
+  )<br>
+{<br>
+  VOID        *ResponseData;<br>
+  UINT32      *ResponseDataSize;<br>
+  EFI_STATUS  Status;<br>
+  VOID        *MockResponseResults = NULL;<br>
+<br>
+  MockResponseResults = (UINT8 *)AllocateZeroPool (BAD_OEN_RESPONSE_SIZE);<br>
+  ResponseDataSize    = (UINT32 *)AllocateZeroPool (sizeof (UINT32));<br>
+  CopyMem (MockResponseResults, &BadOenResponse, BAD_OEN_RESPONSE_SIZE);<br>
+<br>
+  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, BAD_OEN_RESPONSE_SIZE, EFI_SUCCESS);<br>
+  if (EFI_ERROR (Status)) {<br>
+    return UNIT_TEST_ERROR_TEST_FAILED;<br>
+  }<br>
+<br>
+  ResponseData = (UINT8 *)AllocateZeroPool (sizeof (BadOenResponse));<br>
+  Status       = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandGetCount, NULL, 0, ResponseData, ResponseDataSize);<br>
+<br>
+  UT_ASSERT_STATUS_EQUAL (Status, EFI_PROTOCOL_ERROR);<br>
+  FreePool (MockResponseResults);<br>
+  FreePool (ResponseDataSize);<br>
+  FreePool (ResponseData);<br>
+  return UNIT_TEST_PASSED;<br>
+}<br>
+<br>
+/**<br>
+  @param[in]  Context    [Optional] An optional parameter that enables:<br>
+                         1) test-case reuse with varied parameters and<br>
+                         2) test-case re-entry for Target tests that need a<br>
+                         reboot.  This parameter is a VOID* and it is the<br>
+                         responsibility of the test author to ensure that the<br>
+                         contents are well understood by all test cases that may<br>
+                         consume it.<br>
+  @retval  UNIT_TEST_PASSED             The Unit test has completed and the test<br>
+                                        case was successful.<br>
+  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.<br>
+**/<br>
+UNIT_TEST_STATUS<br>
+EFIAPI<br>
+SendIpmiBadCrcResponse (<br>
+  IN UNIT_TEST_CONTEXT  Context<br>
+  )<br>
+{<br>
+  VOID        *ResponseData;<br>
+  UINT32      *ResponseDataSize;<br>
+  EFI_STATUS  Status;<br>
+  VOID        *MockResponseResults = NULL;<br>
+<br>
+  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof (BAD_CRC_RESPONSE_SIZE));<br>
+  ResponseDataSize    = (UINT32 *)AllocateZeroPool (sizeof (UINT32));<br>
+  CopyMem (MockResponseResults, &BadCrcResponse, BAD_CRC_RESPONSE_SIZE);<br>
+<br>
+  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, BAD_CRC_RESPONSE_SIZE, EFI_SUCCESS);<br>
+  if (EFI_ERROR (Status)) {<br>
+    return UNIT_TEST_ERROR_TEST_FAILED;<br>
+  }<br>
+<br>
+  ResponseData = (UINT8 *)AllocateZeroPool (sizeof (BadCrcResponse));<br>
+  Status       = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandGetCount, NULL, 0, ResponseData, ResponseDataSize);<br>
+<br>
+  UT_ASSERT_STATUS_EQUAL (Status, EFI_CRC_ERROR);<br>
+  FreePool (MockResponseResults);<br>
+  FreePool (ResponseDataSize);<br>
+  FreePool (ResponseData);<br>
+  return UNIT_TEST_PASSED;<br>
+}<br>
+<br>
+UINT8  ValidGetCountResponse[] = {<br>
+  0x00,                   // CompletionCode<br>
+  0xCF, 0xC2, 0x00,       // OpenBMC OEN<br>
+  0xA4, 0x78,             // CRC<br>
+  0x01, 0x00, 0x00, 0x00, // Data<br>
+};<br>
+#define VALID_GET_COUNT_RESPONSE_SIZE  10 * sizeof(UINT8)<br>
+<br>
+/**<br>
+  @param[in]  Context    [Optional] An optional parameter that enables:<br>
+                         1) test-case reuse with varied parameters and<br>
+                         2) test-case re-entry for Target tests that need a<br>
+                         reboot.  This parameter is a VOID* and it is the<br>
+                         responsibility of the test author to ensure that the<br>
+                         contents are well understood by all test cases that may<br>
+                         consume it.<br>
+  @retval  UNIT_TEST_PASSED             The Unit test has completed and the test<br>
+                                        case was successful.<br>
+  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.<br>
+**/<br>
+UNIT_TEST_STATUS<br>
+EFIAPI<br>
+SendIpmiValidCountResponse (<br>
+  IN UNIT_TEST_CONTEXT  Context<br>
+  )<br>
+{<br>
+  UINT8       *ResponseData;<br>
+  UINT32      *ResponseDataSize;<br>
+  EFI_STATUS  Status;<br>
+  VOID        *MockResponseResults = NULL;<br>
+<br>
+  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof (VALID_GET_COUNT_RESPONSE_SIZE));<br>
+  ResponseDataSize    = (UINT32 *)AllocateZeroPool (sizeof (UINT32));<br>
+  CopyMem (MockResponseResults, &ValidGetCountResponse, VALID_GET_COUNT_RESPONSE_SIZE);<br>
+<br>
+  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, VALID_GET_COUNT_RESPONSE_SIZE, EFI_SUCCESS);<br>
+  if (EFI_ERROR (Status)) {<br>
+    return UNIT_TEST_ERROR_TEST_FAILED;<br>
+  }<br>
+<br>
+  ResponseData = AllocateZeroPool (sizeof (ValidGetCountResponse));<br>
+  Status       = IpmiBlobTransferSendIpmi (IpmiBlobTransferSubcommandGetCount, NULL, 0, ResponseData, ResponseDataSize);<br>
+<br>
+  UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);<br>
+  FreePool (MockResponseResults);<br>
+  FreePool (ResponseDataSize);<br>
+  FreePool (ResponseData);<br>
+  return UNIT_TEST_PASSED;<br>
+}<br>
+<br>
+/**<br>
+  @param[in]  Context    [Optional] An optional parameter that enables:<br>
+                         1) test-case reuse with varied parameters and<br>
+                         2) test-case re-entry for Target tests that need a<br>
+                         reboot.  This parameter is a VOID* and it is the<br>
+                         responsibility of the test author to ensure that the<br>
+                         contents are well understood by all test cases that may<br>
+                         consume it.<br>
+  @retval  UNIT_TEST_PASSED             The Unit test has completed and the test<br>
+                                        case was successful.<br>
+  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.<br>
+**/<br>
+UNIT_TEST_STATUS<br>
+EFIAPI<br>
+GetCountValidCountResponse (<br>
+  IN UNIT_TEST_CONTEXT  Context<br>
+  )<br>
+{<br>
+  EFI_STATUS  Status;<br>
+  UINT32      Count;<br>
+  VOID        *MockResponseResults = NULL;<br>
+<br>
+  Count = 0;<br>
+<br>
+  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof (VALID_GET_COUNT_RESPONSE_SIZE));<br>
+  CopyMem (MockResponseResults, &ValidGetCountResponse, VALID_GET_COUNT_RESPONSE_SIZE);<br>
+<br>
+  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, VALID_GET_COUNT_RESPONSE_SIZE, EFI_SUCCESS);<br>
+  if (EFI_ERROR (Status)) {<br>
+    return UNIT_TEST_ERROR_TEST_FAILED;<br>
+  }<br>
+<br>
+  Status = IpmiBlobTransferGetCount (&Count);<br>
+<br>
+  UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);<br>
+  UT_ASSERT_EQUAL (Count, 1);<br>
+  FreePool (MockResponseResults);<br>
+  return UNIT_TEST_PASSED;<br>
+}<br>
+<br>
+UINT8  ValidEnumerateResponse[] = {<br>
+  0x00,                   // CompletionCode<br>
+  0xCF, 0xC2, 0x00,       // OpenBMC OEN<br>
+  0x81, 0x13,             // CRC<br>
+  0x2F, 0x73, 0x6D, 0x62, // Data = "/smbios"<br>
+  0x69, 0x6F, 0x73, 0x00,<br>
+};<br>
+#define VALID_ENUMERATE_RESPONSE_SIZE  14 * sizeof(UINT8)<br>
+<br>
+/**<br>
+  @param[in]  Context    [Optional] An optional parameter that enables:<br>
+                         1) test-case reuse with varied parameters and<br>
+                         2) test-case re-entry for Target tests that need a<br>
+                         reboot.  This parameter is a VOID* and it is the<br>
+                         responsibility of the test author to ensure that the<br>
+                         contents are well understood by all test cases that may<br>
+                         consume it.<br>
+  @retval  UNIT_TEST_PASSED             The Unit test has completed and the test<br>
+                                        case was successful.<br>
+  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.<br>
+**/<br>
+UNIT_TEST_STATUS<br>
+EFIAPI<br>
+EnumerateValidResponse (<br>
+  IN UNIT_TEST_CONTEXT  Context<br>
+  )<br>
+{<br>
+  EFI_STATUS  Status;<br>
+  CHAR8       *BlobId;<br>
+  VOID        *MockResponseResults = NULL;<br>
+<br>
+  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof (VALID_ENUMERATE_RESPONSE_SIZE));<br>
+  CopyMem (MockResponseResults, &ValidEnumerateResponse, VALID_ENUMERATE_RESPONSE_SIZE);<br>
+<br>
+  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, VALID_ENUMERATE_RESPONSE_SIZE, EFI_SUCCESS);<br>
+  if (EFI_ERROR (Status)) {<br>
+    return UNIT_TEST_ERROR_TEST_FAILED;<br>
+  }<br>
+<br>
+  BlobId = AllocateZeroPool (sizeof (CHAR8) * IPMI_OEM_BLOB_MAX_DATA_PER_PACKET);<br>
+<br>
+  Status = IpmiBlobTransferEnumerate (0, BlobId);<br>
+<br>
+  UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);<br>
+  UT_ASSERT_MEM_EQUAL (BlobId, "/smbios", 7);<br>
+  FreePool (MockResponseResults);<br>
+  FreePool (BlobId);<br>
+  return UNIT_TEST_PASSED;<br>
+}<br>
+<br>
+/**<br>
+  @param[in]  Context    [Optional] An optional parameter that enables:<br>
+                         1) test-case reuse with varied parameters and<br>
+                         2) test-case re-entry for Target tests that need a<br>
+                         reboot.  This parameter is a VOID* and it is the<br>
+                         responsibility of the test author to ensure that the<br>
+                         contents are well understood by all test cases that may<br>
+                         consume it.<br>
+  @retval  UNIT_TEST_PASSED             The Unit test has completed and the test<br>
+                                        case was successful.<br>
+  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.<br>
+**/<br>
+UNIT_TEST_STATUS<br>
+EFIAPI<br>
+EnumerateInvalidBuffer (<br>
+  IN UNIT_TEST_CONTEXT  Context<br>
+  )<br>
+{<br>
+  CHAR8       *BlobId;<br>
+  EFI_STATUS  Status;<br>
+  VOID        *MockResponseResults = NULL;<br>
+<br>
+  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof (VALID_ENUMERATE_RESPONSE_SIZE));<br>
+  CopyMem (MockResponseResults, &ValidEnumerateResponse, VALID_ENUMERATE_RESPONSE_SIZE);<br>
+<br>
+  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, VALID_ENUMERATE_RESPONSE_SIZE, EFI_SUCCESS);<br>
+  if (EFI_ERROR (Status)) {<br>
+    return UNIT_TEST_ERROR_TEST_FAILED;<br>
+  }<br>
+<br>
+  BlobId = NULL;<br>
+<br>
+  UT_EXPECT_ASSERT_FAILURE (IpmiBlobTransferEnumerate (0, BlobId), NULL);<br>
+<br>
+  FreePool (MockResponseResults);<br>
+  return UNIT_TEST_PASSED;<br>
+}<br>
+<br>
+UINT8  ValidOpenResponse[] = {<br>
+  0x00,             // CompletionCode<br>
+  0xCF, 0xC2, 0x00, // OpenBMC OEN<br>
+  0x93, 0xD1,       // CRC<br>
+  0x03, 0x00,       // SessionId = 3<br>
+};<br>
+#define VALID_OPEN_RESPONSE_SIZE  8 * sizeof(UINT8)<br>
+<br>
+/**<br>
+  @param[in]  Context    [Optional] An optional parameter that enables:<br>
+                         1) test-case reuse with varied parameters and<br>
+                         2) test-case re-entry for Target tests that need a<br>
+                         reboot.  This parameter is a VOID* and it is the<br>
+                         responsibility of the test author to ensure that the<br>
+                         contents are well understood by all test cases that may<br>
+                         consume it.<br>
+  @retval  UNIT_TEST_PASSED             The Unit test has completed and the test<br>
+                                        case was successful.<br>
+  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.<br>
+**/<br>
+UNIT_TEST_STATUS<br>
+EFIAPI<br>
+OpenValidResponse (<br>
+  IN UNIT_TEST_CONTEXT  Context<br>
+  )<br>
+{<br>
+  EFI_STATUS  Status;<br>
+  CHAR8       *BlobId;<br>
+  UINT16      Flags;<br>
+  UINT16      SessionId;<br>
+  VOID        *MockResponseResults  = NULL;<br>
+  VOID        *MockResponseResults2 = NULL;<br>
+  VOID        *MockResponseResults3 = NULL;<br>
+<br>
+  Flags = BLOB_TRANSFER_STAT_OPEN_W;<br>
+<br>
+  //<br>
+  // An open call effectively leads to three IPMI commands<br>
+  // 1. GetCount of blobs<br>
+  // 2. Enumerate the requested blob<br>
+  // 3. Open the requested blob<br>
+  //<br>
+  // So we'll push three Ipmi responses in this case<br>
+  //<br>
+<br>
+  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof (VALID_OPEN_RESPONSE_SIZE));<br>
+<br>
+  CopyMem (MockResponseResults, &ValidOpenResponse, VALID_OPEN_RESPONSE_SIZE);<br>
+  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, VALID_OPEN_RESPONSE_SIZE, EFI_SUCCESS);<br>
+  if (EFI_ERROR (Status)) {<br>
+    return UNIT_TEST_ERROR_TEST_FAILED;<br>
+  }<br>
+<br>
+  MockResponseResults2 = (UINT8 *)AllocateZeroPool (sizeof (VALID_ENUMERATE_RESPONSE_SIZE));<br>
+  CopyMem (MockResponseResults2, &ValidEnumerateResponse, VALID_ENUMERATE_RESPONSE_SIZE);<br>
+  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults2, VALID_ENUMERATE_RESPONSE_SIZE, EFI_SUCCESS);<br>
+  if (EFI_ERROR (Status)) {<br>
+    return UNIT_TEST_ERROR_TEST_FAILED;<br>
+  }<br>
+<br>
+  MockResponseResults3 = (UINT8 *)AllocateZeroPool (sizeof (VALID_GET_COUNT_RESPONSE_SIZE));<br>
+  CopyMem (MockResponseResults3, &ValidGetCountResponse, VALID_GET_COUNT_RESPONSE_SIZE);<br>
+  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults3, VALID_GET_COUNT_RESPONSE_SIZE, EFI_SUCCESS);<br>
+  if (EFI_ERROR (Status)) {<br>
+    return UNIT_TEST_ERROR_TEST_FAILED;<br>
+  }<br>
+<br>
+  BlobId = "/smbios";<br>
+<br>
+  Status = IpmiBlobTransferOpen (BlobId, Flags, &SessionId);<br>
+<br>
+  UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);<br>
+  UT_ASSERT_EQUAL (SessionId, 3);<br>
+  FreePool (MockResponseResults);<br>
+  return UNIT_TEST_PASSED;<br>
+}<br>
+<br>
+UINT8  ValidReadResponse[] = {<br>
+  0x00,                   // CompletionCode<br>
+  0xCF, 0xC2, 0x00,       // OpenBMC OEN<br>
+  0x21, 0x6F,             // CRC<br>
+  0x00, 0x01, 0x02, 0x03, // Data to read<br>
+};<br>
+<br>
+#define VALID_READ_RESPONSE_SIZE  10 * sizeof(UINT8)<br>
+<br>
+/**<br>
+  @param[in]  Context    [Optional] An optional parameter that enables:<br>
+                         1) test-case reuse with varied parameters and<br>
+                         2) test-case re-entry for Target tests that need a<br>
+                         reboot.  This parameter is a VOID* and it is the<br>
+                         responsibility of the test author to ensure that the<br>
+                         contents are well understood by all test cases that may<br>
+                         consume it.<br>
+  @retval  UNIT_TEST_PASSED             The Unit test has completed and the test<br>
+                                        case was successful.<br>
+  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.<br>
+**/<br>
+UNIT_TEST_STATUS<br>
+EFIAPI<br>
+ReadValidResponse (<br>
+  IN UNIT_TEST_CONTEXT  Context<br>
+  )<br>
+{<br>
+  EFI_STATUS  Status;<br>
+  UINT8       *ResponseData;<br>
+  UINT8       ExpectedDataResponse[4] = { 0x00, 0x01, 0x02, 0x03 };<br>
+  VOID        *MockResponseResults    = NULL;<br>
+<br>
+  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof (VALID_READ_RESPONSE_SIZE));<br>
+  CopyMem (MockResponseResults, &ValidReadResponse, VALID_READ_RESPONSE_SIZE);<br>
+  ResponseData = AllocateZeroPool (sizeof (ValidReadResponse));<br>
+<br>
+  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, VALID_READ_RESPONSE_SIZE, EFI_SUCCESS);<br>
+  if (EFI_ERROR (Status)) {<br>
+    return UNIT_TEST_ERROR_TEST_FAILED;<br>
+  }<br>
+<br>
+  Status = IpmiBlobTransferRead (0, 0, 4, ResponseData);<br>
+<br>
+  UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);<br>
+  UT_ASSERT_MEM_EQUAL (ResponseData, ExpectedDataResponse, 4);<br>
+  FreePool (MockResponseResults);<br>
+  FreePool (ResponseData);<br>
+  return UNIT_TEST_PASSED;<br>
+}<br>
+<br>
+/**<br>
+  @param[in]  Context    [Optional] An optional parameter that enables:<br>
+                         1) test-case reuse with varied parameters and<br>
+                         2) test-case re-entry for Target tests that need a<br>
+                         reboot.  This parameter is a VOID* and it is the<br>
+                         responsibility of the test author to ensure that the<br>
+                         contents are well understood by all test cases that may<br>
+                         consume it.<br>
+  @retval  UNIT_TEST_PASSED             The Unit test has completed and the test<br>
+                                        case was successful.<br>
+  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.<br>
+**/<br>
+UNIT_TEST_STATUS<br>
+EFIAPI<br>
+ReadInvalidBuffer (<br>
+  IN UNIT_TEST_CONTEXT  Context<br>
+  )<br>
+{<br>
+  UINT8       *ResponseData;<br>
+  EFI_STATUS  Status;<br>
+  VOID        *MockResponseResults = NULL;<br>
+<br>
+  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof (VALID_READ_RESPONSE_SIZE));<br>
+  CopyMem (MockResponseResults, &ValidReadResponse, VALID_READ_RESPONSE_SIZE);<br>
+  ResponseData = NULL;<br>
+<br>
+  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, VALID_READ_RESPONSE_SIZE, EFI_SUCCESS);<br>
+  if (EFI_ERROR (Status)) {<br>
+    return UNIT_TEST_ERROR_TEST_FAILED;<br>
+  }<br>
+<br>
+  UT_EXPECT_ASSERT_FAILURE (IpmiBlobTransferRead (0, 0, 4, ResponseData), NULL);<br>
+<br>
+  FreePool (MockResponseResults);<br>
+  return UNIT_TEST_PASSED;<br>
+}<br>
+<br>
+/**<br>
+  @param[in]  Context    [Optional] An optional parameter that enables:<br>
+                         1) test-case reuse with varied parameters and<br>
+                         2) test-case re-entry for Target tests that need a<br>
+                         reboot.  This parameter is a VOID* and it is the<br>
+                         responsibility of the test author to ensure that the<br>
+                         contents are well understood by all test cases that may<br>
+                         consume it.<br>
+  @retval  UNIT_TEST_PASSED             The Unit test has completed and the test<br>
+                                        case was successful.<br>
+  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.<br>
+**/<br>
+UNIT_TEST_STATUS<br>
+EFIAPI<br>
+WriteValidResponse (<br>
+  IN UNIT_TEST_CONTEXT  Context<br>
+  )<br>
+{<br>
+  EFI_STATUS  Status;<br>
+  UINT8       SendData[4]          = { 0x00, 0x01, 0x02, 0x03 };<br>
+  VOID        *MockResponseResults = NULL;<br>
+<br>
+  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof (VALID_NODATA_RESPONSE_SIZE));<br>
+  CopyMem (MockResponseResults, &ValidNoDataResponse, VALID_NODATA_RESPONSE_SIZE);<br>
+<br>
+  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, VALID_NODATA_RESPONSE_SIZE, EFI_SUCCESS);<br>
+  if (EFI_ERROR (Status)) {<br>
+    return UNIT_TEST_ERROR_TEST_FAILED;<br>
+  }<br>
+<br>
+  Status = IpmiBlobTransferWrite (0, 0, SendData, 4);<br>
+<br>
+  UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);<br>
+  FreePool (MockResponseResults);<br>
+  return UNIT_TEST_PASSED;<br>
+}<br>
+<br>
+/**<br>
+  @param[in]  Context    [Optional] An optional parameter that enables:<br>
+                         1) test-case reuse with varied parameters and<br>
+                         2) test-case re-entry for Target tests that need a<br>
+                         reboot.  This parameter is a VOID* and it is the<br>
+                         responsibility of the test author to ensure that the<br>
+                         contents are well understood by all test cases that may<br>
+                         consume it.<br>
+  @retval  UNIT_TEST_PASSED             The Unit test has completed and the test<br>
+                                        case was successful.<br>
+  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.<br>
+**/<br>
+UNIT_TEST_STATUS<br>
+EFIAPI<br>
+CommitValidResponse (<br>
+  IN UNIT_TEST_CONTEXT  Context<br>
+  )<br>
+{<br>
+  EFI_STATUS  Status;<br>
+  UINT8       SendData[4]          = { 0x00, 0x01, 0x02, 0x03 };<br>
+  VOID        *MockResponseResults = NULL;<br>
+<br>
+  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof (VALID_NODATA_RESPONSE_SIZE));<br>
+  CopyMem (MockResponseResults, &ValidNoDataResponse, VALID_NODATA_RESPONSE_SIZE);<br>
+<br>
+  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, VALID_NODATA_RESPONSE_SIZE, EFI_SUCCESS);<br>
+  if (EFI_ERROR (Status)) {<br>
+    return UNIT_TEST_ERROR_TEST_FAILED;<br>
+  }<br>
+<br>
+  Status = IpmiBlobTransferCommit (0, 4, SendData);<br>
+<br>
+  UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);<br>
+  FreePool (MockResponseResults);<br>
+  return UNIT_TEST_PASSED;<br>
+}<br>
+<br>
+/**<br>
+  @param[in]  Context    [Optional] An optional parameter that enables:<br>
+                         1) test-case reuse with varied parameters and<br>
+                         2) test-case re-entry for Target tests that need a<br>
+                         reboot.  This parameter is a VOID* and it is the<br>
+                         responsibility of the test author to ensure that the<br>
+                         contents are well understood by all test cases that may<br>
+                         consume it.<br>
+  @retval  UNIT_TEST_PASSED             The Unit test has completed and the test<br>
+                                        case was successful.<br>
+  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.<br>
+**/<br>
+UNIT_TEST_STATUS<br>
+EFIAPI<br>
+CloseValidResponse (<br>
+  IN UNIT_TEST_CONTEXT  Context<br>
+  )<br>
+{<br>
+  EFI_STATUS  Status;<br>
+  VOID        *MockResponseResults = NULL;<br>
+<br>
+  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof (VALID_NODATA_RESPONSE_SIZE));<br>
+  CopyMem (MockResponseResults, &ValidNoDataResponse, VALID_NODATA_RESPONSE_SIZE);<br>
+<br>
+  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, VALID_NODATA_RESPONSE_SIZE, EFI_SUCCESS);<br>
+  if (EFI_ERROR (Status)) {<br>
+    return UNIT_TEST_ERROR_TEST_FAILED;<br>
+  }<br>
+<br>
+  Status = IpmiBlobTransferClose (1);<br>
+<br>
+  UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);<br>
+  FreePool (MockResponseResults);<br>
+  return UNIT_TEST_PASSED;<br>
+}<br>
+<br>
+/**<br>
+  @param[in]  Context    [Optional] An optional parameter that enables:<br>
+                         1) test-case reuse with varied parameters and<br>
+                         2) test-case re-entry for Target tests that need a<br>
+                         reboot.  This parameter is a VOID* and it is the<br>
+                         responsibility of the test author to ensure that the<br>
+                         contents are well understood by all test cases that may<br>
+                         consume it.<br>
+  @retval  UNIT_TEST_PASSED             The Unit test has completed and the test<br>
+                                        case was successful.<br>
+  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.<br>
+**/<br>
+UNIT_TEST_STATUS<br>
+EFIAPI<br>
+DeleteValidResponse (<br>
+  IN UNIT_TEST_CONTEXT  Context<br>
+  )<br>
+{<br>
+  EFI_STATUS  Status;<br>
+  VOID        *MockResponseResults = NULL;<br>
+<br>
+  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof (VALID_NODATA_RESPONSE_SIZE));<br>
+  CopyMem (MockResponseResults, &ValidNoDataResponse, VALID_NODATA_RESPONSE_SIZE);<br>
+<br>
+  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, VALID_NODATA_RESPONSE_SIZE, EFI_SUCCESS);<br>
+  if (EFI_ERROR (Status)) {<br>
+    return UNIT_TEST_ERROR_TEST_FAILED;<br>
+  }<br>
+<br>
+  Status = IpmiBlobTransferDelete ("/smbios");<br>
+<br>
+  UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);<br>
+  FreePool (MockResponseResults);<br>
+  return UNIT_TEST_PASSED;<br>
+}<br>
+<br>
+UINT8  ValidBlobStatResponse[] = {<br>
+  0x00,                   // CompletionCode<br>
+  0xCF, 0xC2, 0x00,       // OpenBMC OEN<br>
+  0x1F, 0x4F,             // Crc<br>
+  0x01, 0x00,             // BlobState<br>
+  0x02, 0x03, 0x04, 0x05, // BlobSize<br>
+  0x04,                   // MetaDataLen<br>
+  0x06, 0x07, 0x08, 0x09, // MetaData<br>
+};<br>
+<br>
+#define VALID_BLOB_STAT_RESPONSE_SIZE  17 * sizeof(UINT8)<br>
+<br>
+/**<br>
+  @param[in]  Context    [Optional] An optional parameter that enables:<br>
+                         1) test-case reuse with varied parameters and<br>
+                         2) test-case re-entry for Target tests that need a<br>
+                         reboot.  This parameter is a VOID* and it is the<br>
+                         responsibility of the test author to ensure that the<br>
+                         contents are well understood by all test cases that may<br>
+                         consume it.<br>
+  @retval  UNIT_TEST_PASSED             The Unit test has completed and the test<br>
+                                        case was successful.<br>
+  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.<br>
+**/<br>
+UNIT_TEST_STATUS<br>
+EFIAPI<br>
+BlobStatValidResponse (<br>
+  IN UNIT_TEST_CONTEXT  Context<br>
+  )<br>
+{<br>
+  EFI_STATUS  Status;<br>
+  UINT16      *BlobState;<br>
+  UINT32      *Size;<br>
+  UINT8       *MetadataLength;<br>
+  UINT8       *Metadata;<br>
+  UINT8       *ExpectedMetadata;<br>
+  CHAR8       *BlobId;<br>
+  VOID        *MockResponseResults = NULL;<br>
+<br>
+  BlobState        = AllocateZeroPool (sizeof (UINT16));<br>
+  Size             = AllocateZeroPool (sizeof (UINT32));<br>
+  BlobId           = "BlobId";<br>
+  MetadataLength   = AllocateZeroPool (sizeof (UINT8));<br>
+  Metadata         = AllocateZeroPool (4 * sizeof (UINT8));<br>
+  ExpectedMetadata = AllocateZeroPool (4 * sizeof (UINT8));<br>
+<br>
+  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof (VALID_BLOB_STAT_RESPONSE_SIZE));<br>
+  CopyMem (MockResponseResults, &ValidBlobStatResponse, VALID_BLOB_STAT_RESPONSE_SIZE);<br>
+<br>
+  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, VALID_BLOB_STAT_RESPONSE_SIZE, EFI_SUCCESS);<br>
+  if (EFI_ERROR (Status)) {<br>
+    return UNIT_TEST_ERROR_TEST_FAILED;<br>
+  }<br>
+<br>
+  Status = IpmiBlobTransferStat (BlobId, BlobState, Size, MetadataLength, Metadata);<br>
+<br>
+  UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);<br>
+  UT_ASSERT_EQUAL (*BlobState, 1);<br>
+  UT_ASSERT_EQUAL (*Size, 0x05040302);<br>
+  UT_ASSERT_EQUAL (*MetadataLength, 4);<br>
+  UT_ASSERT_MEM_EQUAL (Metadata, ExpectedMetadata, 4);<br>
+  FreePool (MockResponseResults);<br>
+  FreePool (BlobState);<br>
+  FreePool (Size);<br>
+  FreePool (MetadataLength);<br>
+  FreePool (Metadata);<br>
+  return UNIT_TEST_PASSED;<br>
+}<br>
+<br>
+/**<br>
+  @param[in]  Context    [Optional] An optional parameter that enables:<br>
+                         1) test-case reuse with varied parameters and<br>
+                         2) test-case re-entry for Target tests that need a<br>
+                         reboot.  This parameter is a VOID* and it is the<br>
+                         responsibility of the test author to ensure that the<br>
+                         contents are well understood by all test cases that may<br>
+                         consume it.<br>
+  @retval  UNIT_TEST_PASSED             The Unit test has completed and the test<br>
+                                        case was successful.<br>
+  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.<br>
+**/<br>
+UNIT_TEST_STATUS<br>
+EFIAPI<br>
+BlobStatInvalidBuffer (<br>
+  IN UNIT_TEST_CONTEXT  Context<br>
+  )<br>
+{<br>
+  UINT8       *Metadata;<br>
+  EFI_STATUS  Status;<br>
+  VOID        *MockResponseResults = NULL;<br>
+<br>
+  Metadata = NULL;<br>
+<br>
+  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof (VALID_BLOB_STAT_RESPONSE_SIZE));<br>
+  CopyMem (MockResponseResults, &ValidBlobStatResponse, VALID_BLOB_STAT_RESPONSE_SIZE);<br>
+<br>
+  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, VALID_BLOB_STAT_RESPONSE_SIZE, EFI_SUCCESS);<br>
+  if (EFI_ERROR (Status)) {<br>
+    return UNIT_TEST_ERROR_TEST_FAILED;<br>
+  }<br>
+<br>
+  UT_EXPECT_ASSERT_FAILURE (IpmiBlobTransferStat (NULL, 0, 0, 0, Metadata), NULL);<br>
+<br>
+  FreePool (MockResponseResults);<br>
+  return UNIT_TEST_PASSED;<br>
+}<br>
+<br>
+/**<br>
+  @param[in]  Context    [Optional] An optional parameter that enables:<br>
+                         1) test-case reuse with varied parameters and<br>
+                         2) test-case re-entry for Target tests that need a<br>
+                         reboot.  This parameter is a VOID* and it is the<br>
+                         responsibility of the test author to ensure that the<br>
+                         contents are well understood by all test cases that may<br>
+                         consume it.<br>
+  @retval  UNIT_TEST_PASSED             The Unit test has completed and the test<br>
+                                        case was successful.<br>
+  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.<br>
+**/<br>
+UNIT_TEST_STATUS<br>
+EFIAPI<br>
+SessionStatValidResponse (<br>
+  IN UNIT_TEST_CONTEXT  Context<br>
+  )<br>
+{<br>
+  EFI_STATUS  Status;<br>
+  UINT16      *BlobState;<br>
+  UINT32      *Size;<br>
+  UINT8       *MetadataLength;<br>
+  UINT8       *Metadata;<br>
+  UINT8       *ExpectedMetadata;<br>
+  VOID        *MockResponseResults = NULL;<br>
+<br>
+  BlobState        = AllocateZeroPool (sizeof (UINT16));<br>
+  Size             = AllocateZeroPool (sizeof (UINT32));<br>
+  MetadataLength   = AllocateZeroPool (sizeof (UINT8));<br>
+  Metadata         = AllocateZeroPool (4 * sizeof (UINT8));<br>
+  ExpectedMetadata = AllocateZeroPool (4 * sizeof (UINT8));<br>
+<br>
+  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof (VALID_BLOB_STAT_RESPONSE_SIZE));<br>
+  CopyMem (MockResponseResults, &ValidBlobStatResponse, VALID_BLOB_STAT_RESPONSE_SIZE);<br>
+<br>
+  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, VALID_BLOB_STAT_RESPONSE_SIZE, EFI_SUCCESS);<br>
+  if (EFI_ERROR (Status)) {<br>
+    return UNIT_TEST_ERROR_TEST_FAILED;<br>
+  }<br>
+<br>
+  Status = IpmiBlobTransferSessionStat (0, BlobState, Size, MetadataLength, Metadata);<br>
+<br>
+  UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);<br>
+  UT_ASSERT_EQUAL (*BlobState, 1);<br>
+  UT_ASSERT_EQUAL (*Size, 0x05040302);<br>
+  UT_ASSERT_EQUAL (*MetadataLength, 4);<br>
+  UT_ASSERT_MEM_EQUAL (Metadata, ExpectedMetadata, 4);<br>
+  FreePool (MockResponseResults);<br>
+  FreePool (BlobState);<br>
+  FreePool (Size);<br>
+  FreePool (MetadataLength);<br>
+  FreePool (Metadata);<br>
+  return UNIT_TEST_PASSED;<br>
+}<br>
+<br>
+/**<br>
+  @param[in]  Context    [Optional] An optional parameter that enables:<br>
+                         1) test-case reuse with varied parameters and<br>
+                         2) test-case re-entry for Target tests that need a<br>
+                         reboot.  This parameter is a VOID* and it is the<br>
+                         responsibility of the test author to ensure that the<br>
+                         contents are well understood by all test cases that may<br>
+                         consume it.<br>
+  @retval  UNIT_TEST_PASSED             The Unit test has completed and the test<br>
+                                        case was successful.<br>
+  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.<br>
+**/<br>
+UNIT_TEST_STATUS<br>
+EFIAPI<br>
+SessionStatInvalidBuffer (<br>
+  IN UNIT_TEST_CONTEXT  Context<br>
+  )<br>
+{<br>
+  UINT8       *Metadata;<br>
+  EFI_STATUS  Status;<br>
+  VOID        *MockResponseResults = NULL;<br>
+<br>
+  Metadata = NULL;<br>
+<br>
+  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof (VALID_BLOB_STAT_RESPONSE_SIZE));<br>
+  CopyMem (MockResponseResults, &ValidBlobStatResponse, VALID_BLOB_STAT_RESPONSE_SIZE);<br>
+<br>
+  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, VALID_BLOB_STAT_RESPONSE_SIZE, EFI_SUCCESS);<br>
+  if (EFI_ERROR (Status)) {<br>
+    return UNIT_TEST_ERROR_TEST_FAILED;<br>
+  }<br>
+<br>
+  UT_EXPECT_ASSERT_FAILURE (IpmiBlobTransferSessionStat (0, 0, 0, 0, Metadata), NULL);<br>
+<br>
+  FreePool (MockResponseResults);<br>
+  return UNIT_TEST_PASSED;<br>
+}<br>
+<br>
+/**<br>
+  @param[in]  Context    [Optional] An optional parameter that enables:<br>
+                         1) test-case reuse with varied parameters and<br>
+                         2) test-case re-entry for Target tests that need a<br>
+                         reboot.  This parameter is a VOID* and it is the<br>
+                         responsibility of the test author to ensure that the<br>
+                         contents are well understood by all test cases that may<br>
+                         consume it.<br>
+  @retval  UNIT_TEST_PASSED             The Unit test has completed and the test<br>
+                                        case was successful.<br>
+  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.<br>
+**/<br>
+UNIT_TEST_STATUS<br>
+EFIAPI<br>
+WriteMetaValidResponse (<br>
+  IN UNIT_TEST_CONTEXT  Context<br>
+  )<br>
+{<br>
+  EFI_STATUS  Status;<br>
+  VOID        *MockResponseResults = NULL;<br>
+<br>
+  MockResponseResults = (UINT8 *)AllocateZeroPool (sizeof (VALID_NODATA_RESPONSE_SIZE));<br>
+  CopyMem (MockResponseResults, &ValidNoDataResponse, VALID_NODATA_RESPONSE_SIZE);<br>
+<br>
+  Status = MockIpmiSubmitCommand ((UINT8 *)MockResponseResults, VALID_NODATA_RESPONSE_SIZE, EFI_SUCCESS);<br>
+  if (EFI_ERROR (Status)) {<br>
+    return UNIT_TEST_ERROR_TEST_FAILED;<br>
+  }<br>
+<br>
+  Status = IpmiBlobTransferWriteMeta (0, 0, NULL, 0);<br>
+<br>
+  UT_ASSERT_STATUS_EQUAL (Status, EFI_SUCCESS);<br>
+  FreePool (MockResponseResults);<br>
+  return UNIT_TEST_PASSED;<br>
+}<br>
+<br>
+/**<br>
+  Initialize the unit test framework, suite, and unit tests for the<br>
+  sample unit tests and run the unit tests.<br>
+  @retval  EFI_SUCCESS           All test cases were dispatched.<br>
+  @retval  EFI_OUT_OF_RESOURCES  There are not enough resources available to<br>
+                                 initialize the unit tests.<br>
+**/<br>
+EFI_STATUS<br>
+EFIAPI<br>
+SetupAndRunUnitTests (<br>
+  VOID<br>
+  )<br>
+{<br>
+  EFI_STATUS                  Status;<br>
+  UNIT_TEST_FRAMEWORK_HANDLE  Framework;<br>
+  UNIT_TEST_SUITE_HANDLE      IpmiBlobTransfer;<br>
+<br>
+  Framework = NULL;<br>
+  DEBUG ((DEBUG_INFO, "%a: v%a\n", UNIT_TEST_NAME, UNIT_TEST_VERSION));<br>
+<br>
+  Status = InitUnitTestFramework (&Framework, UNIT_TEST_NAME, gEfiCallerBaseName, UNIT_TEST_VERSION);<br>
+  if (EFI_ERROR (Status)) {<br>
+    DEBUG ((DEBUG_ERROR, "Failed to setup Test Framework. Exiting with status = %r\n", Status));<br>
+    ASSERT (FALSE);<br>
+    return Status;<br>
+  }<br>
+<br>
+  //<br>
+  // Populate the Unit Test Suite.<br>
+  //<br>
+  Status = CreateUnitTestSuite (&IpmiBlobTransfer, Framework, "IPMI Blob Transfer Tests", "UnitTest.IpmiBlobTransferCB", NULL, NULL);<br>
+  if (EFI_ERROR (Status)) {<br>
+    DEBUG ((DEBUG_ERROR, "Failed in CreateUnitTestSuite for IPMI Blob Transfer Tests\n"));<br>
+    Status = EFI_OUT_OF_RESOURCES;<br>
+    return Status;<br>
+  }<br>
+<br>
+  // CalculateCrc16<br>
+  Status = AddTestCase (IpmiBlobTransfer, "Test CRC Calculation", "GoodCrc", GoodCrc, NULL, NULL, NULL);<br>
+  Status = AddTestCase (IpmiBlobTransfer, "Test Bad CRC Calculation", "BadCrc", BadCrc, NULL, NULL, NULL);<br>
+  // IpmiBlobTransferSendIpmi<br>
+  Status = AddTestCase (IpmiBlobTransfer, "Send IPMI returns bad completion", "SendIpmiBadCompletion", SendIpmiBadCompletion, NULL, NULL, NULL);<br>
+  Status = AddTestCase (IpmiBlobTransfer, "Send IPMI returns successfully with no data", "SendIpmiNoDataResponse", SendIpmiNoDataResponse, NULL, NULL, NULL);<br>
+  Status = AddTestCase (IpmiBlobTransfer, "Send IPMI returns successfully with bad OEN", "SendIpmiBadOenResponse", SendIpmiBadOenResponse, NULL, NULL, NULL);<br>
+  Status = AddTestCase (IpmiBlobTransfer, "Send IPMI returns successfully with bad CRC", "SendIpmiBadCrcResponse", SendIpmiBadCrcResponse, NULL, NULL, NULL);<br>
+  Status = AddTestCase (IpmiBlobTransfer, "Send IPMI returns with valid GetCount data", "SendIpmiValidCountResponse", SendIpmiValidCountResponse, NULL, NULL, NULL);<br>
+  // IpmiBlobTransferGetCount<br>
+  Status = AddTestCase (IpmiBlobTransfer, "GetCount call with valid data", "GetCountValidCountResponse", GetCountValidCountResponse, NULL, NULL, NULL);<br>
+  // IpmiBlobTransferEnumerate<br>
+  Status = AddTestCase (IpmiBlobTransfer, "Enumerate call with valid data", "EnumerateValidResponse", EnumerateValidResponse, NULL, NULL, NULL);<br>
+  Status = AddTestCase (IpmiBlobTransfer, "Enumerate call with invalid output buffer", "EnumerateInvalidBuffer", EnumerateInvalidBuffer, NULL, NULL, NULL);<br>
+  // IpmiBlobTransferOpen<br>
+  Status = AddTestCase (IpmiBlobTransfer, "Open call with valid data", "OpenValidResponse", OpenValidResponse, NULL, NULL, NULL);<br>
+  // IpmiBlobTransferRead<br>
+  Status = AddTestCase (IpmiBlobTransfer, "Read call with valid data", "ReadValidResponse", ReadValidResponse, NULL, NULL, NULL);<br>
+  Status = AddTestCase (IpmiBlobTransfer, "Read call with invalid buffer", "ReadInvalidBuffer", ReadInvalidBuffer, NULL, NULL, NULL);<br>
+  // IpmiBlobTransferWrite<br>
+  Status = AddTestCase (IpmiBlobTransfer, "Write call with valid data", "WriteValidResponse", WriteValidResponse, NULL, NULL, NULL);<br>
+  // IpmiBlobTransferCommit<br>
+  Status = AddTestCase (IpmiBlobTransfer, "Commit call with valid data", "CommitValidResponse", CommitValidResponse, NULL, NULL, NULL);<br>
+  // IpmiBlobTransferClose<br>
+  Status = AddTestCase (IpmiBlobTransfer, "Close call with valid data", "CloseValidResponse", CloseValidResponse, NULL, NULL, NULL);<br>
+  // IpmiBlobTransferDelete<br>
+  Status = AddTestCase (IpmiBlobTransfer, "Delete call with valid data", "DeleteValidResponse", DeleteValidResponse, NULL, NULL, NULL);<br>
+  // IpmiBlobTransferStat<br>
+  Status = AddTestCase (IpmiBlobTransfer, "Blob Stat call with valid data", "BlobStatValidResponse", BlobStatValidResponse, NULL, NULL, NULL);<br>
+  Status = AddTestCase (IpmiBlobTransfer, "Blob Stat call with invalid buffer", "BlobStatInvalidBuffer", BlobStatInvalidBuffer, NULL, NULL, NULL);<br>
+  // IpmiBlobTransferSessionStat<br>
+  Status = AddTestCase (IpmiBlobTransfer, "Session Stat call with valid data", "SessionStatValidResponse", SessionStatValidResponse, NULL, NULL, NULL);<br>
+  Status = AddTestCase (IpmiBlobTransfer, "Session Stat call with invalid buffer", "SessionStatInvalidBuffer", SessionStatInvalidBuffer, NULL, NULL, NULL);<br>
+  // IpmiBlobTransferWriteMeta<br>
+  Status = AddTestCase (IpmiBlobTransfer, "WriteMeta call with valid data", "WriteMetaValidResponse", WriteMetaValidResponse, NULL, NULL, NULL);<br>
+<br>
+  // Execute the tests.<br>
+  Status = RunAllTestSuites (Framework);<br>
+  return Status;<br>
+}<br>
+<br>
+/**<br>
+  Standard UEFI entry point for target based<br>
+  unit test execution from UEFI Shell.<br>
+**/<br>
+EFI_STATUS<br>
+EFIAPI<br>
+BaseLibUnitTestAppEntry (<br>
+  IN EFI_HANDLE        ImageHandle,<br>
+  IN EFI_SYSTEM_TABLE  *SystemTable<br>
+  )<br>
+{<br>
+  return SetupAndRunUnitTests ();<br>
+}<br>
+<br>
+/**<br>
+  Standard POSIX C entry point for host based unit test execution.<br>
+**/<br>
+int<br>
+main (<br>
+  int   argc,<br>
+  char  *argv[]<br>
+  )<br>
+{<br>
+  return SetupAndRunUnitTests ();<br>
+}<br>
diff --git a/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/Readme.md b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/Readme.md<br>
new file mode 100644<br>
index 0000000000..47800f5801<br>
--- /dev/null<br>
+++ b/Features/ManageabilityPkg/Universal/IpmiBlobTransferDxe/Readme.md<br>
@@ -0,0 +1,24 @@<br>
+# IPMI Blob Transfer Interface Driver<br>
+<br>
+This DXE module is a UEFI implementation of the Phorphor Blob Transfer Interface defined in OpenBMC<br>
+https://github.com/openbmc/phosphor-ipmi-blobs<br>
+<br>
+## NVIDIA's OpenBMC implements this interface as a protocol, allowing UEFI and BMC to transfer blobs over IPMI.<br>
+<br>
+### Usage:<br>
+Any DXE module that wishes to use this protocol should do the following:<br>
+1) The module should have a dependency on gEdkiiIpmiBlobTransferProtocolGuid in its inf "Depex" section<br>
+2) The module should list gEdkiiIpmiBlobTransferProtocolGuid in its inf "Protocol" section<br>
+3) The module's entry point should do a LocateProtocol on gEdkiiIpmiBlobTransferProtocolGuid<br>
+<br>
+### A sample flow of protocol usage is as follows:<br>
+1) A call to IpmiBlobTransferOpen ()<br>
+2) Iterative calls to IpmiBlobTransferWrite<br>
+3) A call to IpmiBlobTransferClose ()<br>
+<br>
+### Unit Tests:<br>
+IpmiBlobTransferDxe/UnitTest/ contains host based unit tests of this implementation.<br>
+Any changes to IpmiBlobTransferDxe should include proof of successful unit tests.<br>
+<br>
+### Debugging<br>
+To assist in debugging any issues, change BLOB_TRANSFER_DEBUG to 1<br>
--<br>
2.17.1<br>
<br>
</blockquote>
<br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;">
<br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;">
<span style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;"></span></div>
</blockquote>
</div>
<br>
</body>
</html>


<div width="1" style="color:white;clear:both">_._,_._,_</div>
<hr>


Groups.io Links:<p>


  
    You receive all messages sent to this group.
  
  


<p>
<a target="_blank" href="https://edk2.groups.io/g/devel/message/103116">View/Reply Online (#103116)</a> |


  

|

  <a target="_blank" href="https://groups.io/mt/98212643/1813853">Mute This Topic</a>

| <a href="https://edk2.groups.io/g/devel/post">New Topic</a><br>




<a href="https://edk2.groups.io/g/devel/editsub/1813853">Your Subscription</a> |
<a href="mailto:devel+owner@edk2.groups.io">Contact Group Owner</a> |

<a href="https://edk2.groups.io/g/devel/unsub">Unsubscribe</a>

 [edk2-devel-archive@redhat.com]<br>
<div width="1" style="color:white;clear:both">_._,_._,_</div>