Refactor DMA function and add responder for WriteFileFromMemory command

The WriteFileFromMemory command transfers data to the BMC from the Host
using DMA. Refactor the DMA transfer function so that the code between
the read and write file commands is common.

Signed-off-by: Eddie James <eajames@us.ibm.com>
Change-Id: I1ce5739c312c4789b882bff04f0e686cc438ab52
diff --git a/libpldm/file_io.c b/libpldm/file_io.c
index 426033a..ca33cef 100644
--- a/libpldm/file_io.c
+++ b/libpldm/file_io.c
@@ -2,16 +2,16 @@
 #include <endian.h>
 #include <string.h>
 
-int decode_read_file_memory_req(const uint8_t *msg, size_t payload_length,
-				uint32_t *file_handle, uint32_t *offset,
-				uint32_t *length, uint64_t *address)
+int decode_rw_file_memory_req(const uint8_t *msg, size_t payload_length,
+			      uint32_t *file_handle, uint32_t *offset,
+			      uint32_t *length, uint64_t *address)
 {
 	if (msg == NULL || file_handle == NULL || offset == NULL ||
 	    length == NULL || address == NULL) {
 		return PLDM_ERROR_INVALID_DATA;
 	}
 
-	if (payload_length != PLDM_READ_FILE_MEM_REQ_BYTES) {
+	if (payload_length != PLDM_RW_FILE_MEM_REQ_BYTES) {
 		return PLDM_ERROR_INVALID_LENGTH;
 	}
 
@@ -25,8 +25,9 @@
 	return PLDM_SUCCESS;
 }
 
-int encode_read_file_memory_resp(uint8_t instance_id, uint8_t completion_code,
-				 uint32_t length, struct pldm_msg *msg)
+int encode_rw_file_memory_resp(uint8_t instance_id, uint8_t command,
+			       uint8_t completion_code, uint32_t length,
+			       struct pldm_msg *msg)
 {
 	struct pldm_header_info header = {0};
 	int rc = PLDM_SUCCESS;
@@ -37,7 +38,7 @@
 	header.msg_type = PLDM_RESPONSE;
 	header.instance = instance_id;
 	header.pldm_type = PLDM_IBM_OEM_TYPE;
-	header.command = PLDM_READ_FILE_INTO_MEMORY;
+	header.command = command;
 
 	if ((rc = pack_pldm_header(&header, &(msg->hdr))) > PLDM_SUCCESS) {
 		return rc;
diff --git a/libpldm/file_io.h b/libpldm/file_io.h
index c273608..345b363 100644
--- a/libpldm/file_io.h
+++ b/libpldm/file_io.h
@@ -14,22 +14,25 @@
 
 /** @brief PLDM Commands in IBM OEM type
  */
-enum pldm_fileio_commands { PLDM_READ_FILE_INTO_MEMORY = 0x6 };
+enum pldm_fileio_commands {
+	PLDM_READ_FILE_INTO_MEMORY = 0x6,
+	PLDM_WRITE_FILE_FROM_MEMORY = 0x7,
+};
 
 /** @brief PLDM Command specific codes
  */
 enum pldm_fileio_completion_codes {
 	PLDM_INVALID_FILE_HANDLE = 0x80,
 	PLDM_DATA_OUT_OF_RANGE = 0x81,
-	PLDM_INVALID_READ_LENGTH = 0x82
+	PLDM_INVALID_READ_LENGTH = 0x82,
+	PLDM_INVALID_WRITE_LENGTH = 0x83,
 };
 
-#define PLDM_READ_FILE_MEM_REQ_BYTES 20
-#define PLDM_READ_FILE_MEM_RESP_BYTES 5
+#define PLDM_RW_FILE_MEM_REQ_BYTES 20
+#define PLDM_RW_FILE_MEM_RESP_BYTES 5
 
-/* ReadFileIntoMemory */
-
-/** @brief Decode ReadFileIntoMemory commands request data
+/** @brief Decode ReadFileIntoMemory and WriteFileFromMemory commands request
+ *         data
  *
  *  @param[in] msg - Pointer to PLDM request message payload
  *  @param[in] payload_length - Length of request payload
@@ -40,13 +43,15 @@
  *                        written to
  *  @return pldm_completion_codes
  */
-int decode_read_file_memory_req(const uint8_t *msg, size_t payload_length,
-				uint32_t *file_handle, uint32_t *offset,
-				uint32_t *length, uint64_t *address);
+int decode_rw_file_memory_req(const uint8_t *msg, size_t payload_length,
+			      uint32_t *file_handle, uint32_t *offset,
+			      uint32_t *length, uint64_t *address);
 
-/** @brief Create a PLDM response for ReadFileIntoMemory
+/** @brief Create a PLDM response for ReadFileIntoMemory and
+ *         WriteFileFromMemory
  *
  *  @param[in] instance_id - Message's instance id
+ *  @param[in] command - PLDM command
  *  @param[in] completion_code - PLDM completion code
  *  @param[in] length - Number of bytes read. This could be less than what the
 			 requester asked for.
@@ -54,8 +59,9 @@
  *  @return pldm_completion_codes
  *  @note  Caller is responsible for memory alloc and dealloc of param 'msg'
  */
-int encode_read_file_memory_resp(uint8_t instance_id, uint8_t completion_code,
-				 uint32_t length, struct pldm_msg *msg);
+int encode_rw_file_memory_resp(uint8_t instance_id, uint8_t command,
+			       uint8_t completion_code, uint32_t length,
+			       struct pldm_msg *msg);
 
 #ifdef __cplusplus
 }
diff --git a/libpldmresponder/file_io.cpp b/libpldmresponder/file_io.cpp
index 9caa45a..ed043c6 100644
--- a/libpldmresponder/file_io.cpp
+++ b/libpldmresponder/file_io.cpp
@@ -21,76 +21,141 @@
 namespace fs = std::filesystem;
 using namespace phosphor::logging;
 
-int transferDatatoHost(const fs::path& file, uint32_t offset, uint32_t length,
-                       uint64_t address)
+namespace dma
 {
-    // Align the length of the memory mapping to the page size.
+
+/** @struct AspeedXdmaOp
+ *
+ * Structure representing XDMA operation
+ */
+struct AspeedXdmaOp
+{
+    uint8_t upstream;  //!< boolean indicating the direction of the DMA
+                       //!< operation, true means a transfer from BMC to host.
+    uint64_t hostAddr; //!< the DMA address on the host side, configured by
+                       //!< PCI subsystem.
+    uint32_t len;      //!< the size of the transfer in bytes, it should be a
+                       //!< multiple of 16 bytes
+} __attribute__((packed));
+
+constexpr auto xdmaDev = "/dev/xdma";
+
+int transferDataHost(const fs::path& path, uint32_t offset, uint32_t length,
+                     uint64_t address, bool upstream)
+{
     static const size_t pageSize = getpagesize();
     uint32_t numPages = length / pageSize;
-    uint32_t pageLength = numPages * pageSize;
-    if (length > pageLength)
+    uint32_t pageAlignedLength = numPages * pageSize;
+
+    if (length > pageAlignedLength)
     {
-        pageLength += pageSize;
+        pageAlignedLength += pageSize;
     }
 
-    auto mmapCleanup = [pageLength](void* vgaMem) {
-        munmap(vgaMem, pageLength);
+    auto mmapCleanup = [pageAlignedLength](void* vgaMem) {
+        munmap(vgaMem, pageAlignedLength);
     };
 
     int fd = -1;
     int rc = 0;
-    fd = open(dma::xdmaDev, O_RDWR);
+    fd = open(xdmaDev, O_RDWR);
     if (fd < 0)
     {
-        log<level::ERR>("Opening the xdma device failed", entry("RC=%d", rc));
+        rc = -errno;
+        log<level::ERR>("Failed to open the XDMA device", entry("RC=%d", rc));
         return rc;
     }
-    auto xdmaFDPtr = std::make_unique<utils::CustomFD>(fd);
-    auto& xdmaFD = *(xdmaFDPtr.get());
 
-    void* vgaMem = nullptr;
+    utils::CustomFD xdmaFd(fd);
 
-    vgaMem = mmap(nullptr, pageLength, PROT_WRITE, MAP_SHARED, xdmaFD(), 0);
+    void* vgaMem;
+    vgaMem = mmap(nullptr, pageAlignedLength, upstream ? PROT_WRITE : PROT_READ,
+                  MAP_SHARED, xdmaFd(), 0);
     if (MAP_FAILED == vgaMem)
     {
         rc = -errno;
-        log<level::ERR>("mmap operation failed", entry("RC=%d", rc));
+        log<level::ERR>("Failed to mmap the XDMA device", entry("RC=%d", rc));
         return rc;
     }
+
     std::unique_ptr<void, decltype(mmapCleanup)> vgaMemPtr(vgaMem, mmapCleanup);
 
-    // Populate the VGA memory with the contents of the file
-    std::ifstream stream(file.string());
-    stream.seekg(offset);
-    stream.read(static_cast<char*>(vgaMemPtr.get()), length);
-    if (stream.gcount() != length)
+    if (upstream)
     {
-        log<level::ERR>(
-            "mismatch between number of characters to read and the length read",
-            entry("LENGTH=%d", length), entry("COUNT=%d", stream.gcount()));
-        return -1;
+        std::ifstream stream(path.string());
+
+        stream.seekg(offset);
+        stream.read(static_cast<char*>(vgaMemPtr.get()), length);
+
+        if (stream.gcount() != length)
+        {
+            log<level::ERR>("mismatch between number of characters to read and "
+                            "the length read",
+                            entry("LENGTH=%d", length),
+                            entry("COUNT=%d", stream.gcount()));
+            return -1;
+        }
     }
 
-    struct dma::AspeedXdmaOp xdmaOp
-    {
-    };
-    xdmaOp.upstream = true;
+    AspeedXdmaOp xdmaOp;
+    xdmaOp.upstream = upstream ? 1 : 0;
     xdmaOp.hostAddr = address;
     xdmaOp.len = length;
 
-    // Initiate the DMA operation
-    rc = write(xdmaFD(), &xdmaOp, sizeof(xdmaOp));
+    rc = write(xdmaFd(), &xdmaOp, sizeof(xdmaOp));
     if (rc < 0)
     {
         rc = -errno;
-        log<level::ERR>("the dma operation failed", entry("RC=%d", rc),
-                        entry("UPSTREAM=%d", xdmaOp.upstream),
+        log<level::ERR>("Failed to execute the DMA operation",
+                        entry("RC=%d", rc), entry("UPSTREAM=%d", upstream),
                         entry("ADDRESS=%lld", address),
                         entry("LENGTH=%d", length));
         return rc;
     }
 
-    return rc;
+    if (!upstream)
+    {
+        std::ofstream stream(path.string());
+
+        stream.seekp(offset);
+        stream.write(static_cast<const char*>(vgaMemPtr.get()), length);
+    }
+
+    return 0;
+}
+
+} // namespace dma
+
+void transferAll(uint8_t command, fs::path& path, uint32_t offset,
+                 uint32_t length, uint64_t address, bool upstream,
+                 pldm_msg* response)
+{
+    uint32_t origLength = length;
+
+    while (length > dma::maxSize)
+    {
+        auto rc = dma::transferDataHost(path, offset, dma::maxSize, address,
+                                        upstream);
+        if (rc < 0)
+        {
+            encode_rw_file_memory_resp(0, command, PLDM_ERROR, 0, response);
+            return;
+        }
+
+        offset += dma::maxSize;
+        length -= dma::maxSize;
+        address += dma::maxSize;
+    }
+
+    auto rc = dma::transferDataHost(path, offset, length, address, upstream);
+    if (rc < 0)
+    {
+        encode_rw_file_memory_resp(0, command, PLDM_ERROR, 0, response);
+        return;
+    }
+
+    encode_rw_file_memory_resp(0, command, PLDM_SUCCESS, origLength, response);
+    return;
 }
 
 void readFileIntoMemory(const uint8_t* request, size_t payloadLength,
@@ -100,33 +165,33 @@
     uint32_t offset = 0;
     uint32_t length = 0;
     uint64_t address = 0;
+    fs::path path("");
 
-    if (payloadLength != PLDM_READ_FILE_MEM_REQ_BYTES)
+    if (payloadLength != PLDM_RW_FILE_MEM_REQ_BYTES)
     {
-        encode_read_file_memory_resp(0, PLDM_ERROR_INVALID_LENGTH, 0, response);
+        encode_rw_file_memory_resp(0, PLDM_READ_FILE_INTO_MEMORY,
+                                   PLDM_ERROR_INVALID_LENGTH, 0, response);
         return;
     }
 
-    decode_read_file_memory_req(request, payloadLength, &fileHandle, &offset,
-                                &length, &address);
+    decode_rw_file_memory_req(request, payloadLength, &fileHandle, &offset,
+                              &length, &address);
 
-    constexpr auto readFilePath = "";
-
-    fs::path path{readFilePath};
     if (!fs::exists(path))
     {
         log<level::ERR>("File does not exist", entry("HANDLE=%d", fileHandle));
-        encode_read_file_memory_resp(0, PLDM_INVALID_FILE_HANDLE, 0, response);
+        encode_rw_file_memory_resp(0, PLDM_READ_FILE_INTO_MEMORY,
+                                   PLDM_INVALID_FILE_HANDLE, 0, response);
         return;
     }
 
     auto fileSize = fs::file_size(path);
-
     if (offset >= fileSize)
     {
         log<level::ERR>("Offset exceeds file size", entry("OFFSET=%d", offset),
                         entry("FILE_SIZE=%d", fileSize));
-        encode_read_file_memory_resp(0, PLDM_DATA_OUT_OF_RANGE, 0, response);
+        encode_rw_file_memory_resp(0, PLDM_READ_FILE_INTO_MEMORY,
+                                   PLDM_DATA_OUT_OF_RANGE, 0, response);
         return;
     }
 
@@ -137,41 +202,65 @@
 
     if (length % dma::minSize)
     {
-        log<level::ERR>("Readlength is not a multiple of DMA minSize",
+        log<level::ERR>("Read length is not a multiple of DMA minSize",
                         entry("LENGTH=%d", length));
-        encode_read_file_memory_resp(0, PLDM_INVALID_READ_LENGTH, 0, response);
+        encode_rw_file_memory_resp(0, PLDM_READ_FILE_INTO_MEMORY,
+                                   PLDM_INVALID_READ_LENGTH, 0, response);
         return;
     }
 
-    uint32_t origLength = length;
+    transferAll(PLDM_READ_FILE_INTO_MEMORY, path, offset, length, address, true,
+                response);
+}
 
-    while (length > 0)
+void writeFileFromMemory(const uint8_t* request, size_t payloadLength,
+                         pldm_msg* response)
+{
+    uint32_t fileHandle = 0;
+    uint32_t offset = 0;
+    uint32_t length = 0;
+    uint64_t address = 0;
+    fs::path path("");
+
+    if (payloadLength != PLDM_RW_FILE_MEM_REQ_BYTES)
     {
-        if (length > dma::maxSize)
-        {
-            auto rc =
-                dma::transferDatatoHost(path, offset, dma::maxSize, address);
-            if (rc < 0)
-            {
-                encode_read_file_memory_resp(0, PLDM_ERROR, 0, response);
-                return;
-            }
-            offset += dma::maxSize;
-            length -= dma::maxSize;
-            address += dma::maxSize;
-        }
-        else
-        {
-            auto rc = dma::transferDatatoHost(path, offset, length, address);
-            if (rc < 0)
-            {
-                encode_read_file_memory_resp(0, PLDM_ERROR, 0, response);
-                return;
-            }
-            encode_read_file_memory_resp(0, PLDM_SUCCESS, origLength, response);
-            return;
-        }
+        encode_rw_file_memory_resp(0, PLDM_WRITE_FILE_FROM_MEMORY,
+                                   PLDM_ERROR_INVALID_LENGTH, 0, response);
+        return;
     }
+
+    decode_rw_file_memory_req(request, payloadLength, &fileHandle, &offset,
+                              &length, &address);
+
+    if (length % dma::minSize)
+    {
+        log<level::ERR>("Write length is not a multiple of DMA minSize",
+                        entry("LENGTH=%d", length));
+        encode_rw_file_memory_resp(0, PLDM_WRITE_FILE_FROM_MEMORY,
+                                   PLDM_INVALID_WRITE_LENGTH, 0, response);
+        return;
+    }
+
+    if (!fs::exists(path))
+    {
+        log<level::ERR>("File does not exist", entry("HANDLE=%d", fileHandle));
+        encode_rw_file_memory_resp(0, PLDM_WRITE_FILE_FROM_MEMORY,
+                                   PLDM_INVALID_FILE_HANDLE, 0, response);
+        return;
+    }
+
+    auto fileSize = fs::file_size(path);
+    if (offset >= fileSize)
+    {
+        log<level::ERR>("Offset exceeds file size", entry("OFFSET=%d", offset),
+                        entry("FILE_SIZE=%d", fileSize));
+        encode_rw_file_memory_resp(0, PLDM_WRITE_FILE_FROM_MEMORY,
+                                   PLDM_DATA_OUT_OF_RANGE, 0, response);
+        return;
+    }
+
+    transferAll(PLDM_WRITE_FILE_FROM_MEMORY, path, offset, length, address,
+                false, response);
 }
 
 } // namespace responder
diff --git a/libpldmresponder/file_io.hpp b/libpldmresponder/file_io.hpp
index a983963..ae475b9 100644
--- a/libpldmresponder/file_io.hpp
+++ b/libpldmresponder/file_io.hpp
@@ -51,45 +51,51 @@
 
 } // namespace utils
 
+namespace fs = std::filesystem;
+
 namespace dma
 {
 
-/** @struct AspeedXdmaOp
- *
- * Structure representing XDMA operation
- */
-struct AspeedXdmaOp
-{
-    uint8_t upstream;  //!< boolean indicating the direction of the DMA
-                       //!< operation, true means a transfer from BMC to host.
-    uint64_t hostAddr; //!< the DMA address on the host side, configured by
-                       //!< PCI subsystem.
-    uint32_t len;      //!< the size of the transfer in bytes, it should be a
-                       //!< multiple of 16 bytes
-} __attribute__((packed));
-
-constexpr auto xdmaDev = "/dev/xdma";
-
 // The minimum data size of dma transfer in bytes
 constexpr uint32_t minSize = 16;
 
 // 16MB - 4096B (16773120 bytes) is the maximum data size of DMA transfer
 constexpr size_t maxSize = (16 * 1024 * 1024) - 4096;
 
-namespace fs = std::filesystem;
-
-/** @brief API to transfer data from BMC to host using DMA
+/** @brief API to transfer data between BMC and host using DMA
  *
- *  @param[in] file - pathname of the file from which to DMA data
- *  @param[in] offset - offset in the file
- *  @param[in] length - length of data to read from the file
- *  @param[in] address - dma address on the host side to transfer data
+ * @param[in] path     - pathname of the file to transfer data from or to
+ * @param[in] offset   - offset in the file
+ * @param[in] length   - length of the data to transfer
+ * @param[in] address  - DMA address on the host
+ * @param[in] upstream - indicates directon of the transfer; true indicates
+ *                       transfer to the host
+ *
+ * @return             - returns 0 on success, negative errno on failure
  */
-int transferDatatoHost(const fs::path& file, uint32_t offset, uint32_t length,
-                       uint64_t address);
-
+int transferDataHost(const fs::path& path, uint32_t offset, uint32_t length,
+                     uint64_t address, bool upstream);
 } // namespace dma
 
+/** @brief Transfer the data between BMC and host using DMA.
+ *
+ *  There is a max size for each DMA operation, transferAll API abstracts this
+ *  and the requested length is broken down into multiple DMA operations if the
+ *  length exceed max size.
+ *
+ * @param[in] command  - PLDM command
+ * @param[in] path     - pathname of the file to transfer data from or to
+ * @param[in] offset   - offset in the file
+ * @param[in] length   - length of the data to transfer
+ * @param[in] address  - DMA address on the host
+ * @param[in] upstream - indicates direction of the transfer; true indicates
+ *                       transfer to the host
+ * @param[out] response - response message location
+ */
+void transferAll(uint8_t command, fs::path& path, uint32_t offset,
+                 uint32_t length, uint64_t address, bool upstream,
+                 pldm_msg* response);
+
 /** @brief Handler for readFileIntoMemory command
  *
  *  @param[in] request - pointer to PLDM request payload
@@ -99,5 +105,14 @@
 void readFileIntoMemory(const uint8_t* request, size_t payloadLength,
                         pldm_msg* response);
 
+/** @brief Handler for writeFileIntoMemory command
+ *
+ *  @param[in] request - pointer to PLDM request payload
+ *  @param[in] payloadLength - length of the message payload
+ *  @param[out] response - response message location
+ */
+void writeFileFromMemory(const uint8_t* request, size_t payloadLength,
+                         pldm_msg* response);
+
 } // namespace responder
 } // namespace pldm
diff --git a/test/libpldm_fileio_test.cpp b/test/libpldm_fileio_test.cpp
index 4968d39..2a5dce1 100644
--- a/test/libpldm_fileio_test.cpp
+++ b/test/libpldm_fileio_test.cpp
@@ -7,9 +7,9 @@
 
 #include <gtest/gtest.h>
 
-TEST(ReadFileIntoMemory, testGoodDecodeRequest)
+TEST(ReadWriteFileMemory, testGoodDecodeRequest)
 {
-    std::array<uint8_t, PLDM_READ_FILE_MEM_REQ_BYTES> requestMsg{};
+    std::array<uint8_t, PLDM_RW_FILE_MEM_REQ_BYTES> requestMsg{};
 
     // Random value for fileHandle, offset, length, address
     uint32_t fileHandle = 0x12345678;
@@ -31,9 +31,9 @@
     uint64_t retAddress = 0;
 
     // Invoke decode the read file memory request
-    auto rc = decode_read_file_memory_req(requestMsg.data(), requestMsg.size(),
-                                          &retFileHandle, &retOffset,
-                                          &retLength, &retAddress);
+    auto rc = decode_rw_file_memory_req(requestMsg.data(), requestMsg.size(),
+                                        &retFileHandle, &retOffset, &retLength,
+                                        &retAddress);
 
     ASSERT_EQ(rc, PLDM_SUCCESS);
     ASSERT_EQ(fileHandle, retFileHandle);
@@ -42,7 +42,7 @@
     ASSERT_EQ(address, retAddress);
 }
 
-TEST(ReadFileIntoMemory, testBadDecodeRequest)
+TEST(ReadWriteFileMemory, testBadDecodeRequest)
 {
     uint32_t fileHandle = 0;
     uint32_t offset = 0;
@@ -50,31 +50,33 @@
     uint64_t address = 0;
 
     // Request payload message is missing
-    auto rc = decode_read_file_memory_req(NULL, 0, &fileHandle, &offset,
-                                          &length, &address);
+    auto rc = decode_rw_file_memory_req(NULL, 0, &fileHandle, &offset, &length,
+                                        &address);
     ASSERT_EQ(rc, PLDM_ERROR_INVALID_DATA);
 
-    std::array<uint8_t, PLDM_READ_FILE_MEM_REQ_BYTES> requestMsg{};
+    std::array<uint8_t, PLDM_RW_FILE_MEM_REQ_BYTES> requestMsg{};
 
     // Address is NULL
-    rc = decode_read_file_memory_req(requestMsg.data(), requestMsg.size(),
-                                     &fileHandle, &offset, &length, NULL);
+    rc = decode_rw_file_memory_req(requestMsg.data(), requestMsg.size(),
+                                   &fileHandle, &offset, &length, NULL);
     ASSERT_EQ(rc, PLDM_ERROR_INVALID_DATA);
 
     // Payload length is invalid
-    rc = decode_read_file_memory_req(requestMsg.data(), 0, &fileHandle, &offset,
-                                     &length, &address);
+    rc = decode_rw_file_memory_req(requestMsg.data(), 0, &fileHandle, &offset,
+                                   &length, &address);
     ASSERT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
 }
 
-TEST(ReadFileIntoMemory, testGoodEncodeResponse)
+TEST(ReadWriteFileMemory, testGoodEncodeResponse)
 {
-    std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_READ_FILE_MEM_RESP_BYTES>
+    std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_RESP_BYTES>
         responseMsg{};
     uint32_t length = 0xFF00EE11;
     pldm_msg* response = reinterpret_cast<pldm_msg*>(responseMsg.data());
 
-    auto rc = encode_read_file_memory_resp(0, PLDM_SUCCESS, length, response);
+    // ReadFileIntoMemory
+    auto rc = encode_rw_file_memory_resp(0, PLDM_READ_FILE_INTO_MEMORY,
+                                         PLDM_SUCCESS, length, response);
 
     ASSERT_EQ(rc, PLDM_SUCCESS);
     ASSERT_EQ(response->hdr.request, PLDM_RESPONSE);
@@ -84,16 +86,31 @@
     ASSERT_EQ(response->payload[0], PLDM_SUCCESS);
     ASSERT_EQ(0, memcmp(response->payload + sizeof(response->payload[0]),
                         &length, sizeof(length)));
+
+    // WriteFileFromMemory
+    rc = encode_rw_file_memory_resp(0, PLDM_WRITE_FILE_FROM_MEMORY,
+                                    PLDM_SUCCESS, length, response);
+
+    ASSERT_EQ(rc, PLDM_SUCCESS);
+    ASSERT_EQ(response->hdr.request, PLDM_RESPONSE);
+    ASSERT_EQ(response->hdr.instance_id, 0);
+    ASSERT_EQ(response->hdr.type, PLDM_IBM_OEM_TYPE);
+    ASSERT_EQ(response->hdr.command, PLDM_WRITE_FILE_FROM_MEMORY);
+    ASSERT_EQ(response->payload[0], PLDM_SUCCESS);
+    ASSERT_EQ(0, memcmp(response->payload + sizeof(response->payload[0]),
+                        &length, sizeof(length)));
 }
 
-TEST(ReadFileIntoMemory, testBadEncodeResponse)
+TEST(ReadWriteFileMemory, testBadEncodeResponse)
 {
-    std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_READ_FILE_MEM_RESP_BYTES>
+    std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_RESP_BYTES>
         responseMsg{};
     uint32_t length = 0;
     pldm_msg* response = reinterpret_cast<pldm_msg*>(responseMsg.data());
 
-    auto rc = encode_read_file_memory_resp(0, PLDM_ERROR, length, response);
+    // ReadFileIntoMemory
+    auto rc = encode_rw_file_memory_resp(0, PLDM_READ_FILE_INTO_MEMORY,
+                                         PLDM_ERROR, length, response);
 
     ASSERT_EQ(rc, PLDM_SUCCESS);
     ASSERT_EQ(response->hdr.request, PLDM_RESPONSE);
@@ -101,4 +118,15 @@
     ASSERT_EQ(response->hdr.type, PLDM_IBM_OEM_TYPE);
     ASSERT_EQ(response->hdr.command, PLDM_READ_FILE_INTO_MEMORY);
     ASSERT_EQ(response->payload[0], PLDM_ERROR);
+
+    // WriteFileFromMemory
+    rc = encode_rw_file_memory_resp(0, PLDM_WRITE_FILE_FROM_MEMORY, PLDM_ERROR,
+                                    length, response);
+
+    ASSERT_EQ(rc, PLDM_SUCCESS);
+    ASSERT_EQ(response->hdr.request, PLDM_RESPONSE);
+    ASSERT_EQ(response->hdr.instance_id, 0);
+    ASSERT_EQ(response->hdr.type, PLDM_IBM_OEM_TYPE);
+    ASSERT_EQ(response->hdr.command, PLDM_WRITE_FILE_FROM_MEMORY);
+    ASSERT_EQ(response->payload[0], PLDM_ERROR);
 }