#define HISI_SAS_PROT_MASK (HISI_SAS_DIF_PROT_MASK)
 
+#define HISI_SAS_WAIT_PHYUP_TIMEOUT 20
+
 struct hisi_hba;
 
 enum {
        struct asd_sas_phy      sas_phy;
        struct sas_identify     identify;
        struct completion *reset_completion;
+       struct timer_list timer;
        spinlock_t lock;
        u64             port_id; /* from hw */
        u64             frame_rcvd_size;
 extern void hisi_sas_rst_work_handler(struct work_struct *work);
 extern void hisi_sas_sync_rst_work_handler(struct work_struct *work);
 extern void hisi_sas_kill_tasklets(struct hisi_hba *hisi_hba);
+extern void hisi_sas_phy_oob_ready(struct hisi_hba *hisi_hba, int phy_no);
 extern bool hisi_sas_notify_phy_event(struct hisi_sas_phy *phy,
                                enum hisi_sas_phy_event event);
 extern void hisi_sas_release_tasks(struct hisi_hba *hisi_hba);
 
 }
 EXPORT_SYMBOL_GPL(hisi_sas_notify_phy_event);
 
+static void hisi_sas_wait_phyup_timedout(struct timer_list *t)
+{
+       struct hisi_sas_phy *phy = from_timer(phy, t, timer);
+       struct hisi_hba *hisi_hba = phy->hisi_hba;
+       struct device *dev = hisi_hba->dev;
+       int phy_no = phy->sas_phy.id;
+
+       dev_warn(dev, "phy%d wait phyup timeout, issuing link reset\n", phy_no);
+       hisi_sas_notify_phy_event(phy, HISI_PHYE_LINK_RESET);
+}
+
+void hisi_sas_phy_oob_ready(struct hisi_hba *hisi_hba, int phy_no)
+{
+       struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
+       struct device *dev = hisi_hba->dev;
+
+       if (!timer_pending(&phy->timer)) {
+               dev_dbg(dev, "phy%d OOB ready\n", phy_no);
+               phy->timer.expires = jiffies + HISI_SAS_WAIT_PHYUP_TIMEOUT * HZ;
+               add_timer(&phy->timer);
+       }
+}
+EXPORT_SYMBOL_GPL(hisi_sas_phy_oob_ready);
+
 static void hisi_sas_phy_init(struct hisi_hba *hisi_hba, int phy_no)
 {
        struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
                INIT_WORK(&phy->works[i], hisi_sas_phye_fns[i]);
 
        spin_lock_init(&phy->lock);
+
+       timer_setup(&phy->timer, hisi_sas_wait_phyup_timedout, 0);
 }
 
 static void hisi_sas_port_notify_formed(struct asd_sas_phy *sas_phy)
 
        if (is_sata_phy_v2_hw(hisi_hba, phy_no))
                goto end;
 
+       del_timer(&phy->timer);
+
        if (phy_no == 8) {
                u32 port_state = hisi_sas_read32(hisi_hba, PORT_STATE);
 
        struct hisi_sas_port *port = phy->port;
        struct device *dev = hisi_hba->dev;
 
+       del_timer(&phy->timer);
        hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_NOT_RDY_MSK, 1);
 
        phy_state = hisi_sas_read32(hisi_hba, PHY_STATE);
                        if (irq_value0 & CHL_INT0_SL_RX_BCST_ACK_MSK)
                                phy_bcast_v2_hw(phy_no, hisi_hba);
 
+                       if (irq_value0 & CHL_INT0_PHY_RDY_MSK)
+                               hisi_sas_phy_oob_ready(hisi_hba, phy_no);
+
                        hisi_sas_phy_write32(hisi_hba, phy_no,
                                        CHL_INT0, irq_value0
                                        & (~CHL_INT0_HOTPLUG_TOUT_MSK)
        unsigned long flags;
        int phy_no, offset;
 
+       del_timer(&phy->timer);
+
        phy_no = sas_phy->id;
        initial_fis = &hisi_hba->initial_fis[phy_no];
        fis = &initial_fis->fis;
 
        struct device *dev = hisi_hba->dev;
        unsigned long flags;
 
+       del_timer(&phy->timer);
        hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_PHY_ENA_MSK, 1);
 
        port_id = hisi_sas_read32(hisi_hba, PHY_PORT_NUM_MA);
 
 static irqreturn_t phy_down_v3_hw(int phy_no, struct hisi_hba *hisi_hba)
 {
+       struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
        u32 phy_state, sl_ctrl, txid_auto;
        struct device *dev = hisi_hba->dev;
 
+       del_timer(&phy->timer);
        hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_NOT_RDY_MSK, 1);
 
        phy_state = hisi_sas_read32(hisi_hba, PHY_STATE);
        hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT2, irq_value);
 }
 
+static void handle_chl_int0_v3_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+       u32 irq_value0 = hisi_sas_phy_read32(hisi_hba, phy_no, CHL_INT0);
+
+       if (irq_value0 & CHL_INT0_PHY_RDY_MSK)
+               hisi_sas_phy_oob_ready(hisi_hba, phy_no);
+
+       hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0,
+                            irq_value0 & (~CHL_INT0_SL_RX_BCST_ACK_MSK)
+                            & (~CHL_INT0_SL_PHY_ENABLE_MSK)
+                            & (~CHL_INT0_NOT_RDY_MSK));
+}
+
 static irqreturn_t int_chnl_int_v3_hw(int irq_no, void *p)
 {
        struct hisi_hba *hisi_hba = p;
                                & 0xeeeeeeee;
 
        while (irq_msk) {
-               u32 irq_value0 = hisi_sas_phy_read32(hisi_hba, phy_no,
-                                                    CHL_INT0);
+               if (irq_msk & (2 << (phy_no * 4)))
+                       handle_chl_int0_v3_hw(hisi_hba, phy_no);
 
                if (irq_msk & (4 << (phy_no * 4)))
                        handle_chl_int1_v3_hw(hisi_hba, phy_no);
                if (irq_msk & (8 << (phy_no * 4)))
                        handle_chl_int2_v3_hw(hisi_hba, phy_no);
 
-               if (irq_msk & (2 << (phy_no * 4)) && irq_value0) {
-                       hisi_sas_phy_write32(hisi_hba, phy_no,
-                                       CHL_INT0, irq_value0
-                                       & (~CHL_INT0_SL_RX_BCST_ACK_MSK)
-                                       & (~CHL_INT0_SL_PHY_ENABLE_MSK)
-                                       & (~CHL_INT0_NOT_RDY_MSK));
-               }
                irq_msk &= ~(0xe << (phy_no * 4));
                phy_no++;
        }