hisi_sas: add hisi_sas_slot_abort()
authorJohn Garry <john.garry@huawei.com>
Thu, 25 Feb 2016 09:42:11 +0000 (17:42 +0800)
committerMartin K. Petersen <martin.petersen@oracle.com>
Tue, 1 Mar 2016 02:00:03 +0000 (21:00 -0500)
Add a function to abort a slot (task) in the target
device and then cleanup and complete the task.
The function is called from work queue context as
it cannot be called from the context where it is
triggered (interrupt).
Flag hisi_sas_slot.abort is added as the flag used
in the slot error handler to indicate whether the
slot needs to be aborted in the sdev prior to
cleanup and finish.

Signed-off-by: John Garry <john.garry@huawei.com>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/hisi_sas/hisi_sas.h
drivers/scsi/hisi_sas/hisi_sas_main.c

index 02da7e4f9eb6975172203737479b9cc4b2d7e3bc..c92e65b989a6e1144fd0cc11985049c8e302f7f3 100644 (file)
@@ -112,6 +112,7 @@ struct hisi_sas_slot {
        int     cmplt_queue;
        int     cmplt_queue_slot;
        int     idx;
+       int     abort;
        void    *cmd_hdr;
        dma_addr_t cmd_hdr_dma;
        void    *status_buffer;
@@ -120,6 +121,7 @@ struct hisi_sas_slot {
        dma_addr_t command_table_dma;
        struct hisi_sas_sge_page *sge_page;
        dma_addr_t sge_page_dma;
+       struct work_struct abort_slot;
 };
 
 struct hisi_sas_tmf_task {
index 58ca336c9509c97e48fdee88542b3119a94355c3..e51612f7f933cbcdc83a120aab3f1b1f2b67bacc 100644 (file)
@@ -15,6 +15,9 @@
 #define DEV_IS_GONE(dev) \
        ((!dev) || (dev->dev_type == SAS_PHY_UNUSED))
 
+static int hisi_sas_debug_issue_ssp_tmf(struct domain_device *device,
+                               u8 *lun, struct hisi_sas_tmf_task *tmf);
+
 static struct hisi_hba *dev_to_hisi_hba(struct domain_device *device)
 {
        return device->port->ha->lldd_ha;
@@ -113,6 +116,44 @@ static int hisi_sas_task_prep_ata(struct hisi_hba *hisi_hba,
        return hisi_hba->hw->prep_stp(hisi_hba, slot);
 }
 
+/*
+ * This function will issue an abort TMF regardless of whether the
+ * task is in the sdev or not. Then it will do the task complete
+ * cleanup and callbacks.
+ */
+static void hisi_sas_slot_abort(struct work_struct *work)
+{
+       struct hisi_sas_slot *abort_slot =
+               container_of(work, struct hisi_sas_slot, abort_slot);
+       struct sas_task *task = abort_slot->task;
+       struct hisi_hba *hisi_hba = dev_to_hisi_hba(task->dev);
+       struct scsi_cmnd *cmnd = task->uldd_task;
+       struct hisi_sas_tmf_task tmf_task;
+       struct domain_device *device = task->dev;
+       struct hisi_sas_device *sas_dev = device->lldd_dev;
+       struct scsi_lun lun;
+       struct device *dev = &hisi_hba->pdev->dev;
+       int tag = abort_slot->idx;
+
+       if (!(task->task_proto & SAS_PROTOCOL_SSP)) {
+               dev_err(dev, "cannot abort slot for non-ssp task\n");
+               goto out;
+       }
+
+       int_to_scsilun(cmnd->device->lun, &lun);
+       tmf_task.tmf = TMF_ABORT_TASK;
+       tmf_task.tag_of_task_to_be_managed = cpu_to_le16(tag);
+
+       hisi_sas_debug_issue_ssp_tmf(task->dev, lun.scsi_lun, &tmf_task);
+out:
+       /* Do cleanup for this task */
+       hisi_sas_slot_task_free(hisi_hba, task, abort_slot);
+       if (task->task_done)
+               task->task_done(task);
+       if (sas_dev && sas_dev->running_req)
+               sas_dev->running_req--;
+}
+
 static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba,
                              int is_tmf, struct hisi_sas_tmf_task *tmf,
                              int *pass)
@@ -206,6 +247,7 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba,
        slot->task = task;
        slot->port = port;
        task->lldd_task = slot;
+       INIT_WORK(&slot->abort_slot, hisi_sas_slot_abort);
 
        slot->status_buffer = dma_pool_alloc(hisi_hba->status_buffer_pool,
                                             GFP_ATOMIC,