module_param(prot_mask, int, 0444);
 MODULE_PARM_DESC(prot_mask, " host protection capabilities mask, def=0x0 ");
 
+/* the index of iopoll queues are bigger than interrupt queues' */
+static int experimental_iopoll_q_cnt;
+module_param(experimental_iopoll_q_cnt, int, 0444);
+MODULE_PARM_DESC(experimental_iopoll_q_cnt, "number of queues to be used as poll mode, def=0");
+
 static void debugfs_work_handler_v3_hw(struct work_struct *work);
 static void debugfs_snapshot_regs_v3_hw(struct hisi_hba *hisi_hba);
 
                task->task_done(task);
 }
 
-static void complete_v3_hw(struct hisi_sas_cq *cq)
+static int complete_v3_hw(struct hisi_sas_cq *cq)
 {
        struct hisi_sas_complete_v3_hdr *complete_queue;
        struct hisi_hba *hisi_hba = cq->hisi_hba;
        u32 rd_point, wr_point;
        int queue = cq->id;
+       int completed;
 
        rd_point = cq->rd_point;
        complete_queue = hisi_hba->complete_hdr[queue];
 
        wr_point = hisi_sas_read32(hisi_hba, COMPL_Q_0_WR_PTR +
                                   (0x14 * queue));
+       completed = (wr_point + HISI_SAS_QUEUE_SLOTS - rd_point) % HISI_SAS_QUEUE_SLOTS;
 
        while (rd_point != wr_point) {
                struct hisi_sas_complete_v3_hdr *complete_hdr;
        /* update rd_point */
        cq->rd_point = rd_point;
        hisi_sas_write32(hisi_hba, COMPL_Q_0_RD_PTR + (0x14 * queue), rd_point);
+
+       return completed;
+}
+
+static int queue_complete_v3_hw(struct Scsi_Host *shost, unsigned int queue)
+{
+       struct hisi_hba *hisi_hba = shost_priv(shost);
+       struct hisi_sas_cq *cq = &hisi_hba->cq[queue];
+       int completed;
+
+       spin_lock(&cq->poll_lock);
+       completed = complete_v3_hw(cq);
+       spin_unlock(&cq->poll_lock);
+
+       return completed;
 }
 
 static irqreturn_t cq_thread_v3_hw(int irq_no, void *p)
 
 static int interrupt_preinit_v3_hw(struct hisi_hba *hisi_hba)
 {
-       int vectors;
-       int max_msi = HISI_SAS_MSI_COUNT_V3_HW, min_msi;
+       /* Allocate all MSI vectors to avoid re-insertion issue */
+       int max_msi = HISI_SAS_MSI_COUNT_V3_HW;
+       int vectors, min_msi;
        struct Scsi_Host *shost = hisi_hba->shost;
        struct pci_dev *pdev = hisi_hba->pci_dev;
        struct irq_affinity desc = {
                return -ENOENT;
 
 
-       hisi_hba->cq_nvecs = vectors - BASE_VECTORS_V3_HW;
-       shost->nr_hw_queues = hisi_hba->cq_nvecs;
+       hisi_hba->cq_nvecs = vectors - BASE_VECTORS_V3_HW - hisi_hba->iopoll_q_cnt;
+       shost->nr_hw_queues = hisi_hba->cq_nvecs + hisi_hba->iopoll_q_cnt;
 
        devm_add_action(&pdev->dev, hisi_sas_v3_free_vectors, pdev);
        return 0;
 static void hisi_sas_map_queues(struct Scsi_Host *shost)
 {
        struct hisi_hba *hisi_hba = shost_priv(shost);
-       struct blk_mq_queue_map *qmap = &shost->tag_set.map[HCTX_TYPE_DEFAULT];
+       struct blk_mq_queue_map *qmap;
+       int i, qoff;
+
+       for (i = 0, qoff = 0; i < shost->nr_maps; i++) {
+               qmap = &shost->tag_set.map[i];
+               if (i == HCTX_TYPE_DEFAULT) {
+                       qmap->nr_queues = hisi_hba->cq_nvecs;
+               } else if (i == HCTX_TYPE_POLL) {
+                       qmap->nr_queues = hisi_hba->iopoll_q_cnt;
+               } else {
+                       qmap->nr_queues = 0;
+                       continue;
+               }
 
-       blk_mq_pci_map_queues(qmap, hisi_hba->pci_dev, BASE_VECTORS_V3_HW);
+               /* At least one interrupt hardware queue */
+               if (!qmap->nr_queues)
+                       WARN_ON(i == HCTX_TYPE_DEFAULT);
+               qmap->queue_offset = qoff;
+               if (i == HCTX_TYPE_POLL)
+                       blk_mq_map_queues(qmap);
+               else
+                       blk_mq_pci_map_queues(qmap, hisi_hba->pci_dev,
+                                             BASE_VECTORS_V3_HW);
+               qoff += qmap->nr_queues;
+       }
 }
 
 static struct scsi_host_template sht_v3_hw = {
        .tag_alloc_policy       = BLK_TAG_ALLOC_RR,
        .host_reset             = hisi_sas_host_reset,
        .host_tagset            = 1,
+       .mq_poll                = queue_complete_v3_hw,
 };
 
 static const struct hisi_sas_hw hisi_sas_v3_hw = {
        if (hisi_sas_get_fw_info(hisi_hba) < 0)
                goto err_out;
 
+       if (experimental_iopoll_q_cnt < 0 ||
+               experimental_iopoll_q_cnt >= hisi_hba->queue_count)
+               dev_err(dev, "iopoll queue count %d cannot exceed or equal 16, using default 0\n",
+                       experimental_iopoll_q_cnt);
+       else
+               hisi_hba->iopoll_q_cnt = experimental_iopoll_q_cnt;
+
        if (hisi_sas_alloc(hisi_hba)) {
                hisi_sas_free(hisi_hba);
                goto err_out;
        shost->max_cmd_len = 16;
        shost->can_queue = HISI_SAS_UNRESERVED_IPTT;
        shost->cmd_per_lun = HISI_SAS_UNRESERVED_IPTT;
+       if (hisi_hba->iopoll_q_cnt)
+               shost->nr_maps = 3;
+       else
+               shost->nr_maps = 1;
 
        sha->sas_ha_name = DRV_NAME;
        sha->dev = dev;