Add erase sanitize
Sanitize uses the eMMC firmware to erase all blocks.
Tested:
$ cat /dev/urandom > /dev/mmcblk0
$ 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.VendorSanitize \
--timeout=1200
real 0m1.793s
user 0m0.021s
sys 0m0.009s
root@ytbaz20-nfd01:/# cat /dev/mmcblk0 | hexdump
0000000 0000 0000 0000 0000 0000 0000 0000 0000
*
Signed-off-by: John Edward Broadbent <jebr@google.com>
Change-Id: I31bc21c0b6d31cbba0db752d94a93eb004dbbde6
diff --git a/src/erase/meson.build b/src/erase/meson.build
index 233fc59..57329c2 100644
--- a/src/erase/meson.build
+++ b/src/erase/meson.build
@@ -3,6 +3,7 @@
'verifyDriveGeometry.cpp',
'pattern.cpp',
'cryptoErase.cpp',
+ 'sanitize.cpp',
'zero.cpp',
include_directories : eStoraged_headers,
implicit_include_directories: false,
diff --git a/src/erase/sanitize.cpp b/src/erase/sanitize.cpp
new file mode 100644
index 0000000..26e39fb
--- /dev/null
+++ b/src/erase/sanitize.cpp
@@ -0,0 +1,145 @@
+#include "sanitize.hpp"
+
+#include "estoraged_conf.hpp"
+
+#include <linux/mmc/ioctl.h>
+#include <sys/ioctl.h>
+
+#include <phosphor-logging/lg2.hpp>
+#include <stdplus/fd/create.hpp>
+#include <stdplus/fd/managed.hpp>
+#include <stdplus/handle/managed.hpp>
+#include <xyz/openbmc_project/Common/error.hpp>
+
+#include <array>
+#include <cstddef>
+#include <span>
+#include <string>
+#include <string_view>
+
+namespace
+{
+
+constexpr uint32_t mmcSwitch = 6;
+constexpr uint32_t mmcSendExtCsd = 8;
+constexpr uint32_t mmcSwitchModeWriteByte = 0x03;
+constexpr uint32_t extCsdSanitizeStart = 165;
+constexpr uint32_t extCsdCmdSetNormal = (1 << 0);
+
+constexpr uint32_t mmcRspPresent = (1 << 0);
+constexpr uint32_t mmcRspCrc = (1 << 2);
+constexpr uint32_t mmcRspBusy = (1 << 3);
+constexpr uint32_t mmcRspOpcode = (1 << 4);
+
+constexpr uint32_t mmcCmdAc = (0 << 5);
+constexpr uint32_t mmcCmdAdtc = (1 << 5);
+
+constexpr uint32_t mmcRspSpiS1 = (1 << 7);
+constexpr uint32_t mmcRspSpiBusy = (1 << 10);
+
+constexpr uint32_t mmcRspSpiR1 = (mmcRspSpiS1);
+constexpr uint32_t mmcRspSpiR1B = (mmcRspSpiS1 | mmcRspSpiBusy);
+
+constexpr uint32_t mmcRspR1B =
+ (mmcRspPresent | mmcRspCrc | mmcRspOpcode | mmcRspBusy);
+
+constexpr uint32_t mmcRspR1 = (mmcRspPresent | mmcRspCrc | mmcRspOpcode);
+
+constexpr uint32_t mmcEraseGroupStart = 35;
+constexpr uint32_t mmcEraseGroupEnd = 36;
+constexpr uint32_t mmcErase = 38;
+} // namespace
+
+namespace estoraged
+{
+
+using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
+using stdplus::fd::ManagedFd;
+
+void Sanitize::doSanitize(uint64_t driveSize)
+{
+ try
+ {
+ emmcErase(driveSize);
+ emmcSanitize();
+ }
+ catch (...)
+ {
+ lg2::error("eStorageD erase sanitize failure", "REDFISH_MESSAGE_ID",
+ std::string("eStorageD.1.0.EraseFailure"));
+ throw InternalFailure();
+ }
+ lg2::info("eStorageD successfully erase sanitize", "REDFISH_MESSAGE_ID",
+ std::string("eStorageD.1.0.EraseSuccessful"));
+}
+
+void Sanitize::emmcErase(uint64_t driveSize)
+{
+
+ uint64_t sectorSize = 0x200; // default value see eMMC spec 6.6.34.
+ // NOTE: 0x200 is only valid for eMMC greater
+ // then 2 GB
+ struct mmc_io_multi_cmd_erase eraseCmd = {};
+
+ eraseCmd.num_of_cmds = 3;
+ eraseCmd.cmds[0].opcode = mmcEraseGroupStart;
+ eraseCmd.cmds[0].arg = 0;
+ eraseCmd.cmds[0].flags = mmcRspSpiR1 | mmcRspR1 | mmcCmdAc;
+ eraseCmd.cmds[0].write_flag = 1;
+
+ eraseCmd.cmds[1].opcode = mmcEraseGroupEnd;
+ eraseCmd.cmds[1].arg = (driveSize / sectorSize) - 1;
+ eraseCmd.cmds[1].flags = mmcRspSpiR1 | mmcRspR1 | mmcCmdAc;
+ eraseCmd.cmds[1].write_flag = 1;
+
+ /* Send Erase Command */
+ eraseCmd.cmds[2].opcode = mmcErase;
+ eraseCmd.cmds[2].arg = 0x00000000;
+ eraseCmd.cmds[2].cmd_timeout_ms = 0x0FFFFFFF;
+ eraseCmd.cmds[2].flags = mmcRspSpiR1B | mmcRspR1B | mmcCmdAc;
+ eraseCmd.cmds[2].write_flag = 1;
+
+ if (ioctlWrapper->doIoctlMulti(devPath, MMC_IOC_MULTI_CMD, eraseCmd) != 0)
+ {
+ throw InternalFailure();
+ }
+}
+
+void Sanitize::emmcSanitize()
+{
+
+ struct mmc_ioc_cmd idata = {};
+ idata.write_flag = 1;
+ idata.opcode = mmcSwitch;
+ idata.arg = (mmcSwitchModeWriteByte << 24) | (extCsdSanitizeStart << 16) |
+ (1 << 8) | extCsdCmdSetNormal;
+ idata.flags = mmcRspSpiR1B | mmcRspR1B | mmcCmdAc;
+
+ // make the eMMC sanitize ioctl
+ if (ioctlWrapper->doIoctl(devPath, MMC_IOC_CMD, idata) != 0)
+ {
+ throw InternalFailure();
+ }
+}
+
+int IOCTLWrapperImpl::doIoctl(std::string_view devPath, unsigned long request,
+ struct mmc_ioc_cmd data)
+
+{
+ ManagedFd fd = stdplus::fd::open(std::string(devPath).c_str(),
+ stdplus::fd::OpenAccess::ReadOnly);
+
+ return fd.ioctl(request, static_cast<void*>(&data));
+}
+
+int IOCTLWrapperImpl::doIoctlMulti(std::string_view devPath,
+ unsigned long request,
+ struct mmc_io_multi_cmd_erase data)
+{
+ ManagedFd fd = stdplus::fd::open(std::string(devPath).c_str(),
+ stdplus::fd::OpenAccess::ReadOnly);
+
+ return fd.ioctl(request, static_cast<void*>(&data));
+}
+
+} // namespace estoraged