diff options
author | John Garry <john.garry@huawei.com> | 2022-05-12 14:15:34 +0300 |
---|---|---|
committer | Martin K. Petersen <martin.petersen@oracle.com> | 2022-05-20 03:16:26 +0300 |
commit | e9dedc13bb11bc553754abecb322e5e41d1b4fef (patch) | |
tree | fef4f552b4be286a07f9f93eb480976a2318643f /drivers/scsi/hisi_sas | |
parent | 71453bd9d1bfa2a75f742ac8ad75c084097e9a50 (diff) | |
download | linux-e9dedc13bb11bc553754abecb322e5e41d1b4fef.tar.xz |
scsi: hisi_sas: Fix rescan after deleting a disk
Removing an ATA device via sysfs means that the device may not be found
through re-scanning:
root@ubuntu:/home/john# lsscsi
[0:0:0:0] disk SanDisk LT0200MO P404 /dev/sda
[0:0:1:0] disk ATA HGST HUS724040AL A8B0 /dev/sdb
[0:0:8:0] enclosu 12G SAS Expander RevB -
root@ubuntu:/home/john# echo 1 > /sys/block/sdb/device/delete
root@ubuntu:/home/john# echo "- - -" > /sys/class/scsi_host/host0/scan
root@ubuntu:/home/john# lsscsi
[0:0:0:0] disk SanDisk LT0200MO P404 /dev/sda
[0:0:8:0] enclosu 12G SAS Expander RevB -
root@ubuntu:/home/john#
The problem is that the rescan of the device may conflict with the device
in being re-initialized, as follows:
- In the rescan we call hisi_sas_slave_alloc() in store_scan() ->
sas_user_scan() -> [__]scsi_scan_target() -> scsi_probe_and_add_lunc()
-> scsi_alloc_sdev() -> hisi_sas_slave_alloc() -> hisi_sas_init_device()
In hisi_sas_init_device() we issue an IT nexus reset for ATA devices
- That IT nexus causes the remote PHY to go down and this triggers a bcast
event
- In parallel libsas processes the bcast event, finds that the phy is down
and marks the device as gone
The hard reset issued in hisi_sas_init_device() is unncessary - as
described in the code comment - so remove it. Also set dev status as
HISI_SAS_DEV_NORMAL as the hisi_sas_init_device() call.
Link: https://lore.kernel.org/r/1652354134-171343-4-git-send-email-john.garry@huawei.com
Fixes: 36c6b7613ef1 ("scsi: hisi_sas: Initialise devices in .slave_alloc callback")
Tested-by: Yihang Li <liyihang6@hisilicon.com>
Reviewed-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>
Diffstat (limited to 'drivers/scsi/hisi_sas')
-rw-r--r-- | drivers/scsi/hisi_sas/hisi_sas_main.c | 47 |
1 files changed, 18 insertions, 29 deletions
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 997f27e2f1e5..f81e74fd6263 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -709,8 +709,6 @@ static int hisi_sas_init_device(struct domain_device *device) struct scsi_lun lun; int retry = HISI_SAS_DISK_RECOVER_CNT; struct hisi_hba *hisi_hba = dev_to_hisi_hba(device); - struct device *dev = hisi_hba->dev; - struct sas_phy *local_phy; switch (device->dev_type) { case SAS_END_DEVICE: @@ -729,30 +727,18 @@ static int hisi_sas_init_device(struct domain_device *device) case SAS_SATA_PM_PORT: case SAS_SATA_PENDING: /* - * send HARD RESET to clear previous affiliation of - * STP target port + * If an expander is swapped when a SATA disk is attached then + * we should issue a hard reset to clear previous affiliation + * of STP target port, see SPL (chapter 6.19.4). + * + * However we don't need to issue a hard reset here for these + * reasons: + * a. When probing the device, libsas/libata already issues a + * hard reset in sas_probe_sata() -> ata_sas_async_probe(). + * Note that in hisi_sas_debug_I_T_nexus_reset() we take care + * to issue a hard reset by checking the dev status (== INIT). + * b. When resetting the controller, this is simply unnecessary. */ - local_phy = sas_get_local_phy(device); - if (!scsi_is_sas_phy_local(local_phy) && - !test_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags)) { - unsigned long deadline = ata_deadline(jiffies, 20000); - struct sata_device *sata_dev = &device->sata_dev; - struct ata_host *ata_host = sata_dev->ata_host; - struct ata_port_operations *ops = ata_host->ops; - struct ata_port *ap = sata_dev->ap; - struct ata_link *link; - unsigned int classes; - - ata_for_each_link(link, ap, EDGE) - rc = ops->hardreset(link, &classes, - deadline); - } - sas_put_local_phy(local_phy); - if (rc) { - dev_warn(dev, "SATA disk hardreset fail: %d\n", rc); - return rc; - } - while (retry-- > 0) { rc = hisi_sas_softreset_ata_disk(device); if (!rc) @@ -768,15 +754,19 @@ static int hisi_sas_init_device(struct domain_device *device) int hisi_sas_slave_alloc(struct scsi_device *sdev) { - struct domain_device *ddev; + struct domain_device *ddev = sdev_to_domain_dev(sdev); + struct hisi_sas_device *sas_dev = ddev->lldd_dev; int rc; rc = sas_slave_alloc(sdev); if (rc) return rc; - ddev = sdev_to_domain_dev(sdev); - return hisi_sas_init_device(ddev); + rc = hisi_sas_init_device(ddev); + if (rc) + return rc; + sas_dev->dev_status = HISI_SAS_DEV_NORMAL; + return 0; } EXPORT_SYMBOL_GPL(hisi_sas_slave_alloc); @@ -826,7 +816,6 @@ static int hisi_sas_dev_found(struct domain_device *device) dev_info(dev, "dev[%d:%x] found\n", sas_dev->device_id, sas_dev->dev_type); - sas_dev->dev_status = HISI_SAS_DEV_NORMAL; return 0; err_out: |