scsi: hisi_sas: Mark PHY as in reset for nexus reset
When issuing a nexus reset for directly attached device, we want to ignore the PHY down events so libsas will not deform and reform the port. In the case that the attached SAS changes for the reset, libsas will deform and form a port. For scenario that the PHY does not come up after a timeout period, then report the PHY down to libsas. 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>
This commit is contained in:
parent
d87e72fb4f
commit
3e1fb1b8ab
|
@ -136,11 +136,14 @@ struct hisi_sas_phy {
|
||||||
struct hisi_sas_port *port;
|
struct hisi_sas_port *port;
|
||||||
struct asd_sas_phy sas_phy;
|
struct asd_sas_phy sas_phy;
|
||||||
struct sas_identify identify;
|
struct sas_identify identify;
|
||||||
|
struct completion *reset_completion;
|
||||||
|
spinlock_t lock;
|
||||||
u64 port_id; /* from hw */
|
u64 port_id; /* from hw */
|
||||||
u64 frame_rcvd_size;
|
u64 frame_rcvd_size;
|
||||||
u8 frame_rcvd[32];
|
u8 frame_rcvd[32];
|
||||||
u8 phy_attached;
|
u8 phy_attached;
|
||||||
u8 reserved[3];
|
u8 in_reset;
|
||||||
|
u8 reserved[2];
|
||||||
u32 phy_type;
|
u32 phy_type;
|
||||||
enum sas_linkrate minimum_linkrate;
|
enum sas_linkrate minimum_linkrate;
|
||||||
enum sas_linkrate maximum_linkrate;
|
enum sas_linkrate maximum_linkrate;
|
||||||
|
|
|
@ -1529,12 +1529,39 @@ static int hisi_sas_clear_aca(struct domain_device *device, u8 *lun)
|
||||||
|
|
||||||
static int hisi_sas_debug_I_T_nexus_reset(struct domain_device *device)
|
static int hisi_sas_debug_I_T_nexus_reset(struct domain_device *device)
|
||||||
{
|
{
|
||||||
struct sas_phy *phy = sas_get_local_phy(device);
|
struct sas_phy *local_phy = sas_get_local_phy(device);
|
||||||
int rc, reset_type = (device->dev_type == SAS_SATA_DEV ||
|
int rc, reset_type = (device->dev_type == SAS_SATA_DEV ||
|
||||||
(device->tproto & SAS_PROTOCOL_STP)) ? 0 : 1;
|
(device->tproto & SAS_PROTOCOL_STP)) ? 0 : 1;
|
||||||
rc = sas_phy_reset(phy, reset_type);
|
struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
|
||||||
sas_put_local_phy(phy);
|
struct sas_ha_struct *sas_ha = &hisi_hba->sha;
|
||||||
msleep(2000);
|
struct asd_sas_phy *sas_phy = sas_ha->sas_phy[local_phy->number];
|
||||||
|
struct hisi_sas_phy *phy = container_of(sas_phy,
|
||||||
|
struct hisi_sas_phy, sas_phy);
|
||||||
|
DECLARE_COMPLETION_ONSTACK(phyreset);
|
||||||
|
|
||||||
|
if (scsi_is_sas_phy_local(local_phy)) {
|
||||||
|
phy->in_reset = 1;
|
||||||
|
phy->reset_completion = &phyreset;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = sas_phy_reset(local_phy, reset_type);
|
||||||
|
sas_put_local_phy(local_phy);
|
||||||
|
|
||||||
|
if (scsi_is_sas_phy_local(local_phy)) {
|
||||||
|
int ret = wait_for_completion_timeout(&phyreset, 2 * HZ);
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&phy->lock, flags);
|
||||||
|
phy->reset_completion = NULL;
|
||||||
|
phy->in_reset = 0;
|
||||||
|
spin_unlock_irqrestore(&phy->lock, flags);
|
||||||
|
|
||||||
|
/* report PHY down if timed out */
|
||||||
|
if (!ret)
|
||||||
|
hisi_sas_phy_down(hisi_hba, sas_phy->id, 0);
|
||||||
|
} else
|
||||||
|
msleep(2000);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1883,6 +1910,7 @@ void hisi_sas_phy_down(struct hisi_hba *hisi_hba, int phy_no, int rdy)
|
||||||
struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
|
struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
|
||||||
struct asd_sas_phy *sas_phy = &phy->sas_phy;
|
struct asd_sas_phy *sas_phy = &phy->sas_phy;
|
||||||
struct sas_ha_struct *sas_ha = &hisi_hba->sha;
|
struct sas_ha_struct *sas_ha = &hisi_hba->sha;
|
||||||
|
struct device *dev = hisi_hba->dev;
|
||||||
|
|
||||||
if (rdy) {
|
if (rdy) {
|
||||||
/* Phy down but ready */
|
/* Phy down but ready */
|
||||||
|
@ -1891,6 +1919,10 @@ void hisi_sas_phy_down(struct hisi_hba *hisi_hba, int phy_no, int rdy)
|
||||||
} else {
|
} else {
|
||||||
struct hisi_sas_port *port = phy->port;
|
struct hisi_sas_port *port = phy->port;
|
||||||
|
|
||||||
|
if (phy->in_reset) {
|
||||||
|
dev_info(dev, "ignore flutter phy%d down\n", phy_no);
|
||||||
|
return;
|
||||||
|
}
|
||||||
/* Phy down and not ready */
|
/* Phy down and not ready */
|
||||||
sas_ha->notify_phy_event(sas_phy, PHYE_LOSS_OF_SIGNAL);
|
sas_ha->notify_phy_event(sas_phy, PHYE_LOSS_OF_SIGNAL);
|
||||||
sas_phy_disconnected(sas_phy);
|
sas_phy_disconnected(sas_phy);
|
||||||
|
|
|
@ -1373,6 +1373,7 @@ static irqreturn_t int_phyup_v1_hw(int irq_no, void *p)
|
||||||
u32 *frame_rcvd = (u32 *)sas_phy->frame_rcvd;
|
u32 *frame_rcvd = (u32 *)sas_phy->frame_rcvd;
|
||||||
struct sas_identify_frame *id = (struct sas_identify_frame *)frame_rcvd;
|
struct sas_identify_frame *id = (struct sas_identify_frame *)frame_rcvd;
|
||||||
irqreturn_t res = IRQ_HANDLED;
|
irqreturn_t res = IRQ_HANDLED;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
irq_value = hisi_sas_phy_read32(hisi_hba, phy_no, CHL_INT2);
|
irq_value = hisi_sas_phy_read32(hisi_hba, phy_no, CHL_INT2);
|
||||||
if (!(irq_value & CHL_INT2_SL_PHY_ENA_MSK)) {
|
if (!(irq_value & CHL_INT2_SL_PHY_ENA_MSK)) {
|
||||||
|
@ -1426,6 +1427,13 @@ static irqreturn_t int_phyup_v1_hw(int irq_no, void *p)
|
||||||
SAS_PROTOCOL_SMP;
|
SAS_PROTOCOL_SMP;
|
||||||
hisi_sas_notify_phy_event(phy, HISI_PHYE_PHY_UP);
|
hisi_sas_notify_phy_event(phy, HISI_PHYE_PHY_UP);
|
||||||
|
|
||||||
|
spin_lock_irqsave(&phy->lock, flags);
|
||||||
|
if (phy->reset_completion) {
|
||||||
|
phy->in_reset = 0;
|
||||||
|
complete(phy->reset_completion);
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&phy->lock, flags);
|
||||||
|
|
||||||
end:
|
end:
|
||||||
hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT2,
|
hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT2,
|
||||||
CHL_INT2_SL_PHY_ENA_MSK);
|
CHL_INT2_SL_PHY_ENA_MSK);
|
||||||
|
|
|
@ -2661,6 +2661,7 @@ static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
|
||||||
struct device *dev = hisi_hba->dev;
|
struct device *dev = hisi_hba->dev;
|
||||||
u32 *frame_rcvd = (u32 *)sas_phy->frame_rcvd;
|
u32 *frame_rcvd = (u32 *)sas_phy->frame_rcvd;
|
||||||
struct sas_identify_frame *id = (struct sas_identify_frame *)frame_rcvd;
|
struct sas_identify_frame *id = (struct sas_identify_frame *)frame_rcvd;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_PHY_ENA_MSK, 1);
|
hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_PHY_ENA_MSK, 1);
|
||||||
|
|
||||||
|
@ -2713,6 +2714,12 @@ static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
|
||||||
set_link_timer_quirk(hisi_hba);
|
set_link_timer_quirk(hisi_hba);
|
||||||
}
|
}
|
||||||
hisi_sas_notify_phy_event(phy, HISI_PHYE_PHY_UP);
|
hisi_sas_notify_phy_event(phy, HISI_PHYE_PHY_UP);
|
||||||
|
spin_lock_irqsave(&phy->lock, flags);
|
||||||
|
if (phy->reset_completion) {
|
||||||
|
phy->in_reset = 0;
|
||||||
|
complete(phy->reset_completion);
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&phy->lock, flags);
|
||||||
|
|
||||||
end:
|
end:
|
||||||
hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0,
|
hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0,
|
||||||
|
@ -3201,6 +3208,7 @@ static irqreturn_t sata_int_v2_hw(int irq_no, void *p)
|
||||||
u32 ent_tmp, ent_msk, ent_int, port_id, link_rate, hard_phy_linkrate;
|
u32 ent_tmp, ent_msk, ent_int, port_id, link_rate, hard_phy_linkrate;
|
||||||
irqreturn_t res = IRQ_HANDLED;
|
irqreturn_t res = IRQ_HANDLED;
|
||||||
u8 attached_sas_addr[SAS_ADDR_SIZE] = {0};
|
u8 attached_sas_addr[SAS_ADDR_SIZE] = {0};
|
||||||
|
unsigned long flags;
|
||||||
int phy_no, offset;
|
int phy_no, offset;
|
||||||
|
|
||||||
phy_no = sas_phy->id;
|
phy_no = sas_phy->id;
|
||||||
|
@ -3275,6 +3283,12 @@ static irqreturn_t sata_int_v2_hw(int irq_no, void *p)
|
||||||
phy->identify.target_port_protocols = SAS_PROTOCOL_SATA;
|
phy->identify.target_port_protocols = SAS_PROTOCOL_SATA;
|
||||||
hisi_sas_notify_phy_event(phy, HISI_PHYE_PHY_UP);
|
hisi_sas_notify_phy_event(phy, HISI_PHYE_PHY_UP);
|
||||||
|
|
||||||
|
spin_lock_irqsave(&phy->lock, flags);
|
||||||
|
if (phy->reset_completion) {
|
||||||
|
phy->in_reset = 0;
|
||||||
|
complete(phy->reset_completion);
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&phy->lock, flags);
|
||||||
end:
|
end:
|
||||||
hisi_sas_write32(hisi_hba, ENT_INT_SRC1 + offset, ent_tmp);
|
hisi_sas_write32(hisi_hba, ENT_INT_SRC1 + offset, ent_tmp);
|
||||||
hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK1 + offset, ent_msk);
|
hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK1 + offset, ent_msk);
|
||||||
|
|
|
@ -1143,6 +1143,7 @@ static irqreturn_t phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba)
|
||||||
struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
|
struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
|
||||||
struct asd_sas_phy *sas_phy = &phy->sas_phy;
|
struct asd_sas_phy *sas_phy = &phy->sas_phy;
|
||||||
struct device *dev = hisi_hba->dev;
|
struct device *dev = hisi_hba->dev;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_PHY_ENA_MSK, 1);
|
hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_PHY_ENA_MSK, 1);
|
||||||
|
|
||||||
|
@ -1211,6 +1212,12 @@ static irqreturn_t phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba)
|
||||||
phy->phy_attached = 1;
|
phy->phy_attached = 1;
|
||||||
hisi_sas_notify_phy_event(phy, HISI_PHYE_PHY_UP);
|
hisi_sas_notify_phy_event(phy, HISI_PHYE_PHY_UP);
|
||||||
res = IRQ_HANDLED;
|
res = IRQ_HANDLED;
|
||||||
|
spin_lock_irqsave(&phy->lock, flags);
|
||||||
|
if (phy->reset_completion) {
|
||||||
|
phy->in_reset = 0;
|
||||||
|
complete(phy->reset_completion);
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&phy->lock, flags);
|
||||||
end:
|
end:
|
||||||
hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0,
|
hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0,
|
||||||
CHL_INT0_SL_PHY_ENABLE_MSK);
|
CHL_INT0_SL_PHY_ENABLE_MSK);
|
||||||
|
|
Loading…
Reference in New Issue