diff mbox series

[RFC,v1,1/1] scsi: ufs: core: Add device level exeption support

Message ID fdebf652abb4734d37f957062a2b4568754db374.1740016268.git.quic_nguyenb@quicinc.com (mailing list archive)
State Changes Requested
Headers show
Series [RFC,v1,1/1] scsi: ufs: core: Add device level exeption support | expand

Commit Message

Bao D. Nguyen Feb. 20, 2025, 1:51 a.m. UTC
The device JEDEC standard version 4.1 adds support for the device
level exception events. In order to provide the user space access to
the device level exception information, we propose exposing 2 new
sysfs nodes namely
/sys/bus/platform/drivers/ufshcd/*/device_lvl_exception
/sys/bus/platform/drivers/ufshcd/*/device_lvl_exception_id
The device_lvl_exception sysfs node would report the number of
device level exceptions that have occurred between the
device_lvl_exception_id reads.
The device_lvl_exception_id sysfs node would report the last read of the
exception ID which is the JEDEC standard qDeviceLevelExceptionID attribute.
The user space would query the sysfs nodes to get more information about
the device level exception. Alternatively, we can change the implementation
to notify the user space of the exception.

Signed-off-by: Bao D. Nguyen <quic_nguyenb@quicinc.com>
---
 Documentation/ABI/testing/sysfs-driver-ufs | 21 +++++++++
 drivers/ufs/core/ufs-sysfs.c               | 23 ++++++++++
 drivers/ufs/core/ufshcd.c                  | 69 ++++++++++++++++++++++++++++++
 include/uapi/scsi/scsi_bsg_ufs.h           |  8 ++++
 include/ufs/ufs.h                          |  5 ++-
 include/ufs/ufshcd.h                       |  7 +++
 6 files changed, 132 insertions(+), 1 deletion(-)

Comments

Avri Altman Feb. 20, 2025, 10:01 a.m. UTC | #1
> @@ -419,6 +421,7 @@ enum {
>  	MASK_EE_TOO_LOW_TEMP		= BIT(4),
>  	MASK_EE_WRITEBOOSTER_EVENT	= BIT(5),
>  	MASK_EE_PERFORMANCE_THROTTLING	= BIT(6),
> +	MASK_EE_DEV_LVL_EXCEPTION	= BIT(7),
>  };
I think you need to rebase your work - most probably for-next is best.

Thanks,
Avri
Bart Van Assche Feb. 20, 2025, 6:29 p.m. UTC | #2
On 2/20/25 2:01 AM, Avri Altman wrote:
>> @@ -419,6 +421,7 @@ enum {
>>   	MASK_EE_TOO_LOW_TEMP		= BIT(4),
>>   	MASK_EE_WRITEBOOSTER_EVENT	= BIT(5),
>>   	MASK_EE_PERFORMANCE_THROTTLING	= BIT(6),
>> +	MASK_EE_DEV_LVL_EXCEPTION	= BIT(7),
>>   };
 >
> I think you need to rebase your work - most probably for-next is best.

Hmm ... I think that Martin expects this kernel branch to be used as
basis for SCSI kernel patches intended for the next merge window:

https://git.kernel.org/pub/scm/linux/kernel/git/mkp/scsi.git/log/?h=staging

Thanks,

Bart.
diff mbox series

Patch

diff --git a/Documentation/ABI/testing/sysfs-driver-ufs b/Documentation/ABI/testing/sysfs-driver-ufs
index 5fa6655..e480115 100644
--- a/Documentation/ABI/testing/sysfs-driver-ufs
+++ b/Documentation/ABI/testing/sysfs-driver-ufs
@@ -1559,3 +1559,24 @@  Description:
 		Symbol - HCMID. This file shows the UFSHCD manufacturer id.
 		The Manufacturer ID is defined by JEDEC in JEDEC-JEP106.
 		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_lvl_exception
