On 9/4/26 09:12, Alexey Charkov wrote:
A logical unit explains a CHECK CONDITION through its sense data, and
I'm not sure about the "A logical unit explains a CHECK CONDITION through its sense
data",
I would say instead "A logical unit exposes a CHECK CONDITION through its sense
data".
without it a caller cannot tell a transient condition from a permanent
one. struct scsi_cmd has carried a sense buffer all along that no driver
ever filled, so fill it, and clear the length in scsi_exec() so that one
command cannot be read as another's sense.
Signed-off-by: Alexey Charkov <[email protected]>
---
drivers/scsi/scsi-uclass.c | 3 +++
drivers/ufs/ufs-uclass.c | 23 ++++++++++++++++++++++-
2 files changed, 25 insertions(+), 1 deletion(-)
diff --git a/drivers/scsi/scsi-uclass.c b/drivers/scsi/scsi-uclass.c
index 39b4c7476d45..54afac6eaf51 100644
--- a/drivers/scsi/scsi-uclass.c
+++ b/drivers/scsi/scsi-uclass.c
@@ -22,6 +22,9 @@ int scsi_exec(struct udevice *dev, struct scsi_cmd *pccb)
if (!ops->exec)
return -ENOSYS;
+ /* Whatever a previous command left behind is not this command's sense */
+ pccb->sensedatalen = 0;
+
return ops->exec(dev, pccb);
}
diff --git a/drivers/ufs/ufs-uclass.c b/drivers/ufs/ufs-uclass.c
index 6ef01f8e4aa7..acaecfa1e341 100644
--- a/drivers/ufs/ufs-uclass.c
+++ b/drivers/ufs/ufs-uclass.c
@@ -1657,6 +1657,24 @@ static void prepare_prdt_table(struct ufs_hba *hba,
struct scsi_cmd *pccb)
ufshcd_cache_flush(req_desc, sizeof(*req_desc));
}
+/**
+ * ufshcd_copy_sense_data - hand the response sense data to the SCSI layer
+ *
+ * A logical unit explains a CHECK CONDITION through its sense data, which the
+ * caller needs to tell a transient condition from a permanent one.
+ */
+static void ufshcd_copy_sense_data(struct ufs_hba *hba, struct scsi_cmd *pccb)
+{
+ struct utp_upiu_rsp *rsp = hba->ucd_rsp_ptr;
+ u16 len = be16_to_cpu(rsp->sr.sense_data_len);
+
+ len = min_t(u16, len, RESPONSE_UPIU_SENSE_DATA_LENGTH);
+ len = min_t(u16, len, sizeof(pccb->sense_buf));
+
+ memcpy(pccb->sense_buf, rsp->sr.sense_data, len);
+ pccb->sensedatalen = len;
+}
+
static int ufs_scsi_exec(struct udevice *scsi_dev, struct scsi_cmd *pccb)
{
struct ufs_hba *hba = dev_get_uclass_priv(scsi_dev->parent);
@@ -1683,8 +1701,11 @@ static int ufs_scsi_exec(struct udevice *scsi_dev,
struct scsi_cmd *pccb)
result = ufshcd_get_rsp_upiu_result(hba->ucd_rsp_ptr);
scsi_status = result & MASK_SCSI_STATUS;
- if (scsi_status)
+ if (scsi_status) {
+ ufshcd_copy_sense_data(hba, pccb);
+ pccb->status = scsi_status;
return -EINVAL;
+ }
break;
case UPIU_TRANSACTION_REJECT_UPIU: