Fix Short read/write issue

It was possible for "short" reads and writes to cause the pattern and
zero steps to not work correctly. This change adds logic to deal with
the short reads.

Tested: unit test and machine test
root@bmc# time busctl call xyz.openbmc_project.eStoraged.mmcblk0 \
> /xyz/openbmc_project/inventory/storage/mmcblk0 \
> xyz.openbmc_project.Inventory.Item.Volume Erase s \
> xyz.openbmc_project.Inventory.Item.Volume.EraseMethod.ZeroOverWrite \
> --timeout=1200
real    6m0.815s
user    0m0.010s
sys     0m0.010s

Change-Id: If8df9bdba159a3bcfa77104a4c17b8d352794db2
Signed-off-by: John Edward Broadbent <jebr@google.com>
diff --git a/src/erase/pattern.cpp b/src/erase/pattern.cpp
index 5563661..7d7990b 100644
--- a/src/erase/pattern.cpp
+++ b/src/erase/pattern.cpp
@@ -10,22 +10,20 @@
 #include <xyz/openbmc_project/Common/error.hpp>
 
 #include <array>
+#include <chrono>
 #include <iostream>
 #include <random>
 #include <span>
 #include <string>
+#include <thread>
 
 namespace estoraged
 {
 
-constexpr uint32_t seed = 0x6a656272;
-constexpr size_t blockSize = 4096;
-constexpr size_t blockSizeUsing32 = blockSize / sizeof(uint32_t);
-
 using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
-using stdplus::fd::ManagedFd;
+using stdplus::fd::Fd;
 
-void Pattern::writePattern(const uint64_t driveSize)
+void Pattern::writePattern(const uint64_t driveSize, Fd& fd)
 {
     // static seed defines a fixed prng sequnce so it can be verified later,
     // and validated for entropy
@@ -36,9 +34,6 @@
     std::minstd_rand0 generator(seed);
     std::array<std::byte, blockSize> randArr{};
 
-    ManagedFd fd =
-        stdplus::fd::open(devPath, stdplus::fd::OpenAccess::WriteOnly);
-
     while (currentIndex < driveSize)
     {
         // generate a 4k block of prng
@@ -52,19 +47,34 @@
         size_t writeSize = currentIndex + blockSize < driveSize
                                ? blockSize
                                : driveSize - currentIndex;
-        if (fd.write({randArr.data(), writeSize}).size() != writeSize)
+        size_t written = 0;
+        size_t retry = 0;
+        while (written < writeSize)
         {
-            lg2::error("Estoraged erase pattern unable to write sizeof(long)",
-                       "REDFISH_MESSAGE_ID",
-                       std::string("eStorageD.1.0.EraseFailure"),
-                       "REDFISH_MESSAGE_ARGS", std::to_string(fd.get()));
-            throw InternalFailure();
+            written += fd.write({randArr.data() + written, writeSize - written})
+                           .size();
+            if (written == writeSize)
+            {
+                break;
+            }
+            if (written > writeSize)
+            {
+                throw InternalFailure();
+            }
+            retry++;
+            if (retry > maxRetry)
+            {
+                lg2::error("Unable to do full write", "REDFISH_MESSAGE_ID",
+                           std::string("eStorageD.1.0.EraseFailure"));
+                throw InternalFailure();
+            }
+            std::this_thread::sleep_for(delay);
         }
         currentIndex = currentIndex + writeSize;
     }
 }
 
-void Pattern::verifyPattern(const uint64_t driveSize)
+void Pattern::verifyPattern(const uint64_t driveSize, Fd& fd)
 {
 
     uint64_t currentIndex = 0;
@@ -74,9 +84,6 @@
     std::array<std::byte, blockSize> randArr{};
     std::array<std::byte, blockSize> readArr{};
 
-    ManagedFd fd =
-        stdplus::fd::open(devPath, stdplus::fd::OpenAccess::ReadOnly);
-
     while (currentIndex < driveSize)
     {
         size_t readSize = currentIndex + blockSize < driveSize
@@ -91,14 +98,35 @@
             {
                 (*randArrFill)[i] = generator();
             }
-            fd.read({readArr.data(), readSize});
+            size_t read = 0;
+            size_t retry = 0;
+            while (read < readSize)
+            {
+                read +=
+                    fd.read({readArr.data() + read, readSize - read}).size();
+                if (read == readSize)
+                {
+                    break;
+                }
+                if (read > readSize)
+                {
+                    throw InternalFailure();
+                }
+                retry++;
+                if (retry > maxRetry)
+                {
+                    lg2::error("Unable to do full read", "REDFISH_MESSAGE_ID",
+                               std::string("eStorageD.1.0.EraseFailure"));
+                    throw InternalFailure();
+                }
+                std::this_thread::sleep_for(delay);
+            }
         }
         catch (...)
         {
             lg2::error("Estoraged erase pattern unable to read",
                        "REDFISH_MESSAGE_ID",
-                       std::string("eStorageD.1.0.EraseFailure"),
-                       "REDFISH_MESSAGE_ARGS", std::to_string(fd.get()));
+                       std::string("eStorageD.1.0.EraseFailure"));
             throw InternalFailure();
         }