17f2ab643SJohn Edward Broadbent #include "pattern.hpp"
27f2ab643SJohn Edward Broadbent
37f2ab643SJohn Edward Broadbent #include "erase.hpp"
47f2ab643SJohn Edward Broadbent
57f2ab643SJohn Edward Broadbent #include <unistd.h>
67f2ab643SJohn Edward Broadbent
77f2ab643SJohn Edward Broadbent #include <phosphor-logging/lg2.hpp>
87f2ab643SJohn Edward Broadbent #include <stdplus/fd/create.hpp>
97f2ab643SJohn Edward Broadbent #include <stdplus/fd/managed.hpp>
107f2ab643SJohn Edward Broadbent #include <xyz/openbmc_project/Common/error.hpp>
117f2ab643SJohn Edward Broadbent
127f2ab643SJohn Edward Broadbent #include <array>
13d6071fc2SJohn Edward Broadbent #include <chrono>
147f2ab643SJohn Edward Broadbent #include <iostream>
157f2ab643SJohn Edward Broadbent #include <random>
167f2ab643SJohn Edward Broadbent #include <span>
177f2ab643SJohn Edward Broadbent #include <string>
18d6071fc2SJohn Edward Broadbent #include <thread>
197f2ab643SJohn Edward Broadbent
20d3bfa7bbSJohn Edward Broadbent namespace estoraged
21d3bfa7bbSJohn Edward Broadbent {
22d3bfa7bbSJohn Edward Broadbent
237f2ab643SJohn Edward Broadbent using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
24d6071fc2SJohn Edward Broadbent using stdplus::fd::Fd;
257f2ab643SJohn Edward Broadbent
writePattern(const uint64_t driveSize,Fd & fd)26d6071fc2SJohn Edward Broadbent void Pattern::writePattern(const uint64_t driveSize, Fd& fd)
277f2ab643SJohn Edward Broadbent {
28*d4554f2aSManojkiran Eda // static seed defines a fixed prng sequence so it can be verified later,
297f2ab643SJohn Edward Broadbent // and validated for entropy
307f2ab643SJohn Edward Broadbent uint64_t currentIndex = 0;
3182897c35SEd Tanous
3282897c35SEd Tanous // random number generator seeded with a constant value will
3382897c35SEd Tanous // generate a predictable sequence of values NOLINTNEXTLINE
347f2ab643SJohn Edward Broadbent std::minstd_rand0 generator(seed);
3582897c35SEd Tanous std::array<std::byte, blockSize> randArr{};
3669786761SJohn Edward Broadbent
377f2ab643SJohn Edward Broadbent while (currentIndex < driveSize)
387f2ab643SJohn Edward Broadbent {
397f2ab643SJohn Edward Broadbent // generate a 4k block of prng
407f2ab643SJohn Edward Broadbent std::array<uint32_t, blockSizeUsing32>* randArrFill =
417f2ab643SJohn Edward Broadbent reinterpret_cast<std::array<uint32_t, blockSizeUsing32>*>(&randArr);
427f2ab643SJohn Edward Broadbent for (uint32_t i = 0; i < blockSizeUsing32; i++)
437f2ab643SJohn Edward Broadbent {
447f2ab643SJohn Edward Broadbent (*randArrFill)[i] = generator();
457f2ab643SJohn Edward Broadbent }
467f2ab643SJohn Edward Broadbent // if we can write all 4k bytes do that, else write the remainder
477f2ab643SJohn Edward Broadbent size_t writeSize = currentIndex + blockSize < driveSize
487f2ab643SJohn Edward Broadbent ? blockSize
497f2ab643SJohn Edward Broadbent : driveSize - currentIndex;
50d6071fc2SJohn Edward Broadbent size_t written = 0;
51d6071fc2SJohn Edward Broadbent size_t retry = 0;
52d6071fc2SJohn Edward Broadbent while (written < writeSize)
537f2ab643SJohn Edward Broadbent {
54d6071fc2SJohn Edward Broadbent written += fd.write({randArr.data() + written, writeSize - written})
55d6071fc2SJohn Edward Broadbent .size();
56d6071fc2SJohn Edward Broadbent if (written == writeSize)
57d6071fc2SJohn Edward Broadbent {
58d6071fc2SJohn Edward Broadbent break;
59d6071fc2SJohn Edward Broadbent }
60d6071fc2SJohn Edward Broadbent if (written > writeSize)
61d6071fc2SJohn Edward Broadbent {
627f2ab643SJohn Edward Broadbent throw InternalFailure();
637f2ab643SJohn Edward Broadbent }
64d6071fc2SJohn Edward Broadbent retry++;
65d6071fc2SJohn Edward Broadbent if (retry > maxRetry)
66d6071fc2SJohn Edward Broadbent {
67d6071fc2SJohn Edward Broadbent lg2::error("Unable to do full write", "REDFISH_MESSAGE_ID",
68d6071fc2SJohn Edward Broadbent std::string("eStorageD.1.0.EraseFailure"));
69d6071fc2SJohn Edward Broadbent throw InternalFailure();
70d6071fc2SJohn Edward Broadbent }
71d6071fc2SJohn Edward Broadbent std::this_thread::sleep_for(delay);
72d6071fc2SJohn Edward Broadbent }
737f2ab643SJohn Edward Broadbent currentIndex = currentIndex + writeSize;
747f2ab643SJohn Edward Broadbent }
757f2ab643SJohn Edward Broadbent }
767f2ab643SJohn Edward Broadbent
verifyPattern(const uint64_t driveSize,Fd & fd)77d6071fc2SJohn Edward Broadbent void Pattern::verifyPattern(const uint64_t driveSize, Fd& fd)
787f2ab643SJohn Edward Broadbent {
797f2ab643SJohn Edward Broadbent uint64_t currentIndex = 0;
8082897c35SEd Tanous // random number generator seeded with a constant value will
8182897c35SEd Tanous // generate a predictable sequence of values NOLINTNEXTLINE
827f2ab643SJohn Edward Broadbent std::minstd_rand0 generator(seed);
8382897c35SEd Tanous std::array<std::byte, blockSize> randArr{};
8482897c35SEd Tanous std::array<std::byte, blockSize> readArr{};
8569786761SJohn Edward Broadbent
867f2ab643SJohn Edward Broadbent while (currentIndex < driveSize)
877f2ab643SJohn Edward Broadbent {
887f2ab643SJohn Edward Broadbent size_t readSize = currentIndex + blockSize < driveSize
897f2ab643SJohn Edward Broadbent ? blockSize
907f2ab643SJohn Edward Broadbent : driveSize - currentIndex;
917f2ab643SJohn Edward Broadbent try
927f2ab643SJohn Edward Broadbent {
937f2ab643SJohn Edward Broadbent std::array<uint32_t, blockSizeUsing32>* randArrFill =
947f2ab643SJohn Edward Broadbent reinterpret_cast<std::array<uint32_t, blockSizeUsing32>*>(
957f2ab643SJohn Edward Broadbent &randArr);
967f2ab643SJohn Edward Broadbent for (uint32_t i = 0; i < blockSizeUsing32; i++)
977f2ab643SJohn Edward Broadbent {
987f2ab643SJohn Edward Broadbent (*randArrFill)[i] = generator();
997f2ab643SJohn Edward Broadbent }
100d6071fc2SJohn Edward Broadbent size_t read = 0;
101d6071fc2SJohn Edward Broadbent size_t retry = 0;
102d6071fc2SJohn Edward Broadbent while (read < readSize)
103d6071fc2SJohn Edward Broadbent {
104d6071fc2SJohn Edward Broadbent read +=
105d6071fc2SJohn Edward Broadbent fd.read({readArr.data() + read, readSize - read}).size();
106d6071fc2SJohn Edward Broadbent if (read == readSize)
107d6071fc2SJohn Edward Broadbent {
108d6071fc2SJohn Edward Broadbent break;
109d6071fc2SJohn Edward Broadbent }
110d6071fc2SJohn Edward Broadbent if (read > readSize)
111d6071fc2SJohn Edward Broadbent {
112d6071fc2SJohn Edward Broadbent throw InternalFailure();
113d6071fc2SJohn Edward Broadbent }
114d6071fc2SJohn Edward Broadbent retry++;
115d6071fc2SJohn Edward Broadbent if (retry > maxRetry)
116d6071fc2SJohn Edward Broadbent {
117d6071fc2SJohn Edward Broadbent lg2::error("Unable to do full read", "REDFISH_MESSAGE_ID",
118d6071fc2SJohn Edward Broadbent std::string("eStorageD.1.0.EraseFailure"));
119d6071fc2SJohn Edward Broadbent throw InternalFailure();
120d6071fc2SJohn Edward Broadbent }
121d6071fc2SJohn Edward Broadbent std::this_thread::sleep_for(delay);
122d6071fc2SJohn Edward Broadbent }
1237f2ab643SJohn Edward Broadbent }
1247f2ab643SJohn Edward Broadbent catch (...)
1257f2ab643SJohn Edward Broadbent {
1267f2ab643SJohn Edward Broadbent lg2::error("Estoraged erase pattern unable to read",
1277f2ab643SJohn Edward Broadbent "REDFISH_MESSAGE_ID",
128d6071fc2SJohn Edward Broadbent std::string("eStorageD.1.0.EraseFailure"));
1297f2ab643SJohn Edward Broadbent throw InternalFailure();
1307f2ab643SJohn Edward Broadbent }
1317f2ab643SJohn Edward Broadbent
1327f2ab643SJohn Edward Broadbent if (!std::equal(randArr.begin(), randArr.begin() + readSize,
1337f2ab643SJohn Edward Broadbent readArr.begin(), readArr.begin() + readSize))
1347f2ab643SJohn Edward Broadbent {
1357f2ab643SJohn Edward Broadbent lg2::error("Estoraged erase pattern does not match",
1367f2ab643SJohn Edward Broadbent "REDFISH_MESSAGE_ID",
1377f2ab643SJohn Edward Broadbent std::string("eStorageD.1.0.EraseFailure"));
1387f2ab643SJohn Edward Broadbent throw InternalFailure();
1397f2ab643SJohn Edward Broadbent }
1407f2ab643SJohn Edward Broadbent currentIndex = currentIndex + readSize;
1417f2ab643SJohn Edward Broadbent }
1427f2ab643SJohn Edward Broadbent }
143d3bfa7bbSJohn Edward Broadbent
144d3bfa7bbSJohn Edward Broadbent } // namespace estoraged
145