scsi: ufs: Fix ufshcd_request_sense_async() for Samsung KLUFG8RHDA-B2D1
[linux-2.6-microblaze.git] / drivers / scsi / ufs / ufshcd.c
index b408be3..3841ab4 100644 (file)
@@ -360,11 +360,12 @@ static void ufshcd_add_uic_command_trace(struct ufs_hba *hba,
 static void ufshcd_add_command_trace(struct ufs_hba *hba, unsigned int tag,
                                     enum ufs_trace_str_t str_t)
 {
-       u64 lba = -1;
+       u64 lba;
        u8 opcode = 0, group_id = 0;
        u32 intr, doorbell;
        struct ufshcd_lrb *lrbp = &hba->lrb[tag];
        struct scsi_cmnd *cmd = lrbp->cmd;
+       struct request *rq = scsi_cmd_to_rq(cmd);
        int transfer_len = -1;
 
        if (!cmd)
@@ -390,7 +391,7 @@ static void ufshcd_add_command_trace(struct ufs_hba *hba, unsigned int tag,
                /*
                 * The number of Bytes to be unmapped beginning with the lba.
                 */
-               transfer_len = blk_rq_bytes(cmd->request);
+               transfer_len = blk_rq_bytes(rq);
        }
 
        intr = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
@@ -2054,7 +2055,7 @@ static void ufshcd_update_monitor(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
 
        spin_lock_irqsave(hba->host->host_lock, flags);
        if (dir >= 0 && hba->monitor.nr_queued[dir] > 0) {
-               struct request *req = lrbp->cmd->request;
+               struct request *req = scsi_cmd_to_rq(lrbp->cmd);
                struct ufs_hba_monitor *m = &hba->monitor;
                ktime_t now, inc, lat;
 
@@ -2675,7 +2676,7 @@ static void ufshcd_init_lrb(struct ufs_hba *hba, struct ufshcd_lrb *lrb, int i)
 static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
 {
        struct ufs_hba *hba = shost_priv(host);
-       int tag = cmd->request->tag;
+       int tag = scsi_cmd_to_rq(cmd)->tag;
        struct ufshcd_lrb *lrbp;
        int err = 0;
 
@@ -2734,7 +2735,7 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
        lrbp->lun = ufshcd_scsi_to_upiu_lun(cmd->device->lun);
        lrbp->intr_cmd = !ufshcd_is_intr_aggr_allowed(hba) ? true : false;
 
-       ufshcd_prepare_lrbp_crypto(cmd->request, lrbp);
+       ufshcd_prepare_lrbp_crypto(scsi_cmd_to_rq(cmd), lrbp);
 
        lrbp->req_abort_skip = false;
 
@@ -6993,7 +6994,7 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
 {
        struct Scsi_Host *host = cmd->device->host;
        struct ufs_hba *hba = shost_priv(host);
-       int tag = cmd->request->tag;
+       int tag = scsi_cmd_to_rq(cmd)->tag;
        struct ufshcd_lrb *lrbp = &hba->lrb[tag];
        unsigned long flags;
        int err = FAILED;
@@ -7936,7 +7937,8 @@ out:
 static void ufshcd_request_sense_done(struct request *rq, blk_status_t error)
 {
        if (error != BLK_STS_OK)
-               pr_err("%s: REQUEST SENSE failed (%d)", __func__, error);
+               pr_err("%s: REQUEST SENSE failed (%d)\n", __func__, error);
+       kfree(rq->end_io_data);
        blk_put_request(rq);
 }
 
@@ -7944,16 +7946,30 @@ static int
 ufshcd_request_sense_async(struct ufs_hba *hba, struct scsi_device *sdev)
 {
        /*
-        * From SPC-6: the REQUEST SENSE command with any allocation length
-        * clears the sense data.
+        * Some UFS devices clear unit attention condition only if the sense
+        * size used (UFS_SENSE_SIZE in this case) is non-zero.
         */
-       static const u8 cmd[6] = {REQUEST_SENSE, 0, 0, 0, 0, 0};
+       static const u8 cmd[6] = {REQUEST_SENSE, 0, 0, 0, UFS_SENSE_SIZE, 0};
        struct scsi_request *rq;
        struct request *req;
+       char *buffer;
+       int ret;
 
-       req = blk_get_request(sdev->request_queue, REQ_OP_DRV_IN, /*flags=*/0);
-       if (IS_ERR(req))
-               return PTR_ERR(req);
+       buffer = kzalloc(UFS_SENSE_SIZE, GFP_KERNEL);
+       if (!buffer)
+               return -ENOMEM;
+
+       req = blk_get_request(sdev->request_queue, REQ_OP_DRV_IN,
+                             /*flags=*/BLK_MQ_REQ_PM);
+       if (IS_ERR(req)) {
+               ret = PTR_ERR(req);
+               goto out_free;
+       }
+
+       ret = blk_rq_map_kern(sdev->request_queue, req,
+                             buffer, UFS_SENSE_SIZE, GFP_NOIO);
+       if (ret)
+               goto out_put;
 
        rq = scsi_req(req);
        rq->cmd_len = ARRAY_SIZE(cmd);
@@ -7961,10 +7977,17 @@ ufshcd_request_sense_async(struct ufs_hba *hba, struct scsi_device *sdev)
        rq->retries = 3;
        req->timeout = 1 * HZ;
        req->rq_flags |= RQF_PM | RQF_QUIET;
+       req->end_io_data = buffer;
 
        blk_execute_rq_nowait(/*bd_disk=*/NULL, req, /*at_head=*/true,
                              ufshcd_request_sense_done);
        return 0;
+
+out_put:
+       blk_put_request(req);
+out_free:
+       kfree(buffer);
+       return ret;
 }
 
 static int ufshcd_clear_ua_wlun(struct ufs_hba *hba, u8 wlun)