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

Daejun Park
2021-03-05T00:35:34Z

Hi Bean,

> > +
> > +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-
> > >request));
> > + pre_req->wb.len = sectors_to_logical(cmd->device,
> > + blk_rq_sectors(cmd-
> > >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-
> > >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-
> > >request));
> > if (unlikely(!transfer_len))
> > - return;
> > + return 0;
> >
> > lpn = sectors_to_logical(cmd->device, blk_rq_pos(cmd-
> > >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