]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
scsi: hisi_sas: Add SATA FIS check for v3 hw
[mirror_ubuntu-bionic-kernel.git] / drivers / scsi / hisi_sas / hisi_sas_v2_hw.c
index 5d3467fd728d9f583491617e9e513266100a48b9..7b39c4d23328b5d00ac55cf91fead074821d9262 100644 (file)
 #define SAS_ECC_INTR_NCQ_MEM3_ECC_1B_OFF       19
 #define SAS_ECC_INTR_MSK               0x1ec
 #define HGC_ERR_STAT_EN                        0x238
+#define CQE_SEND_CNT                   0x248
 #define DLVRY_Q_0_BASE_ADDR_LO         0x260
 #define DLVRY_Q_0_BASE_ADDR_HI         0x264
 #define DLVRY_Q_0_DEPTH                        0x268
 #define CHL_INT1_DMAC_TX_ECC_ERR_MSK   (0x1 << CHL_INT1_DMAC_TX_ECC_ERR_OFF)
 #define CHL_INT1_DMAC_RX_ECC_ERR_OFF   17
 #define CHL_INT1_DMAC_RX_ECC_ERR_MSK   (0x1 << CHL_INT1_DMAC_RX_ECC_ERR_OFF)
+#define CHL_INT1_DMAC_TX_AXI_WR_ERR_OFF        19
+#define CHL_INT1_DMAC_TX_AXI_RD_ERR_OFF        20
+#define CHL_INT1_DMAC_RX_AXI_WR_ERR_OFF        21
+#define CHL_INT1_DMAC_RX_AXI_RD_ERR_OFF        22
 #define CHL_INT2                       (PORT_BASE + 0x1bc)
+#define CHL_INT2_SL_IDAF_TOUT_CONF_OFF 0
 #define CHL_INT0_MSK                   (PORT_BASE + 0x1c0)
 #define CHL_INT1_MSK                   (PORT_BASE + 0x1c4)
 #define CHL_INT2_MSK                   (PORT_BASE + 0x1c8)
 #define CMD_HDR_RESP_REPORT_MSK                (0x1 << CMD_HDR_RESP_REPORT_OFF)
 #define CMD_HDR_TLR_CTRL_OFF           6
 #define CMD_HDR_TLR_CTRL_MSK           (0x3 << CMD_HDR_TLR_CTRL_OFF)
+#define CMD_HDR_PHY_ID_OFF             8
+#define CMD_HDR_PHY_ID_MSK             (0x1ff << CMD_HDR_PHY_ID_OFF)
+#define CMD_HDR_FORCE_PHY_OFF          17
+#define CMD_HDR_FORCE_PHY_MSK          (0x1 << CMD_HDR_FORCE_PHY_OFF)
 #define CMD_HDR_PORT_OFF               18
 #define CMD_HDR_PORT_MSK               (0xf << CMD_HDR_PORT_OFF)
 #define CMD_HDR_PRIORITY_OFF           27
@@ -401,6 +411,17 @@ struct hisi_sas_err_record_v2 {
        __le32 dma_rx_err_type;
 };
 
+struct signal_attenuation_s {
+       u32 de_emphasis;
+       u32 preshoot;
+       u32 boost;
+};
+
+struct sig_atten_lu_s {
+       const struct signal_attenuation_s *att;
+       u32 sas_phy_ctrl;
+};
+
 static const struct hisi_sas_hw_error one_bit_ecc_errors[] = {
        {
                .irq_msk = BIT(SAS_ECC_INTR_DQE_ECC_1B_OFF),
@@ -952,7 +973,7 @@ static void setup_itct_v2_hw(struct hisi_hba *hisi_hba,
                                        (0x1ULL << ITCT_HDR_RTOLT_OFF));
 }
 
-static void free_device_v2_hw(struct hisi_hba *hisi_hba,
+static void clear_itct_v2_hw(struct hisi_hba *hisi_hba,
                              struct hisi_sas_device *sas_dev)
 {
        DECLARE_COMPLETION_ONSTACK(completion);
@@ -963,10 +984,6 @@ static void free_device_v2_hw(struct hisi_hba *hisi_hba,
 
        sas_dev->completion = &completion;
 
-       /* SoC bug workaround */
-       if (dev_is_sata(sas_dev->sas_device))
-               clear_bit(sas_dev->sata_idx, hisi_hba->sata_dev_bitmap);
-
        /* clear the itct interrupt state */
        if (ENT_INT_SRC3_ITC_INT_MSK & reg_val)
                hisi_sas_write32(hisi_hba, ENT_INT_SRC3,
@@ -981,6 +998,15 @@ static void free_device_v2_hw(struct hisi_hba *hisi_hba,
        }
 }
 
+static void free_device_v2_hw(struct hisi_sas_device *sas_dev)
+{
+       struct hisi_hba *hisi_hba = sas_dev->hisi_hba;
+
+       /* SoC bug workaround */
+       if (dev_is_sata(sas_dev->sas_device))
+               clear_bit(sas_dev->sata_idx, hisi_hba->sata_dev_bitmap);
+}
+
 static int reset_hw_v2_hw(struct hisi_hba *hisi_hba)
 {
        int i, reset_val;
@@ -1074,8 +1100,10 @@ static int reset_hw_v2_hw(struct hisi_hba *hisi_hba)
                        dev_err(dev, "SAS de-reset fail.\n");
                        return -EIO;
                }
-       } else
-               dev_warn(dev, "no reset method\n");
+       } else {
+               dev_err(dev, "no reset method\n");
+               return -EINVAL;
+       }
 
        return 0;
 }
@@ -1120,9 +1148,16 @@ static void phys_try_accept_stp_links_v2_hw(struct hisi_hba *hisi_hba)
        }
 }
 
