All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v5 0/6] cxl: Support device sanitation
@ 2023-05-26  3:33 Davidlohr Bueso
  2023-05-26  3:33 ` [PATCH 1/6] cxl/mem: Introduce security state sysfs file Davidlohr Bueso
                   ` (5 more replies)
  0 siblings, 6 replies; 19+ messages in thread
From: Davidlohr Bueso @ 2023-05-26  3:33 UTC (permalink / raw)
  To: dan.j.williams
  Cc: dave.jiang, vishal.l.verma, Jonathan.Cameron, fan.ni,
	a.manzanares, dave, linux-cxl

Hi,

Changes from v4 (https://lore.kernel.org/linux-cxl/20230421092321.12741-1-dave@stgolabs.net/):
    o Added patch 1 'security/state' sysfs file which will be the placeholder
      for userspace to know about pmem security or an on-going sanitation op.
    o Renamed some of the sanitation polling variables.
    o Picked up review tags for mock device test patches.

This adds the sanitation part of the background command handling. Some noteworthy items:

    o Treating Sanitation as such a special beast can make the code a bit invasive,
      but couldn't find a decent alternative. For example I realize that this is really
      ad-hoc code in __cxl_pci_mbox_send_cmd(). A lot of this also comes from the fact
      that polling for sanitize is supported, so sw still needs to keep up and serialize.
      
    o Nothing depends explicitly on CPU cacheline management

    o All sysfs files/attributes in the security directory are visible.

    o Continue to use __ATTR() macros for sysfs attributes instead of the requested
      DEVICE_ATTR_*() ones because of the naming the security directory, otherwise
      names don't match.

Patch 1 adds a new security/state file.
Patch 2 paves the required sanitation handling code before actually using it.
Patch 3,4 wires up sanitation + unit test.
Patch 5,6 wires up secure erase + unit test.

Testing.
========

o There are the mock device tests for Sanitize and Secure Erase.

o The latest (v2) qemu bg/sanitize support series is posted here:
	https://lore.kernel.org/linux-cxl/20230418172337.19207-1-dave@stgolabs.net/

(1) Window where driver is out of sync with hw (Sanitation async polling).

[root@fedora ~]# echo 1 > /sys/bus/cxl/devices/mem0/security/sanitize
[  159.297482] cxl_pci:__cxl_pci_mbox_send_cmd:243: cxl_pci 0000:37:00.0: Sending command: 0x4400
[  159.298648] cxl_pci:cxl_pci_mbox_wait_for_doorbell:73: cxl_pci 0000:37:00.0: Doorbell wait took 0ms
[  159.299908] cxl_pci:__cxl_pci_mbox_send_cmd:295: cxl_pci 0000:37:00.0: Sanitation operation started
>>>> qemu informs sanitation is done <<<<<
[root@fedora ~]# echo 1 > /sys/bus/cxl/devices/mem0/security/sanitize
[  165.897345] cxl_pci 0000:37:00.0: Failed to sanitize device : -16
[  171.692050] cxl_pci:cxl_mbox_sanitize_work:147: cxl_pci 0000:37:00.0: Sanitation operation ended
[root@fedora ~]# echo 1 > /sys/bus/cxl/devices/mem0/security/sanitize
[  173.373337] cxl_pci:__cxl_pci_mbox_send_cmd:243: cxl_pci 0000:37:00.0: Sending command: 0x4400
[  173.374498] cxl_pci:cxl_pci_mbox_wait_for_doorbell:73: cxl_pci 0000:37:00.0: Doorbell wait took 0ms
[  173.375727] cxl_pci:__cxl_pci_mbox_send_cmd:295: cxl_pci 0000:37:00.0: Sanitation operation started

(2) Perform sanitation of more than one memdev at a time (Sanitation async polling).

[root@fedora ~]# echo 1 > /sys/bus/cxl/devices/mem1/security/sanitize
[  351.287129] cxl_pci:__cxl_pci_mbox_send_cmd:243: cxl_pci 0000:36:00.0: Sending command: 0x4400
[  351.288403] cxl_pci:cxl_pci_mbox_wait_for_doorbell:73: cxl_pci 0000:36:00.0: Doorbell wait took 0ms
[  351.289706] cxl_pci:__cxl_pci_mbox_send_cmd:295: cxl_pci 0000:36:00.0: Sanitation operation started
[root@fedora ~]# echo 1 > /sys/bus/cxl/devices/mem0/security/sanitize
[  353.058614] cxl_pci:__cxl_pci_mbox_send_cmd:243: cxl_pci 0000:37:00.0: Sending command: 0x4400
[  353.059854] cxl_pci:cxl_pci_mbox_wait_for_doorbell:73: cxl_pci 0000:37:00.0: Doorbell wait took 0ms
[  353.061126] cxl_pci:__cxl_pci_mbox_send_cmd:295: cxl_pci 0000:37:00.0: Sanitation operation started
>>>>  qemu informs sanitation is done <<<<<
>>>>  qemu informs sanitation is done <<<<<
[  363.692138] cxl_pci:cxl_mbox_sanitize_work:147: cxl_pci 0000:36:00.0: Sanitation operation ended
[  365.227416] cxl_pci:cxl_mbox_sanitize_work:147: cxl_pci 0000:37:00.0: Sanitation operation ended

(3) Perform sanitation of more than one memdev at a time (Sanitation async irq).

[root@fedora ~]# echo 1 > /sys/bus/cxl/devices/mem1/security/sanitize
[  193.729821] cxl_pci:__cxl_pci_mbox_send_cmd:243: cxl_pci 0000:c1:00.0: Sending command: 0x4400
[  193.731071] cxl_pci:cxl_pci_mbox_wait_for_doorbell:73: cxl_pci 0000:c1:00.0: Doorbell wait took 0ms
[  193.732360] cxl_pci:__cxl_pci_mbox_send_cmd:295: cxl_pci 0000:c1:00.0: Sanitation operation started
[root@fedora ~]# echo 1 > /sys/bus/cxl/devices/mem0/security/sanitize
[  197.001466] cxl_pci:__cxl_pci_mbox_send_cmd:243: cxl_pci 0000:36:00.0: Sending command: 0x4400
[  197.002694] cxl_pci:cxl_pci_mbox_wait_for_doorbell:73: cxl_pci 0000:36:00.0: Doorbell wait took 0ms
[  197.003956] cxl_pci:__cxl_pci_mbox_send_cmd:295: cxl_pci 0000:36:00.0: Sanitation operation started
>>>> qemu says sanitation is done <<<<
[  197.731473] cxl_pci:cxl_pci_mbox_irq:119: cxl_pci 0000:c1:00.0: Sanitation operation ended
>>>> qemu says sanitation is done <<<<
[  201.003258] cxl_pci:cxl_pci_mbox_irq:119: cxl_pci 0000:36:00.0: Sanitation operation ended

(4) Forbid new sanitation while one is in progress (Sanitation async irq).
 
[root@fedora ~]# cat /sys/bus/cxl/devices/mem0/security/state
disabled
[root@fedora ~]# echo 1 > /sys/bus/cxl/devices/mem0/security/sanitize
[   39.284258] cxl_pci:__cxl_pci_mbox_send_cmd:243: cxl_pci 0000:36:00.0: Sending command: 0x4400
[   39.285459] cxl_pci:cxl_pci_mbox_wait_for_doorbell:73: cxl_pci 0000:36:00.0: Doorbell wait took 0ms
[   39.286723] cxl_pci:__cxl_pci_mbox_send_cmd:295: cxl_pci 0000:36:00.0: Sanitation operation started
[root@fedora ~]# cat /sys/bus/cxl/devices/mem0/security/state
sanitize
[root@fedora ~]# echo 1 > /sys/bus/cxl/devices/mem0/security/sanitize
[   42.697129] cxl_pci:__cxl_pci_mbox_send_cmd:243: cxl_pci 0000:36:00.0: Sending command: 0x4400
[   42.698323] cxl_pci:cxl_pci_mbox_wait_for_doorbell:73: cxl_pci 0000:36:00.0: Doorbell wait took 0ms
[   42.699525] cxl_pci:__cxl_pci_mbox_send_cmd:335: cxl_pci 0000:36:00.0: Mailbox operation had an error: ongoing background operation
[   42.701119] cxl_pci 0000:36:00.0: Failed to sanitize device : -6
>>>> qemu says sanitation is done <<<<
[   43.285334] cxl_pci:cxl_pci_mbox_irq:119: cxl_pci 0000:36:00.0: Sanitation operation ended


Applies against 'for-6.5/cxl-background' from cxl.git.

Please consider for v6.5.

Thanks!

Davidlohr Bueso (6):
  cxl/mem: Introduce security state sysfs file
  cxl/mbox: Add sanitation handling machinery
  cxl/mem: Wire up Sanitation support
  cxl/test: Add Sanitize opcode support
  cxl/mem: Support Secure Erase
  cxl/test: Add Secure Erase opcode support

 Documentation/ABI/testing/sysfs-bus-cxl |  37 +++++++
 drivers/cxl/core/mbox.c                 |  59 ++++++++++
 drivers/cxl/core/memdev.c               | 139 ++++++++++++++++++++++++
 drivers/cxl/cxlmem.h                    |  26 +++++
 drivers/cxl/pci.c                       |  88 ++++++++++++++-
 drivers/cxl/security.c                  |   3 +
 tools/testing/cxl/test/mem.c            |  52 +++++++++
 7 files changed, 400 insertions(+), 4 deletions(-)

--
2.40.1


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH 1/6] cxl/mem: Introduce security state sysfs file
  2023-05-26  3:33 [PATCH v5 0/6] cxl: Support device sanitation Davidlohr Bueso
@ 2023-05-26  3:33 ` Davidlohr Bueso
  2023-05-30 23:30   ` Dave Jiang
                     ` (2 more replies)
  2023-05-26  3:33 ` [PATCH 2/6] cxl/mbox: Add sanitation handling machinery Davidlohr Bueso
                   ` (4 subsequent siblings)
  5 siblings, 3 replies; 19+ messages in thread
From: Davidlohr Bueso @ 2023-05-26  3:33 UTC (permalink / raw)
  To: dan.j.williams
  Cc: dave.jiang, vishal.l.verma, Jonathan.Cameron, fan.ni,
	a.manzanares, dave, linux-cxl

Add a read-only sysfs file to display the security state
of a device (currently only pmem):

    /sys/bus/cxl/devices/memX/security/state

This introduces a cxl_security_state structure that is
to be the placeholder for common CXL security features.

Signed-off-by: Davidlohr Bueso <dave@stgolabs.net>
---
 Documentation/ABI/testing/sysfs-bus-cxl | 10 ++++++
 drivers/cxl/core/memdev.c               | 46 +++++++++++++++++++++++++
 drivers/cxl/cxlmem.h                    | 11 ++++++
 drivers/cxl/security.c                  |  3 ++
 4 files changed, 70 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-bus-cxl b/Documentation/ABI/testing/sysfs-bus-cxl
index 48ac0d911801..721a44d8a482 100644
--- a/Documentation/ABI/testing/sysfs-bus-cxl
+++ b/Documentation/ABI/testing/sysfs-bus-cxl
@@ -58,6 +58,16 @@ Description:
 		affinity for this device.
 
 
+What:		/sys/bus/cxl/devices/memX/security/state
+Date:		June, 2023
+KernelVersion:	v6.5
+Contact:	linux-cxl@vger.kernel.org
+Description:
+		(RO) Reading this file will display the CXL security state for
+		that device. Such states can be: 'disabled', or those available
+		only for persistent memory: 'locked', 'unlocked' or 'frozen'.
+
+
 What:		/sys/bus/cxl/devices/*/devtype
 Date:		June, 2021
 KernelVersion:	v5.14
diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c
index 057a43267290..6e1d7d3610a2 100644
--- a/drivers/cxl/core/memdev.c
+++ b/drivers/cxl/core/memdev.c
@@ -107,6 +107,28 @@ static ssize_t numa_node_show(struct device *dev, struct device_attribute *attr,
 }
 static DEVICE_ATTR_RO(numa_node);
 
+static ssize_t security_state_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;
+	unsigned long state = cxlds->security.state;
+
+	if (!(state & CXL_PMEM_SEC_STATE_USER_PASS_SET))
+		return sysfs_emit(buf, "disabled\n");
+	if (state & CXL_PMEM_SEC_STATE_FROZEN ||
+	    state & CXL_PMEM_SEC_STATE_MASTER_PLIMIT ||
+	    state & CXL_PMEM_SEC_STATE_USER_PLIMIT)
+		return sysfs_emit(buf, "frozen\n");
+	if (state & CXL_PMEM_SEC_STATE_LOCKED)
+		return sysfs_emit(buf, "locked\n");
+	else
+		return sysfs_emit(buf, "unlocked\n");
+}
+static struct device_attribute dev_attr_security_state =
+	__ATTR(state, 0444, security_state_show, NULL);
+
 static int cxl_get_poison_by_memdev(struct cxl_memdev *cxlmd)
 {
 	struct cxl_dev_state *cxlds = cxlmd->cxlds;
@@ -352,6 +374,11 @@ static struct attribute *cxl_memdev_ram_attributes[] = {
 	NULL,
 };
 
+static struct attribute *cxl_memdev_security_attributes[] = {
+	&dev_attr_security_state.attr,
+	NULL,
+};
+
 static umode_t cxl_memdev_visible(struct kobject *kobj, struct attribute *a,
 				  int n)
 {
@@ -375,10 +402,16 @@ static struct attribute_group cxl_memdev_pmem_attribute_group = {
 	.attrs = cxl_memdev_pmem_attributes,
 };
 
+static struct attribute_group cxl_memdev_security_attribute_group = {
+	.name = "security",
+	.attrs = cxl_memdev_security_attributes,
+};
+
 static const struct attribute_group *cxl_memdev_attribute_groups[] = {
 	&cxl_memdev_attribute_group,
 	&cxl_memdev_ram_attribute_group,
 	&cxl_memdev_pmem_attribute_group,
+	&cxl_memdev_security_attribute_group,
 	NULL,
 };
 
@@ -551,6 +584,15 @@ static const struct file_operations cxl_memdev_fops = {
 	.llseek = noop_llseek,
 };
 
+static int cxl_memdev_security_init(struct cxl_memdev *cxlmd)
+{
+	struct cxl_dev_state *cxlds = cxlmd->cxlds;
+
+	cxlds->security.state = 0;
+
+	return 0;
+}
+
 struct cxl_memdev *devm_cxl_add_memdev(struct cxl_dev_state *cxlds)
 {
 	struct cxl_memdev *cxlmd;
@@ -579,6 +621,10 @@ struct cxl_memdev *devm_cxl_add_memdev(struct cxl_dev_state *cxlds)
 	if (rc)
 		goto err;
 
+	rc = cxl_memdev_security_init(cxlmd);
+	if (rc)
+		goto err;
+
 	rc = devm_add_action_or_reset(cxlds->dev, cxl_memdev_unregister, cxlmd);
 	if (rc)
 		return ERR_PTR(rc);
diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h
index 1d8e81c87c6a..5329274b0076 100644
--- a/drivers/cxl/cxlmem.h
+++ b/drivers/cxl/cxlmem.h
@@ -260,6 +260,15 @@ struct cxl_poison_state {
 	struct mutex lock;  /* Protect reads of poison list */
 };
 
+/**
+ * struct cxl_security_state - Device security state
+ *
+ * @state: state of last security operation
+ */
+struct cxl_security_state {
+	unsigned long state;
+};
+
 /**
  * struct cxl_dev_state - The driver device state
  *
@@ -297,6 +306,7 @@ struct cxl_poison_state {
  * @serial: PCIe Device Serial Number
  * @event: event log driver state
  * @poison: poison driver state info
+ * @security: device security state
  * @mbox_send: @dev specific transport for transmitting mailbox commands
  *
  * See section 8.2.9.5.2 Capacity Configuration and Label Storage for
@@ -336,6 +346,7 @@ struct cxl_dev_state {
 
 	struct cxl_event_state event;
 	struct cxl_poison_state poison;
+	struct cxl_security_state security;
 
 	struct rcuwait mbox_wait;
 	int (*mbox_send)(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd);
diff --git a/drivers/cxl/security.c b/drivers/cxl/security.c
index 4ad4bda2d18e..9da6785dfd31 100644
--- a/drivers/cxl/security.c
+++ b/drivers/cxl/security.c
@@ -34,6 +34,9 @@ static unsigned long cxl_pmem_get_security_flags(struct nvdimm *nvdimm,
 		return 0;
 
 	sec_out = le32_to_cpu(out.flags);
+	/* cache security state */
+	cxlds->security.state = sec_out;
+
 	if (ptype == NVDIMM_MASTER) {
 		if (sec_out & CXL_PMEM_SEC_STATE_MASTER_PASS_SET)
 			set_bit(NVDIMM_SECURITY_UNLOCKED, &security_flags);
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 2/6] cxl/mbox: Add sanitation handling machinery
  2023-05-26  3:33 [PATCH v5 0/6] cxl: Support device sanitation Davidlohr Bueso
  2023-05-26  3:33 ` [PATCH 1/6] cxl/mem: Introduce security state sysfs file Davidlohr Bueso
