2022-08-04 05:06:27

by Davidlohr Bueso

[permalink] [raw]
Subject: [RFC PATCH 0/2] cxl: BG operations and device sanitation

Hello,

The following is a followup to some of the discussions around CXL device security
and sanitation[0, 1]. It is marked as RFC mostly to see if the background handling
will satisfy all users, not just sanitize/overwrite. For example there has been ideas
to avoid command hogging the device and/or interleaving scan media regions instead
of all in one, etc. More details in each patch, but:

Patch 1 adds the required background cmd handling bits. While this is currently
only polling, it would be good to know if there are any fundamental blockers for
supporting irqs (beyond just background ops) between PCIe and CXL. For example,
are there any requirements/difficulties that is not the standard MSI/MSI-X PCI
vector allocation + devm_request_irq()? I have not looked at this into details but
it the topic has come up in the past as delicate', iirc.

Patch 2 implements the sanitation commands (overwrite and secure erase).

As for testing, while I used the mock device to test the secure erase command, I
ended up hacking up a prototype[2] for qemu to support overwrite and bg commands.
So while the some of the paths this series introduces have been exercised, there
is of course a lot more to do.

Applies against Dave's cxl-security branch[2] which deals with the pmem-only bits.

Thanks,
Davidlohr

[0]: https://lore.kernel.org/all/20220708172455.gi37dh3od4w5lqrd@offworld/
[1]: https://lore.kernel.org/all/165791918718.2491387.4203738301057301285.stgit@djiang5-desk3.ch.intel.com/
[2]: https://github.com/davidlohr/qemu/commit/64a93a5b824b59d3b547f06f7fbb1269fb4790ce
[3]: https://git.kernel.org/pub/scm/linux/kernel/git/djiang/linux.git/log/?h=cxl-security

Davidlohr Bueso (2):
cxl/mbox: Add background operation handling machinery
cxl/mem: Support sanitation commands

Documentation/ABI/testing/sysfs-bus-cxl | 19 ++
drivers/cxl/core/core.h | 2 +-
drivers/cxl/core/mbox.c | 304 +++++++++++++++++++++++-
drivers/cxl/core/memdev.c | 58 +++++
drivers/cxl/core/port.c | 9 +-
drivers/cxl/cxl.h | 8 +
drivers/cxl/cxlmem.h | 65 ++++-
drivers/cxl/pci.c | 3 +-
drivers/cxl/pmem.c | 5 +-
drivers/cxl/security.c | 13 +-
include/uapi/linux/cxl_mem.h | 2 +
11 files changed, 461 insertions(+), 27 deletions(-)

--
2.37.1



2022-08-04 05:28:55

by Davidlohr Bueso

[permalink] [raw]
Subject: [PATCH 2/2] cxl/mem: Support sanitation commands

Implement support for the non-pmem exclusive sanitize (aka overwrite)
and secure erase commands, per CXL 3.0 specs.

To properly support this feature, create a 'security' sysfs file that
when read will list the current pmem security state or overwrite, and
when written to, perform the requested operation.

As with ndctl-speak, the use cases here would be:

$> cxl sanitize --erase memX
$> cxl sanitize --overwrite memX
$> cxl sanitize --wait-overwrite memX

While userspace can implement entirely the wait/query mechanism for
waiting for the sanitize to complete. Unlike persistent memory
equivalents, there is no command to query in CXL, and as such we can
safely just use cxlds->bg.

Signed-off-by: Davidlohr Bueso <[email protected]>
---
Documentation/ABI/testing/sysfs-bus-cxl | 19 +++++
drivers/cxl/core/mbox.c | 105 ++++++++++++++++++++++++
drivers/cxl/core/memdev.c | 58 +++++++++++++
drivers/cxl/cxlmem.h | 3 +
include/uapi/linux/cxl_mem.h | 2 +
5 files changed, 187 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-bus-cxl b/Documentation/ABI/testing/sysfs-bus-cxl
index 7c2b846521f3..88631b492a11 100644
--- a/Documentation/ABI/testing/sysfs-bus-cxl
+++ b/Documentation/ABI/testing/sysfs-bus-cxl
@@ -52,6 +52,25 @@ Description:
host PCI device for this memory device, emit the CPU node
affinity for this device.