+What:		/sys/bus/platform/devices/*.ufs/device_lvl_exception
+Date:		February 2025
+Contact:	Bao D. Nguyen <quic_nguyenb@quicinc.com>
+Description:
+		Indicates the number times the device level exceptions have occurred
+		since the last device reset. Read the device_lvl_exception_id to know
+		more information about the exception id.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_lvl_exception_id
+What:		/sys/bus/platform/devices/*.ufs/device_lvl_exception_id
+Date:		February 2025
+Contact:	Bao D. Nguyen <quic_nguyenb@quicinc.com>
+Description:
+		This is the device JEDEC standard qDeviceLevelExceptionID attribute.
+		The definition of the qDeviceLevelExceptionID is the ufs device vendor specific.
+		Refer to the device manufacturer datasheet for more information
+		on the meaning of the qDeviceLevelExceptionID attribute value.
+		The file is read only.
diff --git a/drivers/ufs/core/ufs-sysfs.c b/drivers/ufs/core/ufs-sysfs.c
index 3438269..fd74ae0 100644
--- a/drivers/ufs/core/ufs-sysfs.c
+++ b/drivers/ufs/core/ufs-sysfs.c
@@ -458,6 +458,25 @@  static ssize_t pm_qos_enable_store(struct device *dev,
 	return count;
 }
 
+static ssize_t device_lvl_exception_show(struct device *dev,
+					 struct device_attribute *attr,
+					 char *buf)
+{
+	struct ufs_hba *hba = dev_get_drvdata(dev);
+
+	return sysfs_emit(buf, "%u\n", hba->dev_lvl_exception_count);
+}
+
+static ssize_t device_lvl_exception_id_show(struct device *dev,
+					    struct device_attribute *attr,
+					    char *buf)
+{
+	struct ufs_hba *hba = dev_get_drvdata(dev);
+
+	hba->dev_lvl_exception_count = 0;
+	return sysfs_emit(buf, "%llu\n", hba->dev_lvl_exception_id);
+}
+
 static DEVICE_ATTR_RW(rpm_lvl);
 static DEVICE_ATTR_RO(rpm_target_dev_state);
 static DEVICE_ATTR_RO(rpm_target_link_state);
@@ -470,6 +489,8 @@  static DEVICE_ATTR_RW(enable_wb_buf_flush);
 static DEVICE_ATTR_RW(wb_flush_threshold);
 static DEVICE_ATTR_RW(rtc_update_ms);
 static DEVICE_ATTR_RW(pm_qos_enable);
+static DEVICE_ATTR_RO(device_lvl_exception);
+static DEVICE_ATTR_RO(device_lvl_exception_id);
 
 static struct attribute *ufs_sysfs_ufshcd_attrs[] = {
 	&dev_attr_rpm_lvl.attr,
@@ -484,6 +505,8 @@  static struct attribute *ufs_sysfs_ufshcd_attrs[] = {
 	&dev_attr_wb_flush_threshold.attr,
 	&dev_attr_rtc_update_ms.attr,
 	&dev_attr_pm_qos_enable.attr,
+	&dev_attr_device_lvl_exception.attr,
+	&dev_attr_device_lvl_exception_id.attr,
 	NULL
 };
 
diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index cd404ad..4467777 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -5994,6 +5994,54 @@  static void ufshcd_temp_exception_event_handler(struct ufs_hba *hba, u16 status)
 	 */
 }
 
+static int ufshcd_read_device_lvl_exception_id(struct ufs_hba *hba,
+					       u64 *exception_id)
+{
+	struct ufs_query_req *request = NULL;
+	struct ufs_query_res *response = NULL;
+	struct utp_upiu_query_response_v4_0 *upiu_resp;
+	int err;
+
+	ufshcd_hold(hba);
+
+	mutex_lock(&hba->dev_cmd.lock);
+
+	ufshcd_init_query(hba, &request, &response,
+			  UPIU_QUERY_OPCODE_READ_ATTR,
+			  QUERY_ATTR_IDN_DEV_LVL_EXCEPTION_ID, 0, 0);
+
+	request->query_func = UPIU_QUERY_FUNC_STANDARD_READ_REQUEST;
+
+	err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, QUERY_REQ_TIMEOUT);
+
+	if (err) {
+		dev_err(hba->dev, "%s: failed to read device level exception %d\n",
+			__func__, err);
+		goto out;
+	}
+
+	upiu_resp = (struct utp_upiu_query_response_v4_0 *)response;
+	*exception_id = be64_to_cpu(upiu_resp->value);
+out:
+	mutex_unlock(&hba->dev_cmd.lock);
+	ufshcd_release(hba);
+
+	return err;
+}
+
+static void ufshcd_device_lvl_exception_event_handler(struct ufs_hba *hba)
+{
+	u64 *exception_id;
+	int err;
+
+	hba->dev_lvl_exception_count++;
+	exception_id = &hba->dev_lvl_exception_id;
+	err = ufshcd_read_device_lvl_exception_id(hba, exception_id);
+	if (err)
+		dev_err(hba->dev, "%s: read dev lvl exception id err=%d\n",
+			__func__, err);
+}
+
 static int __ufshcd_wb_toggle(struct ufs_hba *hba, bool set, enum flag_idn idn)
 {
 	u8 index;
@@ -6216,6 +6264,9 @@  static void ufshcd_exception_event_handler(struct work_struct *work)
 	if (status & hba->ee_drv_mask & MASK_EE_URGENT_TEMP)
 		ufshcd_temp_exception_event_handler(hba, status);
 
+	if (status & hba->ee_drv_mask & MASK_EE_DEV_LVL_EXCEPTION)
+		ufshcd_device_lvl_exception_event_handler(hba);
+
 	ufs_debugfs_exception_event(hba, status);
 }
 
@@ -8115,6 +8166,22 @@  static void ufshcd_temp_notif_probe(struct ufs_hba *hba, const u8 *desc_buf)
 	}
 }
 
