scsi: hisi_sas: Mark PHY as in reset for nexus reset
authorXiang Chen <chenxiang66@hisilicon.com>
Mon, 21 May 2018 10:09:25 +0000 (18:09 +0800)
committerMartin K. Petersen <martin.petersen@oracle.com>
Tue, 29 May 2018 02:40:32 +0000 (22:40 -0400)
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>
drivers/scsi/hisi_sas/hisi_sas.h
drivers/scsi/hisi_sas/hisi_sas_main.c
drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
drivers/scsi/hisi_sas/hisi_sas_v3_hw.c

index 9400824f23ad89f72f34ce658aae42154b811bae..7052a5d45f7f98fddcaf9adc16df764df888f060 100644 (file)
@@ -136,11 +136,14 @@ struct hisi_sas_phy {
        struct hisi_sas_port    *port;
        struct asd_sas_phy      sas_phy;
        struct sas_identify     identify;
+       struct completion *reset_completion;
+       spinlock_t lock;
        u64             port_id; /* from hw */
        u64             frame_rcvd_size;
        u8              frame_rcvd[32];
        u8              phy_attached;
-       u8              reserved[3];
+       u8              in_reset;
+       u8              reserved[2];
        u32             phy_type;
        enum sas_linkrate       minimum_linkrate;
        enum sas_linkrate       maximum_linkrate;
index 3028024cb437ac876bf6898f995c3e96e30aac2c..6f562974f8f6b44829ac5dda778a6baccde819fa 100644 (file)
@@ -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)
 {
-       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 ||
                        (device->tproto & SAS_PROTOCOL_STP)) ? 0 : 1;
-       rc = sas_phy_reset(phy, reset_type);
-       sas_put_local_phy(phy);
-       msleep(2000);
+       struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
+       struct sas_ha_struct *sas_ha = &hisi_hba->sha;
+       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;
 }
 
@@ -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 asd_sas_phy *sas_phy = &phy->sas_phy;
        struct sas_ha_struct *sas_ha = &hisi_hba->sha;
+       struct device *dev = hisi_hba->dev;
 
        if (rdy) {
                /* Phy down but ready */
@@ -1891,6 +1919,10 @@ void hisi_sas_phy_down(struct hisi_hba *hisi_hba, int phy_no, int rdy)
        } else {
                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 */
                sas_ha->notify_phy_event(sas_phy, PHYE_LOSS_OF_SIGNAL);
                sas_phy_disconnected(sas_phy);
index 05609ac1b31d231359fdaa17e7c604e4c87b7a8d..89ab18c1959c7a00bfe956b646d4c5fd9e600fc1 100644 (file)
@@ -1373,6 +1373,7 @@ static irqreturn_t int_phyup_v1_hw(int irq_no, void *p)
        u32 *frame_rcvd = (u32 *)sas_phy->frame_rcvd;
        struct sas_identify_frame *id = (struct sas_identify_frame *)frame_rcvd;
        irqreturn_t res = IRQ_HANDLED;
+       unsigned long flags;
 
        irq_value = hisi_sas_phy_read32(hisi_hba, phy_no, CHL_INT2);
        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;
        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:
        hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT2,
                             CHL_INT2_SL_PHY_ENA_MSK);
index 369ef7ebb1e00c2fec5e736cc8286ebdc88d05eb..213c530e63f2a8719fdf97af2b13c4931bb28df2 100644 (file)
@@ -2661,6 +2661,7 @@ static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
        struct device *dev = hisi_hba->dev;
        u32 *frame_rcvd = (u32 *)sas_phy->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);
 
@@ -2713,6 +2714,12 @@ static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
                        set_link_timer_quirk(hisi_hba);
        }
        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:
        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;
        irqreturn_t res = IRQ_HANDLED;
        u8 attached_sas_addr[SAS_ADDR_SIZE] = {0};
+       unsigned long flags;
        int phy_no, offset;
 
        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;
        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:
        hisi_sas_write32(hisi_hba, ENT_INT_SRC1 + offset, ent_tmp);
        hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK1 + offset, ent_msk);
index 8c996aa42528f12fdd25e88043738563e97711cb..9f1e2d03f914dd175f4187fd27040a45ee27504b 100644 (file)
@@ -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 asd_sas_phy *sas_phy = &phy->sas_phy;
        struct device *dev = hisi_hba->dev;
+       unsigned long flags;
 
        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;
        hisi_sas_notify_phy_event(phy, HISI_PHYE_PHY_UP);
        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:
        hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0,
                             CHL_INT0_SL_PHY_ENABLE_MSK);