new file mode 100644
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0
+
+cxl-sanitize-memdev(1)
+======================
+
+NAME
+----
+cxl-sanitize-memdev - Perform a cryptographic destruction or sanitation of
+the contents of the given memdevs.
+
+SYNOPSIS
+--------
+[verse]
+'cxl sanitize-memdev' <mem0> [<mem1>..<memN>] [<options>]
+
+DESCRIPTION
+-----------
+The 'sanitize-memdev' command performs two different methods of
+sanitation, per the CXL 3.0 specification. It is required that
+the memdev be disabled before sanitizing, such that the device
+cannot be actively decoding any HPA ranges at the time.
+
+The default is 'sanitize', but additionally, a 'secure-erase'
+option is available. If both types of operations are supplied,
+then the 'secure-erase' is performed before 'sanitize'.
+
+
+OPTIONS
+-------
+<memdev>::
+include::memdev-option.txt[]
+
+-b::
+--bus=::
+include::bus-option.txt[]
+
+-e::
+--secure-erase::
+ Erase user data by changing the media encryption keys for all user
+ data areas of the device.
+
+-s::
+--sanitize::
+ Sanitize the device to securely re-purpose or decommission it. This is
+ done by ensuring that all user data and meta data, whether it resides
+ in persistent capacity, volatile capacity, or the label storage area,
+ is made permanently unavailable by whatever means is appropriate for
+ the media type.
+
+ With this option, the sanitation request is merely submitted to the
+ kernel, and the completion is asynchronous. Depending on the medium and
+ capacity, sanitize may take tens of minutes to many hours. Subsequently,
+ 'cxl wait-sanitize’ can be used to wait for the memdevs that are under
+ the sanitation.
+
+-v::
+--verbose::
+ Emit debug messages.
+
+include::../copyright.txt[]
+
+SEE ALSO
+--------
+linkcxl:cxl-wait-sanitize[1]
+linkcxl:cxl-disable-memdev[1]
@@ -33,3 +33,7 @@ include::bus-option.txt[]
Emit debug messages.
include::../copyright.txt[]
+
+SEE ALSO
+--------
+linkcxl:cxl-sanitize-memdev[1]
@@ -136,6 +136,7 @@ struct cxl_cmd *cxl_cmd_new_get_partition(struct cxl_memdev *memdev);
struct cxl_cmd *cxl_cmd_new_set_partition(struct cxl_memdev *memdev,
unsigned long long volatile_size);
int cxl_memdev_wait_sanitize(struct cxl_memdev *memdev);
+int cxl_memdev_sanitize(struct cxl_memdev *memdev, const char *op);
----
@@ -46,6 +46,7 @@ cxl_manpages = [
'cxl-enable-region.txt',
'cxl-destroy-region.txt',
'cxl-wait-sanitize.txt',
+ 'cxl-sanitize-memdev.txt',
'cxl-monitor.txt',
]
@@ -23,6 +23,7 @@ int cmd_enable_region(int argc, const char **argv, struct cxl_ctx *ctx);
int cmd_disable_region(int argc, const char **argv, struct cxl_ctx *ctx);
int cmd_destroy_region(int argc, const char **argv, struct cxl_ctx *ctx);
int cmd_wait_sanitize(int argc, const char **argv, struct cxl_ctx *ctx);
+int cmd_sanitize_memdev(int argc, const char **argv, struct cxl_ctx *ctx);
#ifdef ENABLE_LIBTRACEFS
int cmd_monitor(int argc, const char **argv, struct cxl_ctx *ctx);
#else
@@ -77,6 +77,7 @@ static struct cmd_struct commands[] = {
{ "disable-region", .c_fn = cmd_disable_region },
{ "destroy-region", .c_fn = cmd_destroy_region },
{ "wait-sanitize", .c_fn = cmd_wait_sanitize },
+ { "sanitize-memdev", .c_fn = cmd_sanitize_memdev },
{ "monitor", .c_fn = cmd_monitor },
};
@@ -3929,6 +3929,22 @@ CXL_EXPORT int cxl_memdev_wait_sanitize(struct cxl_memdev *memdev)
return rc;
}
+int cxl_memdev_sanitize(struct cxl_memdev *memdev, const char *op)
+{
+ struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);
+ char *path = memdev->dev_buf;
+ int len = memdev->buf_len;
+
+ if (snprintf(path, len,
+ "%s/security/%s", memdev->host_path, op) >= len) {
+ err(ctx, "%s: buffer too small!\n",
+ cxl_memdev_get_devname(memdev));
+ return -ERANGE;
+ }
+
+ return sysfs_write_attr(ctx, path, "1");
+}
+
CXL_EXPORT int cxl_cmd_submit(struct cxl_cmd *cmd)
{
struct cxl_memdev *memdev = cmd->memdev;
@@ -71,6 +71,7 @@ global:
cxl_memdev_write_label;
cxl_memdev_read_label;
cxl_memdev_wait_sanitize;
+ cxl_memdev_sanitize;
local:
*;
};
@@ -413,6 +413,7 @@ unsigned long long cxl_cmd_partition_get_next_persistent_size(struct cxl_cmd *cm
struct cxl_cmd *cxl_cmd_new_set_partition(struct cxl_memdev *memdev,
unsigned long long volatile_size);
int cxl_memdev_wait_sanitize(struct cxl_memdev *memdev);
+int cxl_memdev_sanitize(struct cxl_memdev *memdev, const char *op);
enum cxl_setpartition_mode {
CXL_SETPART_NEXTBOOT,
@@ -31,6 +31,8 @@ static struct parameters {
bool serial;
bool force;
bool align;
+ bool sanitize;
+ bool secure_erase;
const char *type;
const char *size;
const char *decoder_filter;
@@ -85,6 +87,12 @@ OPT_STRING('t', "type", ¶m.type, "type", \
OPT_BOOLEAN('f', "force", ¶m.force, \
"Attempt 'expected to fail' operations")
+#define SANITIZE_OPTIONS() \
+OPT_BOOLEAN('e', "secure-erase", ¶m.secure_erase, \
+ "secure erase a memdev"), \
+OPT_BOOLEAN('s', "sanitize", ¶m.sanitize, \
+ "sanitize a memdev")
+
static const struct option read_options[] = {
BASE_OPTIONS(),
LABEL_OPTIONS(),
@@ -140,6 +148,12 @@ static const struct option wait_sanitize_options[] = {
OPT_END(),
};
+static const struct option sanitize_options[] = {
+ BASE_OPTIONS(),
+ SANITIZE_OPTIONS(),
+ OPT_END(),
+};
+
enum reserve_dpa_mode {
DPA_ALLOC,
DPA_FREE,
@@ -668,6 +682,28 @@ static int action_wait_sanitize(struct cxl_memdev *memdev,
return cxl_memdev_wait_sanitize(memdev);
}
+static int action_sanitize_memdev(struct cxl_memdev *memdev,
+ struct action_context *actx)
+{
+ int rc = 0;
+
+ if (cxl_memdev_is_enabled(memdev))
+ return -EBUSY;
+
+ /* let Sanitize be the default */
+ if (!param.secure_erase && !param.sanitize)
+ param.sanitize = true;
+
+ if (param.secure_erase)
+ rc = cxl_memdev_sanitize(memdev, "erase");
+ if (param.sanitize)
+ rc = cxl_memdev_sanitize(memdev, "sanitize");
+ else
+ rc = -EINVAL;
+
+ return rc;
+}
+
static int memdev_action(int argc, const char **argv, struct cxl_ctx *ctx,
int (*action)(struct cxl_memdev *memdev,
struct action_context *actx),
@@ -919,3 +955,14 @@ int cmd_wait_sanitize(int argc, const char **argv, struct cxl_ctx *ctx)
return count >= 0 ? 0 : EXIT_FAILURE;
}
+
+int cmd_sanitize_memdev(int argc, const char **argv, struct cxl_ctx *ctx)
+{
+ int count = memdev_action(argc, argv, ctx, action_sanitize_memdev,
+ sanitize_options,
+ "cxl sanitize-memdev <mem0> [<mem1>..<memn>] [<options>]");
+ log_info(&ml, "sanitation started on %d mem device%s\n",
+ count >= 0 ? count : 0, count > 1 ? "s" : "");
+
+ return count >= 0 ? 0 : EXIT_FAILURE;
+}
Add a new cxl_memdev_sanitize() to libcxl to support triggering memory device sanitation, in either Sanitize and/or Secure Erase, per the CXL 3.0 specs. This is analogous to 'ndctl sanitize-dimm'. Signed-off-by: Davidlohr Bueso <dave@stgolabs.net> --- Documentation/cxl/cxl-sanitize-memdev.txt | 65 +++++++++++++++++++++++ Documentation/cxl/cxl-wait-sanitize.txt | 4 ++ Documentation/cxl/lib/libcxl.txt | 1 + Documentation/cxl/meson.build | 1 + cxl/builtin.h | 1 + cxl/cxl.c | 1 + cxl/lib/libcxl.c | 16 ++++++ cxl/lib/libcxl.sym | 1 + cxl/libcxl.h | 1 + cxl/memdev.c | 47 ++++++++++++++++ 10 files changed, 138 insertions(+) create mode 100644 Documentation/cxl/cxl-sanitize-memdev.txt