From: Santosh Yaraganavi santos...@gmail.com
UFSHCD SCSI error handling includes following implementations,
- Abort task
- Device reset
- Host reset
Signed-off-by: Santosh Yaraganavi santos...@gmail.com
Signed-off-by: Vinayak Holikatti vinholika...@gmail.com
Reviewed-by: Arnd Bergmann a...@linaro.org
Reviewed-by: Vishak G visha...@samsung.com
Reviewed-by: Girish K S girish.shivananja...@linaro.org
---
v1 - v2:
- Change task management function return value to SUCCESS/FAILED,
SCSI midlayer expects SUCCESS/FAILED return value for
error handling routines.
Ex: .eh_host_reset_handler, eh_abort_handler...
- ufshcd_tmc_handler(): use wake_up_interruptible() outside for loop
to wake up all the waiting threads at once.
Change hba-tm_condition[] to hba-tm_condition bitmask.
- ufshcd_abort(): add missing spin_unlock_irqrestore().
drivers/scsi/ufs/ufshcd.c | 298 -
1 files changed, 297 insertions(+), 1 deletions(-)
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 1c6a9ed..856dbc1 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -65,6 +65,7 @@
#include scsi/scsi_host.h
#include scsi/scsi_tcq.h
#include scsi/scsi_dbg.h
+#include scsi/scsi_eh.h
#include ufs.h
#include ufshci.h
@@ -131,11 +132,14 @@ struct uic_command {
* @host: Scsi_Host instance of the driver
* @pdev: PCI device handle
* @lrb: local reference block
+ * @outstanding_tasks: Bits representing outstanding task requests
* @outstanding_reqs: Bits representing outstanding transfer requests
* @capabilities: UFS Controller Capabilities
* @nutrs: Transfer Request Queue depth supported by controller
* @nutmrs: Task Management Queue depth supported by controller
* @active_uic_cmd: handle of active UIC command
+ * @ufshcd_tm_wait_queue: wait queue for task management
+ * @tm_condition: condition variable for task management
* @ufshcd_state: UFSHCD states
* @int_enable_mask: Interrupt Mask Bits
* @uic_workq: Work queue for UIC completion handling
@@ -160,6 +164,7 @@ struct ufs_hba {
struct ufshcd_lrb *lrb;
+ unsigned long outstanding_tasks;
unsigned long outstanding_reqs;
u32 capabilities;
@@ -168,6 +173,8 @@ struct ufs_hba {
u32 ufs_version;
struct uic_command active_uic_cmd;
+ wait_queue_head_t ufshcd_tm_wait_queue;
+ unsigned long tm_condition;
u32 ufshcd_state;
u32 int_enable_mask;
@@ -246,6 +253,42 @@ static inline int ufshcd_get_tr_ocs(struct ufshcd_lrb
*lrbp)
}
/**
+ * ufshcd_get_tmr_ocs - Get the UTMRD Overall Command Status
+ * @task_req_descp: pointer to utp_task_req_desc structure
+ *
+ * This function is used to get the OCS field from UTMRD
+ * Returns the OCS field in the UTMRD
+ */
+static inline int
+ufshcd_get_tmr_ocs(struct utp_task_req_desc *task_req_descp)
+{
+ return task_req_descp-header.dword_2 MASK_OCS;
+}
+
+/**
+ * ufshcd_is_tmq_full - checks if the task management slots are full
+ * @hba: per adapter instance
+ *
+ * Returns maximum number of task management request slots in case of
+ * task management queue full or returns the free slot number
+ */
+static inline int ufshcd_is_tmq_full(struct ufs_hba *hba)
+{
+ return find_first_zero_bit(hba-outstanding_tasks, hba-nutmrs);
+}
+
+/**
+ * ufshcd_utrl_clear - Clear a bit in UTRLCLR register
+ * @hba: per adapter instance
+ * @pos: position of the bit to be cleared
+ */
+static inline void ufshcd_utrl_clear(struct ufs_hba *hba, u32 pos)
+{
+ writel(~(1 pos),
+ (hba-mmio_base + REG_UTP_TRANSFER_REQ_LIST_CLEAR));
+}
+
+/**
* ufshcd_get_lists_status - Check UCRDY, UTRLRDY and UTMRLRDY
* @reg: Register value of host controller status
*
@@ -1038,8 +1081,9 @@ static int ufshcd_do_reset(struct ufs_hba *hba)
}
}
- /* clear outstanding request bit maps */
+ /* clear outstanding request/task bit maps */
hba-outstanding_reqs = 0;
+ hba-outstanding_tasks = 0;
/* start the initialization process */
if (ufshcd_initialize_hba(hba)) {
@@ -1091,6 +1135,47 @@ static void ufshcd_slave_destroy(struct scsi_device
*sdev)
}
/**
+ * ufshcd_task_req_compl - handle task management request completion
+ * @hba: per adapter instance
+ * @index: index of the completed request
+ *
+ * Returns SUCCESS/FAILED
+ */
+static int ufshcd_task_req_compl(struct ufs_hba *hba, u32 index)
+{
+ struct utp_task_req_desc *task_req_descp;
+ struct utp_upiu_task_rsp *task_rsp_upiup;
+ unsigned long flags;
+ int ocs_value;
+ int task_result;
+
+ spin_lock_irqsave(hba-host-host_lock, flags);
+
+ /* Clear completed tasks from outstanding_tasks */
+ __clear_bit(index, hba-outstanding_tasks);
+
+ task_req_descp = hba-utmrdl_base_addr;
+ ocs_value =