mail archive of the barebox mailing list
 help / color / mirror / Atom feed
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




             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