Skip to content

Commit 57dbb2b

Browse files
Xiang Chenmartinkpetersen
authored andcommitted
scsi: hisi_sas: Send HARD RESET to clear the previous affiliation of STP target port
If we exchange SAS expander from one SAS controller to other SAS controller without powering it down, the STP target port will maintain previous affiliation and reject all subsequent connection requests from other STP initiator ports with OPEN_REJECT (STP RESOURCES BUSY). To solve this issue, send HARD RESET to clear the previous affiliation of STP target port according to SPL (chapter 6.19.4). We (re-)introduce dev status flag to know if to sleep in NEXUS reset code or not for remote PHYs. The idea is that if the device is being initialised, we don't require the delay, and caller would wait for link to be established, cf. sas_ata_hard_reset(). Co-developed-by: Luo Jiaxing <luojiaxing@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>
1 parent efdcad6 commit 57dbb2b

File tree

3 files changed

+49
-3
lines changed

3 files changed

+49
-3
lines changed

drivers/scsi/hisi_sas/hisi_sas.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <linux/dmapool.h>
1919
#include <linux/iopoll.h>
2020
#include <linux/lcm.h>
21+
#include <linux/libata.h>
2122
#include <linux/mfd/syscon.h>
2223
#include <linux/module.h>
2324
#include <linux/of_address.h>
@@ -94,6 +95,11 @@ enum {
9495
PORT_TYPE_SATA = (1U << 0),
9596
};
9697

