From: Renaud Barbier <Renaud.Barbier@ametek.com>
To: Barebox List <barebox@lists.infradead.org>
Subject: Subject: [PATCH 1/1] nvme: add erase operation through sanitize command
Date: Thu, 16 Jan 2025 10:52:02 +0000 [thread overview]
Message-ID: <DM5PR07MB3532EA1B89A0848CE2A14C53EC1A2@DM5PR07MB3532.namprd07.prod.outlook.com> (raw)
Based on Linux nvme sanitize command and kernel driver, add the storage
low level block erase. This operation erases the entire device, any
user-specified size smaller than the storage size will result in an error.
Signed-off-by: Renaud Barbier <renaud.barbier@ametek.com>
---
drivers/nvme/host/core.c | 82 ++++++++++++++++++++++++++++++++++++++++
drivers/nvme/host/pci.c | 2 +
include/nvme/types.h | 38 +++++++++++++++++++
3 files changed, 122 insertions(+)
create mode 100644 include/nvme/types.h
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 33a592caeb..fcc2167763 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <common.h>
+#include <nvme/types.h>
#include "nvme.h"
@@ -64,6 +65,72 @@ nvme_set_features(struct nvme_ctrl *dev, unsigned fid, unsigned dword11,
return ret;
}
+static int
+nvme_sanitize_poll_log(struct nvme_ctrl *ctrl)
+{
+ struct nvme_sanitize_log_page *sanitize_log;
+ int log_size = sizeof(*sanitize_log);
+ uint64_t start = get_time_ns();
+ struct nvme_command c = { 0 };
+ uint32_t numd = (log_size >> 2) - 1;
+ uint16_t numdl = numd & 0xffff;
+ int ret;
+
+ sanitize_log = kmalloc(log_size, GFP_KERNEL);
+ if (!sanitize_log)
+ return -ENOMEM;
+
+ memset(sanitize_log, 0, log_size);
+
+ c.common.opcode = nvme_admin_get_log_page;
+ c.common.cdw10[0] = (numdl << 16) | NVME_LOG_LID_SANITIZE;
+ /* Poll the sanitize log for operation completion */
+ do {
+ ret = nvme_submit_sync_cmd(ctrl, &c, sanitize_log, log_size);
+ if (ret) {
+ dev_err(ctrl->dev, "Retrieving log failed\n");
+ goto out;
+ }
+
+ if ((sanitize_log->sstat & 0x3) == 3) {
+ dev_err(ctrl->dev, "Erase failed\n");
+ ret = -EIO;
+ goto out;
+ } else if (sanitize_log->sstat & 1) {
+ ret = 0;
+ goto out;
+ }
+ sanitize_log->sstat = 0;
+
+ mdelay(1000);
+ } while (!is_timeout(start, 30 * SECOND));
+ ret = -ETIME;
+out:
+ if (sanitize_log)
+ free(sanitize_log);
+ return ret;
+}
+
+/* Perform a low level block erase of the whole NVME device */
+static int
+nvme_sanitize_nvm(struct nvme_ctrl *ctrl)
+{
+ struct nvme_command c = { 0 };
+ int ret;
+
+ /* Input arguments based on what the kernel sets up for the cmd */
+ c.common.opcode = nvme_admin_sanitize_nvm;
+ c.common.cdw10[0] = NVME_SANITIZE_SANACT_START_BLOCK_ERASE;
+ ret = nvme_submit_sync_cmd(ctrl, &c, NULL, 0);
+ if (ret) {
+ dev_err(ctrl->dev,
+ "Failed to trigger the sanitize block erase command\n");
+ return -EINVAL;
+ }
+
+ return nvme_sanitize_poll_log(ctrl);
+}
+
int nvme_set_queue_count(struct nvme_ctrl *ctrl, int *count)
{
u32 q_count = (*count - 1) | ((*count - 1) << 16);
@@ -324,11 +391,26 @@ static int __maybe_unused nvme_block_device_flush(struct block_device *blk)
0, 0, NVME_QID_IO);
}
+static int __maybe_unused
+nvme_block_device_erase(struct block_device *blk, sector_t block,
+ blkcnt_t num_blocks)
+{
+ struct nvme_ns *ns = to_nvme_ns(blk);
+
+ if (block != 0 || num_blocks != blk->num_blocks) {
+ dev_err(ns->ctrl->dev, "The whole device must be erased\n");
+ return -ENOSYS;
+ }
+
+ return nvme_sanitize_nvm(ns->ctrl);
+}
+
static struct block_device_ops nvme_block_device_ops = {
.read = nvme_block_device_read,
#ifdef CONFIG_BLOCK_WRITE
.write = nvme_block_device_write,
.flush = nvme_block_device_flush,
+ .erase = nvme_block_device_erase,
#endif
};
diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index e74a43b9aa..543be9a235 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -400,10 +400,12 @@ static int nvme_pci_submit_sync_cmd(struct nvme_ctrl *ctrl,
case nvme_admin_create_cq:
case nvme_admin_delete_sq:
case nvme_admin_delete_cq:
+ case nvme_admin_sanitize_nvm:
case nvme_admin_set_features:
dma_dir = DMA_TO_DEVICE;
break;
case nvme_admin_identify:
+ case nvme_admin_get_log_page:
dma_dir = DMA_FROM_DEVICE;
break;
default:
diff --git a/include/nvme/types.h b/include/nvme/types.h
new file mode 100644
index 0000000000..7b5aad1ca5
--- /dev/null
+++ b/include/nvme/types.h
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+/*
+ * This file is part of libnvme.
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors: Keith Busch <keith.busch@wdc.com>
+ * Chaitanya Kulkarni <chaitanya.kulkarni@wdc.com>
+ */
+#ifndef _LIBNVME_H
+#define _LIBNVME_H
+
+enum nvme_sanitize_sanact {
+ NVME_SANITIZE_SANACT_EXIT_FAILURE = 1,
+ NVME_SANITIZE_SANACT_START_BLOCK_ERASE = 2,
+ NVME_SANITIZE_SANACT_START_OVERWRITE = 3,
+ NVME_SANITIZE_SANACT_START_CRYPTO_ERASE = 4,
+ NVME_SANITIZE_SANACT_EXIT_MEDIA_VERIF = 5,
+};
+
+struct nvme_sanitize_log_page {
+ __le16 sprog;
+ __le16 sstat;
+ __le32 scdw10;
+ __le32 eto;
+ __le32 etbe;
+ __le32 etce;
+ __le32 etond;
+ __le32 etbend;
+ __le32 etcend;
+ __le32 etpvds;
+ __u8 ssi;
+ __u8 rsvd37[475];
+};
+
+enum nvme_cmd_get_log_lid {
+ NVME_LOG_LID_SANITIZE = 0x81,
+};
+#endif /* _LIBNVME_TYPES_H */
--
2.34.1
next reply other threads:[~2025-01-16 10:52 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-01-16 10:52 Renaud Barbier [this message]
2025-01-21 8:32 ` Sascha Hauer
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=DM5PR07MB3532EA1B89A0848CE2A14C53EC1A2@DM5PR07MB3532.namprd07.prod.outlook.com \
--to=renaud.barbier@ametek.com \
--cc=barebox@lists.infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox