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:


Reply via email to