+static const struct signal_attenuation_s x6000 = {9200, 0, 10476};
+static const struct sig_atten_lu_s sig_atten_lu[] = {
+       { &x6000, 0x3016a68 },
+};
+
 static void init_reg_v2_hw(struct hisi_hba *hisi_hba)
 {
        struct device *dev = hisi_hba->dev;
+       u32 sas_phy_ctrl = 0x30b9908;
+       u32 signal[3];
        int i;
 
        /* Global registers init */
@@ -1166,9 +1201,43 @@ static void init_reg_v2_hw(struct hisi_hba *hisi_hba)
        hisi_sas_write32(hisi_hba, AXI_AHB_CLK_CFG, 1);
        hisi_sas_write32(hisi_hba, HYPER_STREAM_ID_EN_CFG, 1);
 
+       /* Get sas_phy_ctrl value to deal with TX FFE issue. */
+       if (!device_property_read_u32_array(dev, "hisilicon,signal-attenuation",
+                                           signal, ARRAY_SIZE(signal))) {
+               for (i = 0; i < ARRAY_SIZE(sig_atten_lu); i++) {
+                       const struct sig_atten_lu_s *lookup = &sig_atten_lu[i];
+                       const struct signal_attenuation_s *att = lookup->att;
+
+                       if ((signal[0] == att->de_emphasis) &&
+                           (signal[1] == att->preshoot) &&
+                           (signal[2] == att->boost)) {
+                               sas_phy_ctrl = lookup->sas_phy_ctrl;
+                               break;
+                       }
+               }
+
+               if (i == ARRAY_SIZE(sig_atten_lu))
+                       dev_warn(dev, "unknown signal attenuation values, using default PHY ctrl config\n");
+       }
+
        for (i = 0; i < hisi_hba->n_phy; i++) {
-               hisi_sas_phy_write32(hisi_hba, i, PROG_PHY_LINK_RATE, 0x855);
-               hisi_sas_phy_write32(hisi_hba, i, SAS_PHY_CTRL, 0x30b9908);
+               struct hisi_sas_phy *phy = &hisi_hba->phy[i];
+               struct asd_sas_phy *sas_phy = &phy->sas_phy;
+               u32 prog_phy_link_rate = 0x800;
+
+               if (!sas_phy->phy || (sas_phy->phy->maximum_linkrate <
+                               SAS_LINK_RATE_1_5_GBPS)) {
+                       prog_phy_link_rate = 0x855;
+               } else {
+                       enum sas_linkrate max = sas_phy->phy->maximum_linkrate;
+
+                       prog_phy_link_rate =
+                               hisi_sas_get_prog_phy_linkrate_mask(max) |
+                               0x800;
+               }
+               hisi_sas_phy_write32(hisi_hba, i, PROG_PHY_LINK_RATE,
+                       prog_phy_link_rate);
+               hisi_sas_phy_write32(hisi_hba, i, SAS_PHY_CTRL, sas_phy_ctrl);
                hisi_sas_phy_write32(hisi_hba, i, SL_TOUT_CFG, 0x7d7d7d7d);
                hisi_sas_phy_write32(hisi_hba, i, SL_CONTROL, 0x0);
                hisi_sas_phy_write32(hisi_hba, i, TXID_AUTO, 0x2);
@@ -1177,8 +1246,8 @@ static void init_reg_v2_hw(struct hisi_hba *hisi_hba)
                hisi_sas_phy_write32(hisi_hba, i, CHL_INT1, 0xffffffff);
                hisi_sas_phy_write32(hisi_hba, i, CHL_INT2, 0xfff87fff);
                hisi_sas_phy_write32(hisi_hba, i, RXOP_CHECK_CFG_H, 0x1000);
-               hisi_sas_phy_write32(hisi_hba, i, CHL_INT1_MSK, 0xffffffff);
-               hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0x8ffffbff);
+               hisi_sas_phy_write32(hisi_hba, i, CHL_INT1_MSK, 0xff857fff);
+               hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0x8ffffbfe);
                hisi_sas_phy_write32(hisi_hba, i, SL_CFG, 0x13f801fc);
                hisi_sas_phy_write32(hisi_hba, i, PHY_CTRL_RDY_MSK, 0x0);
                hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_NOT_RDY_MSK, 0x0);