@ 2023-05-26  3:33 ` Davidlohr Bueso
  2023-05-30 23:36   ` Dave Jiang
  2023-05-31 16:36   ` Jonathan Cameron
  2023-05-26  3:33 ` [PATCH 3/6] cxl/mem: Wire up Sanitation support Davidlohr Bueso
                   ` (3 subsequent siblings)
  5 siblings, 2 replies; 19+ messages in thread
From: Davidlohr Bueso @ 2023-05-26  3:33 UTC (permalink / raw)
  To: dan.j.williams
  Cc: dave.jiang, vishal.l.verma, Jonathan.Cameron, fan.ni,
	a.manzanares, dave, linux-cxl

Sanitation is by definition a device-monopolizing operation, and thus
the timeslicing rules for other background commands do not apply.
As such handle this special case asynchronously and return immediately.
Subsequent changes will allow completion to be pollable from userspace
via a sysfs file interface.

For devices that don't support interrupts for notifying background
command completion, self-poll with the caveat that the poller can
be out of sync with the ready hardware, and therefore care must be
taken to not allow any new commands to go through until the poller
sees the hw completion. The poller takes the mbox_mutex to stabilize
the flagging, minimizing any runtime overhead in the send path to
check for 'sanitize_tmo' for uncommon poll scenarios. This flag
also serves for sanitation (the only user of async polling) to know
when to queue work or simply rely on irqs.

The irq case is much simpler as hardware will serialize/error
appropriately.

Signed-off-by: Davidlohr Bueso <dave@stgolabs.net>
---
 drivers/cxl/core/memdev.c | 10 +++++
 drivers/cxl/cxlmem.h      | 10 +++++
 drivers/cxl/pci.c         | 83 +++++++++++++++++++++++++++++++++++++--
 3 files changed, 99 insertions(+), 4 deletions(-)

diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c
index 6e1d7d3610a2..02763e83545c 100644
--- a/drivers/cxl/core/memdev.c
+++ b/drivers/cxl/core/memdev.c
@@ -460,11 +460,21 @@ void clear_exclusive_cxl_commands(struct cxl_dev_state *cxlds, unsigned long *cm
 }
 EXPORT_SYMBOL_NS_GPL(clear_exclusive_cxl_commands, CXL);
 
+static void cxl_memdev_security_shutdown(struct device *dev)
+{
+	struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
+	struct cxl_dev_state *cxlds = cxlmd->cxlds;
+
+	if (cxlds->security.poll_tmo_secs != -1)
+		cancel_delayed_work_sync(&cxlds->security.poll_dwork);
+}
+
 static void cxl_memdev_shutdown(struct device *dev)
 {
 	struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
 
 	down_write(&cxl_memdev_rwsem);
+	cxl_memdev_security_shutdown(dev);
 	cxlmd->cxlds = NULL;
 	up_write(&cxl_memdev_rwsem);
 }
diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h
index 5329274b0076..02ec68f97de2 100644
--- a/drivers/cxl/cxlmem.h
+++ b/drivers/cxl/cxlmem.h
@@ -264,9 +264,18 @@ struct cxl_poison_state {
  * struct cxl_security_state - Device security state
  *
  * @state: state of last security operation
+ * @poll_tmo_secs: polling timeout
+ * @poll_dwork: polling work item
+ *
+ * Polling (sanitation) is only used when device mbox irqs are not
+ * supported. As such, @poll_tmo_secs == -1 indicates that polling
+ * is disabled. Otherwise, when enabled, @poll_tmo_secs is maxed
+ * at 15 minutes and serialized by the mbox_mutex.
  */
 struct cxl_security_state {
 	unsigned long state;
+	int poll_tmo_secs;
+	struct delayed_work poll_dwork;
 };
 
 /**
@@ -380,6 +389,7 @@ enum cxl_opcode {
 	CXL_MBOX_OP_GET_SCAN_MEDIA_CAPS	= 0x4303,
 	CXL_MBOX_OP_SCAN_MEDIA		= 0x4304,
 	CXL_MBOX_OP_GET_SCAN_MEDIA	= 0x4305,
+	CXL_MBOX_OP_SANITIZE		= 0x4400,
 	CXL_MBOX_OP_GET_SECURITY_STATE	= 0x4500,
 	CXL_MBOX_OP_SET_PASSPHRASE	= 0x4501,
 	CXL_MBOX_OP_DISABLE_PASSPHRASE	= 0x4502,
diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
index a78e40e6d0e0..a0d93719ab18 100644
--- a/drivers/cxl/pci.c
+++ b/drivers/cxl/pci.c
@@ -115,16 +115,52 @@ static bool cxl_mbox_background_complete(struct cxl_dev_state *cxlds)
 
 static irqreturn_t cxl_pci_mbox_irq(int irq, void *id)
 {
+	u64 reg;
+	u16 opcode;
 	struct cxl_dev_id *dev_id = id;
 	struct cxl_dev_state *cxlds = dev_id->cxlds;
 
-	/* short-circuit the wait in __cxl_pci_mbox_send_cmd() */
-	if (cxl_mbox_background_complete(cxlds))
-		rcuwait_wake_up(&cxlds->mbox_wait);
+	if (!cxl_mbox_background_complete(cxlds))
+		goto done;
 
+	reg = readq(cxlds->regs.mbox + CXLDEV_MBOX_BG_CMD_STATUS_OFFSET);
+	opcode = FIELD_GET(CXLDEV_MBOX_BG_CMD_COMMAND_OPCODE_MASK, reg);
+	if (opcode == CXL_MBOX_OP_SANITIZE) {
+		dev_dbg(cxlds->dev, "Sanitation operation ended\n");
+	} else {
+		/* short-circuit the wait in __cxl_pci_mbox_send_cmd() */
+		rcuwait_wake_up(&cxlds->mbox_wait);
+	}
+done:
 	return IRQ_HANDLED;
 }
 
+/*
+ * Sanitation operation polling mode.
+ */
+static void cxl_mbox_sanitize_work(struct work_struct *work)
+{
+	struct cxl_dev_state *cxlds;
+
+	cxlds = container_of(work,
+			     struct cxl_dev_state, security.poll_dwork.work);
+
+	mutex_lock(&cxlds->mbox_mutex);
+	if (cxl_mbox_background_complete(cxlds)) {
+		cxlds->security.poll_tmo_secs = 0;
+		put_device(cxlds->dev);
+
+		dev_dbg(cxlds->dev, "Sanitation operation ended\n");
+	} else {
+		int timeout = cxlds->security.poll_tmo_secs + 10;
+
+		cxlds->security.poll_tmo_secs = min(15 * 60, timeout);
+		queue_delayed_work(system_wq, &cxlds->security.poll_dwork,
+				   timeout * HZ);
+	}
+	mutex_unlock(&cxlds->mbox_mutex);
+}
+
 /**
  * __cxl_pci_mbox_send_cmd() - Execute a mailbox command
  * @cxlds: The device state to communicate with.
@@ -185,6 +221,16 @@ static int __cxl_pci_mbox_send_cmd(struct cxl_dev_state *cxlds,
 		return -EBUSY;
 	}
 
+	/*
+	 * With sanitize polling, hardware might be done and the poller still
+	 * not be in sync. Ensure no new command comes in until so. Keep the
+	 * hardware semantics and only allow device health status.
+	 */
+	if (unlikely(cxlds->security.poll_tmo_secs > 0)) {
+		if (mbox_cmd->opcode != CXL_MBOX_OP_GET_HEALTH_INFO)
+			return -EBUSY;
+	}
+
 	cmd_reg = FIELD_PREP(CXLDEV_MBOX_CMD_COMMAND_OPCODE_MASK,
 			     mbox_cmd->opcode);
 	if (mbox_cmd->size_in) {
@@ -233,11 +279,34 @@ static int __cxl_pci_mbox_send_cmd(struct cxl_dev_state *cxlds,
 	 */
 	if (mbox_cmd->return_code == CXL_MBOX_CMD_RC_BACKGROUND) {
 		u64 bg_status_reg;
-		int i, timeout = mbox_cmd->poll_interval_ms;
+		int i, timeout;
+
+		/*
+		 * Sanitation is a special case which monopolizes the device
+		 * and cannot be timesliced. Handle asynchronously instead,
+		 * and allow userspace to poll(2) for completion.
+		 */
+		if (mbox_cmd->opcode == CXL_MBOX_OP_SANITIZE) {
+			if (cxlds->security.poll_tmo_secs != -1) {
+				/* hold the device throughout */
+				get_device(cxlds->dev);
+
+				/* give first timeout a second */
+				timeout = 1;
+				cxlds->security.poll_tmo_secs = timeout;
+				queue_delayed_work(system_wq,
+						   &cxlds->security.poll_dwork,
+						   timeout * HZ);
+			}
+
+			dev_dbg(dev, "Sanitation operation started\n");
+			goto success;
+		}
 
 		dev_dbg(dev, "Mailbox background operation (0x%04x) started\n",
 			mbox_cmd->opcode);
 
+		timeout = mbox_cmd->poll_interval_ms;
 		for (i = 0; i < mbox_cmd->poll_count; i++) {
 			if (rcuwait_wait_event_timeout(&cxlds->mbox_wait,
 				       cxl_mbox_background_complete(cxlds),
@@ -268,6 +337,7 @@ static int __cxl_pci_mbox_send_cmd(struct cxl_dev_state *cxlds,
 		return 0; /* completed but caller must check return_code */
 	}
 
+success:
 	/* #7 */
 	cmd_reg = readq(cxlds->regs.mbox + CXLDEV_MBOX_CMD_OFFSET);
 	out_len = FIELD_GET(CXLDEV_MBOX_CMD_PAYLOAD_LENGTH_MASK, cmd_reg);
@@ -376,10 +446,15 @@ static int cxl_pci_setup_mailbox(struct cxl_dev_state *cxlds)
 		ctrl |= CXLDEV_MBOX_CTRL_BG_CMD_IRQ;
 		writel(ctrl, cxlds->regs.mbox + CXLDEV_MBOX_CTRL_OFFSET);
 
+		/* flag that irqs are enabled */
+		cxlds->security.poll_tmo_secs = -1;
 		return 0;
 	}
 
 mbox_poll:
+	cxlds->security.poll_tmo_secs = 0;
+	INIT_DELAYED_WORK(&cxlds->security.poll_dwork,
+			  cxl_mbox_sanitize_work);
 	dev_dbg(cxlds->dev, "Mailbox interrupts are unsupported");
 	return 0;
 }
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 3/6] cxl/mem: Wire up Sanitation support
  2023-05-26  3:33 [PATCH v5 0/6] cxl: Support device sanitation Davidlohr Bueso
  2023-05-26  3:33 ` [PATCH 1/6] cxl/mem: Introduce security state sysfs file Davidlohr Bueso
  2023-05-26  3:33 ` [PATCH 2/6] cxl/mbox: Add sanitation handling machinery Davidlohr Bueso
@ 2023-05-26  3:33 ` Davidlohr Bueso
  2023-05-26  3:41   ` Davidlohr Bueso
  2023-05-26  3:33 ` [PATCH 4/6] cxl/test: Add Sanitize opcode support Davidlohr Bueso
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 19+ messages in thread
From: Davidlohr Bueso @ 2023-05-26  3:33 UTC (permalink / raw)
  To: dan.j.williams
  Cc: dave.jiang, vishal.l.verma, Jonathan.Cameron, fan.ni,
	a.manzanares, dave, linux-cxl

Implement support for CXL 3.0 8.2.9.8.5.1 Sanitize. This is done by
adding a security/sanitize' memdev sysfs file, which is poll(2)-capable
for completion. Unlike all other background commands, this is the
only operation that is special and monopolizes the device for long
periods of time.

In addition to the traditional pmem security requirements, all regions
must also be offline in order to perform the operation. This permits
avoiding explicit global CPU cache management, relying instead on
attach_target() setting CXL_REGION_F_INCOHERENT upon reconnect.

The expectation is that userspace can use it such as:

    cxl disable-memdev memX
    echo 1 > /sys/bus/cxl/devices/memX/security/sanitize
    cxl wait-sanitize memX
    cxl enable-memdev memX

Signed-off-by: Davidlohr Bueso <dave@stgolabs.net>
---
 Documentation/ABI/testing/sysfs-bus-cxl | 21 ++++++++-
 drivers/cxl/core/mbox.c                 | 55 ++++++++++++++++++++++++
 drivers/cxl/core/memdev.c               | 57 ++++++++++++++++++++++++-
 drivers/cxl/cxlmem.h                    |  4 ++
 drivers/cxl/pci.c                       |  5 +++
 5 files changed, 139 insertions(+), 3 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-bus-cxl b/Documentation/ABI/testing/sysfs-bus-cxl
index 721a44d8a482..5753cba98692 100644
--- a/Documentation/ABI/testing/sysfs-bus-cxl
+++ b/Documentation/ABI/testing/sysfs-bus-cxl
@@ -64,8 +64,25 @@ KernelVersion:	v6.5
 Contact:	linux-cxl@vger.kernel.org
 Description:
 		(RO) Reading this file will display the CXL security state for
