162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2022 Qualcomm Innovation Center. All rights reserved. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Authors: 662306a36Sopenharmony_ci * Asutosh Das <quic_asutoshd@quicinc.com> 762306a36Sopenharmony_ci * Can Guo <quic_cang@quicinc.com> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <asm/unaligned.h> 1162306a36Sopenharmony_ci#include <linux/dma-mapping.h> 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/platform_device.h> 1462306a36Sopenharmony_ci#include "ufshcd-priv.h" 1562306a36Sopenharmony_ci#include <linux/delay.h> 1662306a36Sopenharmony_ci#include <scsi/scsi_cmnd.h> 1762306a36Sopenharmony_ci#include <linux/bitfield.h> 1862306a36Sopenharmony_ci#include <linux/iopoll.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#define MAX_QUEUE_SUP GENMASK(7, 0) 2162306a36Sopenharmony_ci#define UFS_MCQ_MIN_RW_QUEUES 2 2262306a36Sopenharmony_ci#define UFS_MCQ_MIN_READ_QUEUES 0 2362306a36Sopenharmony_ci#define UFS_MCQ_MIN_POLL_QUEUES 0 2462306a36Sopenharmony_ci#define QUEUE_EN_OFFSET 31 2562306a36Sopenharmony_ci#define QUEUE_ID_OFFSET 16 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#define MCQ_CFG_MAC_MASK GENMASK(16, 8) 2862306a36Sopenharmony_ci#define MCQ_QCFG_SIZE 0x40 2962306a36Sopenharmony_ci#define MCQ_ENTRY_SIZE_IN_DWORD 8 3062306a36Sopenharmony_ci#define CQE_UCD_BA GENMASK_ULL(63, 7) 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci/* Max mcq register polling time in microseconds */ 3362306a36Sopenharmony_ci#define MCQ_POLL_US 500000 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic int rw_queue_count_set(const char *val, const struct kernel_param *kp) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci return param_set_uint_minmax(val, kp, UFS_MCQ_MIN_RW_QUEUES, 3862306a36Sopenharmony_ci num_possible_cpus()); 3962306a36Sopenharmony_ci} 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistatic const struct kernel_param_ops rw_queue_count_ops = { 4262306a36Sopenharmony_ci .set = rw_queue_count_set, 4362306a36Sopenharmony_ci .get = param_get_uint, 4462306a36Sopenharmony_ci}; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic unsigned int rw_queues; 4762306a36Sopenharmony_cimodule_param_cb(rw_queues, &rw_queue_count_ops, &rw_queues, 0644); 4862306a36Sopenharmony_ciMODULE_PARM_DESC(rw_queues, 4962306a36Sopenharmony_ci "Number of interrupt driven I/O queues used for rw. Default value is nr_cpus"); 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistatic int read_queue_count_set(const char *val, const struct kernel_param *kp) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci return param_set_uint_minmax(val, kp, UFS_MCQ_MIN_READ_QUEUES, 5462306a36Sopenharmony_ci num_possible_cpus()); 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistatic const struct kernel_param_ops read_queue_count_ops = { 5862306a36Sopenharmony_ci .set = read_queue_count_set, 5962306a36Sopenharmony_ci .get = param_get_uint, 6062306a36Sopenharmony_ci}; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic unsigned int read_queues; 6362306a36Sopenharmony_cimodule_param_cb(read_queues, &read_queue_count_ops, &read_queues, 0644); 6462306a36Sopenharmony_ciMODULE_PARM_DESC(read_queues, 6562306a36Sopenharmony_ci "Number of interrupt driven read queues used for read. Default value is 0"); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic int poll_queue_count_set(const char *val, const struct kernel_param *kp) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci return param_set_uint_minmax(val, kp, UFS_MCQ_MIN_POLL_QUEUES, 7062306a36Sopenharmony_ci num_possible_cpus()); 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistatic const struct kernel_param_ops poll_queue_count_ops = { 7462306a36Sopenharmony_ci .set = poll_queue_count_set, 7562306a36Sopenharmony_ci .get = param_get_uint, 7662306a36Sopenharmony_ci}; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistatic unsigned int poll_queues = 1; 7962306a36Sopenharmony_cimodule_param_cb(poll_queues, &poll_queue_count_ops, &poll_queues, 0644); 8062306a36Sopenharmony_ciMODULE_PARM_DESC(poll_queues, 8162306a36Sopenharmony_ci "Number of poll queues used for r/w. Default value is 1"); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci/** 8462306a36Sopenharmony_ci * ufshcd_mcq_config_mac - Set the #Max Activ Cmds. 8562306a36Sopenharmony_ci * @hba: per adapter instance 8662306a36Sopenharmony_ci * @max_active_cmds: maximum # of active commands to the device at any time. 8762306a36Sopenharmony_ci * 8862306a36Sopenharmony_ci * The controller won't send more than the max_active_cmds to the device at 8962306a36Sopenharmony_ci * any time. 9062306a36Sopenharmony_ci */ 9162306a36Sopenharmony_civoid ufshcd_mcq_config_mac(struct ufs_hba *hba, u32 max_active_cmds) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci u32 val; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci val = ufshcd_readl(hba, REG_UFS_MCQ_CFG); 9662306a36Sopenharmony_ci val &= ~MCQ_CFG_MAC_MASK; 9762306a36Sopenharmony_ci val |= FIELD_PREP(MCQ_CFG_MAC_MASK, max_active_cmds); 9862306a36Sopenharmony_ci ufshcd_writel(hba, val, REG_UFS_MCQ_CFG); 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ufshcd_mcq_config_mac); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci/** 10362306a36Sopenharmony_ci * ufshcd_mcq_req_to_hwq - find the hardware queue on which the 10462306a36Sopenharmony_ci * request would be issued. 10562306a36Sopenharmony_ci * @hba: per adapter instance 10662306a36Sopenharmony_ci * @req: pointer to the request to be issued 10762306a36Sopenharmony_ci * 10862306a36Sopenharmony_ci * Return: the hardware queue instance on which the request would 10962306a36Sopenharmony_ci * be queued. 11062306a36Sopenharmony_ci */ 11162306a36Sopenharmony_cistruct ufs_hw_queue *ufshcd_mcq_req_to_hwq(struct ufs_hba *hba, 11262306a36Sopenharmony_ci struct request *req) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci u32 utag = blk_mq_unique_tag(req); 11562306a36Sopenharmony_ci u32 hwq = blk_mq_unique_tag_to_hwq(utag); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci return &hba->uhq[hwq]; 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci/** 12162306a36Sopenharmony_ci * ufshcd_mcq_decide_queue_depth - decide the queue depth 12262306a36Sopenharmony_ci * @hba: per adapter instance 12362306a36Sopenharmony_ci * 12462306a36Sopenharmony_ci * Return: queue-depth on success, non-zero on error 12562306a36Sopenharmony_ci * 12662306a36Sopenharmony_ci * MAC - Max. Active Command of the Host Controller (HC) 12762306a36Sopenharmony_ci * HC wouldn't send more than this commands to the device. 12862306a36Sopenharmony_ci * It is mandatory to implement get_hba_mac() to enable MCQ mode. 12962306a36Sopenharmony_ci * Calculates and adjusts the queue depth based on the depth 13062306a36Sopenharmony_ci * supported by the HC and ufs device. 13162306a36Sopenharmony_ci */ 13262306a36Sopenharmony_ciint ufshcd_mcq_decide_queue_depth(struct ufs_hba *hba) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci int mac; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci /* Mandatory to implement get_hba_mac() */ 13762306a36Sopenharmony_ci mac = ufshcd_mcq_vops_get_hba_mac(hba); 13862306a36Sopenharmony_ci if (mac < 0) { 13962306a36Sopenharmony_ci dev_err(hba->dev, "Failed to get mac, err=%d\n", mac); 14062306a36Sopenharmony_ci return mac; 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci WARN_ON_ONCE(!hba->dev_info.bqueuedepth); 14462306a36Sopenharmony_ci /* 14562306a36Sopenharmony_ci * max. value of bqueuedepth = 256, mac is host dependent. 14662306a36Sopenharmony_ci * It is mandatory for UFS device to define bQueueDepth if 14762306a36Sopenharmony_ci * shared queuing architecture is enabled. 14862306a36Sopenharmony_ci */ 14962306a36Sopenharmony_ci return min_t(int, mac, hba->dev_info.bqueuedepth); 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cistatic int ufshcd_mcq_config_nr_queues(struct ufs_hba *hba) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci int i; 15562306a36Sopenharmony_ci u32 hba_maxq, rem, tot_queues; 15662306a36Sopenharmony_ci struct Scsi_Host *host = hba->host; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci /* maxq is 0 based value */ 15962306a36Sopenharmony_ci hba_maxq = FIELD_GET(MAX_QUEUE_SUP, hba->mcq_capabilities) + 1; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci tot_queues = read_queues + poll_queues + rw_queues; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci if (hba_maxq < tot_queues) { 16462306a36Sopenharmony_ci dev_err(hba->dev, "Total queues (%d) exceeds HC capacity (%d)\n", 16562306a36Sopenharmony_ci tot_queues, hba_maxq); 16662306a36Sopenharmony_ci return -EOPNOTSUPP; 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci rem = hba_maxq; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci if (rw_queues) { 17262306a36Sopenharmony_ci hba->nr_queues[HCTX_TYPE_DEFAULT] = rw_queues; 17362306a36Sopenharmony_ci rem -= hba->nr_queues[HCTX_TYPE_DEFAULT]; 17462306a36Sopenharmony_ci } else { 17562306a36Sopenharmony_ci rw_queues = num_possible_cpus(); 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci if (poll_queues) { 17962306a36Sopenharmony_ci hba->nr_queues[HCTX_TYPE_POLL] = poll_queues; 18062306a36Sopenharmony_ci rem -= hba->nr_queues[HCTX_TYPE_POLL]; 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci if (read_queues) { 18462306a36Sopenharmony_ci hba->nr_queues[HCTX_TYPE_READ] = read_queues; 18562306a36Sopenharmony_ci rem -= hba->nr_queues[HCTX_TYPE_READ]; 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci if (!hba->nr_queues[HCTX_TYPE_DEFAULT]) 18962306a36Sopenharmony_ci hba->nr_queues[HCTX_TYPE_DEFAULT] = min3(rem, rw_queues, 19062306a36Sopenharmony_ci num_possible_cpus()); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci for (i = 0; i < HCTX_MAX_TYPES; i++) 19362306a36Sopenharmony_ci host->nr_hw_queues += hba->nr_queues[i]; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci hba->nr_hw_queues = host->nr_hw_queues; 19662306a36Sopenharmony_ci return 0; 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ciint ufshcd_mcq_memory_alloc(struct ufs_hba *hba) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci struct ufs_hw_queue *hwq; 20262306a36Sopenharmony_ci size_t utrdl_size, cqe_size; 20362306a36Sopenharmony_ci int i; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci for (i = 0; i < hba->nr_hw_queues; i++) { 20662306a36Sopenharmony_ci hwq = &hba->uhq[i]; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci utrdl_size = sizeof(struct utp_transfer_req_desc) * 20962306a36Sopenharmony_ci hwq->max_entries; 21062306a36Sopenharmony_ci hwq->sqe_base_addr = dmam_alloc_coherent(hba->dev, utrdl_size, 21162306a36Sopenharmony_ci &hwq->sqe_dma_addr, 21262306a36Sopenharmony_ci GFP_KERNEL); 21362306a36Sopenharmony_ci if (!hwq->sqe_dma_addr) { 21462306a36Sopenharmony_ci dev_err(hba->dev, "SQE allocation failed\n"); 21562306a36Sopenharmony_ci return -ENOMEM; 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci cqe_size = sizeof(struct cq_entry) * hwq->max_entries; 21962306a36Sopenharmony_ci hwq->cqe_base_addr = dmam_alloc_coherent(hba->dev, cqe_size, 22062306a36Sopenharmony_ci &hwq->cqe_dma_addr, 22162306a36Sopenharmony_ci GFP_KERNEL); 22262306a36Sopenharmony_ci if (!hwq->cqe_dma_addr) { 22362306a36Sopenharmony_ci dev_err(hba->dev, "CQE allocation failed\n"); 22462306a36Sopenharmony_ci return -ENOMEM; 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci } 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci return 0; 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci/* Operation and runtime registers configuration */ 23362306a36Sopenharmony_ci#define MCQ_CFG_n(r, i) ((r) + MCQ_QCFG_SIZE * (i)) 23462306a36Sopenharmony_ci#define MCQ_OPR_OFFSET_n(p, i) \ 23562306a36Sopenharmony_ci (hba->mcq_opr[(p)].offset + hba->mcq_opr[(p)].stride * (i)) 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cistatic void __iomem *mcq_opr_base(struct ufs_hba *hba, 23862306a36Sopenharmony_ci enum ufshcd_mcq_opr n, int i) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci struct ufshcd_mcq_opr_info_t *opr = &hba->mcq_opr[n]; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci return opr->base + opr->stride * i; 24362306a36Sopenharmony_ci} 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ciu32 ufshcd_mcq_read_cqis(struct ufs_hba *hba, int i) 24662306a36Sopenharmony_ci{ 24762306a36Sopenharmony_ci return readl(mcq_opr_base(hba, OPR_CQIS, i) + REG_CQIS); 24862306a36Sopenharmony_ci} 24962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ufshcd_mcq_read_cqis); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_civoid ufshcd_mcq_write_cqis(struct ufs_hba *hba, u32 val, int i) 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci writel(val, mcq_opr_base(hba, OPR_CQIS, i) + REG_CQIS); 25462306a36Sopenharmony_ci} 25562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ufshcd_mcq_write_cqis); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci/* 25862306a36Sopenharmony_ci * Current MCQ specification doesn't provide a Task Tag or its equivalent in 25962306a36Sopenharmony_ci * the Completion Queue Entry. Find the Task Tag using an indirect method. 26062306a36Sopenharmony_ci */ 26162306a36Sopenharmony_cistatic int ufshcd_mcq_get_tag(struct ufs_hba *hba, 26262306a36Sopenharmony_ci struct ufs_hw_queue *hwq, 26362306a36Sopenharmony_ci struct cq_entry *cqe) 26462306a36Sopenharmony_ci{ 26562306a36Sopenharmony_ci u64 addr; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci /* sizeof(struct utp_transfer_cmd_desc) must be a multiple of 128 */ 26862306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct utp_transfer_cmd_desc) & GENMASK(6, 0)); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci /* Bits 63:7 UCD base address, 6:5 are reserved, 4:0 is SQ ID */ 27162306a36Sopenharmony_ci addr = (le64_to_cpu(cqe->command_desc_base_addr) & CQE_UCD_BA) - 27262306a36Sopenharmony_ci hba->ucdl_dma_addr; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci return div_u64(addr, ufshcd_get_ucd_size(hba)); 27562306a36Sopenharmony_ci} 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_cistatic void ufshcd_mcq_process_cqe(struct ufs_hba *hba, 27862306a36Sopenharmony_ci struct ufs_hw_queue *hwq) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci struct cq_entry *cqe = ufshcd_mcq_cur_cqe(hwq); 28162306a36Sopenharmony_ci int tag = ufshcd_mcq_get_tag(hba, hwq, cqe); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci if (cqe->command_desc_base_addr) { 28462306a36Sopenharmony_ci ufshcd_compl_one_cqe(hba, tag, cqe); 28562306a36Sopenharmony_ci /* After processed the cqe, mark it empty (invalid) entry */ 28662306a36Sopenharmony_ci cqe->command_desc_base_addr = 0; 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci} 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_civoid ufshcd_mcq_compl_all_cqes_lock(struct ufs_hba *hba, 29162306a36Sopenharmony_ci struct ufs_hw_queue *hwq) 29262306a36Sopenharmony_ci{ 29362306a36Sopenharmony_ci unsigned long flags; 29462306a36Sopenharmony_ci u32 entries = hwq->max_entries; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci spin_lock_irqsave(&hwq->cq_lock, flags); 29762306a36Sopenharmony_ci while (entries > 0) { 29862306a36Sopenharmony_ci ufshcd_mcq_process_cqe(hba, hwq); 29962306a36Sopenharmony_ci ufshcd_mcq_inc_cq_head_slot(hwq); 30062306a36Sopenharmony_ci entries--; 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci ufshcd_mcq_update_cq_tail_slot(hwq); 30462306a36Sopenharmony_ci hwq->cq_head_slot = hwq->cq_tail_slot; 30562306a36Sopenharmony_ci spin_unlock_irqrestore(&hwq->cq_lock, flags); 30662306a36Sopenharmony_ci} 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ciunsigned long ufshcd_mcq_poll_cqe_lock(struct ufs_hba *hba, 30962306a36Sopenharmony_ci struct ufs_hw_queue *hwq) 31062306a36Sopenharmony_ci{ 31162306a36Sopenharmony_ci unsigned long completed_reqs = 0; 31262306a36Sopenharmony_ci unsigned long flags; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci spin_lock_irqsave(&hwq->cq_lock, flags); 31562306a36Sopenharmony_ci ufshcd_mcq_update_cq_tail_slot(hwq); 31662306a36Sopenharmony_ci while (!ufshcd_mcq_is_cq_empty(hwq)) { 31762306a36Sopenharmony_ci ufshcd_mcq_process_cqe(hba, hwq); 31862306a36Sopenharmony_ci ufshcd_mcq_inc_cq_head_slot(hwq); 31962306a36Sopenharmony_ci completed_reqs++; 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci if (completed_reqs) 32362306a36Sopenharmony_ci ufshcd_mcq_update_cq_head(hwq); 32462306a36Sopenharmony_ci spin_unlock_irqrestore(&hwq->cq_lock, flags); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci return completed_reqs; 32762306a36Sopenharmony_ci} 32862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ufshcd_mcq_poll_cqe_lock); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_civoid ufshcd_mcq_make_queues_operational(struct ufs_hba *hba) 33162306a36Sopenharmony_ci{ 33262306a36Sopenharmony_ci struct ufs_hw_queue *hwq; 33362306a36Sopenharmony_ci u16 qsize; 33462306a36Sopenharmony_ci int i; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci for (i = 0; i < hba->nr_hw_queues; i++) { 33762306a36Sopenharmony_ci hwq = &hba->uhq[i]; 33862306a36Sopenharmony_ci hwq->id = i; 33962306a36Sopenharmony_ci qsize = hwq->max_entries * MCQ_ENTRY_SIZE_IN_DWORD - 1; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci /* Submission Queue Lower Base Address */ 34262306a36Sopenharmony_ci ufsmcq_writelx(hba, lower_32_bits(hwq->sqe_dma_addr), 34362306a36Sopenharmony_ci MCQ_CFG_n(REG_SQLBA, i)); 34462306a36Sopenharmony_ci /* Submission Queue Upper Base Address */ 34562306a36Sopenharmony_ci ufsmcq_writelx(hba, upper_32_bits(hwq->sqe_dma_addr), 34662306a36Sopenharmony_ci MCQ_CFG_n(REG_SQUBA, i)); 34762306a36Sopenharmony_ci /* Submission Queue Doorbell Address Offset */ 34862306a36Sopenharmony_ci ufsmcq_writelx(hba, MCQ_OPR_OFFSET_n(OPR_SQD, i), 34962306a36Sopenharmony_ci MCQ_CFG_n(REG_SQDAO, i)); 35062306a36Sopenharmony_ci /* Submission Queue Interrupt Status Address Offset */ 35162306a36Sopenharmony_ci ufsmcq_writelx(hba, MCQ_OPR_OFFSET_n(OPR_SQIS, i), 35262306a36Sopenharmony_ci MCQ_CFG_n(REG_SQISAO, i)); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci /* Completion Queue Lower Base Address */ 35562306a36Sopenharmony_ci ufsmcq_writelx(hba, lower_32_bits(hwq->cqe_dma_addr), 35662306a36Sopenharmony_ci MCQ_CFG_n(REG_CQLBA, i)); 35762306a36Sopenharmony_ci /* Completion Queue Upper Base Address */ 35862306a36Sopenharmony_ci ufsmcq_writelx(hba, upper_32_bits(hwq->cqe_dma_addr), 35962306a36Sopenharmony_ci MCQ_CFG_n(REG_CQUBA, i)); 36062306a36Sopenharmony_ci /* Completion Queue Doorbell Address Offset */ 36162306a36Sopenharmony_ci ufsmcq_writelx(hba, MCQ_OPR_OFFSET_n(OPR_CQD, i), 36262306a36Sopenharmony_ci MCQ_CFG_n(REG_CQDAO, i)); 36362306a36Sopenharmony_ci /* Completion Queue Interrupt Status Address Offset */ 36462306a36Sopenharmony_ci ufsmcq_writelx(hba, MCQ_OPR_OFFSET_n(OPR_CQIS, i), 36562306a36Sopenharmony_ci MCQ_CFG_n(REG_CQISAO, i)); 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci /* Save the base addresses for quicker access */ 36862306a36Sopenharmony_ci hwq->mcq_sq_head = mcq_opr_base(hba, OPR_SQD, i) + REG_SQHP; 36962306a36Sopenharmony_ci hwq->mcq_sq_tail = mcq_opr_base(hba, OPR_SQD, i) + REG_SQTP; 37062306a36Sopenharmony_ci hwq->mcq_cq_head = mcq_opr_base(hba, OPR_CQD, i) + REG_CQHP; 37162306a36Sopenharmony_ci hwq->mcq_cq_tail = mcq_opr_base(hba, OPR_CQD, i) + REG_CQTP; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci /* Reinitializing is needed upon HC reset */ 37462306a36Sopenharmony_ci hwq->sq_tail_slot = hwq->cq_tail_slot = hwq->cq_head_slot = 0; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci /* Enable Tail Entry Push Status interrupt only for non-poll queues */ 37762306a36Sopenharmony_ci if (i < hba->nr_hw_queues - hba->nr_queues[HCTX_TYPE_POLL]) 37862306a36Sopenharmony_ci writel(1, mcq_opr_base(hba, OPR_CQIS, i) + REG_CQIE); 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci /* Completion Queue Enable|Size to Completion Queue Attribute */ 38162306a36Sopenharmony_ci ufsmcq_writel(hba, (1 << QUEUE_EN_OFFSET) | qsize, 38262306a36Sopenharmony_ci MCQ_CFG_n(REG_CQATTR, i)); 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci /* 38562306a36Sopenharmony_ci * Submission Qeueue Enable|Size|Completion Queue ID to 38662306a36Sopenharmony_ci * Submission Queue Attribute 38762306a36Sopenharmony_ci */ 38862306a36Sopenharmony_ci ufsmcq_writel(hba, (1 << QUEUE_EN_OFFSET) | qsize | 38962306a36Sopenharmony_ci (i << QUEUE_ID_OFFSET), 39062306a36Sopenharmony_ci MCQ_CFG_n(REG_SQATTR, i)); 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci} 39362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ufshcd_mcq_make_queues_operational); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_civoid ufshcd_mcq_enable_esi(struct ufs_hba *hba) 39662306a36Sopenharmony_ci{ 39762306a36Sopenharmony_ci ufshcd_writel(hba, ufshcd_readl(hba, REG_UFS_MEM_CFG) | 0x2, 39862306a36Sopenharmony_ci REG_UFS_MEM_CFG); 39962306a36Sopenharmony_ci} 40062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ufshcd_mcq_enable_esi); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_civoid ufshcd_mcq_config_esi(struct ufs_hba *hba, struct msi_msg *msg) 40362306a36Sopenharmony_ci{ 40462306a36Sopenharmony_ci ufshcd_writel(hba, msg->address_lo, REG_UFS_ESILBA); 40562306a36Sopenharmony_ci ufshcd_writel(hba, msg->address_hi, REG_UFS_ESIUBA); 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ufshcd_mcq_config_esi); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ciint ufshcd_mcq_init(struct ufs_hba *hba) 41062306a36Sopenharmony_ci{ 41162306a36Sopenharmony_ci struct Scsi_Host *host = hba->host; 41262306a36Sopenharmony_ci struct ufs_hw_queue *hwq; 41362306a36Sopenharmony_ci int ret, i; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci ret = ufshcd_mcq_config_nr_queues(hba); 41662306a36Sopenharmony_ci if (ret) 41762306a36Sopenharmony_ci return ret; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci ret = ufshcd_vops_mcq_config_resource(hba); 42062306a36Sopenharmony_ci if (ret) 42162306a36Sopenharmony_ci return ret; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci ret = ufshcd_mcq_vops_op_runtime_config(hba); 42462306a36Sopenharmony_ci if (ret) { 42562306a36Sopenharmony_ci dev_err(hba->dev, "Operation runtime config failed, ret=%d\n", 42662306a36Sopenharmony_ci ret); 42762306a36Sopenharmony_ci return ret; 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci hba->uhq = devm_kzalloc(hba->dev, 43062306a36Sopenharmony_ci hba->nr_hw_queues * sizeof(struct ufs_hw_queue), 43162306a36Sopenharmony_ci GFP_KERNEL); 43262306a36Sopenharmony_ci if (!hba->uhq) { 43362306a36Sopenharmony_ci dev_err(hba->dev, "ufs hw queue memory allocation failed\n"); 43462306a36Sopenharmony_ci return -ENOMEM; 43562306a36Sopenharmony_ci } 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci for (i = 0; i < hba->nr_hw_queues; i++) { 43862306a36Sopenharmony_ci hwq = &hba->uhq[i]; 43962306a36Sopenharmony_ci hwq->max_entries = hba->nutrs + 1; 44062306a36Sopenharmony_ci spin_lock_init(&hwq->sq_lock); 44162306a36Sopenharmony_ci spin_lock_init(&hwq->cq_lock); 44262306a36Sopenharmony_ci mutex_init(&hwq->sq_mutex); 44362306a36Sopenharmony_ci } 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci /* The very first HW queue serves device commands */ 44662306a36Sopenharmony_ci hba->dev_cmd_queue = &hba->uhq[0]; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci host->host_tagset = 1; 44962306a36Sopenharmony_ci return 0; 45062306a36Sopenharmony_ci} 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_cistatic int ufshcd_mcq_sq_stop(struct ufs_hba *hba, struct ufs_hw_queue *hwq) 45362306a36Sopenharmony_ci{ 45462306a36Sopenharmony_ci void __iomem *reg; 45562306a36Sopenharmony_ci u32 id = hwq->id, val; 45662306a36Sopenharmony_ci int err; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci if (hba->quirks & UFSHCD_QUIRK_MCQ_BROKEN_RTC) 45962306a36Sopenharmony_ci return -ETIMEDOUT; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci writel(SQ_STOP, mcq_opr_base(hba, OPR_SQD, id) + REG_SQRTC); 46262306a36Sopenharmony_ci reg = mcq_opr_base(hba, OPR_SQD, id) + REG_SQRTS; 46362306a36Sopenharmony_ci err = read_poll_timeout(readl, val, val & SQ_STS, 20, 46462306a36Sopenharmony_ci MCQ_POLL_US, false, reg); 46562306a36Sopenharmony_ci if (err) 46662306a36Sopenharmony_ci dev_err(hba->dev, "%s: failed. hwq-id=%d, err=%d\n", 46762306a36Sopenharmony_ci __func__, id, err); 46862306a36Sopenharmony_ci return err; 46962306a36Sopenharmony_ci} 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_cistatic int ufshcd_mcq_sq_start(struct ufs_hba *hba, struct ufs_hw_queue *hwq) 47262306a36Sopenharmony_ci{ 47362306a36Sopenharmony_ci void __iomem *reg; 47462306a36Sopenharmony_ci u32 id = hwq->id, val; 47562306a36Sopenharmony_ci int err; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci if (hba->quirks & UFSHCD_QUIRK_MCQ_BROKEN_RTC) 47862306a36Sopenharmony_ci return -ETIMEDOUT; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci writel(SQ_START, mcq_opr_base(hba, OPR_SQD, id) + REG_SQRTC); 48162306a36Sopenharmony_ci reg = mcq_opr_base(hba, OPR_SQD, id) + REG_SQRTS; 48262306a36Sopenharmony_ci err = read_poll_timeout(readl, val, !(val & SQ_STS), 20, 48362306a36Sopenharmony_ci MCQ_POLL_US, false, reg); 48462306a36Sopenharmony_ci if (err) 48562306a36Sopenharmony_ci dev_err(hba->dev, "%s: failed. hwq-id=%d, err=%d\n", 48662306a36Sopenharmony_ci __func__, id, err); 48762306a36Sopenharmony_ci return err; 48862306a36Sopenharmony_ci} 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci/** 49162306a36Sopenharmony_ci * ufshcd_mcq_sq_cleanup - Clean up submission queue resources 49262306a36Sopenharmony_ci * associated with the pending command. 49362306a36Sopenharmony_ci * @hba: per adapter instance. 49462306a36Sopenharmony_ci * @task_tag: The command's task tag. 49562306a36Sopenharmony_ci * 49662306a36Sopenharmony_ci * Return: 0 for success; error code otherwise. 49762306a36Sopenharmony_ci */ 49862306a36Sopenharmony_ciint ufshcd_mcq_sq_cleanup(struct ufs_hba *hba, int task_tag) 49962306a36Sopenharmony_ci{ 50062306a36Sopenharmony_ci struct ufshcd_lrb *lrbp = &hba->lrb[task_tag]; 50162306a36Sopenharmony_ci struct scsi_cmnd *cmd = lrbp->cmd; 50262306a36Sopenharmony_ci struct ufs_hw_queue *hwq; 50362306a36Sopenharmony_ci void __iomem *reg, *opr_sqd_base; 50462306a36Sopenharmony_ci u32 nexus, id, val; 50562306a36Sopenharmony_ci int err; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci if (hba->quirks & UFSHCD_QUIRK_MCQ_BROKEN_RTC) 50862306a36Sopenharmony_ci return -ETIMEDOUT; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci if (task_tag != hba->nutrs - UFSHCD_NUM_RESERVED) { 51162306a36Sopenharmony_ci if (!cmd) 51262306a36Sopenharmony_ci return -EINVAL; 51362306a36Sopenharmony_ci hwq = ufshcd_mcq_req_to_hwq(hba, scsi_cmd_to_rq(cmd)); 51462306a36Sopenharmony_ci } else { 51562306a36Sopenharmony_ci hwq = hba->dev_cmd_queue; 51662306a36Sopenharmony_ci } 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci id = hwq->id; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci mutex_lock(&hwq->sq_mutex); 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci /* stop the SQ fetching before working on it */ 52362306a36Sopenharmony_ci err = ufshcd_mcq_sq_stop(hba, hwq); 52462306a36Sopenharmony_ci if (err) 52562306a36Sopenharmony_ci goto unlock; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci /* SQCTI = EXT_IID, IID, LUN, Task Tag */ 52862306a36Sopenharmony_ci nexus = lrbp->lun << 8 | task_tag; 52962306a36Sopenharmony_ci opr_sqd_base = mcq_opr_base(hba, OPR_SQD, id); 53062306a36Sopenharmony_ci writel(nexus, opr_sqd_base + REG_SQCTI); 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci /* SQRTCy.ICU = 1 */ 53362306a36Sopenharmony_ci writel(SQ_ICU, opr_sqd_base + REG_SQRTC); 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci /* Poll SQRTSy.CUS = 1. Return result from SQRTSy.RTC */ 53662306a36Sopenharmony_ci reg = opr_sqd_base + REG_SQRTS; 53762306a36Sopenharmony_ci err = read_poll_timeout(readl, val, val & SQ_CUS, 20, 53862306a36Sopenharmony_ci MCQ_POLL_US, false, reg); 53962306a36Sopenharmony_ci if (err) 54062306a36Sopenharmony_ci dev_err(hba->dev, "%s: failed. hwq=%d, tag=%d err=%ld\n", 54162306a36Sopenharmony_ci __func__, id, task_tag, 54262306a36Sopenharmony_ci FIELD_GET(SQ_ICU_ERR_CODE_MASK, readl(reg))); 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci if (ufshcd_mcq_sq_start(hba, hwq)) 54562306a36Sopenharmony_ci err = -ETIMEDOUT; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ciunlock: 54862306a36Sopenharmony_ci mutex_unlock(&hwq->sq_mutex); 54962306a36Sopenharmony_ci return err; 55062306a36Sopenharmony_ci} 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci/** 55362306a36Sopenharmony_ci * ufshcd_mcq_nullify_sqe - Nullify the submission queue entry. 55462306a36Sopenharmony_ci * Write the sqe's Command Type to 0xF. The host controller will not 55562306a36Sopenharmony_ci * fetch any sqe with Command Type = 0xF. 55662306a36Sopenharmony_ci * 55762306a36Sopenharmony_ci * @utrd: UTP Transfer Request Descriptor to be nullified. 55862306a36Sopenharmony_ci */ 55962306a36Sopenharmony_cistatic void ufshcd_mcq_nullify_sqe(struct utp_transfer_req_desc *utrd) 56062306a36Sopenharmony_ci{ 56162306a36Sopenharmony_ci utrd->header.command_type = 0xf; 56262306a36Sopenharmony_ci} 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci/** 56562306a36Sopenharmony_ci * ufshcd_mcq_sqe_search - Search for the command in the submission queue 56662306a36Sopenharmony_ci * If the command is in the submission queue and not issued to the device yet, 56762306a36Sopenharmony_ci * nullify the sqe so the host controller will skip fetching the sqe. 56862306a36Sopenharmony_ci * 56962306a36Sopenharmony_ci * @hba: per adapter instance. 57062306a36Sopenharmony_ci * @hwq: Hardware Queue to be searched. 57162306a36Sopenharmony_ci * @task_tag: The command's task tag. 57262306a36Sopenharmony_ci * 57362306a36Sopenharmony_ci * Return: true if the SQE containing the command is present in the SQ 57462306a36Sopenharmony_ci * (not fetched by the controller); returns false if the SQE is not in the SQ. 57562306a36Sopenharmony_ci */ 57662306a36Sopenharmony_cistatic bool ufshcd_mcq_sqe_search(struct ufs_hba *hba, 57762306a36Sopenharmony_ci struct ufs_hw_queue *hwq, int task_tag) 57862306a36Sopenharmony_ci{ 57962306a36Sopenharmony_ci struct ufshcd_lrb *lrbp = &hba->lrb[task_tag]; 58062306a36Sopenharmony_ci struct utp_transfer_req_desc *utrd; 58162306a36Sopenharmony_ci __le64 cmd_desc_base_addr; 58262306a36Sopenharmony_ci bool ret = false; 58362306a36Sopenharmony_ci u64 addr, match; 58462306a36Sopenharmony_ci u32 sq_head_slot; 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci if (hba->quirks & UFSHCD_QUIRK_MCQ_BROKEN_RTC) 58762306a36Sopenharmony_ci return true; 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci mutex_lock(&hwq->sq_mutex); 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci ufshcd_mcq_sq_stop(hba, hwq); 59262306a36Sopenharmony_ci sq_head_slot = ufshcd_mcq_get_sq_head_slot(hwq); 59362306a36Sopenharmony_ci if (sq_head_slot == hwq->sq_tail_slot) 59462306a36Sopenharmony_ci goto out; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci cmd_desc_base_addr = lrbp->utr_descriptor_ptr->command_desc_base_addr; 59762306a36Sopenharmony_ci addr = le64_to_cpu(cmd_desc_base_addr) & CQE_UCD_BA; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci while (sq_head_slot != hwq->sq_tail_slot) { 60062306a36Sopenharmony_ci utrd = hwq->sqe_base_addr + 60162306a36Sopenharmony_ci sq_head_slot * sizeof(struct utp_transfer_req_desc); 60262306a36Sopenharmony_ci match = le64_to_cpu(utrd->command_desc_base_addr) & CQE_UCD_BA; 60362306a36Sopenharmony_ci if (addr == match) { 60462306a36Sopenharmony_ci ufshcd_mcq_nullify_sqe(utrd); 60562306a36Sopenharmony_ci ret = true; 60662306a36Sopenharmony_ci goto out; 60762306a36Sopenharmony_ci } 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci sq_head_slot++; 61062306a36Sopenharmony_ci if (sq_head_slot == hwq->max_entries) 61162306a36Sopenharmony_ci sq_head_slot = 0; 61262306a36Sopenharmony_ci } 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ciout: 61562306a36Sopenharmony_ci ufshcd_mcq_sq_start(hba, hwq); 61662306a36Sopenharmony_ci mutex_unlock(&hwq->sq_mutex); 61762306a36Sopenharmony_ci return ret; 61862306a36Sopenharmony_ci} 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci/** 62162306a36Sopenharmony_ci * ufshcd_mcq_abort - Abort the command in MCQ. 62262306a36Sopenharmony_ci * @cmd: The command to be aborted. 62362306a36Sopenharmony_ci * 62462306a36Sopenharmony_ci * Return: SUCCESS or FAILED error codes 62562306a36Sopenharmony_ci */ 62662306a36Sopenharmony_ciint ufshcd_mcq_abort(struct scsi_cmnd *cmd) 62762306a36Sopenharmony_ci{ 62862306a36Sopenharmony_ci struct Scsi_Host *host = cmd->device->host; 62962306a36Sopenharmony_ci struct ufs_hba *hba = shost_priv(host); 63062306a36Sopenharmony_ci int tag = scsi_cmd_to_rq(cmd)->tag; 63162306a36Sopenharmony_ci struct ufshcd_lrb *lrbp = &hba->lrb[tag]; 63262306a36Sopenharmony_ci struct ufs_hw_queue *hwq; 63362306a36Sopenharmony_ci unsigned long flags; 63462306a36Sopenharmony_ci int err = FAILED; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci if (!ufshcd_cmd_inflight(lrbp->cmd)) { 63762306a36Sopenharmony_ci dev_err(hba->dev, 63862306a36Sopenharmony_ci "%s: skip abort. cmd at tag %d already completed.\n", 63962306a36Sopenharmony_ci __func__, tag); 64062306a36Sopenharmony_ci goto out; 64162306a36Sopenharmony_ci } 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci /* Skip task abort in case previous aborts failed and report failure */ 64462306a36Sopenharmony_ci if (lrbp->req_abort_skip) { 64562306a36Sopenharmony_ci dev_err(hba->dev, "%s: skip abort. tag %d failed earlier\n", 64662306a36Sopenharmony_ci __func__, tag); 64762306a36Sopenharmony_ci goto out; 64862306a36Sopenharmony_ci } 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci hwq = ufshcd_mcq_req_to_hwq(hba, scsi_cmd_to_rq(cmd)); 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci if (ufshcd_mcq_sqe_search(hba, hwq, tag)) { 65362306a36Sopenharmony_ci /* 65462306a36Sopenharmony_ci * Failure. The command should not be "stuck" in SQ for 65562306a36Sopenharmony_ci * a long time which resulted in command being aborted. 65662306a36Sopenharmony_ci */ 65762306a36Sopenharmony_ci dev_err(hba->dev, "%s: cmd found in sq. hwq=%d, tag=%d\n", 65862306a36Sopenharmony_ci __func__, hwq->id, tag); 65962306a36Sopenharmony_ci goto out; 66062306a36Sopenharmony_ci } 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci /* 66362306a36Sopenharmony_ci * The command is not in the submission queue, and it is not 66462306a36Sopenharmony_ci * in the completion queue either. Query the device to see if 66562306a36Sopenharmony_ci * the command is being processed in the device. 66662306a36Sopenharmony_ci */ 66762306a36Sopenharmony_ci if (ufshcd_try_to_abort_task(hba, tag)) { 66862306a36Sopenharmony_ci dev_err(hba->dev, "%s: device abort failed %d\n", __func__, err); 66962306a36Sopenharmony_ci lrbp->req_abort_skip = true; 67062306a36Sopenharmony_ci goto out; 67162306a36Sopenharmony_ci } 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci err = SUCCESS; 67462306a36Sopenharmony_ci spin_lock_irqsave(&hwq->cq_lock, flags); 67562306a36Sopenharmony_ci if (ufshcd_cmd_inflight(lrbp->cmd)) 67662306a36Sopenharmony_ci ufshcd_release_scsi_cmd(hba, lrbp); 67762306a36Sopenharmony_ci spin_unlock_irqrestore(&hwq->cq_lock, flags); 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ciout: 68062306a36Sopenharmony_ci return err; 68162306a36Sopenharmony_ci} 682