From e402acdb664134f948b62d13b7db866295689f38 Mon Sep 17 00:00:00 2001 From: Xiaofei Tan Date: Sat, 9 Dec 2017 01:16:38 +0800 Subject: [PATCH] scsi: hisi_sas: add an mechanism to do reset work synchronously 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 Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas.h | 26 ++++++++++++++++++++++++++ drivers/scsi/hisi_sas/hisi_sas_main.c | 19 ++++++++++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index b2534caed45a3..71bc8eaac99e7 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -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 diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index e4b30922a75d3..fb162c06ac830 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -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) @@ -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; -- 2.30.2