Thread (26 messages) 26 messages, 4 authors, 2021-03-15

RE: Re: [PATCH v26 4/4] scsi: ufs: Add HPB 2.0 support

From: Daejun Park <hidden>
Date: 2021-03-05 00:35:34
Also in: lkml

Hi Bean,
quoted
+
+static inline int ufshpb_get_read_id(struct ufshpb_lu *hpb)
+{
+       if (++hpb->cur_read_id >= MAX_HPB_READ_ID)
+               hpb->cur_read_id = 0;
+       return hpb->cur_read_id;
+}
+
+static int ufshpb_execute_pre_req(struct ufshpb_lu *hpb, struct
scsi_cmnd *cmd,
+                                 struct ufshpb_req *pre_req, int
read_id)
+{
+       struct scsi_device *sdev = cmd->device;
+       struct request_queue *q = sdev->request_queue;
+       struct request *req;
+       struct scsi_request *rq;
+       struct bio *bio = pre_req->bio;
+
+       pre_req->hpb = hpb;
+       pre_req->wb.lpn = sectors_to_logical(cmd->device,
+                                            blk_rq_pos(cmd-
quoted
request));
+       pre_req->wb.len = sectors_to_logical(cmd->device,
+                                            blk_rq_sectors(cmd-
quoted
request));
+       if (ufshpb_pre_req_add_bio_page(hpb, q, pre_req))
+               return -ENOMEM;
+
+       req = pre_req->req;
+
+       /* 1. request setup */
+       blk_rq_append_bio(req, &bio);
+       req->rq_disk = NULL;
+       req->end_io_data = (void *)pre_req;
+       req->end_io = ufshpb_pre_req_compl_fn;
+
+       /* 2. scsi_request setup */
+       rq = scsi_req(req);
+       rq->retries = 1;
+
+       ufshpb_set_write_buf_cmd(rq->cmd, pre_req->wb.lpn, pre_req-
quoted
wb.len,
+                                read_id);
+       rq->cmd_len = scsi_command_size(rq->cmd);
+
+       if (blk_insert_cloned_request(q, req) != BLK_STS_OK)
+               return -EAGAIN;
+
+       hpb->stats.pre_req_cnt++;
+
+       return 0;
+}
+
+static int ufshpb_issue_pre_req(struct ufshpb_lu *hpb, struct
scsi_cmnd *cmd,
+                               int *read_id)
+{
+       struct ufshpb_req *pre_req;
+       struct request *req = NULL;
+       struct bio *bio = NULL;
+       unsigned long flags;
+       int _read_id;
+       int ret = 0;
+
+       req = blk_get_request(cmd->device->request_queue,
+                             REQ_OP_SCSI_OUT | REQ_SYNC,
BLK_MQ_REQ_NOWAIT);
+       if (IS_ERR(req))
+               return -EAGAIN;
+
+       bio = bio_alloc(GFP_ATOMIC, 1);
+       if (!bio) {
+               blk_put_request(req);
+               return -EAGAIN;
+       }
+
+       spin_lock_irqsave(&hpb->rgn_state_lock, flags);
+       pre_req = ufshpb_get_pre_req(hpb);
+       if (!pre_req) {
+               ret = -EAGAIN;
+               goto unlock_out;
+       }
+       _read_id = ufshpb_get_read_id(hpb);
+       spin_unlock_irqrestore(&hpb->rgn_state_lock, flags);
+
+       pre_req->req = req;
+       pre_req->bio = bio;
+
+       ret = ufshpb_execute_pre_req(hpb, cmd, pre_req, _read_id);
+       if (ret)
+               goto free_pre_req;
+
+       *read_id = _read_id;
+
+       return ret;
+free_pre_req:
+       spin_lock_irqsave(&hpb->rgn_state_lock, flags);
+       ufshpb_put_pre_req(hpb, pre_req);
+unlock_out:
+       spin_unlock_irqrestore(&hpb->rgn_state_lock, flags);
+       bio_put(bio);
+       blk_put_request(req);
+       return ret;
+}
+
 /*
  * This function will set up HPB read command using host-side L2P
map data.
- * In HPB v1.0, maximum size of HPB read command is 4KB.
  */