-		that device. Such states can be: 'disabled', or those available
-		only for persistent memory: 'locked', 'unlocked' or 'frozen'.
+		that device. Such states can be: 'disabled', 'sanitize', when
+		a sanitation is currently underway; or those available only
+		for persistent memory: 'locked', 'unlocked' or 'frozen'. This
+		sysfs entry is select/poll capable from userspace to notify
+		upon completion of a sanitize operation.
+
+
+What:           /sys/bus/cxl/devices/memX/security/sanitize
+Date:           June, 2023
+KernelVersion:  v6.5
+Contact:        linux-cxl@vger.kernel.org
+Description:
+		(WO) Write a boolean 'true' string value to this attribute to
+		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 LSA, is made permanently unavailable by whatever means
+		is appropriate for the media type. This functionality requires
+		the device to be not be actively decoding any HPA ranges.
 
 
 What:		/sys/bus/cxl/devices/*/devtype
diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c
index 5993261e3e08..51c64829f20a 100644
--- a/drivers/cxl/core/mbox.c
+++ b/drivers/cxl/core/mbox.c
@@ -1075,6 +1075,61 @@ int cxl_dev_state_identify(struct cxl_dev_state *cxlds)
 }
 EXPORT_SYMBOL_NS_GPL(cxl_dev_state_identify, CXL);
 
+/**
+ * cxl_mem_sanitize() - Send a sanitation command to the device.
+ * @cxlds: The device data for the operation
+ * @cmd: The specific sanitation command opcode
+ *
+ * Return: 0 if the command was executed successfully, regardless of
+ * whether or not the actual security operation is done in the background,
+ * such as for the Sanitize case.
+ * Error return values can be the result of the mailbox command, -EINVAL
+ * when security requirements are not met or invalid contexts.
+ *
+ * See CXL 3.0 @8.2.9.8.5.1 Sanitize and @8.2.9.8.5.2 Secure Erase.
+ */
+int cxl_mem_sanitize(struct cxl_dev_state *cxlds, u16 cmd)
+{
+	int rc;
+	u32 sec_out = 0;
+	struct cxl_get_security_output {
+		__le32 flags;
+	} out;
+	struct cxl_mbox_cmd sec_cmd = {
+		.opcode = CXL_MBOX_OP_GET_SECURITY_STATE,
+		.payload_out = &out,
+		.size_out = sizeof(out),
+	};
+	struct cxl_mbox_cmd mbox_cmd = { .opcode = cmd };
+
+	if (cmd != CXL_MBOX_OP_SANITIZE)
+		return -EINVAL;
+
+	rc = cxl_internal_send_cmd(cxlds, &sec_cmd);
+	if (rc < 0) {
+		dev_err(cxlds->dev, "Failed to get security state : %d", rc);
+		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).
+	 */
+	sec_out = le32_to_cpu(out.flags);
+	if (sec_out & CXL_PMEM_SEC_STATE_USER_PASS_SET)
+		return -EINVAL;
+
+	rc = cxl_internal_send_cmd(cxlds, &mbox_cmd);
+	if (rc < 0) {
+		dev_err(cxlds->dev, "Failed to sanitize device : %d", rc);
+		return rc;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_NS_GPL(cxl_mem_sanitize, CXL);
+
 static int add_dpa_res(struct device *dev, struct resource *parent,
 		       struct resource *res, resource_size_t start,
 		       resource_size_t size, const char *type)
diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c
index 02763e83545c..90f23e53d483 100644
--- a/drivers/cxl/core/memdev.c
+++ b/drivers/cxl/core/memdev.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /* Copyright(c) 2020 Intel Corporation. */
 
+#include <linux/io-64-nonatomic-lo-hi.h>
 #include <linux/device.h>
 #include <linux/slab.h>
 #include <linux/idr.h>
@@ -114,6 +115,12 @@ static ssize_t security_state_show(struct device *dev,
 	struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
 	struct cxl_dev_state *cxlds = cxlmd->cxlds;
 	unsigned long state = cxlds->security.state;
+	u64 reg = readq(cxlds->regs.mbox + CXLDEV_MBOX_BG_CMD_STATUS_OFFSET);
+	u32 pct = FIELD_GET(CXLDEV_MBOX_BG_CMD_COMMAND_PCT_MASK, reg);
+	u16 cmd = FIELD_GET(CXLDEV_MBOX_BG_CMD_COMMAND_OPCODE_MASK, reg);
+
+	if (cmd == CXL_MBOX_OP_SANITIZE && pct != 100)
+		return sysfs_emit(buf, "sanitize\n");
 
 	if (!(state & CXL_PMEM_SEC_STATE_USER_PASS_SET))
 		return sysfs_emit(buf, "disabled\n");
@@ -129,6 +136,33 @@ static ssize_t security_state_show(struct device *dev,
 static struct device_attribute dev_attr_security_state =
 	__ATTR(state, 0444, security_state_show, NULL);
 
+static ssize_t security_sanitize_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;
+	struct cxl_port *port = dev_get_drvdata(&cxlmd->dev);
+	ssize_t rc;
+	bool sanitize;
+
+	if (kstrtobool(buf, &sanitize) || !sanitize)
+		return -EINVAL;
+
+	if (!port || !is_cxl_endpoint(port))
+		return -EINVAL;
+
+	/* ensure no regions are mapped to this memdev */
+	if (port->commit_end != -1)
+		return -EBUSY;
+
+	rc = cxl_mem_sanitize(cxlds, CXL_MBOX_OP_SANITIZE);
+
+	return rc ? rc : len;
+}
+static struct device_attribute dev_attr_security_sanitize =
+	__ATTR(sanitize, 0200, NULL, security_sanitize_store);
+
 static int cxl_get_poison_by_memdev(struct cxl_memdev *cxlmd)
 {
 	struct cxl_dev_state *cxlds = cxlmd->cxlds;
@@ -376,6 +410,7 @@ static struct attribute *cxl_memdev_ram_attributes[] = {
 
 static struct attribute *cxl_memdev_security_attributes[] = {
 	&dev_attr_security_state.attr,
+	&dev_attr_security_sanitize.attr,
 	NULL,
 };
 
@@ -594,13 +629,33 @@ static const struct file_operations cxl_memdev_fops = {
 	.llseek = noop_llseek,
 };
 
+static void put_sanitize(void *data)
+{
+	struct cxl_dev_state *cxlds = data;
+
+	sysfs_put(cxlds->security.sanitize_node);
+}
+
 static int cxl_memdev_security_init(struct cxl_memdev *cxlmd)
 {
 	struct cxl_dev_state *cxlds = cxlmd->cxlds;
+	struct device *dev = &cxlmd->dev;
+	struct kernfs_node *sec;
 
 	cxlds->security.state = 0;
+	sec = sysfs_get_dirent(dev->kobj.sd, "security");
+	if (!sec) {
+		dev_err(dev, "sysfs_get_dirent 'security' failed\n");
+		return -ENODEV;
+	}
+	cxlds->security.sanitize_node = sysfs_get_dirent(sec, "state");
+	sysfs_put(sec);
+	if (!cxlds->security.sanitize_node) {
+		dev_err(dev, "sysfs_get_dirent 'state' failed\n");
+		return -ENODEV;
+	}
 
-	return 0;
+	return devm_add_action_or_reset(cxlds->dev, put_sanitize, cxlds);
 }
 
 struct cxl_memdev *devm_cxl_add_memdev(struct cxl_dev_state *cxlds)
diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h
index 02ec68f97de2..408ec33c8480 100644
--- a/drivers/cxl/cxlmem.h
+++ b/drivers/cxl/cxlmem.h
@@ -266,6 +266,7 @@ struct cxl_poison_state {
  * @state: state of last security operation
  * @poll_tmo_secs: polling timeout
  * @poll_dwork: polling work item
+ * @sanitize_node: sanitation sysfs file to notify
  *
  * Polling (sanitation) is only used when device mbox irqs are not
  * supported. As such, @poll_tmo_secs == -1 indicates that polling
@@ -276,6 +277,7 @@ struct cxl_security_state {
 	unsigned long state;
 	int poll_tmo_secs;
 	struct delayed_work poll_dwork;
+	struct kernfs_node *sanitize_node;
 };
 
 /**
@@ -750,6 +752,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/drivers/cxl/pci.c b/drivers/cxl/pci.c
index a0d93719ab18..195c4267d3db 100644
--- a/drivers/cxl/pci.c
+++ b/drivers/cxl/pci.c
@@ -126,6 +126,9 @@ static irqreturn_t cxl_pci_mbox_irq(int irq, void *id)
 	reg = readq(cxlds->regs.mbox + CXLDEV_MBOX_BG_CMD_STATUS_OFFSET);
 	opcode = FIELD_GET(CXLDEV_MBOX_BG_CMD_COMMAND_OPCODE_MASK, reg);
 	if (opcode == CXL_MBOX_OP_SANITIZE) {
+		if (cxlds->security.sanitize_node)
+			sysfs_notify_dirent(cxlds->security.sanitize_node);
+
 		dev_dbg(cxlds->dev, "Sanitation operation ended\n");
 	} else {
 		/* short-circuit the wait in __cxl_pci_mbox_send_cmd() */
@@ -149,6 +152,8 @@ static void cxl_mbox_sanitize_work(struct work_struct *work)
 	if (cxl_mbox_background_complete(cxlds)) {
 		cxlds->security.poll_tmo_secs = 0;
 		put_device(cxlds->dev);
+		if (cxlds->security.sanitize_node)
+			sysfs_notify_dirent(cxlds->security.sanitize_node);
 
 		dev_dbg(cxlds->dev, "Sanitation operation ended\n");
 	} else {
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 4/6] cxl/test: Add Sanitize opcode support
  2023-05-26  3:33 [PATCH v5 0/6] cxl: Support device sanitation Davidlohr Bueso
                   ` (2 preceding siblings ...)
  2023-05-26  3:33 ` [PATCH 3/6] cxl/mem: Wire up Sanitation support Davidlohr Bueso
@ 2023-05-26  3:33 ` Davidlohr Bueso
  2023-05-26  3:33 ` [PATCH 5/6] cxl/mem: Support Secure Erase Davidlohr Bueso
  2023-05-26  3:33 ` [PATCH 6/6] cxl/test: Add Secure Erase opcode support Davidlohr Bueso
  5 siblings, 0 replies; 19+ messages in thread
From: Davidlohr Bueso @ 2023-05-26  3:33 UTC (permalink / raw)
  To: dan.j.williams
  Cc: dave.jiang, vishal.l.verma, Jonathan.Cameron, fan.ni,
	a.manzanares, dave, linux-cxl

Add support to emulate the "Sanitize" operation, without
incurring in the background.

Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Signed-off-by: Davidlohr Bueso <dave@stgolabs.net>
---
 tools/testing/cxl/test/mem.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/tools/testing/cxl/test/mem.c b/tools/testing/cxl/test/mem.c
index 34b48027b3de..faa484ea5b0b 100644
--- a/tools/testing/cxl/test/mem.c
+++ b/tools/testing/cxl/test/mem.c
@@ -535,6 +535,28 @@ static int mock_partition_info(struct cxl_dev_state *cxlds,
 	return 0;
 }
 
+static int mock_sanitize(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
+{
+	struct cxl_mockmem_data *mdata = dev_get_drvdata(cxlds->dev);
+
+	if (cmd->size_in != 0)
+		return -EINVAL;
+
+	if (cmd->size_out != 0)
+		return -EINVAL;
+
+	if (mdata->security_state & CXL_PMEM_SEC_STATE_USER_PASS_SET) {
+		cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
+		return -ENXIO;
+	}
+	if (mdata->security_state & CXL_PMEM_SEC_STATE_LOCKED) {
+		cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
+		return -ENXIO;
+	}
+
+	return 0; /* assume less than 2 secs, no bg */
+}
+
 static int mock_get_security_state(struct cxl_dev_state *cxlds,
 				   struct cxl_mbox_cmd *cmd)
 {
@@ -1153,6 +1175,9 @@ static int cxl_mock_mbox_send(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *
 	case CXL_MBOX_OP_GET_HEALTH_INFO:
 		rc = mock_health_info(cxlds, cmd);
 		break;
+	case CXL_MBOX_OP_SANITIZE:
+		rc = mock_sanitize(cxlds, cmd);
+		break;
 	case CXL_MBOX_OP_GET_SECURITY_STATE:
 		rc = mock_get_security_state(cxlds, cmd);
 		break;
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 5/6] cxl/mem: Support Secure Erase
  2023-05-26  3:33 [PATCH v5 0/6] cxl: Support device sanitation Davidlohr Bueso
                   ` (3 preceding siblings ...)
  2023-05-26  3:33 ` [PATCH 4/6] cxl/test: Add Sanitize opcode support Davidlohr Bueso
@ 2023-05-26  3:33 ` Davidlohr Bueso
  2023-05-30 23:54   ` Dave Jiang
                     ` (2 more replies)
  2023-05-26  3:33 ` [PATCH 6/6] cxl/test: Add Secure Erase opcode support Davidlohr Bueso
  5 siblings, 3 replies; 19+ messages in thread
From: Davidlohr Bueso @ 2023-05-26  3:33 UTC (permalink / raw)
  To: dan.j.williams
  Cc: dave.jiang, vishal.l.verma, Jonathan.Cameron, fan.ni,
	a.manzanares, dave, linux-cxl

Implement support for the non-pmem exclusive secure erase, per
CXL specs. Create a write-only 'security/erase' sysfs file to
perform the requested operation.

As with the sanitation this requires the device being offline
and thus no active HPA-DPA decoding.

The expectation is that userspace can use it such as:

	cxl disable-memdev memX
	echo 1 > /sys/bus/cxl/devices/memX/security/erase
	cxl enable-memdev memX

Signed-off-by: Davidlohr Bueso <dave@stgolabs.net>
---
 Documentation/ABI/testing/sysfs-bus-cxl | 10 +++++++++
 drivers/cxl/core/mbox.c                 |  6 +++++-
 drivers/cxl/core/memdev.c               | 28 +++++++++++++++++++++++++
 drivers/cxl/cxlmem.h                    |  1 +
 4 files changed, 44 insertions(+), 1 deletion(-)

diff --git a/Documentation/ABI/testing/sysfs-bus-cxl b/Documentation/ABI/testing/sysfs-bus-cxl
index 5753cba98692..f224c1215f22 100644
--- a/Documentation/ABI/testing/sysfs-bus-cxl
+++ b/Documentation/ABI/testing/sysfs-bus-cxl
@@ -85,6 +85,16 @@ Description:
 		the device to be not be actively decoding any HPA ranges.
 
 
+What            /sys/bus/cxl/devices/memX/security/erase
+Date:           June, 2023
+KernelVersion:  v6.5
+Contact:        linux-cxl@vger.kernel.org
+Description:
+		(WO) Write a boolean 'true' string value to this attribute to
+		secure erase user data by changing the media encryption keys for
+		all user data areas of the device.
+
+
 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 51c64829f20a..6622eac66bf1 100644
--- a/drivers/cxl/core/mbox.c
+++ b/drivers/cxl/core/mbox.c
@@ -1102,7 +1102,7 @@ int cxl_mem_sanitize(struct cxl_dev_state *cxlds, u16 cmd)
 	};
 	struct cxl_mbox_cmd mbox_cmd = { .opcode = cmd };
 
-	if (cmd != CXL_MBOX_OP_SANITIZE)
+	if (cmd != CXL_MBOX_OP_SANITIZE && cmd != CXL_MBOX_OP_SECURE_ERASE)
 		return -EINVAL;
 
 	rc = cxl_internal_send_cmd(cxlds, &sec_cmd);
@@ -1120,6 +1120,10 @@ int cxl_mem_sanitize(struct cxl_dev_state *cxlds, u16 cmd)
 	if (sec_out & CXL_PMEM_SEC_STATE_USER_PASS_SET)
 		return -EINVAL;
 
+	if (cmd == CXL_MBOX_OP_SECURE_ERASE &&
+	    sec_out & CXL_PMEM_SEC_STATE_LOCKED)
+		return -EINVAL;
+
 	rc = cxl_internal_send_cmd(cxlds, &mbox_cmd);
 	if (rc < 0) {
 		dev_err(cxlds->dev, "Failed to sanitize device : %d", rc);
diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c
index 90f23e53d483..d06c8539e82c 100644
--- a/drivers/cxl/core/memdev.c
+++ b/drivers/cxl/core/memdev.c
@@ -163,6 +163,33 @@ static ssize_t security_sanitize_store(struct device *dev,
 static struct device_attribute dev_attr_security_sanitize =
 	__ATTR(sanitize, 0200, NULL, security_sanitize_store);
 
+static ssize_t security_erase_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;
+	struct cxl_port *port = dev_get_drvdata(&cxlmd->dev);
+	ssize_t rc;
+	bool erase;
+
+	if (kstrtobool(buf, &erase) || !erase)
+		return -EINVAL;
+
+	if (!port || !is_cxl_endpoint(port))
+		return -EINVAL;
+
+	/* ensure no regions are mapped to this memdev */
+	if (port->commit_end != -1)
+		return -EBUSY;
+
+	rc = cxl_mem_sanitize(cxlds, CXL_MBOX_OP_SECURE_ERASE);
+
+	return rc ? rc : len;
+}
+static struct device_attribute dev_attr_security_erase =
+	__ATTR(erase, 0200, NULL, security_erase_store);
+
 static int cxl_get_poison_by_memdev(struct cxl_memdev *cxlmd)
 {
 	struct cxl_dev_state *cxlds = cxlmd->cxlds;
@@ -411,6 +438,7 @@ static struct attribute *cxl_memdev_ram_attributes[] = {
 static struct attribute *cxl_memdev_security_attributes[] = {
 	&dev_attr_security_state.attr,
 	&dev_attr_security_sanitize.attr,
+	&dev_attr_security_erase.attr,
 	NULL,
 };
 
diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h
index 408ec33c8480..758fea7b9dbf 100644
--- a/drivers/cxl/cxlmem.h
+++ b/drivers/cxl/cxlmem.h
@@ -392,6 +392,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,
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 6/6] cxl/test: Add Secure Erase opcode support
  2023-05-26  3:33 [PATCH v5 0/6] cxl: Support device sanitation Davidlohr Bueso
                   ` (4 preceding siblings ...)
  2023-05-26  3:33 ` [PATCH 5/6] cxl/mem: Support Secure Erase Davidlohr Bueso
@ 2023-05-26  3:33 ` Davidlohr Bueso
  5 siblings, 0 replies; 19+ messages in thread
From: Davidlohr Bueso @ 2023-05-26  3:33 UTC (permalink / raw)
  To: dan.j.williams
  Cc: dave.jiang, vishal.l.verma, Jonathan.Cameron, fan.ni,
	a.manzanares, dave, linux-cxl

Add support to emulate the CXL the "Secure Erase" operation.

Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Signed-off-by: Davidlohr Bueso <dave@stgolabs.net>
---
 tools/testing/cxl/test/mem.c | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/tools/testing/cxl/test/mem.c b/tools/testing/cxl/test/mem.c
index faa484ea5b0b..97de0d3b2fd0 100644
--- a/tools/testing/cxl/test/mem.c
+++ b/tools/testing/cxl/test/mem.c
@@ -557,6 +557,30 @@ static int mock_sanitize(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
 	return 0; /* assume less than 2 secs, no bg */
 }
 
+static int mock_secure_erase(struct cxl_dev_state *cxlds,
+			     struct cxl_mbox_cmd *cmd)
+{
+	struct cxl_mockmem_data *mdata = dev_get_drvdata(cxlds->dev);
+
+	if (cmd->size_in != 0)
+		return -EINVAL;
+
+	if (cmd->size_out != 0)
+		return -EINVAL;
+
+	if (mdata->security_state & CXL_PMEM_SEC_STATE_USER_PASS_SET) {
+		cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
+		return -ENXIO;
+	}
+
+	if (mdata->security_state & CXL_PMEM_SEC_STATE_LOCKED) {
+		cmd->return_code = CXL_MBOX_CMD_RC_SECURITY;
+		return -ENXIO;
+	}
+
+	return 0;
+}
+
 static int mock_get_security_state(struct cxl_dev_state *cxlds,
 				   struct cxl_mbox_cmd *cmd)
 {
@@ -1178,6 +1202,9 @@ static int cxl_mock_mbox_send(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *
 	case CXL_MBOX_OP_SANITIZE:
 		rc = mock_sanitize(cxlds, cmd);
 		break;
+	case CXL_MBOX_OP_SECURE_ERASE:
+		rc = mock_secure_erase(cxlds, cmd);
+		break;
 	case CXL_MBOX_OP_GET_SECURITY_STATE:
 		rc = mock_get_security_state(cxlds, cmd);
 		break;
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Re: [PATCH 3/6] cxl/mem: Wire up Sanitation support
  2023-05-26  3:33 ` [PATCH 3/6] cxl/mem: Wire up Sanitation support Davidlohr Bueso
@ 2023-05-26  3:41   ` Davidlohr Bueso
  2023-05-30 23:53     ` Dave Jiang
  0 siblings, 1 reply; 19+ messages in thread
From: Davidlohr Bueso @ 2023-05-26  3:41 UTC (permalink / raw)
  To: dan.j.williams
  Cc: dave.jiang, vishal.l.verma, Jonathan.Cameron, fan.ni,
	a.manzanares, linux-cxl

On Thu, 25 May 2023, Davidlohr Bueso wrote:

>Implement support for CXL 3.0 8.2.9.8.5.1 Sanitize. This is done by
>adding a security/sanitize' memdev sysfs file, which is poll(2)-capable
>for completion. Unlike all other background commands, this is the
>only operation that is special and monopolizes the device for long
>periods of time.

As becomes obvious in the code, this paragraph actually should have
been updated: the pollable/read file for the status of sanitation
is the security/state.

Thanks,
Davidlohr

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 1/6] cxl/mem: Introduce security state sysfs file
  2023-05-26  3:33 ` [PATCH 1/6] cxl/mem: Introduce security state sysfs file Davidlohr Bueso
@ 2023-05-30 23:30   ` Dave Jiang
  2023-05-31 16:10   ` Jonathan Cameron
       [not found]   ` <CGME20230531174804uscas1p2c18bceeaf3415c86d778bb42709b75bc@uscas1p2.samsung.com>
  2 siblings, 0 replies; 19+ messages in thread
From: Dave Jiang @ 2023-05-30 23:30 UTC (permalink / raw)
  To: Davidlohr Bueso, dan.j.williams
  Cc: vishal.l.verma, Jonathan.Cameron, fan.ni, a.manzanares, linux-cxl


On 5/25/23 20:33, Davidlohr Bueso wrote:
> Add a read-only sysfs file to display the security state
> of a device (currently only pmem):
>
>      /sys/bus/cxl/devices/memX/security/state
>
> This introduces a cxl_security_state structure that is
> to be the placeholder for common CXL security features.
>
> Signed-off-by: Davidlohr Bueso <dave@stgolabs.net>
> ---
>   Documentation/ABI/testing/sysfs-bus-cxl | 10 ++++++
>   drivers/cxl/core/memdev.c               | 46 +++++++++++++++++++++++++
>   drivers/cxl/cxlmem.h                    | 11 ++++++
>   drivers/cxl/security.c                  |  3 ++
>   4 files changed, 70 insertions(+)
>
> diff --git a/Documentation/ABI/testing/sysfs-bus-cxl b/Documentation/ABI/testing/sysfs-bus-cxl
> index 48ac0d911801..721a44d8a482 100644
> --- a/Documentation/ABI/testing/sysfs-bus-cxl
> +++ b/Documentation/ABI/testing/sysfs-bus-cxl
> @@ -58,6 +58,16 @@ Description:
>   		affinity for this device.
>   
>   
> +What:		/sys/bus/cxl/devices/memX/security/state
> +Date:		June, 2023
> +KernelVersion:	v6.5
> +Contact:	linux-cxl@vger.kernel.org
> +Description:
> +		(RO) Reading this file will display the CXL security state for
> +		that device. Such states can be: 'disabled', or those available
> +		only for persistent memory: 'locked', 'unlocked' or 'frozen'.
> +
> +
>   What:		/sys/bus/cxl/devices/*/devtype
>   Date:		June, 2021
>   KernelVersion:	v5.14
> diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c
> index 057a43267290..6e1d7d3610a2 100644
> --- a/drivers/cxl/core/memdev.c
> +++ b/drivers/cxl/core/memdev.c
> @@ -107,6 +107,28 @@ static ssize_t numa_node_show(struct device *dev, struct device_attribute *attr,
>   }
>   static DEVICE_ATTR_RO(numa_node);
>   
> +static ssize_t security_state_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;
> +	unsigned long state = cxlds->security.state;
> +
> +	if (!(state & CXL_PMEM_SEC_STATE_USER_PASS_SET))
> +		return sysfs_emit(buf, "disabled\n");
> +	if (state & CXL_PMEM_SEC_STATE_FROZEN ||
> +	    state & CXL_PMEM_SEC_STATE_MASTER_PLIMIT ||
> +	    state & CXL_PMEM_SEC_STATE_USER_PLIMIT)
> +		return sysfs_emit(buf, "frozen\n");
> +	if (state & CXL_PMEM_SEC_STATE_LOCKED)
> +		return sysfs_emit(buf, "locked\n");
> +	else
> +		return sysfs_emit(buf, "unlocked\n");
> +}
> +static struct device_attribute dev_attr_security_state =
> +	__ATTR(state, 0444, security_state_show, NULL);
> +
>   static int cxl_get_poison_by_memdev(struct cxl_memdev *cxlmd)
>   {
>   	struct cxl_dev_state *cxlds = cxlmd->cxlds;
> @@ -352,6 +374,11 @@ static struct attribute *cxl_memdev_ram_attributes[] = {
>   	NULL,
>   };
>   
> +static struct attribute *cxl_memdev_security_attributes[] = {
> +	&dev_attr_security_state.attr,
> +	NULL,
> +};
> +
>   static umode_t cxl_memdev_visible(struct kobject *kobj, struct attribute *a,
>   				  int n)
>   {
> @@ -375,10 +402,16 @@ static struct attribute_group cxl_memdev_pmem_attribute_group = {
>   	.attrs = cxl_memdev_pmem_attributes,
>   };
>   
> +static struct attribute_group cxl_memdev_security_attribute_group = {
> +	.name = "security",
> +	.attrs = cxl_memdev_security_attributes,
> +};
> +
>   static const struct attribute_group *cxl_memdev_attribute_groups[] = {
>   	&cxl_memdev_attribute_group,
>   	&cxl_memdev_ram_attribute_group,
>   	&cxl_memdev_pmem_attribute_group,
> +	&cxl_memdev_security_attribute_group,
>   	NULL,
>   };
>   
> @@ -551,6 +584,15 @@ static const struct file_operations cxl_memdev_fops = {
>   	.llseek = noop_llseek,
>   };
>   
> +static int cxl_memdev_security_init(struct cxl_memdev *cxlmd)
> +{
> +	struct cxl_dev_state *cxlds = cxlmd->cxlds;
> +
> +	cxlds->security.state = 0;

This is not necessary with cxlds allocated with devm_kzalloc()?


> +
> +	return 0;
> +}
> +
>   struct cxl_memdev *devm_cxl_add_memdev(struct cxl_dev_state *cxlds)
>   {
>   	struct cxl_memdev *cxlmd;
> @@ -579,6 +621,10 @@ struct cxl_memdev *devm_cxl_add_memdev(struct cxl_dev_state *cxlds)
>   	if (rc)
>   		goto err;
>   
> +	rc = cxl_memdev_security_init(cxlmd);
> +	if (rc)
> +		goto err;
> +
>   	rc = devm_add_action_or_reset(cxlds->dev, cxl_memdev_unregister, cxlmd);
>   	if (rc)
>   		return ERR_PTR(rc);
> diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h
> index 1d8e81c87c6a..5329274b0076 100644
> --- a/drivers/cxl/cxlmem.h
> +++ b/drivers/cxl/cxlmem.h
> @@ -260,6 +260,15 @@ struct cxl_poison_state {
>   	struct mutex lock;  /* Protect reads of poison list */
>   };
>   
> +/**
> + * struct cxl_security_state - Device security state
> + *
> + * @state: state of last security operation
> + */
> +struct cxl_security_state {
> +	unsigned long state;
> +};
> +
>   /**
>    * struct cxl_dev_state - The driver device state
>    *
> @@ -297,6 +306,7 @@ struct cxl_poison_state {
>    * @serial: PCIe Device Serial Number
>    * @event: event log driver state
>    * @poison: poison driver state info
> + * @security: device security state
>    * @mbox_send: @dev specific transport for transmitting mailbox commands
>    *
>    * See section 8.2.9.5.2 Capacity Configuration and Label Storage for
> @@ -336,6 +346,7 @@ struct cxl_dev_state {
>   
>   	struct cxl_event_state event;
>   	struct cxl_poison_state poison;
> +	struct cxl_security_state security;
>   
>   	struct rcuwait mbox_wait;
>   	int (*mbox_send)(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd);
> diff --git a/drivers/cxl/security.c b/drivers/cxl/security.c
> index 4ad4bda2d18e..9da6785dfd31 100644
> --- a/drivers/cxl/security.c
> +++ b/drivers/cxl/security.c
> @@ -34,6 +34,9 @@ static unsigned long cxl_pmem_get_security_flags(struct nvdimm *nvdimm,
>   		return 0;
>   
>   	sec_out = le32_to_cpu(out.flags);
> +	/* cache security state */
> +	cxlds->security.state = sec_out;
> +
>   	if (ptype == NVDIMM_MASTER) {
>   		if (sec_out & CXL_PMEM_SEC_STATE_MASTER_PASS_SET)
>   			set_bit(NVDIMM_SECURITY_UNLOCKED, &security_flags);

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 2/6] cxl/mbox: Add sanitation handling machinery
  2023-05-26  3:33 ` [PATCH 2/6] cxl/mbox: Add sanitation handling machinery Davidlohr Bueso
@ 2023-05-30 23:36   ` Dave Jiang
  2023-05-31 16:29     ` Jonathan Cameron
  2023-05-31 16:36   ` Jonathan Cameron
  1 sibling, 1 reply; 19+ messages in thread
From: Dave Jiang @ 2023-05-30 23:36 UTC (permalink / raw)
  To: Davidlohr Bueso, dan.j.williams
  Cc: vishal.l.verma, Jonathan.Cameron, fan.ni, a.manzanares, linux-cxl


On 5/25/23 20:33, Davidlohr Bueso wrote:
> Sanitation is by definition a device-monopolizing operation, and thus
> the timeslicing rules for other background commands do not apply.
> As such handle this special case asynchronously and return immediately.
> Subsequent changes will allow completion to be pollable from userspace
> via a sysfs file interface.
>
> For devices that don't support interrupts for notifying background
> command completion, self-poll with the caveat that the poller can
> be out of sync with the ready hardware, and therefore care must be
> taken to not allow any new commands to go through until the poller
> sees the hw completion. The poller takes the mbox_mutex to stabilize
> the flagging, minimizing any runtime overhead in the send path to
> check for 'sanitize_tmo' for uncommon poll scenarios. This flag
> also serves for sanitation (the only user of async polling) to know
> when to queue work or simply rely on irqs.
>
> The irq case is much simpler as hardware will serialize/error
> appropriately.
>
> Signed-off-by: Davidlohr Bueso <dave@stgolabs.net>

Just a minor nit below, otherwise

Reviewed-by: Dave Jiang <dave.jiang@intel.com>


> ---
>   drivers/cxl/core/memdev.c | 10 +++++
>   drivers/cxl/cxlmem.h      | 10 +++++
>   drivers/cxl/pci.c         | 83 +++++++++++++++++++++++++++++++++++++--
>   3 files changed, 99 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c
> index 6e1d7d3610a2..02763e83545c 100644
> --- a/drivers/cxl/core/memdev.c
> +++ b/drivers/cxl/core/memdev.c
> @@ -460,11 +460,21 @@ void clear_exclusive_cxl_commands(struct cxl_dev_state *cxlds, unsigned long *cm
>   }
>   EXPORT_SYMBOL_NS_GPL(clear_exclusive_cxl_commands, CXL);
>   
> +static void cxl_memdev_security_shutdown(struct device *dev)
> +{
> +	struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
> +	struct cxl_dev_state *cxlds = cxlmd->cxlds;
> +
> +	if (cxlds->security.poll_tmo_secs != -1)
> +		cancel_delayed_work_sync(&cxlds->security.poll_dwork);
> +}
> +
>   static void cxl_memdev_shutdown(struct device *dev)
>   {
>   	struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
>   
>   	down_write(&cxl_memdev_rwsem);
> +	cxl_memdev_security_shutdown(dev);
>   	cxlmd->cxlds = NULL;
>   	up_write(&cxl_memdev_rwsem);
>   }
> diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h
> index 5329274b0076..02ec68f97de2 100644
> --- a/drivers/cxl/cxlmem.h
> +++ b/drivers/cxl/cxlmem.h
> @@ -264,9 +264,18 @@ struct cxl_poison_state {
>    * struct cxl_security_state - Device security state
>    *
>    * @state: state of last security operation
> + * @poll_tmo_secs: polling timeout
> + * @poll_dwork: polling work item
> + *
> + * Polling (sanitation) is only used when device mbox irqs are not
> + * supported. As such, @poll_tmo_secs == -1 indicates that polling
> + * is disabled. Otherwise, when enabled, @poll_tmo_secs is maxed
> + * at 15 minutes and serialized by the mbox_mutex.
>    */
>   struct cxl_security_state {
>   	unsigned long state;
> +	int poll_tmo_secs;
> +	struct delayed_work poll_dwork;
>   };
>   
>   /**
> @@ -380,6 +389,7 @@ enum cxl_opcode {
>   	CXL_MBOX_OP_GET_SCAN_MEDIA_CAPS	= 0x4303,
>   	CXL_MBOX_OP_SCAN_MEDIA		= 0x4304,
>   	CXL_MBOX_OP_GET_SCAN_MEDIA	= 0x4305,
> +	CXL_MBOX_OP_SANITIZE		= 0x4400,
>   	CXL_MBOX_OP_GET_SECURITY_STATE	= 0x4500,
>   	CXL_MBOX_OP_SET_PASSPHRASE	= 0x4501,
>   	CXL_MBOX_OP_DISABLE_PASSPHRASE	= 0x4502,
> diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
> index a78e40e6d0e0..a0d93719ab18 100644
> --- a/drivers/cxl/pci.c
> +++ b/drivers/cxl/pci.c
> @@ -115,16 +115,52 @@ static bool cxl_mbox_background_complete(struct cxl_dev_state *cxlds)
>   
>   static irqreturn_t cxl_pci_mbox_irq(int irq, void *id)
>   {
> +	u64 reg;
> +	u16 opcode;
>   	struct cxl_dev_id *dev_id = id;
>   	struct cxl_dev_state *cxlds = dev_id->cxlds;
>   
> -	/* short-circuit the wait in __cxl_pci_mbox_send_cmd() */
> -	if (cxl_mbox_background_complete(cxlds))
> -		rcuwait_wake_up(&cxlds->mbox_wait);
> +	if (!cxl_mbox_background_complete(cxlds))
> +		goto done;
>   
> +	reg = readq(cxlds->regs.mbox + CXLDEV_MBOX_BG_CMD_STATUS_OFFSET);
> +	opcode = FIELD_GET(CXLDEV_MBOX_BG_CMD_COMMAND_OPCODE_MASK, reg);
> +	if (opcode == CXL_MBOX_OP_SANITIZE) {
> +		dev_dbg(cxlds->dev, "Sanitation operation ended\n");
> +	} else {
> +		/* short-circuit the wait in __cxl_pci_mbox_send_cmd() */
> +		rcuwait_wake_up(&cxlds->mbox_wait);
> +	}
> +done:
>   	return IRQ_HANDLED;
>   }
>   
> +/*
> + * Sanitation operation polling mode.
> + */
> +static void cxl_mbox_sanitize_work(struct work_struct *work)
> +{
> +	struct cxl_dev_state *cxlds;
> +
> +	cxlds = container_of(work,
> +			     struct cxl_dev_state, security.poll_dwork.work);
> +
> +	mutex_lock(&cxlds->mbox_mutex);
> +	if (cxl_mbox_background_complete(cxlds)) {
> +		cxlds->security.poll_tmo_secs = 0;
> +		put_device(cxlds->dev);
> +
> +		dev_dbg(cxlds->dev, "Sanitation operation ended\n");
> +	} else {
> +		int timeout = cxlds->security.poll_tmo_secs + 10;
> +
> +		cxlds->security.poll_tmo_secs = min(15 * 60, timeout);
> +		queue_delayed_work(system_wq, &cxlds->security.poll_dwork,
> +				   timeout * HZ);
> +	}
> +	mutex_unlock(&cxlds->mbox_mutex);
> +}
> +
>   /**
>    * __cxl_pci_mbox_send_cmd() - Execute a mailbox command
>    * @cxlds: The device state to communicate with.
> @@ -185,6 +221,16 @@ static int __cxl_pci_mbox_send_cmd(struct cxl_dev_state *cxlds,
>   		return -EBUSY;
>   	}
>   
> +	/*
> +	 * With sanitize polling, hardware might be done and the poller still
> +	 * not be in sync. Ensure no new command comes in until so. Keep the
> +	 * hardware semantics and only allow device health status.
> +	 */
> +	if (unlikely(cxlds->security.poll_tmo_secs > 0)) {
> +		if (mbox_cmd->opcode != CXL_MBOX_OP_GET_HEALTH_INFO)
> +			return -EBUSY;
> +	}
> +
>   	cmd_reg = FIELD_PREP(CXLDEV_MBOX_CMD_COMMAND_OPCODE_MASK,
>   			     mbox_cmd->opcode);
>   	if (mbox_cmd->size_in) {
> @@ -233,11 +279,34 @@ static int __cxl_pci_mbox_send_cmd(struct cxl_dev_state *cxlds,
>   	 */
>   	if (mbox_cmd->return_code == CXL_MBOX_CMD_RC_BACKGROUND) {
>   		u64 bg_status_reg;
> -		int i, timeout = mbox_cmd->poll_interval_ms;
> +		int i, timeout;
> +
> +		/*
> +		 * Sanitation is a special case which monopolizes the device
> +		 * and cannot be timesliced. Handle asynchronously instead,
> +		 * and allow userspace to poll(2) for completion.
> +		 */
> +		if (mbox_cmd->opcode == CXL_MBOX_OP_SANITIZE) {
> +			if (cxlds->security.poll_tmo_secs != -1) {
> +				/* hold the device throughout */
> +				get_device(cxlds->dev);
> +
> +				/* give first timeout a second */
> +				timeout = 1;
> +				cxlds->security.poll_tmo_secs = timeout;
> +				queue_delayed_work(system_wq,
> +						   &cxlds->security.poll_dwork,
> +						   timeout * HZ);
> +			}
> +
> +			dev_dbg(dev, "Sanitation operation started\n");
> +			goto success;
> +		}
>   
>   		dev_dbg(dev, "Mailbox background operation (0x%04x) started\n",
>   			mbox_cmd->opcode);
>   
> +		timeout = mbox_cmd->poll_interval_ms;
>   		for (i = 0; i < mbox_cmd->poll_count; i++) {
>   			if (rcuwait_wait_event_timeout(&cxlds->mbox_wait,
>   				       cxl_mbox_background_complete(cxlds),
> @@ -268,6 +337,7 @@ static int __cxl_pci_mbox_send_cmd(struct cxl_dev_state *cxlds,
>   		return 0; /* completed but caller must check return_code */
>   	}
>   
> +success:
>   	/* #7 */
>   	cmd_reg = readq(cxlds->regs.mbox + CXLDEV_MBOX_CMD_OFFSET);
>   	out_len = FIELD_GET(CXLDEV_MBOX_CMD_PAYLOAD_LENGTH_MASK, cmd_reg);
> @@ -376,10 +446,15 @@ static int cxl_pci_setup_mailbox(struct cxl_dev_state *cxlds)
>   		ctrl |= CXLDEV_MBOX_CTRL_BG_CMD_IRQ;
>   		writel(ctrl, cxlds->regs.mbox + CXLDEV_MBOX_CTRL_OFFSET);
>   
> +		/* flag that irqs are enabled */
> +		cxlds->security.poll_tmo_secs = -1;

Use a #define instead of -1 magic number? CXL_CMD_TIMEOUT_INVALID 
perhaps? Would also apply to all the checking of poll_tmo_secs in this 
patch.


>   		return 0;
>   	}
>   
>   mbox_poll:
> +	cxlds->security.poll_tmo_secs = 0;
> +	INIT_DELAYED_WORK(&cxlds->security.poll_dwork,
> +			  cxl_mbox_sanitize_work);
>   	dev_dbg(cxlds->dev, "Mailbox interrupts are unsupported");
>   	return 0;
>   }

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 3/6] cxl/mem: Wire up Sanitation support
  2023-05-26  3:41   ` Davidlohr Bueso
@ 2023-05-30 23:53     ` Dave Jiang
  2023-05-31 16:39       ` Jonathan Cameron
  0 siblings, 1 reply; 19+ messages in thread
From: Dave Jiang @ 2023-05-30 23:53 UTC (permalink / raw)
  To: Davidlohr Bueso, dan.j.williams
  Cc: vishal.l.verma, Jonathan.Cameron, fan.ni, a.manzanares, linux-cxl


On 5/25/23 20:41, Davidlohr Bueso wrote:
> On Thu, 25 May 2023, Davidlohr Bueso wrote:
>
>> Implement support for CXL 3.0 8.2.9.8.5.1 Sanitize. This is done by
>> adding a security/sanitize' memdev sysfs file, which is poll(2)-capable
>> for completion. Unlike all other background commands, this is the
>> only operation that is special and monopolizes the device for long
>> periods of time.
>
> As becomes obvious in the code, this paragraph actually should have
> been updated: the pollable/read file for the status of sanitation
> is the security/state.


Reviewed-by: Dave Jiang <dave.jiang@intel.com> with above update.




>
> Thanks,
> Davidlohr

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 5/6] cxl/mem: Support Secure Erase
  2023-05-26  3:33 ` [PATCH 5/6] cxl/mem: Support Secure Erase Davidlohr Bueso
@ 2023-05-30 23:54   ` Dave Jiang
  2023-05-31 16:41   ` Jonathan Cameron
  2023-06-01 17:24   ` Fan Ni
  2 siblings, 0 replies; 19+ messages in thread
From: Dave Jiang @ 2023-05-30 23:54 UTC (permalink / raw)
  To: Davidlohr Bueso, dan.j.williams
  Cc: vishal.l.verma, Jonathan.Cameron, fan.ni, a.manzanares, linux-cxl


On 5/25/23 20:33, Davidlohr Bueso wrote:
> Implement support for the non-pmem exclusive secure erase, per
> CXL specs. Create a write-only 'security/erase' sysfs file to
> perform the requested operation.
>
> As with the sanitation this requires the device being offline
> and thus no active HPA-DPA decoding.
>
> The expectation is that userspace can use it such as:
>
> 	cxl disable-memdev memX
> 	echo 1 > /sys/bus/cxl/devices/memX/security/erase
> 	cxl enable-memdev memX
>
> Signed-off-by: Davidlohr Bueso <dave@stgolabs.net>

Reviewed-by: Dave Jiang <dave.jiang@intel.com>


> ---
>   Documentation/ABI/testing/sysfs-bus-cxl | 10 +++++++++
>   drivers/cxl/core/mbox.c                 |  6 +++++-
>   drivers/cxl/core/memdev.c               | 28 +++++++++++++++++++++++++
>   drivers/cxl/cxlmem.h                    |  1 +
>   4 files changed, 44 insertions(+), 1 deletion(-)
>
> diff --git a/Documentation/ABI/testing/sysfs-bus-cxl b/Documentation/ABI/testing/sysfs-bus-cxl
> index 5753cba98692..f224c1215f22 100644
> --- a/Documentation/ABI/testing/sysfs-bus-cxl
> +++ b/Documentation/ABI/testing/sysfs-bus-cxl
> @@ -85,6 +85,16 @@ Description:
>   		the device to be not be actively decoding any HPA ranges.
>   
>   
> +What            /sys/bus/cxl/devices/memX/security/erase
> +Date:           June, 2023
> +KernelVersion:  v6.5
> +Contact:        linux-cxl@vger.kernel.org
> +Description:
> +		(WO) Write a boolean 'true' string value to this attribute to
> +		secure erase user data by changing the media encryption keys for
> +		all user data areas of the device.
> +
> +
>   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 51c64829f20a..6622eac66bf1 100644
> --- a/drivers/cxl/core/mbox.c
> +++ b/drivers/cxl/core/mbox.c
> @@ -1102,7 +1102,7 @@ int cxl_mem_sanitize(struct cxl_dev_state *cxlds, u16 cmd)
>   	};
>   	struct cxl_mbox_cmd mbox_cmd = { .opcode = cmd };
>   
> -	if (cmd != CXL_MBOX_OP_SANITIZE)
> +	if (cmd != CXL_MBOX_OP_SANITIZE && cmd != CXL_MBOX_OP_SECURE_ERASE)
>   		return -EINVAL;
>   
>   	rc = cxl_internal_send_cmd(cxlds, &sec_cmd);
> @@ -1120,6 +1120,10 @@ int cxl_mem_sanitize(struct cxl_dev_state *cxlds, u16 cmd)
>   	if (sec_out & CXL_PMEM_SEC_STATE_USER_PASS_SET)
>   		return -EINVAL;
>   
> +	if (cmd == CXL_MBOX_OP_SECURE_ERASE &&
> +	    sec_out & CXL_PMEM_SEC_STATE_LOCKED)
> +		return -EINVAL;
> +
>   	rc = cxl_internal_send_cmd(cxlds, &mbox_cmd);
>   	if (rc < 0) {
>   		dev_err(cxlds->dev, "Failed to sanitize device : %d", rc);
> diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c
> index 90f23e53d483..d06c8539e82c 100644
> --- a/drivers/cxl/core/memdev.c
> +++ b/drivers/cxl/core/memdev.c
> @@ -163,6 +163,33 @@ static ssize_t security_sanitize_store(struct device *dev,
>   static struct device_attribute dev_attr_security_sanitize =
>   	__ATTR(sanitize, 0200, NULL, security_sanitize_store);
>   
> +static ssize_t security_erase_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;
> +	struct cxl_port *port = dev_get_drvdata(&cxlmd->dev);
> +	ssize_t rc;
> +	bool erase;
> +
> +	if (kstrtobool(buf, &erase) || !erase)
> +		return -EINVAL;
> +
> +	if (!port || !is_cxl_endpoint(port))
> +		return -EINVAL;
> +
> +	/* ensure no regions are mapped to this memdev */
> +	if (port->commit_end != -1)
> +		return -EBUSY;
> +
> +	rc = cxl_mem_sanitize(cxlds, CXL_MBOX_OP_SECURE_ERASE);
> +
> +	return rc ? rc : len;
> +}
> +static struct device_attribute dev_attr_security_erase =
> +	__ATTR(erase, 0200, NULL, security_erase_store);
> +
>   static int cxl_get_poison_by_memdev(struct cxl_memdev *cxlmd)
>   {
>   	struct cxl_dev_state *cxlds = cxlmd->cxlds;
> @@ -411,6 +438,7 @@ static struct attribute *cxl_memdev_ram_attributes[] = {
>   static struct attribute *cxl_memdev_security_attributes[] = {
>   	&dev_attr_security_state.attr,
>   	&dev_attr_security_sanitize.attr,
> +	&dev_attr_security_erase.attr,
>   	NULL,
>   };
>   
> diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h
> index 408ec33c8480..758fea7b9dbf 100644
> --- a/drivers/cxl/cxlmem.h
> +++ b/drivers/cxl/cxlmem.h
> @@ -392,6 +392,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,

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 1/6] cxl/mem: Introduce security state sysfs file
  2023-05-26  3:33 ` [PATCH 1/6] cxl/mem: Introduce security state sysfs file Davidlohr Bueso
  2023-05-30 23:30   ` Dave Jiang
@ 2023-05-31 16:10   ` Jonathan Cameron
       [not found]   ` <CGME20230531174804uscas1p2c18bceeaf3415c86d778bb42709b75bc@uscas1p2.samsung.com>
  2 siblings, 0 replies; 19+ messages in thread
From: Jonathan Cameron @ 2023-05-31 16:10 UTC (permalink / raw)
  To: Davidlohr Bueso
  Cc: dan.j.williams, dave.jiang, vishal.l.verma, fan.ni, a.manzanares,
	linux-cxl

On Thu, 25 May 2023 20:33:39 -0700
Davidlohr Bueso <dave@stgolabs.net> wrote:

> Add a read-only sysfs file to display the security state
> of a device (currently only pmem):
> 
>     /sys/bus/cxl/devices/memX/security/state
> 
> This introduces a cxl_security_state structure that is
> to be the placeholder for common CXL security features.
> 
> Signed-off-by: Davidlohr Bueso <dave@stgolabs.net>
Nothing to add to Dave's review. Given comment is minor, either
way...

Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

> ---
>  Documentation/ABI/testing/sysfs-bus-cxl | 10 ++++++
>  drivers/cxl/core/memdev.c               | 46 +++++++++++++++++++++++++
>  drivers/cxl/cxlmem.h                    | 11 ++++++
>  drivers/cxl/security.c                  |  3 ++
>  4 files changed, 70 insertions(+)
> 
> diff --git a/Documentation/ABI/testing/sysfs-bus-cxl b/Documentation/ABI/testing/sysfs-bus-cxl
> index 48ac0d911801..721a44d8a482 100644
> --- a/Documentation/ABI/testing/sysfs-bus-cxl
> +++ b/Documentation/ABI/testing/sysfs-bus-cxl
> @@ -58,6 +58,16 @@ Description:
>  		affinity for this device.
>  
>  
> +What:		/sys/bus/cxl/devices/memX/security/state
> +Date:		June, 2023
> +KernelVersion:	v6.5
> +Contact:	linux-cxl@vger.kernel.org
> +Description:
> +		(RO) Reading this file will display the CXL security state for
> +		that device. Such states can be: 'disabled', or those available
> +		only for persistent memory: 'locked', 'unlocked' or 'frozen'.
> +
> +
>  What:		/sys/bus/cxl/devices/*/devtype
>  Date:		June, 2021
>  KernelVersion:	v5.14
> diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c
> index 057a43267290..6e1d7d3610a2 100644
> --- a/drivers/cxl/core/memdev.c
> +++ b/drivers/cxl/core/memdev.c
> @@ -107,6 +107,28 @@ static ssize_t numa_node_show(struct device *dev, struct device_attribute *attr,
>  }
>  static DEVICE_ATTR_RO(numa_node);
>  
> +static ssize_t security_state_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;
> +	unsigned long state = cxlds->security.state;
> +
> +	if (!(state & CXL_PMEM_SEC_STATE_USER_PASS_SET))
> +		return sysfs_emit(buf, "disabled\n");
> +	if (state & CXL_PMEM_SEC_STATE_FROZEN ||
> +	    state & CXL_PMEM_SEC_STATE_MASTER_PLIMIT ||
> +	    state & CXL_PMEM_SEC_STATE_USER_PLIMIT)
> +		return sysfs_emit(buf, "frozen\n");
> +	if (state & CXL_PMEM_SEC_STATE_LOCKED)
> +		return sysfs_emit(buf, "locked\n");
> +	else
> +		return sysfs_emit(buf, "unlocked\n");
> +}
> +static struct device_attribute dev_attr_security_state =
> +	__ATTR(state, 0444, security_state_show, NULL);
> +
>  static int cxl_get_poison_by_memdev(struct cxl_memdev *cxlmd)
>  {
>  	struct cxl_dev_state *cxlds = cxlmd->cxlds;
> @@ -352,6 +374,11 @@ static struct attribute *cxl_memdev_ram_attributes[] = {
>  	NULL,
>  };
>  
> +static struct attribute *cxl_memdev_security_attributes[] = {
> +	&dev_attr_security_state.attr,
> +	NULL,
> +};
> +
>  static umode_t cxl_memdev_visible(struct kobject *kobj, struct attribute *a,
>  				  int n)
>  {
> @@ -375,10 +402,16 @@ static struct attribute_group cxl_memdev_pmem_attribute_group = {
>  	.attrs = cxl_memdev_pmem_attributes,
>  };
>  
> +static struct attribute_group cxl_memdev_security_attribute_group = {
> +	.name = "security",
> +	.attrs = cxl_memdev_security_attributes,
> +};
> +
>  static const struct attribute_group *cxl_memdev_attribute_groups[] = {
>  	&cxl_memdev_attribute_group,
>  	&cxl_memdev_ram_attribute_group,
>  	&cxl_memdev_pmem_attribute_group,
> +	&cxl_memdev_security_attribute_group,
>  	NULL,
>  };
>  
> @@ -551,6 +584,15 @@ static const struct file_operations cxl_memdev_fops = {
>  	.llseek = noop_llseek,
>  };
>  
> +static int cxl_memdev_security_init(struct cxl_memdev *cxlmd)
> +{
> +	struct cxl_dev_state *cxlds = cxlmd->cxlds;
> +
> +	cxlds->security.state = 0;
> +
> +	return 0;
> +}
> +
>  struct cxl_memdev *devm_cxl_add_memdev(struct cxl_dev_state *cxlds)
>  {
>  	struct cxl_memdev *cxlmd;
> @@ -579,6 +621,10 @@ struct cxl_memdev *devm_cxl_add_memdev(struct cxl_dev_state *cxlds)
>  	if (rc)
>  		goto err;
>  
> +	rc = cxl_memdev_security_init(cxlmd);
> +	if (rc)
> +		goto err;
> +
>  	rc = devm_add_action_or_reset(cxlds->dev, cxl_memdev_unregister, cxlmd);
>  	if (rc)
>  		return ERR_PTR(rc);
> diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h
> index 1d8e81c87c6a..5329274b0076 100644
> --- a/drivers/cxl/cxlmem.h
> +++ b/drivers/cxl/cxlmem.h
> @@ -260,6 +260,15 @@ struct cxl_poison_state {
>  	struct mutex lock;  /* Protect reads of poison list */
>  };
>  
> +/**
> + * struct cxl_security_state - Device security state
> + *
> + * @state: state of last security operation
> + */
> +struct cxl_security_state {
> +	unsigned long state;
> +};
> +
>  /**
>   * struct cxl_dev_state - The driver device state
>   *
> @@ -297,6 +306,7 @@ struct cxl_poison_state {
>   * @serial: PCIe Device Serial Number
>   * @event: event log driver state
>   * @poison: poison driver state info
> + * @security: device security state
>   * @mbox_send: @dev specific transport for transmitting mailbox commands
>   *
>   * See section 8.2.9.5.2 Capacity Configuration and Label Storage for
> @@ -336,6 +346,7 @@ struct cxl_dev_state {
>  
>  	struct cxl_event_state event;
>  	struct cxl_poison_state poison;
> +	struct cxl_security_state security;
>  
>  	struct rcuwait mbox_wait;
>  	int (*mbox_send)(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd);
> diff --git a/drivers/cxl/security.c b/drivers/cxl/security.c
> index 4ad4bda2d18e..9da6785dfd31 100644
> --- a/drivers/cxl/security.c
> +++ b/drivers/cxl/security.c
> @@ -34,6 +34,9 @@ static unsigned long cxl_pmem_get_security_flags(struct nvdimm *nvdimm,
>  		return 0;
>  
>  	sec_out = le32_to_cpu(out.flags);
> +	/* cache security state */
> +	cxlds->security.state = sec_out;
> +
>  	if (ptype == NVDIMM_MASTER) {
>  		if (sec_out & CXL_PMEM_SEC_STATE_MASTER_PASS_SET)
>  			set_bit(NVDIMM_SECURITY_UNLOCKED, &security_flags);


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 2/6] cxl/mbox: Add sanitation handling machinery
  2023-05-30 23:36   ` Dave Jiang
@ 2023-05-31 16:29     ` Jonathan Cameron
  0 siblings, 0 replies; 19+ messages in thread
From: Jonathan Cameron @ 2023-05-31 16:29 UTC (permalink / raw)
  To: Dave Jiang
  Cc: Davidlohr Bueso, dan.j.williams, vishal.l.verma, fan.ni,
	a.manzanares, linux-cxl

On Tue, 30 May 2023 16:36:21 -0700
Dave Jiang <dave.jiang@intel.com> wrote:

> On 5/25/23 20:33, Davidlohr Bueso wrote:
> > Sanitation is by definition a device-monopolizing operation, and thus
> > the timeslicing rules for other background commands do not apply.
> > As such handle this special case asynchronously and return immediately.
> > Subsequent changes will allow completion to be pollable from userspace
> > via a sysfs file interface.
> >
> > For devices that don't support interrupts for notifying background
> > command completion, self-poll with the caveat that the poller can
> > be out of sync with the ready hardware, and therefore care must be
> > taken to not allow any new commands to go through until the poller
> > sees the hw completion. The poller takes the mbox_mutex to stabilize
> > the flagging, minimizing any runtime overhead in the send path to
> > check for 'sanitize_tmo' for uncommon poll scenarios. This flag
> > also serves for sanitation (the only user of async polling) to know
> > when to queue work or simply rely on irqs.
> >
> > The irq case is much simpler as hardware will serialize/error
> > appropriately.
> >
> > Signed-off-by: Davidlohr Bueso <dave@stgolabs.net>  
> 
> Just a minor nit below, otherwise
> 
> Reviewed-by: Dave Jiang <dave.jiang@intel.com>
> 
> 
> > ---
> >   drivers/cxl/core/memdev.c | 10 +++++
> >   drivers/cxl/cxlmem.h      | 10 +++++
> >   drivers/cxl/pci.c         | 83 +++++++++++++++++++++++++++++++++++++--
> >   3 files changed, 99 insertions(+), 4 deletions(-)
> >
> > diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c
> > index 6e1d7d3610a2..02763e83545c 100644
> > --- a/drivers/cxl/core/memdev.c
> > +++ b/drivers/cxl/core/memdev.c
> > @@ -460,11 +460,21 @@ void clear_exclusive_cxl_commands(struct cxl_dev_state *cxlds, unsigned long *cm
> >   }
> >   EXPORT_SYMBOL_NS_GPL(clear_exclusive_cxl_commands, CXL);
> >   
> > +static void cxl_memdev_security_shutdown(struct device *dev)
> > +{
> > +	struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
> > +	struct cxl_dev_state *cxlds = cxlmd->cxlds;
> > +
> > +	if (cxlds->security.poll_tmo_secs != -1)
> > +		cancel_delayed_work_sync(&cxlds->security.poll_dwork);
> > +}
> > +
> >   static void cxl_memdev_shutdown(struct device *dev)
> >   {
> >   	struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
> >   
> >   	down_write(&cxl_memdev_rwsem);
> > +	cxl_memdev_security_shutdown(dev);
> >   	cxlmd->cxlds = NULL;
> >   	up_write(&cxl_memdev_rwsem);
> >   }
> > diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h
> > index 5329274b0076..02ec68f97de2 100644
> > --- a/drivers/cxl/cxlmem.h
> > +++ b/drivers/cxl/cxlmem.h
> > @@ -264,9 +264,18 @@ struct cxl_poison_state {
> >    * struct cxl_security_state - Device security state
> >    *
> >    * @state: state of last security operation
> > + * @poll_tmo_secs: polling timeout
> > + * @poll_dwork: polling work item
> > + *
> > + * Polling (sanitation) is only used when device mbox irqs are not
> > + * supported. As such, @poll_tmo_secs == -1 indicates that polling
> > + * is disabled. Otherwise, when enabled, @poll_tmo_secs is maxed
> > + * at 15 minutes and serialized by the mbox_mutex.
> >    */
> >   struct cxl_security_state {
> >   	unsigned long state;
> > +	int poll_tmo_secs;
> > +	struct delayed_work poll_dwork;
> >   };
> >   
> >   /**
> > @@ -380,6 +389,7 @@ enum cxl_opcode {
> >   	CXL_MBOX_OP_GET_SCAN_MEDIA_CAPS	= 0x4303,
> >   	CXL_MBOX_OP_SCAN_MEDIA		= 0x4304,
> >   	CXL_MBOX_OP_GET_SCAN_MEDIA	= 0x4305,
> > +	CXL_MBOX_OP_SANITIZE		= 0x4400,
> >   	CXL_MBOX_OP_GET_SECURITY_STATE	= 0x4500,
> >   	CXL_MBOX_OP_SET_PASSPHRASE	= 0x4501,
> >   	CXL_MBOX_OP_DISABLE_PASSPHRASE	= 0x4502,
> > diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
> > index a78e40e6d0e0..a0d93719ab18 100644
> > --- a/drivers/cxl/pci.c
> > +++ b/drivers/cxl/pci.c
> > @@ -115,16 +115,52 @@ static bool cxl_mbox_background_complete(struct cxl_dev_state *cxlds)
> >   
> >   static irqreturn_t cxl_pci_mbox_irq(int irq, void *id)
> >   {
> > +	u64 reg;
> > +	u16 opcode;
> >   	struct cxl_dev_id *dev_id = id;
> >   	struct cxl_dev_state *cxlds = dev_id->cxlds;
> >   
> > -	/* short-circuit the wait in __cxl_pci_mbox_send_cmd() */
> > -	if (cxl_mbox_background_complete(cxlds))
> > -		rcuwait_wake_up(&cxlds->mbox_wait);
> > +	if (!cxl_mbox_background_complete(cxlds))
> > +		goto done;
> >   
> > +	reg = readq(cxlds->regs.mbox + CXLDEV_MBOX_BG_CMD_STATUS_OFFSET);
> > +	opcode = FIELD_GET(CXLDEV_MBOX_BG_CMD_COMMAND_OPCODE_MASK, reg);
> > +	if (opcode == CXL_MBOX_OP_SANITIZE) {
> > +		dev_dbg(cxlds->dev, "Sanitation operation ended\n");
> > +	} else {
> > +		/* short-circuit the wait in __cxl_pci_mbox_send_cmd() */
> > +		rcuwait_wake_up(&cxlds->mbox_wait);
> > +	}
> > +done:
> >   	return IRQ_HANDLED;
> >   }
> >   
> > +/*
> > + * Sanitation operation polling mode.
> > + */
> > +static void cxl_mbox_sanitize_work(struct work_struct *work)
> > +{
> > +	struct cxl_dev_state *cxlds;
> > +
> > +	cxlds = container_of(work,
> > +			     struct cxl_dev_state, security.poll_dwork.work);
> > +
> > +	mutex_lock(&cxlds->mbox_mutex);
> > +	if (cxl_mbox_background_complete(cxlds)) {
> > +		cxlds->security.poll_tmo_secs = 0;
> > +		put_device(cxlds->dev);
> > +
> > +		dev_dbg(cxlds->dev, "Sanitation operation ended\n");
> > +	} else {
> > +		int timeout = cxlds->security.poll_tmo_secs + 10;
> > +
> > +		cxlds->security.poll_tmo_secs = min(15 * 60, timeout);
> > +		queue_delayed_work(system_wq, &cxlds->security.poll_dwork,
> > +				   timeout * HZ);
> > +	}
> > +	mutex_unlock(&cxlds->mbox_mutex);
> > +}
> > +
> >   /**
> >    * __cxl_pci_mbox_send_cmd() - Execute a mailbox command
> >    * @cxlds: The device state to communicate with.
> > @@ -185,6 +221,16 @@ static int __cxl_pci_mbox_send_cmd(struct cxl_dev_state *cxlds,
> >   		return -EBUSY;
> >   	}
> >   
> > +	/*
> > +	 * With sanitize polling, hardware might be done and the poller still
> > +	 * not be in sync. Ensure no new command comes in until so. Keep the
> > +	 * hardware semantics and only allow device health status.
> > +	 */
> > +	if (unlikely(cxlds->security.poll_tmo_secs > 0)) {
> > +		if (mbox_cmd->opcode != CXL_MBOX_OP_GET_HEALTH_INFO)
> > +			return -EBUSY;
> > +	}
> > +
> >   	cmd_reg = FIELD_PREP(CXLDEV_MBOX_CMD_COMMAND_OPCODE_MASK,
> >   			     mbox_cmd->opcode);
> >   	if (mbox_cmd->size_in) {
> > @@ -233,11 +279,34 @@ static int __cxl_pci_mbox_send_cmd(struct cxl_dev_state *cxlds,
> >   	 */
> >   	if (mbox_cmd->return_code == CXL_MBOX_CMD_RC_BACKGROUND) {
> >   		u64 bg_status_reg;
> > -		int i, timeout = mbox_cmd->poll_interval_ms;
> > +		int i, timeout;
> > +
> > +		/*
> > +		 * Sanitation is a special case which monopolizes the device
> > +		 * and cannot be timesliced. Handle asynchronously instead,
> > +		 * and allow userspace to poll(2) for completion.
> > +		 */
> > +		if (mbox_cmd->opcode == CXL_MBOX_OP_SANITIZE) {
> > +			if (cxlds->security.poll_tmo_secs != -1) {
> > +				/* hold the device throughout */
> > +				get_device(cxlds->dev);
> > +
> > +				/* give first timeout a second */
> > +				timeout = 1;
> > +				cxlds->security.poll_tmo_secs = timeout;
> > +				queue_delayed_work(system_wq,
> > +						   &cxlds->security.poll_dwork,
> > +						   timeout * HZ);
> > +			}
> > +
> > +			dev_dbg(dev, "Sanitation operation started\n");
> > +			goto success;
> > +		}
> >   
> >   		dev_dbg(dev, "Mailbox background operation (0x%04x) started\n",
> >   			mbox_cmd->opcode);
> >   
> > +		timeout = mbox_cmd->poll_interval_ms;
> >   		for (i = 0; i < mbox_cmd->poll_count; i++) {
> >   			if (rcuwait_wait_event_timeout(&cxlds->mbox_wait,
> >   				       cxl_mbox_background_complete(cxlds),
> > @@ -268,6 +337,7 @@ static int __cxl_pci_mbox_send_cmd(struct cxl_dev_state *cxlds,
> >   		return 0; /* completed but caller must check return_code */
> >   	}
> >   
> > +success:
> >   	/* #7 */
> >   	cmd_reg = readq(cxlds->regs.mbox + CXLDEV_MBOX_CMD_OFFSET);
> >   	out_len = FIELD_GET(CXLDEV_MBOX_CMD_PAYLOAD_LENGTH_MASK, cmd_reg);
> > @@ -376,10 +446,15 @@ static int cxl_pci_setup_mailbox(struct cxl_dev_state *cxlds)
> >   		ctrl |= CXLDEV_MBOX_CTRL_BG_CMD_IRQ;
> >   		writel(ctrl, cxlds->regs.mbox + CXLDEV_MBOX_CTRL_OFFSET);
> >   
> > +		/* flag that irqs are enabled */
> > +		cxlds->security.poll_tmo_secs = -1;  
> 
> Use a #define instead of -1 magic number? CXL_CMD_TIMEOUT_INVALID 
> perhaps? Would also apply to all the checking of poll_tmo_secs in this 
> patch.

If we can avoid this use of magic numbers entirely it would be more readable.
Either a nicely named boolean, or querying it directly from the hardware
/ other cached state (which looks fiddly).

> 
> 
> >   		return 0;
> >   	}
> >   
> >   mbox_poll:
> > +	cxlds->security.poll_tmo_secs = 0;
> > +	INIT_DELAYED_WORK(&cxlds->security.poll_dwork,
> > +			  cxl_mbox_sanitize_work);
> >   	dev_dbg(cxlds->dev, "Mailbox interrupts are unsupported");
> >   	return 0;
> >   }  
> 


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 2/6] cxl/mbox: Add sanitation handling machinery
  2023-05-26  3:33 ` [PATCH 2/6] cxl/mbox: Add sanitation handling machinery Davidlohr Bueso
  2023-05-30 23:36   ` Dave Jiang
@ 2023-05-31 16:36   ` Jonathan Cameron
  1 sibling, 0 replies; 19+ messages in thread
From: Jonathan Cameron @ 2023-05-31 16:36 UTC (permalink / raw)
  To: Davidlohr Bueso
  Cc: dan.j.williams, dave.jiang, vishal.l.verma, fan.ni, a.manzanares,
	linux-cxl

On Thu, 25 May 2023 20:33:40 -0700
Davidlohr Bueso <dave@stgolabs.net> wrote:

> Sanitation is by definition a device-monopolizing operation, and thus
> the timeslicing rules for other background commands do not apply.
> As such handle this special case asynchronously and return immediately.
> Subsequent changes will allow completion to be pollable from userspace
> via a sysfs file interface.
> 
> For devices that don't support interrupts for notifying background
> command completion, self-poll with the caveat that the poller can
> be out of sync with the ready hardware, and therefore care must be
> taken to not allow any new commands to go through until the poller
> sees the hw completion. The poller takes the mbox_mutex to stabilize
> the flagging, minimizing any runtime overhead in the send path to
> check for 'sanitize_tmo' for uncommon poll scenarios. This flag
> also serves for sanitation (the only user of async polling) to know
> when to queue work or simply rely on irqs.
> 
> The irq case is much simpler as hardware will serialize/error
> appropriately.
> 
> Signed-off-by: Davidlohr Bueso <dave@stgolabs.net>
...

> diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h
> index 5329274b0076..02ec68f97de2 100644
> --- a/drivers/cxl/cxlmem.h
> +++ b/drivers/cxl/cxlmem.h
> @@ -264,9 +264,18 @@ struct cxl_poison_state {
>   * struct cxl_security_state - Device security state
>   *
>   * @state: state of last security operation
> + * @poll_tmo_secs: polling timeout
> + * @poll_dwork: polling work item
> + *
> + * Polling (sanitation) is only used when device mbox irqs are not
> + * supported. As such, @poll_tmo_secs == -1 indicates that polling
> + * is disabled. Otherwise, when enabled, @poll_tmo_secs is maxed
> + * at 15 minutes and serialized by the mbox_mutex.

Long comment to avoid a bool :)

>   */
>  struct cxl_security_state {
>  	unsigned long state;
> +	int poll_tmo_secs;
> +	struct delayed_work poll_dwork;
>  };

> diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
> index a78e40e6d0e0..a0d93719ab18 100644
> --- a/drivers/cxl/pci.c
> +++ b/drivers/cxl/pci.c
> @@ -115,16 +115,52 @@ static bool cxl_mbox_background_complete(struct cxl_dev_state *cxlds)
>  
>  static irqreturn_t cxl_pci_mbox_irq(int irq, void *id)
>  {
> +	u64 reg;
> +	u16 opcode;
>  	struct cxl_dev_id *dev_id = id;
>  	struct cxl_dev_state *cxlds = dev_id->cxlds;
>  
> -	/* short-circuit the wait in __cxl_pci_mbox_send_cmd() */
> -	if (cxl_mbox_background_complete(cxlds))
> -		rcuwait_wake_up(&cxlds->mbox_wait);
> +	if (!cxl_mbox_background_complete(cxlds))

If we hit this path, does it mean it wasn't our interrupt?
Or an we get here via a race as well - but if so there should
be a comment on why this isn't returning IRQ_NONE. So either
a comment on the race or IRQ_NONE return.


> +		goto done;
>  
> +	reg = readq(cxlds->regs.mbox + CXLDEV_MBOX_BG_CMD_STATUS_OFFSET);
> +	opcode = FIELD_GET(CXLDEV_MBOX_BG_CMD_COMMAND_OPCODE_MASK, reg);
> +	if (opcode == CXL_MBOX_OP_SANITIZE) {
> +		dev_dbg(cxlds->dev, "Sanitation operation ended\n");
> +	} else {
> +		/* short-circuit the wait in __cxl_pci_mbox_send_cmd() */
> +		rcuwait_wake_up(&cxlds->mbox_wait);
> +	}
> +done:
>  	return IRQ_HANDLED;
>  }
>

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 3/6] cxl/mem: Wire up Sanitation support
  2023-05-30 23:53     ` Dave Jiang
@ 2023-05-31 16:39       ` Jonathan Cameron
  0 siblings, 0 replies; 19+ messages in thread
From: Jonathan Cameron @ 2023-05-31 16:39 UTC (permalink / raw)
  To: Dave Jiang
  Cc: Davidlohr Bueso, dan.j.williams, vishal.l.verma, fan.ni,
	a.manzanares, linux-cxl

On Tue, 30 May 2023 16:53:25 -0700
Dave Jiang <dave.jiang@intel.com> wrote:

> On 5/25/23 20:41, Davidlohr Bueso wrote:
> > On Thu, 25 May 2023, Davidlohr Bueso wrote:
> >  
> >> Implement support for CXL 3.0 8.2.9.8.5.1 Sanitize. This is done by
> >> adding a security/sanitize' memdev sysfs file, which is poll(2)-capable
> >> for completion. Unlike all other background commands, this is the
> >> only operation that is special and monopolizes the device for long
> >> periods of time.  
> >
> > As becomes obvious in the code, this paragraph actually should have
> > been updated: the pollable/read file for the status of sanitation
> > is the security/state.  
> 
> 
> Reviewed-by: Dave Jiang <dave.jiang@intel.com> with above update.
LGTM as well
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

> 
> 
> 
> 
> >
> > Thanks,
> > Davidlohr  
> 


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 5/6] cxl/mem: Support Secure Erase
  2023-05-26  3:33 ` [PATCH 5/6] cxl/mem: Support Secure Erase Davidlohr Bueso
  2023-05-30 23:54   ` Dave Jiang
@ 2023-05-31 16:41   ` Jonathan Cameron
  2023-06-01 17:24   ` Fan Ni
  2 siblings, 0 replies; 19+ messages in thread
From: Jonathan Cameron @ 2023-05-31 16:41 UTC (permalink / raw)
  To: Davidlohr Bueso
  Cc: dan.j.williams, dave.jiang, vishal.l.verma, fan.ni, a.manzanares,
	linux-cxl

On Thu, 25 May 2023 20:33:43 -0700
Davidlohr Bueso <dave@stgolabs.net> wrote:

> Implement support for the non-pmem exclusive secure erase, per
> CXL specs. Create a write-only 'security/erase' sysfs file to
> perform the requested operation.
> 
> As with the sanitation this requires the device being offline
> and thus no active HPA-DPA decoding.
> 
> The expectation is that userspace can use it such as:
> 
> 	cxl disable-memdev memX
> 	echo 1 > /sys/bus/cxl/devices/memX/security/erase
> 	cxl enable-memdev memX
> 
> Signed-off-by: Davidlohr Bueso <dave@stgolabs.net>
Trivial comment inline.

Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

> ---
>  Documentation/ABI/testing/sysfs-bus-cxl | 10 +++++++++
>  drivers/cxl/core/mbox.c                 |  6 +++++-
>  drivers/cxl/core/memdev.c               | 28 +++++++++++++++++++++++++
>  drivers/cxl/cxlmem.h                    |  1 +
>  4 files changed, 44 insertions(+), 1 deletion(-)
> 
> diff --git a/Documentation/ABI/testing/sysfs-bus-cxl b/Documentation/ABI/testing/sysfs-bus-cxl
> index 5753cba98692..f224c1215f22 100644
> --- a/Documentation/ABI/testing/sysfs-bus-cxl
> +++ b/Documentation/ABI/testing/sysfs-bus-cxl
> @@ -85,6 +85,16 @@ Description:
>  		the device to be not be actively decoding any HPA ranges.
>  
>  
> +What            /sys/bus/cxl/devices/memX/security/erase
> +Date:           June, 2023
> +KernelVersion:  v6.5
> +Contact:        linux-cxl@vger.kernel.org
> +Description:
> +		(WO) Write a boolean 'true' string value to this attribute to
> +		secure erase user data by changing the media encryption keys for
> +		all user data areas of the device.
> +
> +
>  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 51c64829f20a..6622eac66bf1 100644
> --- a/drivers/cxl/core/mbox.c
> +++ b/drivers/cxl/core/mbox.c
> @@ -1102,7 +1102,7 @@ int cxl_mem_sanitize(struct cxl_dev_state *cxlds, u16 cmd)
>  	};
>  	struct cxl_mbox_cmd mbox_cmd = { .opcode = cmd };
>  
> -	if (cmd != CXL_MBOX_OP_SANITIZE)
> +	if (cmd != CXL_MBOX_OP_SANITIZE && cmd != CXL_MBOX_OP_SECURE_ERASE)

Maybe just use a switch + default for the inevitable growth of this list and
attempting to avoid churn?

>  		return -EINVAL;
>  
>  	rc = cxl_internal_send_cmd(cxlds, &sec_cmd);
> @@ -1120,6 +1120,10 @@ int cxl_mem_sanitize(struct cxl_dev_state *cxlds, u16 cmd)
>  	if (sec_out & CXL_PMEM_SEC_STATE_USER_PASS_SET)
>  		return -EINVAL;
>  
> +	if (cmd == CXL_MBOX_OP_SECURE_ERASE &&
> +	    sec_out & CXL_PMEM_SEC_STATE_LOCKED)
> +		return -EINVAL;
> +
>  	rc = cxl_internal_send_cmd(cxlds, &mbox_cmd);
>  	if (rc < 0) {
>  		dev_err(cxlds->dev, "Failed to sanitize device : %d", rc);
> diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c
> index 90f23e53d483..d06c8539e82c 100644
> --- a/drivers/cxl/core/memdev.c
> +++ b/drivers/cxl/core/memdev.c
> @@ -163,6 +163,33 @@ static ssize_t security_sanitize_store(struct device *dev,
>  static struct device_attribute dev_attr_security_sanitize =
>  	__ATTR(sanitize, 0200, NULL, security_sanitize_store);
>  
> +static ssize_t security_erase_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;
> +	struct cxl_port *port = dev_get_drvdata(&cxlmd->dev);
> +	ssize_t rc;
> +	bool erase;
> +
> +	if (kstrtobool(buf, &erase) || !erase)
> +		return -EINVAL;
> +
> +	if (!port || !is_cxl_endpoint(port))
> +		return -EINVAL;
> +
> +	/* ensure no regions are mapped to this memdev */
> +	if (port->commit_end != -1)
> +		return -EBUSY;
> +
> +	rc = cxl_mem_sanitize(cxlds, CXL_MBOX_OP_SECURE_ERASE);
> +
> +	return rc ? rc : len;
> +}
> +static struct device_attribute dev_attr_security_erase =
> +	__ATTR(erase, 0200, NULL, security_erase_store);
> +
>  static int cxl_get_poison_by_memdev(struct cxl_memdev *cxlmd)
>  {
>  	struct cxl_dev_state *cxlds = cxlmd->cxlds;
> @@ -411,6 +438,7 @@ static struct attribute *cxl_memdev_ram_attributes[] = {
>  static struct attribute *cxl_memdev_security_attributes[] = {
>  	&dev_attr_security_state.attr,
>  	&dev_attr_security_sanitize.attr,
> +	&dev_attr_security_erase.attr,
>  	NULL,
>  };
>  
> diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h
> index 408ec33c8480..758fea7b9dbf 100644
> --- a/drivers/cxl/cxlmem.h
> +++ b/drivers/cxl/cxlmem.h
> @@ -392,6 +392,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,


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 1/6] cxl/mem: Introduce security state sysfs file
       [not found]   ` <CGME20230531174804uscas1p2c18bceeaf3415c86d778bb42709b75bc@uscas1p2.samsung.com>
@ 2023-05-31 17:48     ` Fan Ni
  0 siblings, 0 replies; 19+ messages in thread
From: Fan Ni @ 2023-05-31 17:48 UTC (permalink / raw)
  To: Davidlohr Bueso
  Cc: dan.j.williams, dave.jiang, vishal.l.verma, Jonathan.Cameron,
	Adam Manzanares, linux-cxl

On Thu, May 25, 2023 at 08:33:39PM -0700, Davidlohr Bueso wrote:
> Add a read-only sysfs file to display the security state
> of a device (currently only pmem):
> 
>     /sys/bus/cxl/devices/memX/security/state
> 
> This introduces a cxl_security_state structure that is
> to be the placeholder for common CXL security features.
> 
> Signed-off-by: Davidlohr Bueso <dave@stgolabs.net>
> ---

Reviewed-by: Fan Ni <fan.ni@samsung.com>

>  Documentation/ABI/testing/sysfs-bus-cxl | 10 ++++++
>  drivers/cxl/core/memdev.c               | 46 +++++++++++++++++++++++++
>  drivers/cxl/cxlmem.h                    | 11 ++++++
>  drivers/cxl/security.c                  |  3 ++
>  4 files changed, 70 insertions(+)
> 
> diff --git a/Documentation/ABI/testing/sysfs-bus-cxl b/Documentation/ABI/testing/sysfs-bus-cxl
> index 48ac0d911801..721a44d8a482 100644
> --- a/Documentation/ABI/testing/sysfs-bus-cxl
> +++ b/Documentation/ABI/testing/sysfs-bus-cxl
> @@ -58,6 +58,16 @@ Description:
>  		affinity for this device.
>  
>  
> +What:		/sys/bus/cxl/devices/memX/security/state
> +Date:		June, 2023
> +KernelVersion:	v6.5
> +Contact:	linux-cxl@vger.kernel.org
> +Description:
> +		(RO) Reading this file will display the CXL security state for
> +		that device. Such states can be: 'disabled', or those available
> +		only for persistent memory: 'locked', 'unlocked' or 'frozen'.
> +
> +
>  What:		/sys/bus/cxl/devices/*/devtype
>  Date:		June, 2021
>  KernelVersion:	v5.14
> diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c
> index 057a43267290..6e1d7d3610a2 100644
> --- a/drivers/cxl/core/memdev.c
> +++ b/drivers/cxl/core/memdev.c
> @@ -107,6 +107,28 @@ static ssize_t numa_node_show(struct device *dev, struct device_attribute *attr,
>  }
>  static DEVICE_ATTR_RO(numa_node);
>  
> +static ssize_t security_state_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;
> +	unsigned long state = cxlds->security.state;
> +
> +	if (!(state & CXL_PMEM_SEC_STATE_USER_PASS_SET))
> +		return sysfs_emit(buf, "disabled\n");
> +	if (state & CXL_PMEM_SEC_STATE_FROZEN ||
> +	    state & CXL_PMEM_SEC_STATE_MASTER_PLIMIT ||
> +	    state & CXL_PMEM_SEC_STATE_USER_PLIMIT)
> +		return sysfs_emit(buf, "frozen\n");
> +	if (state & CXL_PMEM_SEC_STATE_LOCKED)
> +		return sysfs_emit(buf, "locked\n");
> +	else
> +		return sysfs_emit(buf, "unlocked\n");
> +}
> +static struct device_attribute dev_attr_security_state =
> +	__ATTR(state, 0444, security_state_show, NULL);
> +
>  static int cxl_get_poison_by_memdev(struct cxl_memdev *cxlmd)
>  {
>  	struct cxl_dev_state *cxlds = cxlmd->cxlds;
> @@ -352,6 +374,11 @@ static struct attribute *cxl_memdev_ram_attributes[] = {
>  	NULL,
>  };
>  
> +static struct attribute *cxl_memdev_security_attributes[] = {
> +	&dev_attr_security_state.attr,
> +	NULL,
> +};
> +
>  static umode_t cxl_memdev_visible(struct kobject *kobj, struct attribute *a,
>  				  int n)
>  {
> @@ -375,10 +402,16 @@ static struct attribute_group cxl_memdev_pmem_attribute_group = {
>  	.attrs = cxl_memdev_pmem_attributes,
>  };
>  
> +static struct attribute_group cxl_memdev_security_attribute_group = {
> +	.name = "security",
> +	.attrs = cxl_memdev_security_attributes,
> +};
> +
>  static const struct attribute_group *cxl_memdev_attribute_groups[] = {
>  	&cxl_memdev_attribute_group,
>  	&cxl_memdev_ram_attribute_group,
>  	&cxl_memdev_pmem_attribute_group,
> +	&cxl_memdev_security_attribute_group,
>  	NULL,
>  };
>  
> @@ -551,6 +584,15 @@ static const struct file_operations cxl_memdev_fops = {
>  	.llseek = noop_llseek,
>  };
>  
> +static int cxl_memdev_security_init(struct cxl_memdev *cxlmd)
> +{
> +	struct cxl_dev_state *cxlds = cxlmd->cxlds;
> +
> +	cxlds->security.state = 0;
> +
> +	return 0;
> +}
> +
>  struct cxl_memdev *devm_cxl_add_memdev(struct cxl_dev_state *cxlds)
>  {
>  	struct cxl_memdev *cxlmd;
> @@ -579,6 +621,10 @@ struct cxl_memdev *devm_cxl_add_memdev(struct cxl_dev_state *cxlds)
>  	if (rc)
>  		goto err;
>  
> +	rc = cxl_memdev_security_init(cxlmd);
> +	if (rc)
> +		goto err;
> +
>  	rc = devm_add_action_or_reset(cxlds->dev, cxl_memdev_unregister, cxlmd);
>  	if (rc)
>  		return ERR_PTR(rc);
> diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h
> index 1d8e81c87c6a..5329274b0076 100644
> --- a/drivers/cxl/cxlmem.h
> +++ b/drivers/cxl/cxlmem.h
> @@ -260,6 +260,15 @@ struct cxl_poison_state {
>  	struct mutex lock;  /* Protect reads of poison list */
>  };
>  
> +/**
> + * struct cxl_security_state - Device security state
> + *
> + * @state: state of last security operation
> + */
> +struct cxl_security_state {
> +	unsigned long state;
> +};
> +
>  /**
>   * struct cxl_dev_state - The driver device state
>   *
> @@ -297,6 +306,7 @@ struct cxl_poison_state {
>   * @serial: PCIe Device Serial Number
>   * @event: event log driver state
>   * @poison: poison driver state info
> + * @security: device security state
>   * @mbox_send: @dev specific transport for transmitting mailbox commands
>   *
>   * See section 8.2.9.5.2 Capacity Configuration and Label Storage for
> @@ -336,6 +346,7 @@ struct cxl_dev_state {
>  
>  	struct cxl_event_state event;
>  	struct cxl_poison_state poison;
> +	struct cxl_security_state security;
>  
>  	struct rcuwait mbox_wait;
>  	int (*mbox_send)(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd);
> diff --git a/drivers/cxl/security.c b/drivers/cxl/security.c
> index 4ad4bda2d18e..9da6785dfd31 100644
> --- a/drivers/cxl/security.c
> +++ b/drivers/cxl/security.c
> @@ -34,6 +34,9 @@ static unsigned long cxl_pmem_get_security_flags(struct nvdimm *nvdimm,
>  		return 0;
>  
>  	sec_out = le32_to_cpu(out.flags);
> +	/* cache security state */
> +	cxlds->security.state = sec_out;
> +
>  	if (ptype == NVDIMM_MASTER) {
>  		if (sec_out & CXL_PMEM_SEC_STATE_MASTER_PASS_SET)
>  			set_bit(NVDIMM_SECURITY_UNLOCKED, &security_flags);
> -- 
> 2.40.1
> 
> 

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 5/6] cxl/mem: Support Secure Erase
  2023-05-26  3:33 ` [PATCH 5/6] cxl/mem: Support Secure Erase Davidlohr Bueso
  2023-05-30 23:54   ` Dave Jiang
  2023-05-31 16:41   ` Jonathan Cameron
@ 2023-06-01 17:24   ` Fan Ni
  2 siblings, 0 replies; 19+ messages in thread
From: Fan Ni @ 2023-06-01 17:24 UTC (permalink / raw)
  To: Davidlohr Bueso
  Cc: dan.j.williams, dave.jiang, vishal.l.verma, Jonathan.Cameron,
	fan.ni, a.manzanares, linux-cxl

The 05/25/2023 20:33, Davidlohr Bueso wrote:
> Implement support for the non-pmem exclusive secure erase, per
> CXL specs. Create a write-only 'security/erase' sysfs file to
> perform the requested operation.
> 
> As with the sanitation this requires the device being offline
> and thus no active HPA-DPA decoding.
> 
> The expectation is that userspace can use it such as:
> 
> 	cxl disable-memdev memX
> 	echo 1 > /sys/bus/cxl/devices/memX/security/erase
> 	cxl enable-memdev memX
> 
> Signed-off-by: Davidlohr Bueso <dave@stgolabs.net>
> ---

Reviewed-by: Fan Ni <fan.ni@samsung.com>

>  Documentation/ABI/testing/sysfs-bus-cxl | 10 +++++++++
>  drivers/cxl/core/mbox.c                 |  6 +++++-
>  drivers/cxl/core/memdev.c               | 28 +++++++++++++++++++++++++
>  drivers/cxl/cxlmem.h                    |  1 +
>  4 files changed, 44 insertions(+), 1 deletion(-)
> 
> diff --git a/Documentation/ABI/testing/sysfs-bus-cxl b/Documentation/ABI/testing/sysfs-bus-cxl
> index 5753cba98692..f224c1215f22 100644
> --- a/Documentation/ABI/testing/sysfs-bus-cxl
> +++ b/Documentation/ABI/testing/sysfs-bus-cxl
> @@ -85,6 +85,16 @@ Description:
>  		the device to be not be actively decoding any HPA ranges.
>  
>  
> +What            /sys/bus/cxl/devices/memX/security/erase
> +Date:           June, 2023
> +KernelVersion:  v6.5
> +Contact:        linux-cxl@vger.kernel.org
> +Description:
> +		(WO) Write a boolean 'true' string value to this attribute to
> +		secure erase user data by changing the media encryption keys for
> +		all user data areas of the device.
> +
> +
>  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 51c64829f20a..6622eac66bf1 100644
> --- a/drivers/cxl/core/mbox.c
> +++ b/drivers/cxl/core/mbox.c
> @@ -1102,7 +1102,7 @@ int cxl_mem_sanitize(struct cxl_dev_state *cxlds, u16 cmd)
>  	};
>  	struct cxl_mbox_cmd mbox_cmd = { .opcode = cmd };
>  
> -	if (cmd != CXL_MBOX_OP_SANITIZE)
> +	if (cmd != CXL_MBOX_OP_SANITIZE && cmd != CXL_MBOX_OP_SECURE_ERASE)
>  		return -EINVAL;
>  
>  	rc = cxl_internal_send_cmd(cxlds, &sec_cmd);
> @@ -1120,6 +1120,10 @@ int cxl_mem_sanitize(struct cxl_dev_state *cxlds, u16 cmd)
>  	if (sec_out & CXL_PMEM_SEC_STATE_USER_PASS_SET)
>  		return -EINVAL;
>  
> +	if (cmd == CXL_MBOX_OP_SECURE_ERASE &&
> +	    sec_out & CXL_PMEM_SEC_STATE_LOCKED)
> +		return -EINVAL;
> +
>  	rc = cxl_internal_send_cmd(cxlds, &mbox_cmd);
>  	if (rc < 0) {
>  		dev_err(cxlds->dev, "Failed to sanitize device : %d", rc);
> diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c
> index 90f23e53d483..d06c8539e82c 100644
> --- a/drivers/cxl/core/memdev.c
> +++ b/drivers/cxl/core/memdev.c
> @@ -163,6 +163,33 @@ static ssize_t security_sanitize_store(struct device *dev,
>  static struct device_attribute dev_attr_security_sanitize =
>  	__ATTR(sanitize, 0200, NULL, security_sanitize_store);
>  
> +static ssize_t security_erase_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;
> +	struct cxl_port *port = dev_get_drvdata(&cxlmd->dev);
> +	ssize_t rc;
> +	bool erase;
> +
> +	if (kstrtobool(buf, &erase) || !erase)
> +		return -EINVAL;
> +
> +	if (!port || !is_cxl_endpoint(port))
> +		return -EINVAL;
> +
> +	/* ensure no regions are mapped to this memdev */
> +	if (port->commit_end != -1)
> +		return -EBUSY;
> +
> +	rc = cxl_mem_sanitize(cxlds, CXL_MBOX_OP_SECURE_ERASE);
> +
> +	return rc ? rc : len;
> +}
> +static struct device_attribute dev_attr_security_erase =
> +	__ATTR(erase, 0200, NULL, security_erase_store);
> +
>  static int cxl_get_poison_by_memdev(struct cxl_memdev *cxlmd)
>  {
>  	struct cxl_dev_state *cxlds = cxlmd->cxlds;
> @@ -411,6 +438,7 @@ static struct attribute *cxl_memdev_ram_attributes[] = {
>  static struct attribute *cxl_memdev_security_attributes[] = {
>  	&dev_attr_security_state.attr,
>  	&dev_attr_security_sanitize.attr,
> +	&dev_attr_security_erase.attr,
>  	NULL,
>  };
>  
> diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h
> index 408ec33c8480..758fea7b9dbf 100644
> --- a/drivers/cxl/cxlmem.h
> +++ b/drivers/cxl/cxlmem.h
> @@ -392,6 +392,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,
> -- 
> 2.40.1
> 

-- 
Fan Ni <nifan@outlook.com>

^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2023-06-01 17:24 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-05-26  3:33 [PATCH v5 0/6] cxl: Support device sanitation Davidlohr Bueso
2023-05-26  3:33 ` [PATCH 1/6] cxl/mem: Introduce security state sysfs file Davidlohr Bueso
2023-05-30 23:30   ` Dave Jiang
2023-05-31 16:10   ` Jonathan Cameron
     [not found]   ` <CGME20230531174804uscas1p2c18bceeaf3415c86d778bb42709b75bc@uscas1p2.samsung.com>
2023-05-31 17:48     ` Fan Ni
2023-05-26  3:33 ` [PATCH 2/6] cxl/mbox: Add sanitation handling machinery Davidlohr Bueso
2023-05-30 23:36   ` Dave Jiang
2023-05-31 16:29     ` Jonathan Cameron
2023-05-31 16:36   ` Jonathan Cameron
2023-05-26  3:33 ` [PATCH 3/6] cxl/mem: Wire up Sanitation support Davidlohr Bueso
2023-05-26  3:41   ` Davidlohr Bueso
2023-05-30 23:53     ` Dave Jiang
2023-05-31 16:39       ` Jonathan Cameron
2023-05-26  3:33 ` [PATCH 4/6] cxl/test: Add Sanitize opcode support Davidlohr Bueso
2023-05-26  3:33 ` [PATCH 5/6] cxl/mem: Support Secure Erase Davidlohr Bueso
2023-05-30 23:54   ` Dave Jiang
2023-05-31 16:41   ` Jonathan Cameron
2023-06-01 17:24   ` Fan Ni
2023-05-26  3:33 ` [PATCH 6/6] cxl/test: Add Secure Erase opcode support Davidlohr Bueso

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.