xref: /openbmc/estoraged/src/erase/pattern.cpp (revision 1e169d0cdf79269db9208a8e4cd594432641faab)
1 #include "pattern.hpp"
2 
3 #include "erase.hpp"
4 
5 #include <unistd.h>
6 
7 #include <phosphor-logging/lg2.hpp>
8 #include <stdplus/fd/create.hpp>
9 #include <stdplus/fd/managed.hpp>
10 #include <xyz/openbmc_project/Common/error.hpp>
11 
12 #include <algorithm>
13 #include <array>
14 #include <chrono>
15 #include <iostream>
16 #include <random>
17 #include <span>
18 #include <string>
19 #include <thread>
20 
21 namespace estoraged
22 {
23 
24 using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
25 using stdplus::fd::Fd;
26 
writePattern(const uint64_t driveSize,Fd & fd)27 void Pattern::writePattern(const uint64_t driveSize, Fd& fd)
28 {
29     // static seed defines a fixed prng sequence so it can be verified later,
30     // and validated for entropy
31     uint64_t currentIndex = 0;
32 
33     // random number generator seeded with a constant value will
34     // generate a predictable sequence of values NOLINTNEXTLINE
35     std::minstd_rand0 generator(seed);
36     std::array<std::byte, blockSize> randArr{};
37 
38     while (currentIndex < driveSize)
39     {
40         // generate a 4k block of prng
41         std::array<uint32_t, blockSizeUsing32>* randArrFill =
42             reinterpret_cast<std::array<uint32_t, blockSizeUsing32>*>(&randArr);
43         for (uint32_t i = 0; i < blockSizeUsing32; i++)
44         {
45             (*randArrFill)[i] = generator();
46         }
47         // if we can write all 4k bytes do that, else write the remainder
48         size_t writeSize = currentIndex + blockSize < driveSize
49                                ? blockSize
50                                : driveSize - currentIndex;
51         size_t written = 0;
52         size_t retry = 0;
53         while (written < writeSize)
54         {
55             written += fd.write(std::span{randArr}.subspan(written,
56                                                            writeSize - written))
57                            .size();
58             if (written == writeSize)
59             {
60                 break;
61             }
62             if (written > writeSize)
63             {
64                 throw InternalFailure();
65             }
66             retry++;
67             if (retry > maxRetry)
68             {
69                 lg2::error("Unable to do full write", "REDFISH_MESSAGE_ID",
70                            std::string("eStorageD.1.0.EraseFailure"));
71                 throw InternalFailure();
72             }
73             std::this_thread::sleep_for(delay);
74         }
75         currentIndex = currentIndex + writeSize;
76     }
77 }
78 
verifyPattern(const uint64_t driveSize,Fd & fd)79 void Pattern::verifyPattern(const uint64_t driveSize, Fd& fd)
80 {
81     uint64_t currentIndex = 0;
82     // random number generator seeded with a constant value will
83     // generate a predictable sequence of values NOLINTNEXTLINE
84     std::minstd_rand0 generator(seed);
85     std::array<std::byte, blockSize> randArr{};
86     std::array<std::byte, blockSize> readArr{};
87 
88     while (currentIndex < driveSize)
89     {
90         size_t readSize = currentIndex + blockSize < driveSize
91                               ? blockSize
92                               : driveSize - currentIndex;
93         try
94         {
95             std::array<uint32_t, blockSizeUsing32>* randArrFill =
96                 reinterpret_cast<std::array<uint32_t, blockSizeUsing32>*>(
97                     &randArr);
98             for (uint32_t i = 0; i < blockSizeUsing32; i++)
99             {
100                 (*randArrFill)[i] = generator();
101             }
102             size_t read = 0;
103             size_t retry = 0;
104             while (read < readSize)
105             {
106                 read +=
107                     fd.read(std::span{readArr}.subspan(read, readSize - read))
108                         .size();
109                 if (read == readSize)
110                 {
111                     break;
112                 }
113                 if (read > readSize)
114                 {
115                     throw InternalFailure();
116                 }
117                 retry++;
118                 if (retry > maxRetry)
119                 {
120                     lg2::error("Unable to do full read", "REDFISH_MESSAGE_ID",
121                                std::string("eStorageD.1.0.EraseFailure"));
122                     throw InternalFailure();
123                 }
124                 std::this_thread::sleep_for(delay);
125             }
126         }
127         catch (...)
128         {
129             lg2::error("Estoraged erase pattern unable to read",
130                        "REDFISH_MESSAGE_ID",
131                        std::string("eStorageD.1.0.EraseFailure"));
132             throw InternalFailure();
133         }
134 
135         if (!std::ranges::equal(std::span{randArr}.subspan(0, readSize),
136                                 std::span{readArr}.subspan(0, readSize)))
137         {
138             lg2::error("Estoraged erase pattern does not match",
139                        "REDFISH_MESSAGE_ID",
140                        std::string("eStorageD.1.0.EraseFailure"));
141             throw InternalFailure();
142         }
143         currentIndex = currentIndex + readSize;
144     }
145 }
146 
147 } // namespace estoraged
148