diff options
author | Andrey Markovytch <andreym@codeaurora.org> | 2016-04-14 16:02:05 +0300 |
---|---|---|
committer | Jeevan Shriram <jshriram@codeaurora.org> | 2016-04-25 17:46:15 -0700 |
commit | d9d0ee4b785cfd710c6ae6ea9695a8a6a2ab7855 (patch) | |
tree | eaa838d6f12fe859d9accd3f1ff63a715412890a /drivers/scsi/ufs | |
parent | fe9cbb77bf9b673eb3743b6986406c55e254c4ce (diff) |
scsi: ufs: qcom-ice: block further requests until ICE config is complete
Requests that need to go through the ICE must be setup with a key
before and have a key index ready. In cases where the key is not
ready as it is not in the key cache, the ICE 'config_start' callback
returns -EAGAIN and we need to block further requests and call
'config_start' again from a non-atomic context until key setup
is ready and then resume requests handling.
Change-Id: I51ff1e99240386ce533b5ab3f5f024043532b0ad
Signed-off-by: Gilad Broner <gbroner@codeaurora.org>
Signed-off-by: Andrey Markovytch <andreym@codeaurora.org>
Diffstat (limited to 'drivers/scsi/ufs')
-rw-r--r-- | drivers/scsi/ufs/ufs-qcom-ice.c | 47 | ||||
-rw-r--r-- | drivers/scsi/ufs/ufs-qcom.h | 3 | ||||
-rw-r--r-- | drivers/scsi/ufs/ufshcd.c | 36 |
3 files changed, 74 insertions, 12 deletions
diff --git a/drivers/scsi/ufs/ufs-qcom-ice.c b/drivers/scsi/ufs/ufs-qcom-ice.c index 195f6b39989d..6d2a8f8cf3c1 100644 --- a/drivers/scsi/ufs/ufs-qcom-ice.c +++ b/drivers/scsi/ufs/ufs-qcom-ice.c @@ -164,7 +164,35 @@ int ufs_qcom_ice_get_dev(struct ufs_qcom_host *qcom_host) out: return err; +} + +static void ufs_qcom_ice_cfg_work(struct work_struct *work) +{ + struct ice_data_setting ice_set; + struct ufs_qcom_host *qcom_host = + container_of(work, struct ufs_qcom_host, ice_cfg_work); + + if (!qcom_host->ice.vops->config_start || !qcom_host->req_pending) + return; + + memset(&ice_set, 0, sizeof(ice_set)); + + /* + * config_start is called again as previous attempt returned -EAGAIN, + * this call shall now take care of the necessary key setup. + * 'ice_set' will not actually be used, instead the next call to + * config_start() for this request, in the normal call flow, will + * succeed as the key has now been setup. + */ + qcom_host->ice.vops->config_start(qcom_host->ice.pdev, + qcom_host->req_pending, &ice_set, false); + /* + * Resume with requests processing. We assume config_start has been + * successful, but even if it wasn't we still must resume in order to + * allow for the request to be retried. + */ + ufshcd_scsi_unblock_requests(qcom_host->hba); } /** @@ -193,6 +221,7 @@ int ufs_qcom_ice_init(struct ufs_qcom_host *qcom_host) } qcom_host->dbg_print_en |= UFS_QCOM_ICE_DEFAULT_DBG_PRINT_EN; + INIT_WORK(&qcom_host->ice_cfg_work, ufs_qcom_ice_cfg_work); out: return err; @@ -300,8 +329,22 @@ int ufs_qcom_ice_cfg_start(struct ufs_qcom_host *qcom_host, err = qcom_host->ice.vops->config_start(qcom_host->ice.pdev, req, &ice_set, true); if (err) { - dev_err(dev, "%s: error in ice_vops->config %d\n", - __func__, err); + /* + * config_start() returns -EAGAIN when a key slot is + * available but still not configured. As configuration + * requires a non-atomic context, this means we should + * call the function again from the worker thread to do + * the configuration. For this request the error will + * propagate so it will be re-queued and until the + * configuration is is completed we block further + * request processing. + */ + if (err == -EAGAIN) { + qcom_host->req_pending = req; + if (schedule_work(&qcom_host->ice_cfg_work)) + ufshcd_scsi_block_requests( + qcom_host->hba); + } goto out; } } diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h index 7dbae4764c5e..ec22c290c45d 100644 --- a/drivers/scsi/ufs/ufs-qcom.h +++ b/drivers/scsi/ufs/ufs-qcom.h @@ -337,6 +337,9 @@ struct ufs_qcom_host { /* Bitmask for enabling debug prints */ u32 dbg_print_en; struct ufs_qcom_testbus testbus; + + struct work_struct ice_cfg_work; + struct request *req_pending; }; static inline u32 diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 66d66f9799df..6863cc1013f8 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -1954,14 +1954,6 @@ int ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag) { int ret = 0; - ret = ufshcd_vops_crypto_engine_cfg_start(hba, task_tag); - if (ret) { - dev_err(hba->dev, - "%s: failed to configure crypto engine %d\n", - __func__, ret); - return ret; - } - hba->lrb[task_tag].issue_time_stamp = ktime_get(); hba->lrb[task_tag].complete_time_stamp = ktime_set(0, 0); ufshcd_clk_scaling_start_busy(hba); @@ -2627,6 +2619,22 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) goto out; } + err = ufshcd_vops_crypto_engine_cfg_start(hba, tag); + if (err) { + if (err != -EAGAIN) + dev_err(hba->dev, + "%s: failed to configure crypto engine %d\n", + __func__, err); + + scsi_dma_unmap(lrbp->cmd); + lrbp->cmd = NULL; + clear_bit_unlock(tag, &hba->lrb_in_use); + ufshcd_release_all(hba); + ufshcd_vops_pm_qos_req_end(hba, cmd->request, true); + + goto out; + } + /* Make sure descriptors are ready before ringing the doorbell */ wmb(); /* issue command to the controller */ @@ -2640,6 +2648,7 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) clear_bit_unlock(tag, &hba->lrb_in_use); ufshcd_release_all(hba); ufshcd_vops_pm_qos_req_end(hba, cmd->request, true); + ufshcd_vops_crypto_engine_cfg_end(hba, lrbp, cmd->request); dev_err(hba->dev, "%s: failed sending command, %d\n", __func__, err); err = DID_ERROR; @@ -4938,7 +4947,7 @@ void ufshcd_abort_outstanding_transfer_requests(struct ufs_hba *hba, int result) /* Mark completed command as NULL in LRB */ lrbp->cmd = NULL; ufshcd_release_all(hba); - if (cmd->request) + if (cmd->request) { /* * As we are accessing the "request" structure, * this must be called before calling @@ -4946,6 +4955,9 @@ void ufshcd_abort_outstanding_transfer_requests(struct ufs_hba *hba, int result) */ ufshcd_vops_pm_qos_req_end(hba, cmd->request, true); + ufshcd_vops_crypto_engine_cfg_end(hba, + lrbp, cmd->request); + } /* Do not touch lrbp after scsi done */ cmd->scsi_done(cmd); } else if (lrbp->command_type == UTP_CMD_TYPE_DEV_MANAGE) { @@ -4990,7 +5002,7 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba, lrbp->cmd = NULL; __ufshcd_release(hba, false); __ufshcd_hibern8_release(hba, false); - if (cmd->request) + if (cmd->request) { /* * As we are accessing the "request" structure, * this must be called before calling @@ -4998,6 +5010,10 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba, */ ufshcd_vops_pm_qos_req_end(hba, cmd->request, false); + ufshcd_vops_crypto_engine_cfg_end(hba, + lrbp, cmd->request); + } + /* Do not touch lrbp after scsi done */ cmd->scsi_done(cmd); } else if (lrbp->command_type == UTP_CMD_TYPE_DEV_MANAGE) { |