4.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiaofei Tan tanxiaofei@huawei.com
[ Upstream commit d2fc401e47529d9ffd2673a5395d56002e31ad98 ]
There is a possible conflict when a device is removed and host reset occurs concurrently.
The reason is that then the device is notified as gone, we try to clear the ITCT, which is notified via an interrupt. The dev gone function pends on this event with a completion, which is completed when the ITCT interrupt occurs.
But host reset will disable all interrupts, the wait_for_completion() may wait indefinitely.
This patch adds an semaphore to synchronise this two processes. The semaphore is taken by the host reset as the basis of synchronising.
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 Signed-off-by: Sasha Levin alexander.levin@microsoft.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- drivers/scsi/hisi_sas/hisi_sas.h | 1 + drivers/scsi/hisi_sas/hisi_sas_main.c | 6 ++++++ 2 files changed, 7 insertions(+)
--- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -277,6 +277,7 @@ struct hisi_hba {
int n_phy; spinlock_t lock; + struct semaphore sem;
struct timer_list timer; struct workqueue_struct *wq; --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -914,7 +914,9 @@ static void hisi_sas_dev_gone(struct dom
hisi_sas_dereg_device(hisi_hba, device);
+ down(&hisi_hba->sem); hisi_hba->hw->clear_itct(hisi_hba, sas_dev); + up(&hisi_hba->sem); device->lldd_dev = NULL; }
@@ -1364,6 +1366,7 @@ static int hisi_sas_controller_reset(str if (test_and_set_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)) return -1;
+ down(&hisi_hba->sem); dev_info(dev, "controller resetting...\n"); old_state = hisi_hba->hw->get_phys_state(hisi_hba);
@@ -1378,6 +1381,7 @@ static int hisi_sas_controller_reset(str if (rc) { dev_warn(dev, "controller reset failed (%d)\n", rc); clear_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags); + up(&hisi_hba->sem); scsi_unblock_requests(shost); goto out; } @@ -1388,6 +1392,7 @@ static int hisi_sas_controller_reset(str hisi_hba->hw->phys_init(hisi_hba); msleep(1000); hisi_sas_refresh_port_id(hisi_hba); + up(&hisi_hba->sem);
if (hisi_hba->reject_stp_links_msk) hisi_sas_terminate_stp_reject(hisi_hba); @@ -2016,6 +2021,7 @@ int hisi_sas_alloc(struct hisi_hba *hisi struct device *dev = hisi_hba->dev; int i, s, max_command_entries = hisi_hba->hw->max_command_entries;
+ sema_init(&hisi_hba->sem, 1); spin_lock_init(&hisi_hba->lock); for (i = 0; i < hisi_hba->n_phy; i++) { hisi_sas_phy_init(hisi_hba, i);