@@ -1536,13 +1605,10 @@ static enum sas_linkrate phy_get_max_linkrate_v2_hw(void)
 static void phy_set_linkrate_v2_hw(struct hisi_hba *hisi_hba, int phy_no,
                struct sas_phy_linkrates *r)
 {
-       u32 prog_phy_link_rate =
-               hisi_sas_phy_read32(hisi_hba, phy_no, PROG_PHY_LINK_RATE);
        struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
        struct asd_sas_phy *sas_phy = &phy->sas_phy;
-       int i;
        enum sas_linkrate min, max;
-       u32 rate_mask = 0;
+       u32 prog_phy_link_rate = 0x800;
 
        if (r->maximum_linkrate == SAS_LINK_RATE_UNKNOWN) {
                max = sas_phy->phy->maximum_linkrate;
@@ -1555,20 +1621,13 @@ static void phy_set_linkrate_v2_hw(struct hisi_hba *hisi_hba, int phy_no,
 
        sas_phy->phy->maximum_linkrate = max;
        sas_phy->phy->minimum_linkrate = min;
+       prog_phy_link_rate |= hisi_sas_get_prog_phy_linkrate_mask(max);
 
-       min -= SAS_LINK_RATE_1_5_GBPS;
-       max -= SAS_LINK_RATE_1_5_GBPS;
-
-       for (i = 0; i <= max; i++)
-               rate_mask |= 1 << (i * 2);
-
-       prog_phy_link_rate &= ~0xff;
-       prog_phy_link_rate |= rate_mask;
-
+       disable_phy_v2_hw(hisi_hba, phy_no);
+       msleep(100);
        hisi_sas_phy_write32(hisi_hba, phy_no, PROG_PHY_LINK_RATE,
                        prog_phy_link_rate);
-
-       phy_hard_reset_v2_hw(hisi_hba, phy_no);
+       start_phy_v2_hw(hisi_hba, phy_no);
 }
 
 static int get_wideport_bitmap_v2_hw(struct hisi_hba *hisi_hba, int port_id)
@@ -1609,42 +1668,55 @@ get_free_slot_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_dq *dq)
        r = hisi_sas_read32_relaxed(hisi_hba,
                                DLVRY_Q_0_RD_PTR + (queue * 0x14));
        if (r == (w+1) % HISI_SAS_QUEUE_SLOTS) {
-               dev_warn(dev, "full queue=%d r=%d w=%d\n\n",
+               dev_warn(dev, "full queue=%d r=%d w=%d\n",
                                queue, r, w);
                return -EAGAIN;
        }
 
-       return 0;
+       dq->wr_point = (dq->wr_point + 1) % HISI_SAS_QUEUE_SLOTS;
+
+       return w;
 }
 
+/* DQ lock must be taken here */
 static void start_delivery_v2_hw(struct hisi_sas_dq *dq)
 {
        struct hisi_hba *hisi_hba = dq->hisi_hba;
-       int dlvry_queue = dq->slot_prep->dlvry_queue;
-       int dlvry_queue_slot = dq->slot_prep->dlvry_queue_slot;
+       struct hisi_sas_slot *s, *s1, *s2 = NULL;
+       struct list_head *dq_list;
+       int dlvry_queue = dq->id;
+       int wp;
+
+       dq_list = &dq->list;
+       list_for_each_entry_safe(s, s1, &dq->list, delivery) {
+               if (!s->ready)
+                       break;
+               s2 = s;
+               list_del(&s->delivery);
+       }
 
-       dq->wr_point = ++dlvry_queue_slot % HISI_SAS_QUEUE_SLOTS;
-       hisi_sas_write32(hisi_hba, DLVRY_Q_0_WR_PTR + (dlvry_queue * 0x14),
-                        dq->wr_point);
+       if (!s2)
+               return;
+
+       /*
+        * Ensure that memories for slots built on other CPUs is observed.
+        */
+       smp_rmb();
+       wp = (s2->dlvry_queue_slot + 1) % HISI_SAS_QUEUE_SLOTS;
+
+       hisi_sas_write32(hisi_hba, DLVRY_Q_0_WR_PTR + (dlvry_queue * 0x14), wp);
 }
 
-static int prep_prd_sge_v2_hw(struct hisi_hba *hisi_hba,
+static void prep_prd_sge_v2_hw(struct hisi_hba *hisi_hba,
                              struct hisi_sas_slot *slot,
                              struct hisi_sas_cmd_hdr *hdr,
                              struct scatterlist *scatter,
                              int n_elem)
 {
        struct hisi_sas_sge_page *sge_page = hisi_sas_sge_addr_mem(slot);
-       struct device *dev = hisi_hba->dev;
        struct scatterlist *sg;
        int i;
 
-       if (n_elem > HISI_SAS_SGE_PAGE_CNT) {
-               dev_err(dev, "prd err: n_elem(%d) > HISI_SAS_SGE_PAGE_CNT",
-                       n_elem);
-               return -EINVAL;
-       }
-
        for_each_sg(scatter, sg, n_elem, i) {
                struct hisi_sas_sge *entry = &sge_page->sge[i];
 
@@ -1657,47 +1729,24 @@ static int prep_prd_sge_v2_hw(struct hisi_hba *hisi_hba,
        hdr->prd_table_addr = cpu_to_le64(hisi_sas_sge_addr_dma(slot));
 
        hdr->sg_len = cpu_to_le32(n_elem << CMD_HDR_DATA_SGL_LEN_OFF);
-
-       return 0;
 }
 
-static int prep_smp_v2_hw(struct hisi_hba *hisi_hba,
+static void prep_smp_v2_hw(struct hisi_hba *hisi_hba,
                          struct hisi_sas_slot *slot)
 {
        struct sas_task *task = slot->task;
        struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
        struct domain_device *device = task->dev;
-       struct device *dev = hisi_hba->dev;
        struct hisi_sas_port *port = slot->port;
-       struct scatterlist *sg_req, *sg_resp;
+       struct scatterlist *sg_req;
        struct hisi_sas_device *sas_dev = device->lldd_dev;
        dma_addr_t req_dma_addr;
-       unsigned int req_len, resp_len;
-       int elem, rc;
+       unsigned int req_len;
 
-       /*
-       * DMA-map SMP request, response buffers
-       */
        /* req */
        sg_req = &task->smp_task.smp_req;
-       elem = dma_map_sg(dev, sg_req, 1, DMA_TO_DEVICE);
-       if (!elem)
-               return -ENOMEM;
-       req_len = sg_dma_len(sg_req);
        req_dma_addr = sg_dma_address(sg_req);
-
-       /* resp */
-       sg_resp = &task->smp_task.smp_resp;
-       elem = dma_map_sg(dev, sg_resp, 1, DMA_FROM_DEVICE);
-       if (!elem) {
-               rc = -ENOMEM;
-               goto err_out_req;
-       }
-       resp_len = sg_dma_len(sg_resp);
-       if ((req_len & 0x3) || (resp_len & 0x3)) {
-               rc = -EINVAL;
-               goto err_out_resp;
-       }
+       req_len = sg_dma_len(&task->smp_task.smp_req);
 
        /* create header */
        /* dw0 */
@@ -1719,21 +1768,10 @@ static int prep_smp_v2_hw(struct hisi_hba *hisi_hba,
 
        hdr->cmd_table_addr = cpu_to_le64(req_dma_addr);
        hdr->sts_buffer_addr = cpu_to_le64(hisi_sas_status_buf_addr_dma(slot));
-
-       return 0;
-
-err_out_resp:
-       dma_unmap_sg(dev, &slot->task->smp_task.smp_resp, 1,
-                    DMA_FROM_DEVICE);
-err_out_req:
-       dma_unmap_sg(dev, &slot->task->smp_task.smp_req, 1,
-                    DMA_TO_DEVICE);
-       return rc;
 }
 
-static int prep_ssp_v2_hw(struct hisi_hba *hisi_hba,
-                         struct hisi_sas_slot *slot, int is_tmf,
-                         struct hisi_sas_tmf_task *tmf)
+static void prep_ssp_v2_hw(struct hisi_hba *hisi_hba,
+                         struct hisi_sas_slot *slot)
 {
        struct sas_task *task = slot->task;
        struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
@@ -1742,7 +1780,8 @@ static int prep_ssp_v2_hw(struct hisi_hba *hisi_hba,
        struct hisi_sas_port *port = slot->port;
        struct sas_ssp_task *ssp_task = &task->ssp_task;
        struct scsi_cmnd *scsi_cmnd = ssp_task->cmd;
-       int has_data = 0, rc, priority = is_tmf;
+       struct hisi_sas_tmf_task *tmf = slot->tmf;
+       int has_data = 0, priority = !!tmf;
        u8 *buf_cmd;
        u32 dw1 = 0, dw2 = 0;
 
@@ -1753,7 +1792,7 @@ static int prep_ssp_v2_hw(struct hisi_hba *hisi_hba,
                               (1 << CMD_HDR_CMD_OFF)); /* ssp */
 
        dw1 = 1 << CMD_HDR_VDTL_OFF;
-       if (is_tmf) {
+       if (tmf) {
                dw1 |= 2 << CMD_HDR_FRAME_TYPE_OFF;
                dw1 |= DIR_NO_DATA << CMD_HDR_DIR_OFF;
        } else {
@@ -1784,12 +1823,9 @@ static int prep_ssp_v2_hw(struct hisi_hba *hisi_hba,
 
        hdr->transfer_tags = cpu_to_le32(slot->idx);
 
-       if (has_data) {
-               rc = prep_prd_sge_v2_hw(hisi_hba, slot, hdr, task->scatter,
+       if (has_data)
+               prep_prd_sge_v2_hw(hisi_hba, slot, hdr, task->scatter,
                                        slot->n_elem);
-               if (rc)
-                       return rc;
-       }
 
        hdr->data_transfer_len = cpu_to_le32(task->total_xfer_len);
        hdr->cmd_table_addr = cpu_to_le64(hisi_sas_cmd_hdr_addr_dma(slot));
@@ -1799,7 +1835,7 @@ static int prep_ssp_v2_hw(struct hisi_hba *hisi_hba,
                sizeof(struct ssp_frame_hdr);
 
        memcpy(buf_cmd, &task->ssp_task.LUN, 8);
-       if (!is_tmf) {
+       if (!tmf) {
                buf_cmd[9] = task->ssp_task.task_attr |
                                (task->ssp_task.task_prio << 3);
                memcpy(buf_cmd + 12, task->ssp_task.cmd->cmnd,
@@ -1818,8 +1854,6 @@ static int prep_ssp_v2_hw(struct hisi_hba *hisi_hba,
                        break;
                }
        }
-
-       return 0;
 }
 
 #define TRANS_TX_ERR   0
@@ -2331,23 +2365,24 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot)
        struct device *dev = hisi_hba->dev;
        struct task_status_struct *ts;
        struct domain_device *device;
+       struct sas_ha_struct *ha;
        enum exec_status sts;
        struct hisi_sas_complete_v2_hdr *complete_queue =
                        hisi_hba->complete_hdr[slot->cmplt_queue];
        struct hisi_sas_complete_v2_hdr *complete_hdr =
                        &complete_queue[slot->cmplt_queue_slot];
        unsigned long flags;
-       int aborted;
+       bool is_internal = slot->is_internal;
 
        if (unlikely(!task || !task->lldd_task || !task->dev))
                return -EINVAL;
 
        ts = &task->task_status;
        device = task->dev;
+       ha = device->port->ha;
        sas_dev = device->lldd_dev;
 
        spin_lock_irqsave(&task->task_state_lock, flags);
-       aborted = task->task_state_flags & SAS_TASK_STATE_ABORTED;
        task->task_state_flags &=
                ~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR);
        spin_unlock_irqrestore(&task->task_state_lock, flags);
@@ -2355,14 +2390,6 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot)
        memset(ts, 0, sizeof(*ts));
        ts->resp = SAS_TASK_COMPLETE;
 
-       if (unlikely(aborted)) {
-               ts->stat = SAS_ABORTED_TASK;
-               spin_lock_irqsave(&hisi_hba->lock, flags);
-               hisi_sas_slot_task_free(hisi_hba, task, slot);
-               spin_unlock_irqrestore(&hisi_hba->lock, flags);
-               return -1;
-       }
-
        if (unlikely(!sas_dev)) {
                dev_dbg(dev, "slot complete: port has no device\n");
                ts->stat = SAS_PHY_DOWN;
@@ -2400,6 +2427,7 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot)
                (!(complete_hdr->dw0 & CMPLT_HDR_RSPNS_XFRD_MSK))) {
                u32 err_phase = (complete_hdr->dw0 & CMPLT_HDR_ERR_PHASE_MSK)
                                >> CMPLT_HDR_ERR_PHASE_OFF;
+               u32 *error_info = hisi_sas_status_buf_addr_mem(slot);
 
                /* Analyse error happens on which phase TX or RX */
                if (ERR_ON_TX_PHASE(err_phase))
@@ -2407,6 +2435,16 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot)
                else if (ERR_ON_RX_PHASE(err_phase))
                        slot_err_v2_hw(hisi_hba, task, slot, 2);
 
+               if (ts->stat != SAS_DATA_UNDERRUN)
+                       dev_info(dev, "erroneous completion iptt=%d task=%p dev id=%d "
+                               "CQ hdr: 0x%x 0x%x 0x%x 0x%x "
+                               "Error info: 0x%x 0x%x 0x%x 0x%x\n",
+                               slot->idx, task, sas_dev->device_id,
+                               complete_hdr->dw0, complete_hdr->dw1,
+                               complete_hdr->act, complete_hdr->dw3,
+                               error_info[0], error_info[1],
+                               error_info[2], error_info[3]);
+
                if (unlikely(slot->abort))
                        return ts->stat;
                goto out;
@@ -2456,19 +2494,33 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot)
        }
 
        if (!slot->port->port_attached) {
-               dev_err(dev, "slot complete: port %d has removed\n",
+               dev_warn(dev, "slot complete: port %d has removed\n",
                        slot->port->sas_port.id);
                ts->stat = SAS_PHY_DOWN;
        }
 
 out:
+       hisi_sas_slot_task_free(hisi_hba, task, slot);
+       sts = ts->stat;
        spin_lock_irqsave(&task->task_state_lock, flags);
+       if (task->task_state_flags & SAS_TASK_STATE_ABORTED) {
+               spin_unlock_irqrestore(&task->task_state_lock, flags);
+               dev_info(dev, "slot complete: task(%p) aborted\n", task);
+               return SAS_ABORTED_TASK;
+       }
        task->task_state_flags |= SAS_TASK_STATE_DONE;
        spin_unlock_irqrestore(&task->task_state_lock, flags);
-       spin_lock_irqsave(&hisi_hba->lock, flags);
-       hisi_sas_slot_task_free(hisi_hba, task, slot);
-       spin_unlock_irqrestore(&hisi_hba->lock, flags);
-       sts = ts->stat;
+
+       if (!is_internal && (task->task_proto != SAS_PROTOCOL_SMP)) {
+               spin_lock_irqsave(&device->done_lock, flags);
+               if (test_bit(SAS_HA_FROZEN, &ha->state)) {
+                       spin_unlock_irqrestore(&device->done_lock, flags);
+                       dev_info(dev, "slot complete: task(%p) ignored\n ",
+                                task);
+                       return sts;
+               }
+               spin_unlock_irqrestore(&device->done_lock, flags);
+       }
 
        if (task->task_done)
                task->task_done(task);
@@ -2476,7 +2528,7 @@ out:
        return sts;
 }
 
-static int prep_ata_v2_hw(struct hisi_hba *hisi_hba,
+static void prep_ata_v2_hw(struct hisi_hba *hisi_hba,
                          struct hisi_sas_slot *slot)
 {
        struct sas_task *task = slot->task;
@@ -2486,8 +2538,9 @@ static int prep_ata_v2_hw(struct hisi_hba *hisi_hba,
        struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
        struct asd_sas_port *sas_port = device->port;
        struct hisi_sas_port *port = to_hisi_sas_port(sas_port);
+       struct hisi_sas_tmf_task *tmf = slot->tmf;
        u8 *buf_cmd;
-       int has_data = 0, rc = 0, hdr_tag = 0;
+       int has_data = 0, hdr_tag = 0;
        u32 dw1 = 0, dw2 = 0;
 
        /* create header */
@@ -2498,6 +2551,12 @@ static int prep_ata_v2_hw(struct hisi_hba *hisi_hba,
        else
                hdr->dw0 |= cpu_to_le32(4 << CMD_HDR_CMD_OFF);
 
+       if (tmf && tmf->force_phy) {
+               hdr->dw0 |= CMD_HDR_FORCE_PHY_MSK;
+               hdr->dw0 |= cpu_to_le32((1 << tmf->phy_id)
+                               << CMD_HDR_PHY_ID_OFF);
+       }
+
        /* dw1 */
        switch (task->data_dir) {
        case DMA_TO_DEVICE:
@@ -2517,7 +2576,7 @@ static int prep_ata_v2_hw(struct hisi_hba *hisi_hba,
                dw1 |= 1 << CMD_HDR_RESET_OFF;
 
        dw1 |= (hisi_sas_get_ata_protocol(
-               task->ata_task.fis.command, task->data_dir))
+               &task->ata_task.fis, task->data_dir))
                << CMD_HDR_FRAME_TYPE_OFF;
        dw1 |= sas_dev->device_id << CMD_HDR_DEV_ID_OFF;
        hdr->dw1 = cpu_to_le32(dw1);
@@ -2535,12 +2594,9 @@ static int prep_ata_v2_hw(struct hisi_hba *hisi_hba,
        /* dw3 */
        hdr->transfer_tags = cpu_to_le32(slot->idx);
 
-       if (has_data) {
-               rc = prep_prd_sge_v2_hw(hisi_hba, slot, hdr, task->scatter,
+       if (has_data)
+               prep_prd_sge_v2_hw(hisi_hba, slot, hdr, task->scatter,
                                        slot->n_elem);
-               if (rc)
-                       return rc;
-       }
 
        hdr->data_transfer_len = cpu_to_le32(task->total_xfer_len);
        hdr->cmd_table_addr = cpu_to_le64(hisi_sas_cmd_hdr_addr_dma(slot));
@@ -2552,8 +2608,6 @@ static int prep_ata_v2_hw(struct hisi_hba *hisi_hba,
                task->ata_task.fis.flags |= 0x80; /* C=1: update ATA cmd reg */
        /* fill in command FIS */
        memcpy(buf_cmd, &task->ata_task.fis, sizeof(struct host_to_dev_fis));
-
-       return 0;
 }
 
 static void hisi_sas_internal_abort_quirk_timeout(struct timer_list *t)
@@ -2590,7 +2644,7 @@ static void hisi_sas_internal_abort_quirk_timeout(struct timer_list *t)
        }
 }
 
-static int prep_abort_v2_hw(struct hisi_hba *hisi_hba,
+static void prep_abort_v2_hw(struct hisi_hba *hisi_hba,
                struct hisi_sas_slot *slot,
                int device_id, int abort_flag, int tag_to_abort)
 {
@@ -2608,7 +2662,7 @@ static int prep_abort_v2_hw(struct hisi_hba *hisi_hba,
        /* dw0 */
        hdr->dw0 = cpu_to_le32((5 << CMD_HDR_CMD_OFF) | /*abort*/
                               (port->id << CMD_HDR_PORT_OFF) |
-                              ((dev_is_sata(dev) ? 1:0) <<
+                              (dev_is_sata(dev) <<
                                CMD_HDR_ABORT_DEVICE_TYPE_OFF) |
                               (abort_flag << CMD_HDR_ABORT_FLAG_OFF));
 
@@ -2618,19 +2672,18 @@ static int prep_abort_v2_hw(struct hisi_hba *hisi_hba,
        /* dw7 */
        hdr->dw7 = cpu_to_le32(tag_to_abort << CMD_HDR_ABORT_IPTT_OFF);
        hdr->transfer_tags = cpu_to_le32(slot->idx);
-
-       return 0;
 }
 
 static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
 {
        int i, res = IRQ_HANDLED;
-       u32 port_id, link_rate, hard_phy_linkrate;
+       u32 port_id, link_rate;
        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;
        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);
 
@@ -2664,11 +2717,6 @@ static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
        }
 
        sas_phy->linkrate = link_rate;
-       hard_phy_linkrate = hisi_sas_phy_read32(hisi_hba, phy_no,
-                                               HARD_PHY_LINKRATE);
-       phy->maximum_linkrate = hard_phy_linkrate & 0xf;
-       phy->minimum_linkrate = (hard_phy_linkrate >> 4) & 0xf;
-
        sas_phy->oob_mode = SAS_OOB_MODE;
        memcpy(sas_phy->attached_sas_addr, &id->sas_addr, SAS_ADDR_SIZE);
        dev_info(dev, "phyup: phy%d link_rate=%d\n", phy_no, link_rate);
@@ -2687,7 +2735,13 @@ static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
                if (!timer_pending(&hisi_hba->timer))
                        set_link_timer_quirk(hisi_hba);
        }
-       queue_work(hisi_hba->wq, &phy->phyup_ws);
+       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,
@@ -2713,10 +2767,12 @@ static int phy_down_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
        u32 phy_state, sl_ctrl, txid_auto;
        struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
        struct hisi_sas_port *port = phy->port;
+       struct device *dev = hisi_hba->dev;
 
        hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_NOT_RDY_MSK, 1);
 
        phy_state = hisi_sas_read32(hisi_hba, PHY_STATE);
+       dev_info(dev, "phydown: phy%d phy_state=0x%x\n", phy_no, phy_state);
        hisi_sas_phy_down(hisi_hba, phy_no, (phy_state & 1 << phy_no) ? 1 : 0);
 
        sl_ctrl = hisi_sas_phy_read32(hisi_hba, phy_no, SL_CONTROL);
@@ -2806,13 +2862,41 @@ static void phy_bcast_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
 
        hisi_sas_phy_write32(hisi_hba, phy_no, SL_RX_BCAST_CHK_MSK, 1);
        bcast_status = hisi_sas_phy_read32(hisi_hba, phy_no, RX_PRIMS_STATUS);
-       if (bcast_status & RX_BCAST_CHG_MSK)
+       if ((bcast_status & RX_BCAST_CHG_MSK) &&
+           !test_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags))
                sas_ha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD);
        hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0,
                             CHL_INT0_SL_RX_BCST_ACK_MSK);
        hisi_sas_phy_write32(hisi_hba, phy_no, SL_RX_BCAST_CHK_MSK, 0);
 }
 
+static const struct hisi_sas_hw_error port_ecc_axi_error[] = {
+       {
+               .irq_msk = BIT(CHL_INT1_DMAC_TX_ECC_ERR_OFF),
+               .msg = "dmac_tx_ecc_bad_err",
+       },
+       {
+               .irq_msk = BIT(CHL_INT1_DMAC_RX_ECC_ERR_OFF),
+               .msg = "dmac_rx_ecc_bad_err",
+       },
+       {
+               .irq_msk = BIT(CHL_INT1_DMAC_TX_AXI_WR_ERR_OFF),
+               .msg = "dma_tx_axi_wr_err",
+       },
+       {
+               .irq_msk = BIT(CHL_INT1_DMAC_TX_AXI_RD_ERR_OFF),
+               .msg = "dma_tx_axi_rd_err",
+       },
+       {
+               .irq_msk = BIT(CHL_INT1_DMAC_RX_AXI_WR_ERR_OFF),
+               .msg = "dma_rx_axi_wr_err",
+       },
+       {
+               .irq_msk = BIT(CHL_INT1_DMAC_RX_AXI_RD_ERR_OFF),
+               .msg = "dma_rx_axi_rd_err",
+       },
+};
+
 static irqreturn_t int_chnl_int_v2_hw(int irq_no, void *p)
 {
        struct hisi_hba *hisi_hba = p;
@@ -2829,40 +2913,55 @@ static irqreturn_t int_chnl_int_v2_hw(int irq_no, void *p)
                        HGC_INVLD_DQE_INFO_FB_CH3_OFF) & 0x1ff;
 
        while (irq_msk) {
-               if (irq_msk & (1 << phy_no)) {
-                       u32 irq_value0 = hisi_sas_phy_read32(hisi_hba, phy_no,
-                                                            CHL_INT0);
-                       u32 irq_value1 = hisi_sas_phy_read32(hisi_hba, phy_no,
-                                                            CHL_INT1);
-                       u32 irq_value2 = hisi_sas_phy_read32(hisi_hba, phy_no,
-                                                            CHL_INT2);
-
-                       if (irq_value1) {
-                               if (irq_value1 & (CHL_INT1_DMAC_RX_ECC_ERR_MSK |
-                                                 CHL_INT1_DMAC_TX_ECC_ERR_MSK))
-                                       panic("%s: DMAC RX/TX ecc bad error!\
-                                              (0x%x)",
-                                             dev_name(dev), irq_value1);
-
-                               hisi_sas_phy_write32(hisi_hba, phy_no,
-                                                    CHL_INT1, irq_value1);
-                       }
+               u32 irq_value0 = hisi_sas_phy_read32(hisi_hba, phy_no,
+                                                    CHL_INT0);
+               u32 irq_value1 = hisi_sas_phy_read32(hisi_hba, phy_no,
+                                                    CHL_INT1);
+               u32 irq_value2 = hisi_sas_phy_read32(hisi_hba, phy_no,
+                                                    CHL_INT2);
 
-                       if (irq_value2)
-                               hisi_sas_phy_write32(hisi_hba, phy_no,
-                                                    CHL_INT2, irq_value2);
+               if ((irq_msk & (1 << phy_no)) && irq_value1) {
+                       int i;
 
+                       for (i = 0; i < ARRAY_SIZE(port_ecc_axi_error); i++) {
+                               const struct hisi_sas_hw_error *error =
+                                               &port_ecc_axi_error[i];
 
-                       if (irq_value0) {
-                               if (irq_value0 & CHL_INT0_SL_RX_BCST_ACK_MSK)
-                                       phy_bcast_v2_hw(phy_no, hisi_hba);
+                               if (!(irq_value1 & error->irq_msk))
+                                       continue;
 
-                               hisi_sas_phy_write32(hisi_hba, phy_no,
-                                               CHL_INT0, irq_value0
-                                               & (~CHL_INT0_HOTPLUG_TOUT_MSK)
-                                               & (~CHL_INT0_SL_PHY_ENABLE_MSK)
-                                               & (~CHL_INT0_NOT_RDY_MSK));
+                               dev_warn(dev, "%s error (phy%d 0x%x) found!\n",
+                                       error->msg, phy_no, irq_value1);
+                               queue_work(hisi_hba->wq, &hisi_hba->rst_work);
                        }
+
+                       hisi_sas_phy_write32(hisi_hba, phy_no,
+                                            CHL_INT1, irq_value1);
+               }
+
+               if ((irq_msk & (1 << phy_no)) && irq_value2) {
+                       struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
+
+                       if (irq_value2 & BIT(CHL_INT2_SL_IDAF_TOUT_CONF_OFF)) {
+                               dev_warn(dev, "phy%d identify timeout\n",
+                                               phy_no);
+                               hisi_sas_notify_phy_event(phy,
+                                               HISI_PHYE_LINK_RESET);
+                       }
+
+                       hisi_sas_phy_write32(hisi_hba, phy_no,
+                                                CHL_INT2, irq_value2);
+               }
+
+               if ((irq_msk & (1 << phy_no)) && irq_value0) {
+                       if (irq_value0 & CHL_INT0_SL_RX_BCST_ACK_MSK)
+                               phy_bcast_v2_hw(phy_no, hisi_hba);
+
+                       hisi_sas_phy_write32(hisi_hba, phy_no,
+                                       CHL_INT0, irq_value0
+                                       & (~CHL_INT0_HOTPLUG_TOUT_MSK)
+                                       & (~CHL_INT0_SL_PHY_ENABLE_MSK)
+                                       & (~CHL_INT0_NOT_RDY_MSK));
                }
                irq_msk &= ~(1 << phy_no);
                phy_no++;
@@ -2906,7 +3005,7 @@ static void multi_bit_ecc_error_process_v2_hw(struct hisi_hba *hisi_hba,
                        val = hisi_sas_read32(hisi_hba, ecc_error->reg);
                        val &= ecc_error->msk;
                        val >>= ecc_error->shift;
-                       dev_warn(dev, ecc_error->msg, irq_value, val);
+                       dev_err(dev, ecc_error->msg, irq_value, val);
                        queue_work(hisi_hba->wq, &hisi_hba->rst_work);
                }
        }
@@ -3015,12 +3114,12 @@ static irqreturn_t fatal_axi_int_v2_hw(int irq_no, void *p)
                        for (; sub->msk || sub->msg; sub++) {
                                if (!(err_value & sub->msk))
                                        continue;
-                               dev_warn(dev, "%s (0x%x) found!\n",
+                               dev_err(dev, "%s (0x%x) found!\n",
                                         sub->msg, irq_value);
                                queue_work(hisi_hba->wq, &hisi_hba->rst_work);
                        }
                } else {
-                       dev_warn(dev, "%s (0x%x) found!\n",
+                       dev_err(dev, "%s (0x%x) found!\n",
                                 axi_error->msg, irq_value);
                        queue_work(hisi_hba->wq, &hisi_hba->rst_work);
                }
@@ -3051,14 +3150,12 @@ static void cq_tasklet_v2_hw(unsigned long val)
        struct hisi_sas_complete_v2_hdr *complete_queue;
        u32 rd_point = cq->rd_point, wr_point, dev_id;
        int queue = cq->id;
-       struct hisi_sas_dq *dq = &hisi_hba->dq[queue];
 
        if (unlikely(hisi_hba->reject_stp_links_msk))
                phys_try_accept_stp_links_v2_hw(hisi_hba);
 
        complete_queue = hisi_hba->complete_hdr[queue];
 
-       spin_lock(&dq->lock);
        wr_point = hisi_sas_read32(hisi_hba, COMPL_Q_0_WR_PTR +
                                   (0x14 * queue));
 
@@ -3108,7 +3205,6 @@ static void cq_tasklet_v2_hw(unsigned long val)
        /* update rd_point */
        cq->rd_point = rd_point;
        hisi_sas_write32(hisi_hba, COMPL_Q_0_RD_PTR + (0x14 * queue), rd_point);
-       spin_unlock(&dq->lock);
 }
 
 static irqreturn_t cq_interrupt_v2_hw(int irq_no, void *p)
@@ -3135,6 +3231,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;
@@ -3160,8 +3257,7 @@ static irqreturn_t sata_int_v2_hw(int irq_no, void *p)
        if (fis->status & ATA_ERR) {
                dev_warn(dev, "sata int: phy%d FIS status: 0x%x\n", phy_no,
                                fis->status);
-               disable_phy_v2_hw(hisi_hba, phy_no);
-               enable_phy_v2_hw(hisi_hba, phy_no);
+               hisi_sas_notify_phy_event(phy, HISI_PHYE_LINK_RESET);
                res = IRQ_NONE;
                goto end;
        }
@@ -3195,6 +3291,7 @@ static irqreturn_t sata_int_v2_hw(int irq_no, void *p)
        sas_phy->oob_mode = SATA_OOB_MODE;
        /* Make up some unique SAS address */
        attached_sas_addr[0] = 0x50;
+       attached_sas_addr[6] = hisi_hba->shost->host_no;
        attached_sas_addr[7] = phy_no;
        memcpy(sas_phy->attached_sas_addr, attached_sas_addr, SAS_ADDR_SIZE);
        memcpy(sas_phy->frame_rcvd, fis, sizeof(struct dev_to_host_fis));
@@ -3206,8 +3303,14 @@ static irqreturn_t sata_int_v2_hw(int irq_no, void *p)
        phy->identify.device_type = SAS_SATA_DEV;
        phy->frame_rcvd_size = sizeof(struct dev_to_host_fis);
        phy->identify.target_port_protocols = SAS_PROTOCOL_SATA;
-       queue_work(hisi_hba->wq, &phy->phyup_ws);
+       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);
@@ -3392,7 +3495,7 @@ static int soft_reset_v2_hw(struct hisi_hba *hisi_hba)
 
                udelay(10);
                if (cnt++ > 10) {
-                       dev_info(dev, "wait axi bus state to idle timeout!\n");
+                       dev_err(dev, "wait axi bus state to idle timeout!\n");
                        return -1;
                }
        }
@@ -3408,6 +3511,84 @@ static int soft_reset_v2_hw(struct hisi_hba *hisi_hba)
        return 0;
 }
 
+static int write_gpio_v2_hw(struct hisi_hba *hisi_hba, u8 reg_type,
+                       u8 reg_index, u8 reg_count, u8 *write_data)
+{
+       struct device *dev = hisi_hba->dev;
+       int phy_no, count;
+
+       if (!hisi_hba->sgpio_regs)
+               return -EOPNOTSUPP;
+
+       switch (reg_type) {
+       case SAS_GPIO_REG_TX:
+               count = reg_count * 4;
+               count = min(count, hisi_hba->n_phy);
+
+               for (phy_no = 0; phy_no < count; phy_no++) {
+                       /*
+                        * GPIO_TX[n] register has the highest numbered drive
+                        * of the four in the first byte and the lowest
+                        * numbered drive in the fourth byte.
+                        * See SFF-8485 Rev. 0.7 Table 24.
+                        */
+                       void __iomem  *reg_addr = hisi_hba->sgpio_regs +
+                                       reg_index * 4 + phy_no;
+                       int data_idx = phy_no + 3 - (phy_no % 4) * 2;
+
+                       writeb(write_data[data_idx], reg_addr);
+               }
+
+               break;
+       default:
+               dev_err(dev, "write gpio: unsupported or bad reg type %d\n",
+                               reg_type);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void wait_cmds_complete_timeout_v2_hw(struct hisi_hba *hisi_hba,
+                                            int delay_ms, int timeout_ms)
+{
+       struct device *dev = hisi_hba->dev;
+       int entries, entries_old = 0, time;
+
+       for (time = 0; time < timeout_ms; time += delay_ms) {
+               entries = hisi_sas_read32(hisi_hba, CQE_SEND_CNT);
+               if (entries == entries_old)
+                       break;
+
+               entries_old = entries;
+               msleep(delay_ms);
+       }
+
+       dev_dbg(dev, "wait commands complete %dms\n", time);
+}
+
+static struct scsi_host_template sht_v2_hw = {
+       .name                   = DRV_NAME,
+       .module                 = THIS_MODULE,
+       .queuecommand           = sas_queuecommand,
+       .target_alloc           = sas_target_alloc,
+       .slave_configure        = hisi_sas_slave_configure,
+       .scan_finished          = hisi_sas_scan_finished,
+       .scan_start             = hisi_sas_scan_start,
+       .change_queue_depth     = sas_change_queue_depth,
+       .bios_param             = sas_bios_param,
+       .can_queue              = 1,
+       .this_id                = -1,
+       .sg_tablesize           = SG_ALL,
+       .max_sectors            = SCSI_DEFAULT_MAX_SECTORS,
+       .use_clustering         = ENABLE_CLUSTERING,
+       .eh_device_reset_handler = sas_eh_device_reset_handler,
+       .eh_target_reset_handler = sas_eh_target_reset_handler,
+       .target_destroy         = sas_target_destroy,
+       .ioctl                  = sas_ioctl,
+       .shost_attrs            = host_attrs,
+};
+
 static const struct hisi_sas_hw hisi_sas_v2_hw = {
        .hw_init = hisi_sas_v2_init,
        .setup_itct = setup_itct_v2_hw,
@@ -3415,6 +3596,7 @@ static const struct hisi_sas_hw hisi_sas_v2_hw = {
        .alloc_dev = alloc_dev_quirk_v2_hw,
        .sl_notify = sl_notify_v2_hw,
        .get_wideport_bitmap = get_wideport_bitmap_v2_hw,
+       .clear_itct = clear_itct_v2_hw,
        .free_device = free_device_v2_hw,
        .prep_smp = prep_smp_v2_hw,
        .prep_ssp = prep_ssp_v2_hw,
@@ -3434,6 +3616,9 @@ static const struct hisi_sas_hw hisi_sas_v2_hw = {
        .complete_hdr_size = sizeof(struct hisi_sas_complete_v2_hdr),
        .soft_reset = soft_reset_v2_hw,
        .get_phys_state = get_phys_state_v2_hw,
+       .write_gpio = write_gpio_v2_hw,
+       .wait_cmds_complete_timeout = wait_cmds_complete_timeout_v2_hw,
+       .sht = &sht_v2_hw,
 };
 
 static int hisi_sas_v2_probe(struct platform_device *pdev)
@@ -3458,9 +3643,6 @@ static int hisi_sas_v2_remove(struct platform_device *pdev)
        struct sas_ha_struct *sha = platform_get_drvdata(pdev);
        struct hisi_hba *hisi_hba = sha->lldd_ha;
 
-       if (timer_pending(&hisi_hba->timer))
-               del_timer(&hisi_hba->timer);
-
        hisi_sas_kill_tasklets(hisi_hba);
 
        return hisi_sas_remove(pdev);