]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
scsi: hisi_sas: add an mechanism to do reset work synchronously
authorXiaofei Tan <tanxiaofei@huawei.com>
Fri, 8 Dec 2017 17:16:38 +0000 (01:16 +0800)
committerSeth Forshee <seth.forshee@canonical.com>
Fri, 16 Mar 2018 15:42:57 +0000 (10:42 -0500)
BugLink: http://bugs.launchpad.net/bugs/1756094
Sometimes it is required to know when the controller reset has completed and
also if it has completed successfully.  For such places, we call
hisi_sas_controller_reset() directly before. That may lead to multiple calls
to this function.

This patch create a per-reset structure which contains a completion structure
and status flag to know when the reset completes and also the status. It is
also in hisi_hba.wq to do reset work.

As all host reset works are done in hisi_hba.wq, we don't worry multiple calls
to hisi_sas_controller_reset().

Signed-off-by: Xiaofei Tan <tanxiaofei@huawei.com>
Signed-off-by: John Garry <john.garry@huawei.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
(cherry picked from commit e402acdb664134f948b62d13b7db866295689f38)
Signed-off-by: Manoj Iyer <manoj.iyer@canonical.com>
Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
drivers/scsi/hisi_sas/hisi_sas.h
drivers/scsi/hisi_sas/hisi_sas_main.c

index dd897125988a0eb261633dee1a79d2cd196ff68f..f7accfadd9f6a5e6132f88d3014902c0b2b30aee 100644 (file)
@@ -99,6 +99,31 @@ struct hisi_sas_hw_error {
        const struct hisi_sas_hw_error *sub;
 };
 
+struct hisi_sas_rst {
+       struct hisi_hba *hisi_hba;
+       struct completion *completion;
+       struct work_struct work;
+       bool done;
+};
+
+#define HISI_SAS_RST_WORK_INIT(r, c) \
+       {       .hisi_hba = hisi_hba, \
+               .completion = &c, \
+               .work = __WORK_INITIALIZER(r.work, \
+                               hisi_sas_sync_rst_work_handler), \
+               .done = false, \
+               }
+
+#define HISI_SAS_DECLARE_RST_WORK_ON_STACK(r) \
+       DECLARE_COMPLETION_ONSTACK(c); \
+       DECLARE_WORK(w, hisi_sas_sync_rst_work_handler); \
+       struct hisi_sas_rst r = HISI_SAS_RST_WORK_INIT(r, c)
+
+enum hisi_sas_bit_err_type {
+       HISI_SAS_ERR_SINGLE_BIT_ECC = 0x0,
+       HISI_SAS_ERR_MULTI_BIT_ECC = 0x1,
+};
+
 struct hisi_sas_phy {
        struct hisi_hba *hisi_hba;
        struct hisi_sas_port    *port;
@@ -429,5 +454,6 @@ extern void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba,
                                    struct hisi_sas_slot *slot);
 extern void hisi_sas_init_mem(struct hisi_hba *hisi_hba);
 extern void hisi_sas_rst_work_handler(struct work_struct *work);
+extern void hisi_sas_sync_rst_work_handler(struct work_struct *work);
 extern void hisi_sas_kill_tasklets(struct hisi_hba *hisi_hba);
 #endif
index 01c96a967b4c985d942100bf6c4a7793973bcecd..f74f43c32a072be5dd206339297883afb8324486 100644 (file)
@@ -1299,8 +1299,14 @@ out:
 static int hisi_sas_clear_nexus_ha(struct sas_ha_struct *sas_ha)
 {
        struct hisi_hba *hisi_hba = sas_ha->lldd_ha;
+       HISI_SAS_DECLARE_RST_WORK_ON_STACK(r);
 
-       return hisi_sas_controller_reset(hisi_hba);
+       queue_work(hisi_hba->wq, &r.work);
+       wait_for_completion(r.completion);
+       if (r.done)
+               return TMF_RESP_FUNC_COMPLETE;
+
+       return TMF_RESP_FUNC_FAILED;
 }
 
 static int hisi_sas_query_task(struct sas_task *task)
@@ -1838,6 +1844,17 @@ void hisi_sas_rst_work_handler(struct work_struct *work)
 }
 EXPORT_SYMBOL_GPL(hisi_sas_rst_work_handler);
 
+void hisi_sas_sync_rst_work_handler(struct work_struct *work)
+{
+       struct hisi_sas_rst *rst =
+               container_of(work, struct hisi_sas_rst, work);
+
+       if (!hisi_sas_controller_reset(rst->hisi_hba))
+               rst->done = true;
+       complete(rst->completion);
+}
+EXPORT_SYMBOL_GPL(hisi_sas_sync_rst_work_handler);
+
 int hisi_sas_get_fw_info(struct hisi_hba *hisi_hba)
 {
        struct device *dev = hisi_hba->dev;