aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorXiang Chen <chenxiang66@hisilicon.com>2019-09-06 08:55:37 -0400
committerMartin K. Petersen <martin.petersen@oracle.com>2019-09-10 22:28:57 -0400
commite74006edd0d42b45ff37ae4ae13c614cfa30056b (patch)
tree7c6b677ec57b4a6ff5d3b868f24c751d101872cf
parent97b151e75861674a176ff8fb5e243dc2aa066af4 (diff)
scsi: hisi_sas: Fix the conflict between device gone and host reset
When device gone, it will check whether it is during reset, if not, it will send internal task abort. Before internal task abort returned, reset begins, and it will check whether SAS_PHY_UNUSED is set, if not, it will call hisi_sas_init_device(), but at that time domain_device may already be freed or part of it is freed, so it may referenece null pointer in hisi_sas_init_device(). It may occur as follows: thread0 thread1 hisi_sas_dev_gone() check whether in RESET(no) internal task abort reset prep soft_reset ... (part of reset_done) internal task abort failed release resource anyway clear_itct device->lldd_dev=NULL hisi_sas_reset_init_all_device check sas_dev->dev_type is SAS_PHY_UNUSED and !device set dev_type SAS_PHY_UNUSED sas_free_device hisi_sas_init_device ... Semaphore hisi_hba.sema is used to sync the processes of device gone and host reset. To solve the issue, expand the scope that semaphore protects and let them never occur together. And also some places will check whether domain_device is NULL to judge whether the device is gone. So when device gone, need to clear sas_dev->sas_device. Link: https://lore.kernel.org/r/1567774537-20003-14-git-send-email-john.garry@huawei.com Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com> Signed-off-by: John Garry <john.garry@huawei.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_main.c7
1 files changed, 4 insertions, 3 deletions
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index fdf6bb10c556..d1513fdf1e00 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -1049,21 +1049,22 @@ static void hisi_sas_dev_gone(struct domain_device *device)
1049 dev_info(dev, "dev[%d:%x] is gone\n", 1049 dev_info(dev, "dev[%d:%x] is gone\n",
1050 sas_dev->device_id, sas_dev->dev_type); 1050 sas_dev->device_id, sas_dev->dev_type);
1051 1051
1052 down(&hisi_hba->sem);
1052 if (!test_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)) { 1053 if (!test_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)) {
1053 hisi_sas_internal_task_abort(hisi_hba, device, 1054 hisi_sas_internal_task_abort(hisi_hba, device,
1054 HISI_SAS_INT_ABT_DEV, 0); 1055 HISI_SAS_INT_ABT_DEV, 0);
1055 1056
1056 hisi_sas_dereg_device(hisi_hba, device); 1057 hisi_sas_dereg_device(hisi_hba, device);
1057 1058
1058 down(&hisi_hba->sem);
1059 hisi_hba->hw->clear_itct(hisi_hba, sas_dev); 1059 hisi_hba->hw->clear_itct(hisi_hba, sas_dev);
1060 up(&hisi_hba->sem);
1061 device->lldd_dev = NULL; 1060 device->lldd_dev = NULL;
1062 } 1061 }
1063 1062
1064 if (hisi_hba->hw->free_device) 1063 if (hisi_hba->hw->free_device)
1065 hisi_hba->hw->free_device(sas_dev); 1064 hisi_hba->hw->free_device(sas_dev);
1066 sas_dev->dev_type = SAS_PHY_UNUSED; 1065 sas_dev->dev_type = SAS_PHY_UNUSED;
1066 sas_dev->sas_device = NULL;
1067 up(&hisi_hba->sem);
1067} 1068}
1068 1069
1069static int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags) 1070static int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags)
@@ -1543,11 +1544,11 @@ void hisi_sas_controller_reset_done(struct hisi_hba *hisi_hba)
1543 msleep(1000); 1544 msleep(1000);
1544 hisi_sas_refresh_port_id(hisi_hba); 1545 hisi_sas_refresh_port_id(hisi_hba);
1545 clear_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags); 1546 clear_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags);
1546 up(&hisi_hba->sem);
1547 1547
1548 if (hisi_hba->reject_stp_links_msk) 1548 if (hisi_hba->reject_stp_links_msk)
1549 hisi_sas_terminate_stp_reject(hisi_hba); 1549 hisi_sas_terminate_stp_reject(hisi_hba);
1550 hisi_sas_reset_init_all_devices(hisi_hba); 1550 hisi_sas_reset_init_all_devices(hisi_hba);
1551 up(&hisi_hba->sem);
1551 scsi_unblock_requests(shost); 1552 scsi_unblock_requests(shost);
1552 clear_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags); 1553 clear_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags);
1553 1554