+static void ufshcd_device_lvl_exception_probe(struct ufs_hba *hba, u8 *desc_buf)
+{
+	u32 ext_ufs_feature;
+
+	if (hba->dev_info.wspecversion < 0x410)
+		return;
+
+	ext_ufs_feature = get_unaligned_be32(desc_buf +
+				DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP);
+	if (!(ext_ufs_feature & UFS_DEV_LVL_EXCEPTION_SUP))
+		return;
+
+	hba->dev_lvl_exception_count = 0;
+	ufshcd_enable_ee(hba, MASK_EE_DEV_LVL_EXCEPTION);
+}
+
 static void ufshcd_set_rtt(struct ufs_hba *hba)
 {
 	struct ufs_dev_info *dev_info = &hba->dev_info;
@@ -8310,6 +8377,8 @@  static int ufs_get_device_desc(struct ufs_hba *hba)
 
 	ufs_init_rtc(hba, desc_buf);
 
+	ufshcd_device_lvl_exception_probe(hba, desc_buf);
+
 	/*
 	 * ufshcd_read_string_desc returns size of the string
 	 * reset the error value
diff --git a/include/uapi/scsi/scsi_bsg_ufs.h b/include/uapi/scsi/scsi_bsg_ufs.h
index 8c29e49..7a4e2f9 100644
--- a/include/uapi/scsi/scsi_bsg_ufs.h
+++ b/include/uapi/scsi/scsi_bsg_ufs.h
@@ -143,6 +143,14 @@  struct utp_upiu_query_v4_0 {
 	__be32 reserved;
 };
 
+struct utp_upiu_query_response_v4_0 {
+	__u8 opcode;
+	__u8 idn;
+	__u8 index;
+	__u8 selector;
+	__be64 value;
+};
+
 /**
  * struct utp_upiu_cmd - Command UPIU structure
  * @exp_data_transfer_len: Data Transfer Length DW-3
diff --git a/include/ufs/ufs.h b/include/ufs/ufs.h
index 89672ad..f2303e9 100644
--- a/include/ufs/ufs.h
+++ b/include/ufs/ufs.h
@@ -180,7 +180,8 @@  enum attr_idn {
 	QUERY_ATTR_IDN_AVAIL_WB_BUFF_SIZE       = 0x1D,
 	QUERY_ATTR_IDN_WB_BUFF_LIFE_TIME_EST    = 0x1E,
 	QUERY_ATTR_IDN_CURR_WB_BUFF_SIZE        = 0x1F,
-	QUERY_ATTR_IDN_TIMESTAMP		= 0x30
+	QUERY_ATTR_IDN_TIMESTAMP		= 0x30,
+	QUERY_ATTR_IDN_DEV_LVL_EXCEPTION_ID     = 0x34
 };
 
 /* Descriptor idn for Query requests */
@@ -390,6 +391,7 @@  enum {
 	UFS_DEV_EXT_TEMP_NOTIF		= BIT(6),
 	UFS_DEV_HPB_SUPPORT		= BIT(7),
 	UFS_DEV_WRITE_BOOSTER_SUP	= BIT(8),
+	UFS_DEV_LVL_EXCEPTION_SUP       = BIT(12),
 };
 #define UFS_DEV_HPB_SUPPORT_VERSION		0x310
 
@@ -419,6 +421,7 @@  enum {
 	MASK_EE_TOO_LOW_TEMP		= BIT(4),
 	MASK_EE_WRITEBOOSTER_EVENT	= BIT(5),
 	MASK_EE_PERFORMANCE_THROTTLING	= BIT(6),
+	MASK_EE_DEV_LVL_EXCEPTION	= BIT(7),
 };
 #define MASK_EE_URGENT_TEMP (MASK_EE_TOO_HIGH_TEMP | MASK_EE_TOO_LOW_TEMP)
 
diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h
index 650ff23..d9e8fdd 100644
--- a/include/ufs/ufshcd.h
+++ b/include/ufs/ufshcd.h
@@ -962,6 +962,10 @@  enum ufshcd_mcq_opr {
  * @ufs_rtc_update_work: A work for UFS RTC periodic update
  * @pm_qos_req: PM QoS request handle
  * @pm_qos_enabled: flag to check if pm qos is enabled
+ * @dev_lvl_exception_count: Number of device level exception events
+ * between device level exception id reads.
+ * @dev_lvl_exception_id: vendor specific information about the
+ * device level exception event.
  */
 struct ufs_hba {
 	void __iomem *mmio_base;
@@ -1130,6 +1134,9 @@  struct ufs_hba {
 	struct delayed_work ufs_rtc_update_work;
 	struct pm_qos_request pm_qos_req;
 	bool pm_qos_enabled;
+
+	u32 dev_lvl_exception_count;
+	u64 dev_lvl_exception_id;
 };
 
 /**