]> asedeno.scripts.mit.edu Git - linux.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)
committerMartin K. Petersen <martin.petersen@oracle.com>
Fri, 15 Dec 2017 02:25:02 +0000 (21:25 -0500)
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>
drivers/scsi/hisi_sas/hisi_sas.h
drivers/scsi/hisi_sas/hisi_sas_main.c

index b2534caed45a30097f50865f97d7728a9900f2d8..71bc8eaac99e71bc9af2d8823f172ee2d2907f3c 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;
@@ -426,5 +451,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 e4b30922a75d3292c376d4fb20ba7db2b65e3d12..fb162c06ac830dd01f1e6c4e44391b3cbb9f8421 100644 (file)
@@ -1299,8 +1299,14 @@ static int hisi_sas_lu_reset(struct domain_device *device, u8 *lun)
 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)
@@ -1820,6 +1826,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;