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