-void ufshpb_prep(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
+int ufshpb_prep(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
 {
        struct ufshpb_lu *hpb;
        struct ufshpb_region *rgn;
@@ -291,26 +560,27 @@ void ufshpb_prep(struct ufs_hba *hba, struct
ufshcd_lrb *lrbp)
        u64 ppn;
        unsigned long flags;
        int transfer_len, rgn_idx, srgn_idx, srgn_offset;
+       int read_id = 0;
        int err = 0;
 
        hpb = ufshpb_get_hpb_data(cmd->device);
        if (!hpb)
-               return;
+               return -ENODEV;
 
        if (ufshpb_get_state(hpb) != HPB_PRESENT) {
                dev_notice(&hpb->sdev_ufs_lu->sdev_dev,
                           "%s: ufshpb state is not PRESENT",
__func__);
-               return;
+               return -ENODEV;
        }
 
        if (!ufshpb_is_write_or_discard_cmd(cmd) &&
            !ufshpb_is_read_cmd(cmd))
-               return;
+               return 0;
 
        transfer_len = sectors_to_logical(cmd->device,
                                          blk_rq_sectors(cmd-
quoted
request));
        if (unlikely(!transfer_len))
-               return;
+               return 0;
 
        lpn = sectors_to_logical(cmd->device, blk_rq_pos(cmd-
quoted
request));
        ufshpb_get_pos_from_lpn(hpb, lpn, &rgn_idx, &srgn_idx,
&srgn_offset);
@@ -323,18 +593,19 @@ void ufshpb_prep(struct ufs_hba *hba, struct
ufshcd_lrb *lrbp)
                ufshpb_set_ppn_dirty(hpb, rgn_idx, srgn_idx,
srgn_offset,
                                 transfer_len);
                spin_unlock_irqrestore(&hpb->rgn_state_lock, flags);
-               return;
+               return 0;
        }
 
-       if (!ufshpb_is_support_chunk(transfer_len))
-               return;
+       if (!ufshpb_is_support_chunk(hpb, transfer_len) &&
+           (ufshpb_is_legacy(hba) && (transfer_len !=
HPB_LEGACY_CHUNK_HIGH)))
+               return 0;
 
        spin_lock_irqsave(&hpb->rgn_state_lock, flags);
        if (ufshpb_test_ppn_dirty(hpb, rgn_idx, srgn_idx,
srgn_offset,
                                   transfer_len)) {
                hpb->stats.miss_cnt++;
                spin_unlock_irqrestore(&hpb->rgn_state_lock, flags);
-               return;
+               return 0;
        }
 
        err = ufshpb_fill_ppn_from_page(hpb, srgn->mctx, srgn_offset,
1, &ppn);
@@ -347,28 +618,46 @@ void ufshpb_prep(struct ufs_hba *hba, struct
ufshcd_lrb *lrbp)
                 * active state.
                 */
                dev_err(hba->dev, "get ppn failed. err %d\n", err);
-               return;
+               return err;
+       }
+
+       if (!ufshpb_is_legacy(hba) &&
+           ufshpb_is_required_wb(hpb, transfer_len)) {
+               err = ufshpb_issue_pre_req(hpb, cmd, &read_id);
+               if (err) {
+                       unsigned long timeout;
+
+                       timeout = cmd->jiffies_at_alloc +
msecs_to_jiffies(
+                                 hpb->params.requeue_timeout_ms);
+
+                       if (time_before(jiffies, timeout))
+                               return -EAGAIN;
+
+                       hpb->stats.miss_cnt++;
+                       return 0;
+               }
        }
 
-       ufshpb_set_hpb_read_to_upiu(hpb, lrbp, lpn, ppn,
transfer_len);
+       ufshpb_set_hpb_read_to_upiu(hpb, lrbp, lpn, ppn,
transfer_len, read_id);
 
        hpb->stats.hit_cnt++;
+       return 0;
 }
 
 
 
BUG!!!
 
 
Please read HPB 2.0 Spec carefully, and check how to correctly use HPB
READ ID. you are assigning 0 for HPB write buffer. how can you expect
the HPB READ be paired???
 
I fixed as follows,

static inline int ufshpb_get_read_id(struct ufshpb_lu *hpb)
{
	if (hpb->cur_read_id >= MAX_HPB_READ_ID)
		hpb->cur_read_id = 0;
	return ++hpb->cur_read_id;
}

Thanks for comments, I will check carefully.

Thanks,
Daejun
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help