98+
enum dev_status {
99+
HISI_SAS_DEV_INIT,
100+
HISI_SAS_DEV_NORMAL,
101+
};
102+
97103
enum {
98104
HISI_SAS_INT_ABT_CMD = 0,
99105
HISI_SAS_INT_ABT_DEV = 1,
@@ -195,6 +201,7 @@ struct hisi_sas_device {
195201
struct hisi_sas_dq *dq;
196202
struct list_head list;
197203
enum sas_device_type dev_type;
204+
enum dev_status dev_status;
198205
int device_id;
199206
int sata_idx;
200207
spinlock_t lock; /* For protecting slots */

drivers/scsi/hisi_sas/hisi_sas_main.c

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -708,6 +708,7 @@ static struct hisi_sas_device *hisi_sas_alloc_dev(struct domain_device *device)
708708

709709
hisi_hba->devices[i].device_id = i;
710710
sas_dev = &hisi_hba->devices[i];
711+
sas_dev->dev_status = HISI_SAS_DEV_INIT;
711712
sas_dev->dev_type = device->dev_type;
712713
sas_dev->hisi_hba = hisi_hba;
713714
sas_dev->sas_device = device;
@@ -732,6 +733,8 @@ static int hisi_sas_init_device(struct domain_device *device)
732733
struct hisi_sas_tmf_task tmf_task;
733734
int retry = HISI_SAS_SRST_ATA_DISK_CNT;
734735
struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
736+
struct device *dev = hisi_hba->dev;
737+
struct sas_phy *local_phy;
735738

736739
switch (device->dev_type) {
737740
case SAS_END_DEVICE:
@@ -747,6 +750,31 @@ static int hisi_sas_init_device(struct domain_device *device)
747750
case SAS_SATA_PM:
748751
case SAS_SATA_PM_PORT:
749752
case SAS_SATA_PENDING:
753+
/*
754+
* send HARD RESET to clear previous affiliation of
755+
* STP target port
756+
*/
757+
local_phy = sas_get_local_phy(device);
758+
if (!scsi_is_sas_phy_local(local_phy)) {
759+
unsigned long deadline = ata_deadline(jiffies, 20000);
760+
struct sata_device *sata_dev = &device->sata_dev;
761+
struct ata_host *ata_host = sata_dev->ata_host;
762+
struct ata_port_operations *ops = ata_host->ops;
763+
struct ata_port *ap = sata_dev->ap;
764+
struct ata_link *link;
765+
unsigned int classes;
766+
767+
ata_for_each_link(link, ap, EDGE)
768+
rc = ops->hardreset(link, &classes,
769+
deadline);
770+
}
771+
sas_put_local_phy(local_phy);
772+
if (rc) {
773+
dev_warn(dev, "SATA disk hardreset fail: 0x%x\n",
774+
rc);
775+
return rc;
776+
}
777+
750778
while (retry-- > 0) {
751779
rc = hisi_sas_softreset_ata_disk(device);
752780
if (!rc)
@@ -809,6 +837,7 @@ static int hisi_sas_dev_found(struct domain_device *device)
809837
rc = hisi_sas_init_device(device);
810838
if (rc)
811839
goto err_out;
840+
sas_dev->dev_status = HISI_SAS_DEV_NORMAL;
812841
return 0;
813842

814843
err_out:
@@ -1715,20 +1744,23 @@ static int hisi_sas_clear_aca(struct domain_device *device, u8 *lun)
17151744
static int hisi_sas_debug_I_T_nexus_reset(struct domain_device *device)
17161745
{
17171746
struct sas_phy *local_phy = sas_get_local_phy(device);
1718-
int rc, reset_type = (device->dev_type == SAS_SATA_DEV ||
1719-
(device->tproto & SAS_PROTOCOL_STP)) ? 0 : 1;
1747+
struct hisi_sas_device *sas_dev = device->lldd_dev;
17201748
struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
17211749
struct sas_ha_struct *sas_ha = &hisi_hba->sha;
17221750
struct asd_sas_phy *sas_phy = sas_ha->sas_phy[local_phy->number];
17231751
struct hisi_sas_phy *phy = container_of(sas_phy,
17241752
struct hisi_sas_phy, sas_phy);
17251753
DECLARE_COMPLETION_ONSTACK(phyreset);
1754+
int rc, reset_type;
17261755

17271756
if (scsi_is_sas_phy_local(local_phy)) {
17281757
phy->in_reset = 1;
17291758
phy->reset_completion = &phyreset;
17301759
}
17311760

1761+
reset_type = (sas_dev->dev_status == HISI_SAS_DEV_INIT ||
1762+
!dev_is_sata(device)) ? 1 : 0;
1763+
17321764
rc = sas_phy_reset(local_phy, reset_type);
17331765
sas_put_local_phy(local_phy);
17341766

@@ -1744,8 +1776,13 @@ static int hisi_sas_debug_I_T_nexus_reset(struct domain_device *device)
17441776
/* report PHY down if timed out */
17451777
if (!ret)
17461778
hisi_sas_phy_down(hisi_hba, sas_phy->id, 0);
1747-
} else
1779+
} else if (sas_dev->dev_status != HISI_SAS_DEV_INIT) {
1780+
/*
1781+
* If in init state, we rely on caller to wait for link to be
1782+
* ready; otherwise, delay.
1783+
*/
17481784
msleep(2000);
1785+
}
17491786

17501787
return rc;
17511788
}
@@ -2264,6 +2301,7 @@ int hisi_sas_alloc(struct hisi_hba *hisi_hba)
22642301
for (i = 0; i < HISI_SAS_MAX_DEVICES; i++) {
22652302
hisi_hba->devices[i].dev_type = SAS_PHY_UNUSED;
22662303
hisi_hba->devices[i].device_id = i;
2304+
hisi_hba->devices[i].dev_status = HISI_SAS_DEV_INIT;
22672305
}
22682306

22692307
for (i = 0; i < hisi_hba->queue_count; i++) {

drivers/scsi/hisi_sas/hisi_sas_v2_hw.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -868,6 +868,7 @@ hisi_sas_device *alloc_dev_quirk_v2_hw(struct domain_device *device)
868868

869869
hisi_hba->devices[i].device_id = i;
870870
sas_dev = &hisi_hba->devices[i];
871+
sas_dev->dev_status = HISI_SAS_DEV_INIT;
871872
sas_dev->dev_type = device->dev_type;
872873
sas_dev->hisi_hba = hisi_hba;
873874
sas_dev->sas_device = device;

0 commit comments

Comments
 (0)