+What: /sys/bus/cxl/devices/memX/security
+Date: August, 2022
+KernelVersion: v5.21
+Contact: [email protected]
+Description:
+ Reading this file will display the security state for that
+ device. The following states are available: disabled, frozen,
+ locked, unlocked and overwrite. When writing to the file, the
+ following commands are supported:
+ * overwrite - 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. This causes all CPU caches to be flushed.
+ * erase - Secure Erase user data by changing the media encryption
+ keys for all user data areas of the device. This causes all
+ CPU caches to be flushed.
+
What: /sys/bus/cxl/devices/*/devtype
Date: June, 2021
KernelVersion: v5.14
diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c
index db6e5a4d1f6d..06bbb760b392 100644
--- a/drivers/cxl/core/mbox.c
+++ b/drivers/cxl/core/mbox.c
@@ -41,6 +41,8 @@ static struct workqueue_struct *cxl_mbox_bgcmd_wq;
#define CXL_BGCMD(_id, sin, sout, _flags, _bgops) \
__CXL_CMD(_id, sin, sout, _flags | CXL_CMD_FLAG_BACKGROUND, _bgops)

+static struct cxl_mem_bgcommand_ops sanitize_bgops;
+
#define CXL_VARIABLE_PAYLOAD ~0U
/*
* This table defines the supported mailbox commands for the driver. This table
@@ -71,6 +73,8 @@ static struct cxl_mem_command cxl_mem_commands[CXL_MEM_COMMAND_ID_MAX] = {
CXL_CMD(GET_SCAN_MEDIA_CAPS, 0x10, 0x4, 0),
CXL_BGCMD(SCAN_MEDIA, 0x11, 0, 0, NULL),
CXL_CMD(GET_SCAN_MEDIA, 0, CXL_VARIABLE_PAYLOAD, 0),
+ CXL_BGCMD(SANITIZE, 0, 0, 0, &sanitize_bgops),
+ CXL_CMD(SECURE_ERASE, 0, 0, 0),
CXL_CMD(GET_SECURITY_STATE, 0, 0x4, 0),
CXL_CMD(SET_PASSPHRASE, 0x60, 0, 0),
CXL_CMD(DISABLE_PASSPHRASE, 0x40, 0, 0),
@@ -962,6 +966,107 @@ int cxl_dev_state_identify(struct cxl_dev_state *cxlds)
}
EXPORT_SYMBOL_NS_GPL(cxl_dev_state_identify, CXL);

+static int sanitize_bgcmd_conflicts(u16 new)
+{
+ /* Forbid anyone but health related commands */
+ if (new == CXL_MBOX_OP_GET_HEALTH_INFO)
+ return 0;
+ return -EBUSY;
+}
+
+static unsigned long sanitize_bgcmd_delay(struct cxl_dev_state *cxlds)
+{
+ unsigned long secs;
+ u64 total_mem;
+
+ if (!cxlds)
+ return 0;
+
+ total_mem = cxlds->total_bytes / CXL_CAPACITY_MULTIPLIER;
+
+ if (total_mem <= 16)
+ secs = 1;
+ else if (total_mem <= 64)
+ secs = 10;
+ else if (total_mem <= 256)
+ secs = 20;
+ else if (total_mem <= 512)
+ secs = 40;
+ else if (total_mem <= 1024)
+ secs = 50;
+ else
+ secs = 60; /* max */
+ return secs;
+}
+
+static void sanitize_bgcmd_post(struct cxl_dev_state *cxlds, bool success)
+{
+ if (success)
+ flush_cache_all();
+}
+
+static struct cxl_mem_bgcommand_ops sanitize_bgops = {
+ .conflicts = sanitize_bgcmd_conflicts,
+ .delay = sanitize_bgcmd_delay,
+ .post = sanitize_bgcmd_post,
+};
+/**
+ * cxl_mem_sanitize() - Send sanitation related commands to the device.
+ * @cxlds: The device data for the operation
+ * @cmd: The command opcode to send
+ *
+ * Return: 0 if the command was executed successfully, regardless of
+ * whether or not the actual security operation is done in the background.
+ * Upon error, return the result of the mailbox command or -EINVAL if
+ * security requirements are not met. CPU caches are flushed before and
+ * after succesful completion of each command.
+ *
+ * See CXL 2.0 @8.2.9.5.5 Sanitize.
+ */
+int cxl_mem_sanitize(struct cxl_dev_state *cxlds, u16 cmd)
+{
+ int rc;
+ bool skip_security;
+ u32 sec_out;
+ u16 ret_code; /* hw */
+
+ rc = cxl_mbox_send_cmd(cxlds, CXL_MBOX_OP_GET_SECURITY_STATE,
+ NULL, 0, &sec_out, sizeof(sec_out), &ret_code);
+ /* this may just be plain unsupported, do not error out */
+ skip_security = (ret_code == CXL_MBOX_CMD_RC_UNSUPPORTED);
+ if (rc && !skip_security)
+ return rc;
+
+ /*
+ * Prior to using these commands, any security applied to
+ * the user data areas of the device shall be DISABLED (or
+ * UNLOCKED for secure erase case).
+ */
+ if (!skip_security && (sec_out & CXL_PMEM_SEC_STATE_USER_PASS_SET))
+ return -EINVAL;
+
+ if (cmd == CXL_MBOX_OP_SANITIZE) {
+ flush_cache_all();
+
+ rc = cxl_mbox_send_cmd(cxlds, cmd, NULL, 0, NULL, 0, &ret_code);
+ if (rc == 0 && ret_code != CXL_MBOX_CMD_RC_BACKGROUND)
+ flush_cache_all();
+ } else if (cmd == CXL_MBOX_OP_SECURE_ERASE) {
+ if (!skip_security && (sec_out & CXL_PMEM_SEC_STATE_LOCKED))
+ return -EINVAL;
+
+ flush_cache_all();
+
+ rc = cxl_mbox_send_cmd(cxlds, cmd, NULL, 0, NULL, 0, NULL);
+ if (rc == 0)
+ flush_cache_all();
+ } else
+ rc = -EINVAL;
+
+ return rc;
+}
+EXPORT_SYMBOL_NS_GPL(cxl_mem_sanitize, CXL);
+
int cxl_mem_create_range_info(struct cxl_dev_state *cxlds)
{
int rc;
diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c
index f7cdcd33504a..db3c5eab7099 100644
--- a/drivers/cxl/core/memdev.c
+++ b/drivers/cxl/core/memdev.c
@@ -106,12 +106,70 @@ static ssize_t numa_node_show(struct device *dev, struct device_attribute *attr,
}
static DEVICE_ATTR_RO(numa_node);

+#define CXL_SEC_CMD_SIZE 32
+
+static ssize_t security_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
+ struct cxl_dev_state *cxlds = cxlmd->cxlds;
+ u32 sec_out = 0;
+ u16 ret_code;
+ int rc;
+
+ if (cxl_mbox_bgcmd_running(cxlds) == CXL_MBOX_OP_SANITIZE)
+ return sprintf(buf, "overwrite\n");
+
+ rc = cxl_mbox_send_cmd(cxlds, CXL_MBOX_OP_GET_SECURITY_STATE,
+ NULL, 0, &sec_out, sizeof(sec_out), &ret_code);
+ if (ret_code == CXL_MBOX_CMD_RC_UNSUPPORTED)
+ return sprintf(buf, "disabled\n");
+ if (rc)
+ return rc;
+
+ if (!(sec_out & CXL_PMEM_SEC_STATE_USER_PASS_SET))
+ return sprintf(buf, "disabled\n");
+ if (sec_out & CXL_PMEM_SEC_STATE_FROZEN)
+ return sprintf(buf, "frozen\n");
+ if (sec_out & CXL_PMEM_SEC_STATE_LOCKED)
+ return sprintf(buf, "locked\n");
+ else
+ return sprintf(buf, "unlocked\n");
+}
+
+static ssize_t security_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
+ struct cxl_dev_state *cxlds = cxlmd->cxlds;
+ char cmd[CXL_SEC_CMD_SIZE+1];
+ ssize_t rc;
+
+ rc = sscanf(buf, "%"__stringify(CXL_SEC_CMD_SIZE)"s", cmd);
+ if (rc < 1)
+ return -EINVAL;
+
+ if (sysfs_streq(cmd, "overwrite"))
+ rc = cxl_mem_sanitize(cxlds, CXL_MBOX_OP_SANITIZE);
+ else if (sysfs_streq(cmd, "erase"))
+ rc = cxl_mem_sanitize(cxlds, CXL_MBOX_OP_SECURE_ERASE);
+ else
+ rc = -EINVAL;
+
+ if (rc == 0)
+ rc = len;
+ return rc;
+}
+static DEVICE_ATTR_RW(security);
+
static struct attribute *cxl_memdev_attributes[] = {
&dev_attr_serial.attr,
&dev_attr_firmware_version.attr,
&dev_attr_payload_max.attr,
&dev_attr_label_storage_size.attr,
&dev_attr_numa_node.attr,
+ &dev_attr_security.attr,
NULL,
};

diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h
index c05dc1b8189a..ee56a4802b34 100644
--- a/drivers/cxl/cxlmem.h
+++ b/drivers/cxl/cxlmem.h
@@ -256,6 +256,7 @@ enum cxl_opcode {
CXL_MBOX_OP_SCAN_MEDIA = 0x4304,
CXL_MBOX_OP_GET_SCAN_MEDIA = 0x4305,
CXL_MBOX_OP_SANITIZE = 0x4400,
+ CXL_MBOX_OP_SECURE_ERASE = 0x4401,
CXL_MBOX_OP_GET_SECURITY_STATE = 0x4500,
CXL_MBOX_OP_SET_PASSPHRASE = 0x4501,
CXL_MBOX_OP_DISABLE_PASSPHRASE = 0x4502,
@@ -457,6 +458,8 @@ static inline void cxl_mem_active_dec(void)
}
#endif

+int cxl_mem_sanitize(struct cxl_dev_state *cxlds, u16 cmd);
+
struct cxl_hdm {
struct cxl_component_regs regs;
unsigned int decoder_count;
diff --git a/include/uapi/linux/cxl_mem.h b/include/uapi/linux/cxl_mem.h
index 6da25f2e1bf9..2cea8fb33249 100644
--- a/include/uapi/linux/cxl_mem.h
+++ b/include/uapi/linux/cxl_mem.h
@@ -41,6 +41,8 @@
___C(GET_SCAN_MEDIA_CAPS, "Get Scan Media Capabilities"), \
___C(SCAN_MEDIA, "Scan Media"), \
___C(GET_SCAN_MEDIA, "Get Scan Media Results"), \
+ ___C(SANITIZE, "Sanitize"), \
+ ___C(SECURE_ERASE, "Secure Erase"), \
___C(GET_SECURITY_STATE, "Get Security State"), \
___C(SET_PASSPHRASE, "Set Passphrase"), \
___C(DISABLE_PASSPHRASE, "Disable Passphrase"), \
--
2.37.1


2022-08-04 18:31:50

by Dave Jiang

[permalink] [raw]
Subject: Re: [RFC PATCH 0/2] cxl: BG operations and device sanitation


On 8/3/2022 9:50 PM, Davidlohr Bueso wrote:
> Hello,
>
> The following is a followup to some of the discussions around CXL device security
> and sanitation[0, 1]. It is marked as RFC mostly to see if the background handling
> will satisfy all users, not just sanitize/overwrite. For example there has been ideas
> to avoid command hogging the device and/or interleaving scan media regions instead
> of all in one, etc. More details in each patch, but:
>
> Patch 1 adds the required background cmd handling bits. While this is currently
> only polling, it would be good to know if there are any fundamental blockers for
> supporting irqs (beyond just background ops) between PCIe and CXL. For example,
> are there any requirements/difficulties that is not the standard MSI/MSI-X PCI
> vector allocation + devm_request_irq()? I have not looked at this into details but
> it the topic has come up in the past as delicate', iirc.
>
> Patch 2 implements the sanitation commands (overwrite and secure erase).
>
> As for testing, while I used the mock device to test the secure erase command, I
> ended up hacking up a prototype[2] for qemu to support overwrite and bg commands.
> So while the some of the paths this series introduces have been exercised, there
> is of course a lot more to do.
>
> Applies against Dave's cxl-security branch[2] which deals with the pmem-only bits.

From the operational sense everything looks good to me. As for the
polling delay on overwrite, with pre-CXL pmem on Optane, we've
discovered that overwrite can take a long time depending on the size.
Sometimes MANY hours if the size is really large. We just opted to
increment the polling interval as time went on [1] instead of based on size.

[1]:
https://elixir.bootlin.com/linux/v5.19/source/drivers/nvdimm/security.c#L434


> Thanks,
> Davidlohr
>
> [0]: https://lore.kernel.org/all/20220708172455.gi37dh3od4w5lqrd@offworld/
> [1]: https://lore.kernel.org/all/165791918718.2491387.4203738301057301285.stgit@djiang5-desk3.ch.intel.com/
> [2]: https://github.com/davidlohr/qemu/commit/64a93a5b824b59d3b547f06f7fbb1269fb4790ce
> [3]: https://git.kernel.org/pub/scm/linux/kernel/git/djiang/linux.git/log/?h=cxl-security
>
> Davidlohr Bueso (2):
> cxl/mbox: Add background operation handling machinery
> cxl/mem: Support sanitation commands
>
> Documentation/ABI/testing/sysfs-bus-cxl | 19 ++
> drivers/cxl/core/core.h | 2 +-
> drivers/cxl/core/mbox.c | 304 +++++++++++++++++++++++-
> drivers/cxl/core/memdev.c | 58 +++++
> drivers/cxl/core/port.c | 9 +-
> drivers/cxl/cxl.h | 8 +
> drivers/cxl/cxlmem.h | 65 ++++-
> drivers/cxl/pci.c | 3 +-
> drivers/cxl/pmem.c | 5 +-
> drivers/cxl/security.c | 13 +-
> include/uapi/linux/cxl_mem.h | 2 +
> 11 files changed, 461 insertions(+), 27 deletions(-)
>
> --
> 2.37.1
>

2022-08-04 20:32:13

by Davidlohr Bueso

[permalink] [raw]
Subject: Re: [RFC PATCH 0/2] cxl: BG operations and device sanitation

On Thu, 04 Aug 2022, Dave Jiang wrote:

>From the operational sense everything looks good to me. As for the
>polling delay on overwrite, with pre-CXL pmem on Optane, we've
>discovered that overwrite can take a long time depending on the size.
>Sometimes MANY hours if the size is really large. We just opted to
>increment the polling interval as time went on [1] instead of based on
>size.

Thanks for having a look. Sure, we can do that, I have no particular attachment
to doing it based on size (it's just the way it occured to me). I am curious,
though: While regardless of size vs time based estimates, are the numbers
expected to be similar for volatile regions? All these numbers being from
nvdimm DSM docs.

Thanks,
Davidlohr

2022-08-08 21:16:41

by Dave Jiang

[permalink] [raw]
Subject: Re: [RFC PATCH 0/2] cxl: BG operations and device sanitation


On 8/4/2022 1:07 PM, Davidlohr Bueso wrote:
> On Thu, 04 Aug 2022, Dave Jiang wrote:
>
>> From the operational sense everything looks good to me. As for the
>> polling delay on overwrite, with pre-CXL pmem on Optane, we've
>> discovered that overwrite can take a long time depending on the size.
>> Sometimes MANY hours if the size is really large. We just opted to
>> increment the polling interval as time went on [1] instead of based on
>> size.
>
> Thanks for having a look. Sure, we can do that, I have no particular
> attachment
> to doing it based on size (it's just the way it occured to me). I am
> curious,
> though: While regardless of size vs time based estimates, are the numbers
> expected to be similar for volatile regions? All these numbers being from
> nvdimm DSM docs.

I don't either. Just pointing out that's what we did with the Optane
stuff. I think that the volatile devices (DRAM?) would probably be a lot
faster when it comes to writes. So maybe won't take as long. And also
perhaps smaller in size in the immediate future? Just guessing.


>
> Thanks,
> Davidlohr

2022-08-25 14:43:34

by Jonathan Cameron

[permalink] [raw]
Subject: Re: [PATCH 2/2] cxl/mem: Support sanitation commands

On Wed, 3 Aug 2022 21:50:29 -0700
Davidlohr Bueso <[email protected]> wrote:

> Implement support for the non-pmem exclusive sanitize (aka overwrite)
> and secure erase commands, per CXL 3.0 specs.
>
> To properly support this feature, create a 'security' sysfs file that
> when read will list the current pmem security state or overwrite, and
> when written to, perform the requested operation.
>
> As with ndctl-speak, the use cases here would be:
>
> $> cxl sanitize --erase memX
> $> cxl sanitize --overwrite memX
> $> cxl sanitize --wait-overwrite memX
>
> While userspace can implement entirely the wait/query mechanism for
> waiting for the sanitize to complete. Unlike persistent memory
> equivalents, there is no command to query in CXL, and as such we can
> safely just use cxlds->bg.
>
> Signed-off-by: Davidlohr Bueso <[email protected]>
> ---
> Documentation/ABI/testing/sysfs-bus-cxl | 19 +++++
> drivers/cxl/core/mbox.c | 105 ++++++++++++++++++++++++
> drivers/cxl/core/memdev.c | 58 +++++++++++++
> drivers/cxl/cxlmem.h | 3 +
> include/uapi/linux/cxl_mem.h | 2 +
> 5 files changed, 187 insertions(+)
>
> diff --git a/Documentation/ABI/testing/sysfs-bus-cxl b/Documentation/ABI/testing/sysfs-bus-cxl
> index 7c2b846521f3..88631b492a11 100644
> --- a/Documentation/ABI/testing/sysfs-bus-cxl
> +++ b/Documentation/ABI/testing/sysfs-bus-cxl
> @@ -52,6 +52,25 @@ Description:
> host PCI device for this memory device, emit the CPU node
> affinity for this device.
>
> +What: /sys/bus/cxl/devices/memX/security
> +Date: August, 2022
> +KernelVersion: v5.21

v6.1

> +Contact: [email protected]
> +Description:
> + Reading this file will display the security state for that
> + device. The following states are available: disabled, frozen,
> + locked, unlocked and overwrite. When writing to the file, the
> + following commands are supported:
> + * overwrite - 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. This causes all CPU caches to be flushed.
> + * erase - Secure Erase user data by changing the media encryption
> + keys for all user data areas of the device. This causes all
> + CPU caches to be flushed.
> +
> What: /sys/bus/cxl/devices/*/devtype
> Date: June, 2021
> KernelVersion: v5.14
> diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c
> index db6e5a4d1f6d..06bbb760b392 100644
> --- a/drivers/cxl/core/mbox.c
> +++ b/drivers/cxl/core/mbox.c
> @@ -41,6 +41,8 @@ static struct workqueue_struct *cxl_mbox_bgcmd_wq;
> #define CXL_BGCMD(_id, sin, sout, _flags, _bgops) \
> __CXL_CMD(_id, sin, sout, _flags | CXL_CMD_FLAG_BACKGROUND, _bgops)
>
> +static struct cxl_mem_bgcommand_ops sanitize_bgops;
> +
> #define CXL_VARIABLE_PAYLOAD ~0U
> /*
> * This table defines the supported mailbox commands for the driver. This table
> @@ -71,6 +73,8 @@ static struct cxl_mem_command cxl_mem_commands[CXL_MEM_COMMAND_ID_MAX] = {
> CXL_CMD(GET_SCAN_MEDIA_CAPS, 0x10, 0x4, 0),
> CXL_BGCMD(SCAN_MEDIA, 0x11, 0, 0, NULL),
> CXL_CMD(GET_SCAN_MEDIA, 0, CXL_VARIABLE_PAYLOAD, 0),
> + CXL_BGCMD(SANITIZE, 0, 0, 0, &sanitize_bgops),
> + CXL_CMD(SECURE_ERASE, 0, 0, 0),
> CXL_CMD(GET_SECURITY_STATE, 0, 0x4, 0),
> CXL_CMD(SET_PASSPHRASE, 0x60, 0, 0),
> CXL_CMD(DISABLE_PASSPHRASE, 0x40, 0, 0),
> @@ -962,6 +966,107 @@ int cxl_dev_state_identify(struct cxl_dev_state *cxlds)
> }
> EXPORT_SYMBOL_NS_GPL(cxl_dev_state_identify, CXL);
>
> +static int sanitize_bgcmd_conflicts(u16 new)
> +{
> + /* Forbid anyone but health related commands */
> + if (new == CXL_MBOX_OP_GET_HEALTH_INFO)
> + return 0;
> + return -EBUSY;
> +}
> +
> +static unsigned long sanitize_bgcmd_delay(struct cxl_dev_state *cxlds)
> +{
> + unsigned long secs;
> + u64 total_mem;
> +
> + if (!cxlds)
> + return 0;
> +
> + total_mem = cxlds->total_bytes / CXL_CAPACITY_MULTIPLIER;
> +
> + if (total_mem <= 16)
> + secs = 1;
> + else if (total_mem <= 64)
> + secs = 10;
> + else if (total_mem <= 256)
> + secs = 20;
> + else if (total_mem <= 512)
> + secs = 40;
> + else if (total_mem <= 1024)
> + secs = 50;
> + else
> + secs = 60; /* max */
> + return secs;
> +}
> +
> +static void sanitize_bgcmd_post(struct cxl_dev_state *cxlds, bool success)
> +{
> + if (success)
> + flush_cache_all();
> +}
> +
> +static struct cxl_mem_bgcommand_ops sanitize_bgops = {
> + .conflicts = sanitize_bgcmd_conflicts,
> + .delay = sanitize_bgcmd_delay,
> + .post = sanitize_bgcmd_post,
> +};

blank line here.

> +/**
> + * cxl_mem_sanitize() - Send sanitation related commands to the device.
> + * @cxlds: The device data for the operation
> + * @cmd: The command opcode to send
> + *
> + * Return: 0 if the command was executed successfully, regardless of
> + * whether or not the actual security operation is done in the background.
> + * Upon error, return the result of the mailbox command or -EINVAL if
> + * security requirements are not met. CPU caches are flushed before and
> + * after succesful completion of each command.
> + *
> + * See CXL 2.0 @8.2.9.5.5 Sanitize.
> + */
> +int cxl_mem_sanitize(struct cxl_dev_state *cxlds, u16 cmd)
> +{
> + int rc;
> + bool skip_security;
> + u32 sec_out;
> + u16 ret_code; /* hw */
> +
> + rc = cxl_mbox_send_cmd(cxlds, CXL_MBOX_OP_GET_SECURITY_STATE,
> + NULL, 0, &sec_out, sizeof(sec_out), &ret_code);
> + /* this may just be plain unsupported, do not error out */
> + skip_security = (ret_code == CXL_MBOX_CMD_RC_UNSUPPORTED);

Ah. Now I'm understanding why you had the ret_code. I'd rather see this
done using the CEL so we don't send the command if not supported.

> + if (rc && !skip_security)
> + return rc;
> +
> + /*
> + * Prior to using these commands, any security applied to
> + * the user data areas of the device shall be DISABLED (or
> + * UNLOCKED for secure erase case).
> + */
> + if (!skip_security && (sec_out & CXL_PMEM_SEC_STATE_USER_PASS_SET))
> + return -EINVAL;
> +
> + if (cmd == CXL_MBOX_OP_SANITIZE) {
> + flush_cache_all();
> +
> + rc = cxl_mbox_send_cmd(cxlds, cmd, NULL, 0, NULL, 0, &ret_code);
> + if (rc == 0 && ret_code != CXL_MBOX_CMD_RC_BACKGROUND)
> + flush_cache_all();
> + } else if (cmd == CXL_MBOX_OP_SECURE_ERASE) {
> + if (!skip_security && (sec_out & CXL_PMEM_SEC_STATE_LOCKED))
> + return -EINVAL;
> +
> + flush_cache_all();
> +
> + rc = cxl_mbox_send_cmd(cxlds, cmd, NULL, 0, NULL, 0, NULL);
> + if (rc == 0)
> + flush_cache_all();
> + } else
> + rc = -EINVAL;
> +
> + return rc;
> +}
> +EXPORT_SYMBOL_NS_GPL(cxl_mem_sanitize, CXL);
> +
> int cxl_mem_create_range_info(struct cxl_dev_state *cxlds)
> {
> int rc;
> diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c
> index f7cdcd33504a..db3c5eab7099 100644
> --- a/drivers/cxl/core/memdev.c
> +++ b/drivers/cxl/core/memdev.c
> @@ -106,12 +106,70 @@ static ssize_t numa_node_show(struct device *dev, struct device_attribute *attr,
> }
> static DEVICE_ATTR_RO(numa_node);
>
> +#define CXL_SEC_CMD_SIZE 32
> +
> +static ssize_t security_show(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
> + struct cxl_dev_state *cxlds = cxlmd->cxlds;
> + u32 sec_out = 0;
> + u16 ret_code;
> + int rc;
> +
> + if (cxl_mbox_bgcmd_running(cxlds) == CXL_MBOX_OP_SANITIZE)
> + return sprintf(buf, "overwrite\n");
> +
> + rc = cxl_mbox_send_cmd(cxlds, CXL_MBOX_OP_GET_SECURITY_STATE,
> + NULL, 0, &sec_out, sizeof(sec_out), &ret_code);
> + if (ret_code == CXL_MBOX_CMD_RC_UNSUPPORTED)

As above - if not supported, don't send command.

If none of this stuff is supported, hide the sysfs interface via
the is_visible callback.

> + return sprintf(buf, "disabled\n");
> + if (rc)
> + return rc;
> +
> + if (!(sec_out & CXL_PMEM_SEC_STATE_USER_PASS_SET))
> + return sprintf(buf, "disabled\n");
> + if (sec_out & CXL_PMEM_SEC_STATE_FROZEN)
> + return sprintf(buf, "frozen\n");
> + if (sec_out & CXL_PMEM_SEC_STATE_LOCKED)
> + return sprintf(buf, "locked\n");
> + else
> + return sprintf(buf, "unlocked\n");
> +}
> +
> +static ssize_t security_store(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf, size_t len)
> +{
> + struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
> + struct cxl_dev_state *cxlds = cxlmd->cxlds;
> + char cmd[CXL_SEC_CMD_SIZE+1];
> + ssize_t rc;
> +
> + rc = sscanf(buf, "%"__stringify(CXL_SEC_CMD_SIZE)"s", cmd);
> + if (rc < 1)
> + return -EINVAL;
> +
> + if (sysfs_streq(cmd, "overwrite"))
> + rc = cxl_mem_sanitize(cxlds, CXL_MBOX_OP_SANITIZE);
> + else if (sysfs_streq(cmd, "erase"))
> + rc = cxl_mem_sanitize(cxlds, CXL_MBOX_OP_SECURE_ERASE);
> + else
> + rc = -EINVAL;
> +
> + if (rc == 0)
> + rc = len;
> + return rc;
> +}
> +static DEVICE_ATTR_RW(security);
> +
> static struct attribute *cxl_memdev_attributes[] = {
> &dev_attr_serial.attr,
> &dev_attr_firmware_version.attr,
> &dev_attr_payload_max.attr,
> &dev_attr_label_storage_size.attr,
> &dev_attr_numa_node.attr,
> + &dev_attr_security.attr,
> NULL,
> };
>
> diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h
> index c05dc1b8189a..ee56a4802b34 100644
> --- a/drivers/cxl/cxlmem.h
> +++ b/drivers/cxl/cxlmem.h
> @@ -256,6 +256,7 @@ enum cxl_opcode {
> CXL_MBOX_OP_SCAN_MEDIA = 0x4304,
> CXL_MBOX_OP_GET_SCAN_MEDIA = 0x4305,
> CXL_MBOX_OP_SANITIZE = 0x4400,

This definition should be pulled forwards from previous patch I think.

> + CXL_MBOX_OP_SECURE_ERASE = 0x4401,
> CXL_MBOX_OP_GET_SECURITY_STATE = 0x4500,
> CXL_MBOX_OP_SET_PASSPHRASE = 0x4501,
> CXL_MBOX_OP_DISABLE_PASSPHRASE = 0x4502,
> @@ -457,6 +458,8 @@ static inline void cxl_mem_active_dec(void)
> }
> #endif
>
> +int cxl_mem_sanitize(struct cxl_dev_state *cxlds, u16 cmd);
> +
> struct cxl_hdm {
> struct cxl_component_regs regs;
> unsigned int decoder_count;
> diff --git a/include/uapi/linux/cxl_mem.h b/include/uapi/linux/cxl_mem.h
> index 6da25f2e1bf9..2cea8fb33249 100644
> --- a/include/uapi/linux/cxl_mem.h
> +++ b/include/uapi/linux/cxl_mem.h
> @@ -41,6 +41,8 @@
> ___C(GET_SCAN_MEDIA_CAPS, "Get Scan Media Capabilities"), \
> ___C(SCAN_MEDIA, "Scan Media"), \
> ___C(GET_SCAN_MEDIA, "Get Scan Media Results"), \
> + ___C(SANITIZE, "Sanitize"), \
> + ___C(SECURE_ERASE, "Secure Erase"), \
> ___C(GET_SECURITY_STATE, "Get Security State"), \
> ___C(SET_PASSPHRASE, "Set Passphrase"), \
> ___C(DISABLE_PASSPHRASE, "Disable Passphrase"), \