]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - drivers/scsi/hisi_sas/hisi_sas_main.c
scsi: hisi_sas: optimise DMA slot memory
[mirror_ubuntu-bionic-kernel.git] / drivers / scsi / hisi_sas / hisi_sas_main.c
index d622db502ec98b4b2d2599d2fad9d5c05641ac4b..4022c3f8295f7e04161f30884763b99dda4dcc56 100644 (file)
@@ -23,6 +23,97 @@ hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
                             int abort_flag, int tag);
 static int hisi_sas_softreset_ata_disk(struct domain_device *device);
 
+u8 hisi_sas_get_ata_protocol(u8 cmd, int direction)
+{
+       switch (cmd) {
+       case ATA_CMD_FPDMA_WRITE:
+       case ATA_CMD_FPDMA_READ:
+       case ATA_CMD_FPDMA_RECV:
+       case ATA_CMD_FPDMA_SEND:
+       case ATA_CMD_NCQ_NON_DATA:
+       return HISI_SAS_SATA_PROTOCOL_FPDMA;
+
+       case ATA_CMD_DOWNLOAD_MICRO:
+       case ATA_CMD_ID_ATA:
+       case ATA_CMD_PMP_READ:
+       case ATA_CMD_READ_LOG_EXT:
+       case ATA_CMD_PIO_READ:
+       case ATA_CMD_PIO_READ_EXT:
+       case ATA_CMD_PMP_WRITE:
+       case ATA_CMD_WRITE_LOG_EXT:
+       case ATA_CMD_PIO_WRITE:
+       case ATA_CMD_PIO_WRITE_EXT:
+       return HISI_SAS_SATA_PROTOCOL_PIO;
+
+       case ATA_CMD_DSM:
+       case ATA_CMD_DOWNLOAD_MICRO_DMA:
+       case ATA_CMD_PMP_READ_DMA:
+       case ATA_CMD_PMP_WRITE_DMA:
+       case ATA_CMD_READ:
+       case ATA_CMD_READ_EXT:
+       case ATA_CMD_READ_LOG_DMA_EXT:
+       case ATA_CMD_READ_STREAM_DMA_EXT:
+       case ATA_CMD_TRUSTED_RCV_DMA:
+       case ATA_CMD_TRUSTED_SND_DMA:
+       case ATA_CMD_WRITE:
+       case ATA_CMD_WRITE_EXT:
+       case ATA_CMD_WRITE_FUA_EXT:
+       case ATA_CMD_WRITE_QUEUED:
+       case ATA_CMD_WRITE_LOG_DMA_EXT:
+       case ATA_CMD_WRITE_STREAM_DMA_EXT:
+       return HISI_SAS_SATA_PROTOCOL_DMA;
+
+       case ATA_CMD_CHK_POWER:
+       case ATA_CMD_DEV_RESET:
+       case ATA_CMD_EDD:
+       case ATA_CMD_FLUSH:
+       case ATA_CMD_FLUSH_EXT:
+       case ATA_CMD_VERIFY:
+       case ATA_CMD_VERIFY_EXT:
+       case ATA_CMD_SET_FEATURES:
+       case ATA_CMD_STANDBY:
+       case ATA_CMD_STANDBYNOW1:
+       return HISI_SAS_SATA_PROTOCOL_NONDATA;
+       default:
+               if (direction == DMA_NONE)
+                       return HISI_SAS_SATA_PROTOCOL_NONDATA;
+               return HISI_SAS_SATA_PROTOCOL_PIO;
+       }
+}
+EXPORT_SYMBOL_GPL(hisi_sas_get_ata_protocol);
+
+void hisi_sas_sata_done(struct sas_task *task,
+                           struct hisi_sas_slot *slot)
+{
+       struct task_status_struct *ts = &task->task_status;
+       struct ata_task_resp *resp = (struct ata_task_resp *)ts->buf;
+       struct hisi_sas_status_buffer *status_buf =
+                       hisi_sas_status_buf_addr_mem(slot);
+       u8 *iu = &status_buf->iu[0];
+       struct dev_to_host_fis *d2h =  (struct dev_to_host_fis *)iu;
+
+       resp->frame_len = sizeof(struct dev_to_host_fis);
+       memcpy(&resp->ending_fis[0], d2h, sizeof(struct dev_to_host_fis));
+
+       ts->buf_valid_size = sizeof(*resp);
+}
+EXPORT_SYMBOL_GPL(hisi_sas_sata_done);
+
+int hisi_sas_get_ncq_tag(struct sas_task *task, u32 *tag)
+{
+       struct ata_queued_cmd *qc = task->uldd_task;
+
+       if (qc) {
+               if (qc->tf.command == ATA_CMD_FPDMA_WRITE ||
+                       qc->tf.command == ATA_CMD_FPDMA_READ) {
+                       *tag = qc->tag;
+                       return 1;
+               }
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(hisi_sas_get_ncq_tag);
+
 static struct hisi_hba *dev_to_hisi_hba(struct domain_device *device)
 {
        return device->port->ha->lldd_ha;
@@ -79,7 +170,7 @@ void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task,
 {
 
        if (task) {
-               struct device *dev = &hisi_hba->pdev->dev;
+               struct device *dev = hisi_hba->dev;
                struct domain_device *device = task->dev;
                struct hisi_sas_device *sas_dev = device->lldd_dev;
 
@@ -94,17 +185,9 @@ void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task,
                        atomic64_dec(&sas_dev->running_req);
        }
 
-       if (slot->command_table)
-               dma_pool_free(hisi_hba->command_table_pool,
-                             slot->command_table, slot->command_table_dma);
-
-       if (slot->status_buffer)
-               dma_pool_free(hisi_hba->status_buffer_pool,
-                             slot->status_buffer, slot->status_buffer_dma);
+       if (slot->buf)
+               dma_pool_free(hisi_hba->buffer_pool, slot->buf, slot->buf_dma);
 
-       if (slot->sge_page)
-               dma_pool_free(hisi_hba->sge_page_pool, slot->sge_page,
-                             slot->sge_page_dma);
 
        list_del_init(&slot->entry);
        slot->task = NULL;
@@ -156,7 +239,7 @@ static void hisi_sas_slot_abort(struct work_struct *work)
        struct scsi_cmnd *cmnd = task->uldd_task;
        struct hisi_sas_tmf_task tmf_task;
        struct scsi_lun lun;
-       struct device *dev = &hisi_hba->pdev->dev;
+       struct device *dev = hisi_hba->dev;
        int tag = abort_slot->idx;
        unsigned long flags;
 
@@ -179,17 +262,18 @@ out:
                task->task_done(task);
 }
 
-static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba,
-                             int is_tmf, struct hisi_sas_tmf_task *tmf,
-                             int *pass)
+static int hisi_sas_task_prep(struct sas_task *task, struct hisi_sas_dq
+               *dq, int is_tmf, struct hisi_sas_tmf_task *tmf,
+               int *pass)
 {
+       struct hisi_hba *hisi_hba = dq->hisi_hba;
        struct domain_device *device = task->dev;
        struct hisi_sas_device *sas_dev = device->lldd_dev;
        struct hisi_sas_port *port;
        struct hisi_sas_slot *slot;
        struct hisi_sas_cmd_hdr *cmd_hdr_base;
        struct asd_sas_port *sas_port = device->port;
-       struct device *dev = &hisi_hba->pdev->dev;
+       struct device *dev = hisi_hba->dev;
        int dlvry_queue_slot, dlvry_queue, n_elem = 0, rc, slot_idx;
        unsigned long flags;
 
@@ -209,7 +293,7 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba,
 
        if (DEV_IS_GONE(sas_dev)) {
                if (sas_dev)
-                       dev_info(dev, "task prep: device %llu not ready\n",
+                       dev_info(dev, "task prep: device %d not ready\n",
                                 sas_dev->device_id);
                else
                        dev_info(dev, "task prep: device %016llx not ready\n",
@@ -240,18 +324,24 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba,
        } else
                n_elem = task->num_scatter;
 
+       spin_lock_irqsave(&hisi_hba->lock, flags);
        if (hisi_hba->hw->slot_index_alloc)
                rc = hisi_hba->hw->slot_index_alloc(hisi_hba, &slot_idx,
                                                    device);
        else
                rc = hisi_sas_slot_index_alloc(hisi_hba, &slot_idx);
-       if (rc)
+       if (rc) {
+               spin_unlock_irqrestore(&hisi_hba->lock, flags);
                goto err_out;
-       rc = hisi_hba->hw->get_free_slot(hisi_hba, sas_dev->device_id,
-                                       &dlvry_queue, &dlvry_queue_slot);
+       }
+       spin_unlock_irqrestore(&hisi_hba->lock, flags);
+
+       rc = hisi_hba->hw->get_free_slot(hisi_hba, dq);
        if (rc)
                goto err_out_tag;
 
+       dlvry_queue = dq->id;
+       dlvry_queue_slot = dq->wr_point;
        slot = &hisi_hba->slot_info[slot_idx];
        memset(slot, 0, sizeof(struct hisi_sas_slot));
 
@@ -266,24 +356,15 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba,
        task->lldd_task = slot;
        INIT_WORK(&slot->abort_slot, hisi_sas_slot_abort);
 
-       slot->status_buffer = dma_pool_alloc(hisi_hba->status_buffer_pool,
-                                            GFP_ATOMIC,
-                                            &slot->status_buffer_dma);
-       if (!slot->status_buffer) {
+       slot->buf = dma_pool_alloc(hisi_hba->buffer_pool,
+                                  GFP_ATOMIC, &slot->buf_dma);
+       if (!slot->buf) {
                rc = -ENOMEM;
                goto err_out_slot_buf;
        }
-       memset(slot->status_buffer, 0, HISI_SAS_STATUS_BUF_SZ);
-
-       slot->command_table = dma_pool_alloc(hisi_hba->command_table_pool,
-                                            GFP_ATOMIC,
-                                            &slot->command_table_dma);
-       if (!slot->command_table) {
-               rc = -ENOMEM;
-               goto err_out_status_buf;
-       }
-       memset(slot->command_table, 0, HISI_SAS_COMMAND_TABLE_SZ);
        memset(slot->cmd_hdr, 0, sizeof(struct hisi_sas_cmd_hdr));
+       memset(hisi_sas_cmd_hdr_addr_mem(slot), 0, HISI_SAS_COMMAND_TABLE_SZ);
+       memset(hisi_sas_status_buf_addr_mem(slot), 0, HISI_SAS_STATUS_BUF_SZ);
 
        switch (task->task_proto) {
        case SAS_PROTOCOL_SMP:
@@ -306,9 +387,7 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba,
 
        if (rc) {
                dev_err(dev, "task prep: rc = 0x%x\n", rc);
-               if (slot->sge_page)
-                       goto err_out_sge;
-               goto err_out_command_table;
+               goto err_out_buf;
        }
 
        list_add_tail(&slot->entry, &sas_dev->list);
@@ -316,26 +395,22 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba,
        task->task_state_flags |= SAS_TASK_AT_INITIATOR;
        spin_unlock_irqrestore(&task->task_state_lock, flags);
 
-       hisi_hba->slot_prep = slot;
+       dq->slot_prep = slot;
 
        atomic64_inc(&sas_dev->running_req);
        ++(*pass);
 
        return 0;
 
-err_out_sge:
-       dma_pool_free(hisi_hba->sge_page_pool, slot->sge_page,
-               slot->sge_page_dma);
-err_out_command_table:
-       dma_pool_free(hisi_hba->command_table_pool, slot->command_table,
-               slot->command_table_dma);
-err_out_status_buf:
-       dma_pool_free(hisi_hba->status_buffer_pool, slot->status_buffer,
-               slot->status_buffer_dma);
+err_out_buf:
+       dma_pool_free(hisi_hba->buffer_pool, slot->buf,
+               slot->buf_dma);
 err_out_slot_buf:
        /* Nothing to be done */
 err_out_tag:
+       spin_lock_irqsave(&hisi_hba->lock, flags);
        hisi_sas_slot_index_free(hisi_hba, slot_idx);
+       spin_unlock_irqrestore(&hisi_hba->lock, flags);
 err_out:
        dev_err(dev, "task prep: failed[%d]!\n", rc);
        if (!sas_protocol_ata(task->task_proto))
@@ -353,20 +428,23 @@ static int hisi_sas_task_exec(struct sas_task *task, gfp_t gfp_flags,
        u32 pass = 0;
        unsigned long flags;
        struct hisi_hba *hisi_hba = dev_to_hisi_hba(task->dev);
-       struct device *dev = &hisi_hba->pdev->dev;
+       struct device *dev = hisi_hba->dev;
+       struct domain_device *device = task->dev;
+       struct hisi_sas_device *sas_dev = device->lldd_dev;
+       struct hisi_sas_dq *dq = sas_dev->dq;
 
        if (unlikely(test_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)))
                return -EINVAL;
 
        /* protect task_prep and start_delivery sequence */
-       spin_lock_irqsave(&hisi_hba->lock, flags);
-       rc = hisi_sas_task_prep(task, hisi_hba, is_tmf, tmf, &pass);
+       spin_lock_irqsave(&dq->lock, flags);
+       rc = hisi_sas_task_prep(task, dq, is_tmf, tmf, &pass);
        if (rc)
                dev_err(dev, "task exec: failed[%d]!\n", rc);
 
        if (likely(pass))
-               hisi_hba->hw->start_delivery(hisi_hba);
-       spin_unlock_irqrestore(&hisi_hba->lock, flags);
+               hisi_hba->hw->start_delivery(dq);
+       spin_unlock_irqrestore(&dq->lock, flags);
 
        return rc;
 }
@@ -421,12 +499,16 @@ static struct hisi_sas_device *hisi_sas_alloc_dev(struct domain_device *device)
        spin_lock(&hisi_hba->lock);
        for (i = 0; i < HISI_SAS_MAX_DEVICES; i++) {
                if (hisi_hba->devices[i].dev_type == SAS_PHY_UNUSED) {
+                       int queue = i % hisi_hba->queue_count;
+                       struct hisi_sas_dq *dq = &hisi_hba->dq[queue];
+
                        hisi_hba->devices[i].device_id = i;
                        sas_dev = &hisi_hba->devices[i];
                        sas_dev->dev_status = HISI_SAS_DEV_NORMAL;
                        sas_dev->dev_type = device->dev_type;
                        sas_dev->hisi_hba = hisi_hba;
                        sas_dev->sas_device = device;
+                       sas_dev->dq = dq;
                        INIT_LIST_HEAD(&hisi_hba->devices[i].list);
                        break;
                }
@@ -441,7 +523,7 @@ static int hisi_sas_dev_found(struct domain_device *device)
        struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
        struct domain_device *parent_dev = device->parent;
        struct hisi_sas_device *sas_dev;
-       struct device *dev = &hisi_hba->pdev->dev;
+       struct device *dev = hisi_hba->dev;
 
        if (hisi_hba->hw->alloc_dev)
                sas_dev = hisi_hba->hw->alloc_dev(device);
@@ -622,19 +704,28 @@ static void hisi_sas_release_tasks(struct hisi_hba *hisi_hba)
        }
 }
 
+static void hisi_sas_dereg_device(struct hisi_hba *hisi_hba,
+                               struct domain_device *device)
+{
+       if (hisi_hba->hw->dereg_device)
+               hisi_hba->hw->dereg_device(hisi_hba, device);
+}
+
 static void hisi_sas_dev_gone(struct domain_device *device)
 {
        struct hisi_sas_device *sas_dev = device->lldd_dev;
        struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
-       struct device *dev = &hisi_hba->pdev->dev;
-       u64 dev_id = sas_dev->device_id;
+       struct device *dev = hisi_hba->dev;
+       int dev_id = sas_dev->device_id;
 
-       dev_info(dev, "found dev[%lld:%x] is gone\n",
+       dev_info(dev, "found dev[%d:%x] is gone\n",
                 sas_dev->device_id, sas_dev->dev_type);
 
        hisi_sas_internal_task_abort(hisi_hba, device,
                                     HISI_SAS_INT_ABT_DEV, 0);
 
+       hisi_sas_dereg_device(hisi_hba, device);
+
        hisi_hba->hw->free_device(hisi_hba, sas_dev);
        device->lldd_dev = NULL;
        memset(sas_dev, 0, sizeof(*sas_dev));
@@ -691,8 +782,13 @@ static void hisi_sas_task_done(struct sas_task *task)
 static void hisi_sas_tmf_timedout(unsigned long data)
 {
        struct sas_task *task = (struct sas_task *)data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&task->task_state_lock, flags);
+       if (!(task->task_state_flags & SAS_TASK_STATE_DONE))
+               task->task_state_flags |= SAS_TASK_STATE_ABORTED;
+       spin_unlock_irqrestore(&task->task_state_lock, flags);
 
-       task->task_state_flags |= SAS_TASK_STATE_ABORTED;
        complete(&task->slow_task->completion);
 }
 
@@ -704,7 +800,7 @@ static int hisi_sas_exec_internal_tmf_task(struct domain_device *device,
 {
        struct hisi_sas_device *sas_dev = device->lldd_dev;
        struct hisi_hba *hisi_hba = sas_dev->hisi_hba;
-       struct device *dev = &hisi_hba->pdev->dev;
+       struct device *dev = hisi_hba->dev;
        struct sas_task *task;
        int res, retry;
 
@@ -821,7 +917,7 @@ static int hisi_sas_softreset_ata_disk(struct domain_device *device)
        struct ata_link *link;
        int rc = TMF_RESP_FUNC_FAILED;
        struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
-       struct device *dev = &hisi_hba->pdev->dev;
+       struct device *dev = hisi_hba->dev;
        int s = sizeof(struct host_to_dev_fis);
        unsigned long flags;
 
@@ -879,7 +975,7 @@ static int hisi_sas_controller_reset(struct hisi_hba *hisi_hba)
                return -1;
 
        if (!test_and_set_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)) {
-               struct device *dev = &hisi_hba->pdev->dev;
+               struct device *dev = hisi_hba->dev;
                struct sas_ha_struct *sas_ha = &hisi_hba->sha;
                unsigned long flags;
 
@@ -912,7 +1008,7 @@ static int hisi_sas_abort_task(struct sas_task *task)
        struct domain_device *device = task->dev;
        struct hisi_sas_device *sas_dev = device->lldd_dev;
        struct hisi_hba *hisi_hba = dev_to_hisi_hba(task->dev);
-       struct device *dev = &hisi_hba->pdev->dev;
+       struct device *dev = hisi_hba->dev;
        int rc = TMF_RESP_FUNC_FAILED;
        unsigned long flags;
 
@@ -961,9 +1057,10 @@ static int hisi_sas_abort_task(struct sas_task *task)
                if (task->dev->dev_type == SAS_SATA_DEV) {
                        hisi_sas_internal_task_abort(hisi_hba, device,
                                                     HISI_SAS_INT_ABT_DEV, 0);
+                       hisi_sas_dereg_device(hisi_hba, device);
                        rc = hisi_sas_softreset_ata_disk(device);
                }
-       } else if (task->task_proto & SAS_PROTOCOL_SMP) {
+       } else if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SMP) {
                /* SMP */
                struct hisi_sas_slot *slot = task->lldd_task;
                u32 tag = slot->idx;
@@ -1027,6 +1124,10 @@ static int hisi_sas_I_T_nexus_reset(struct domain_device *device)
                return TMF_RESP_FUNC_FAILED;
        sas_dev->dev_status = HISI_SAS_DEV_NORMAL;
 
+       hisi_sas_internal_task_abort(hisi_hba, device,
+                                       HISI_SAS_INT_ABT_DEV, 0);
+       hisi_sas_dereg_device(hisi_hba, device);
+
        rc = hisi_sas_debug_I_T_nexus_reset(device);
 
        if (rc == TMF_RESP_FUNC_COMPLETE) {
@@ -1041,7 +1142,7 @@ static int hisi_sas_lu_reset(struct domain_device *device, u8 *lun)
 {
        struct hisi_sas_device *sas_dev = device->lldd_dev;
        struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
-       struct device *dev = &hisi_hba->pdev->dev;
+       struct device *dev = hisi_hba->dev;
        unsigned long flags;
        int rc = TMF_RESP_FUNC_FAILED;
 
@@ -1054,6 +1155,7 @@ static int hisi_sas_lu_reset(struct domain_device *device, u8 *lun)
                                                  HISI_SAS_INT_ABT_DEV, 0);
                if (rc == TMF_RESP_FUNC_FAILED)
                        goto out;
+               hisi_sas_dereg_device(hisi_hba, device);
 
                phy = sas_get_local_phy(device);
 
@@ -1077,7 +1179,7 @@ static int hisi_sas_lu_reset(struct domain_device *device, u8 *lun)
        }
 out:
        if (rc != TMF_RESP_FUNC_COMPLETE)
-               dev_err(dev, "lu_reset: for device[%llx]:rc= %d\n",
+               dev_err(dev, "lu_reset: for device[%d]:rc= %d\n",
                             sas_dev->device_id, rc);
        return rc;
 }
@@ -1124,19 +1226,20 @@ static int hisi_sas_query_task(struct sas_task *task)
 }
 
 static int
-hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, u64 device_id,
+hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id,
                                  struct sas_task *task, int abort_flag,
                                  int task_tag)
 {
        struct domain_device *device = task->dev;
        struct hisi_sas_device *sas_dev = device->lldd_dev;
-       struct device *dev = &hisi_hba->pdev->dev;
+       struct device *dev = hisi_hba->dev;
        struct hisi_sas_port *port;
        struct hisi_sas_slot *slot;
        struct asd_sas_port *sas_port = device->port;
        struct hisi_sas_cmd_hdr *cmd_hdr_base;
+       struct hisi_sas_dq *dq = sas_dev->dq;
        int dlvry_queue_slot, dlvry_queue, n_elem = 0, rc, slot_idx;
-       unsigned long flags;
+       unsigned long flags, flags_dq;
 
        if (unlikely(test_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)))
                return -EINVAL;
@@ -1147,14 +1250,22 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, u64 device_id,
        port = to_hisi_sas_port(sas_port);
 
        /* simply get a slot and send abort command */
+       spin_lock_irqsave(&hisi_hba->lock, flags);
        rc = hisi_sas_slot_index_alloc(hisi_hba, &slot_idx);
-       if (rc)
+       if (rc) {
+               spin_unlock_irqrestore(&hisi_hba->lock, flags);
                goto err_out;
-       rc = hisi_hba->hw->get_free_slot(hisi_hba, sas_dev->device_id,
-                                       &dlvry_queue, &dlvry_queue_slot);
+       }
+       spin_unlock_irqrestore(&hisi_hba->lock, flags);
+
+       spin_lock_irqsave(&dq->lock, flags_dq);
+       rc = hisi_hba->hw->get_free_slot(hisi_hba, dq);
        if (rc)
                goto err_out_tag;
 
+       dlvry_queue = dq->id;
+       dlvry_queue_slot = dq->wr_point;
+
        slot = &hisi_hba->slot_info[slot_idx];
        memset(slot, 0, sizeof(struct hisi_sas_slot));
 
@@ -1181,17 +1292,21 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, u64 device_id,
        task->task_state_flags |= SAS_TASK_AT_INITIATOR;
        spin_unlock_irqrestore(&task->task_state_lock, flags);
 
-       hisi_hba->slot_prep = slot;
+       dq->slot_prep = slot;
 
        atomic64_inc(&sas_dev->running_req);
 
-       /* send abort command to our chip */
-       hisi_hba->hw->start_delivery(hisi_hba);
+       /* send abort command to the chip */
+       hisi_hba->hw->start_delivery(dq);
+       spin_unlock_irqrestore(&dq->lock, flags_dq);
 
        return 0;
 
 err_out_tag:
+       spin_lock_irqsave(&hisi_hba->lock, flags);
        hisi_sas_slot_index_free(hisi_hba, slot_idx);
+       spin_unlock_irqrestore(&hisi_hba->lock, flags);
+       spin_unlock_irqrestore(&dq->lock, flags_dq);
 err_out:
        dev_err(dev, "internal abort task prep: failed[%d]!\n", rc);
 
@@ -1214,9 +1329,8 @@ hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
 {
        struct sas_task *task;
        struct hisi_sas_device *sas_dev = device->lldd_dev;
-       struct device *dev = &hisi_hba->pdev->dev;
+       struct device *dev = hisi_hba->dev;
        int res;
-       unsigned long flags;
 
        if (!hisi_hba->hw->prep_abort)
                return -EOPNOTSUPP;
@@ -1233,11 +1347,8 @@ hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
        task->slow_task->timer.expires = jiffies + msecs_to_jiffies(110);
        add_timer(&task->slow_task->timer);
 
-       /* Lock as we are alloc'ing a slot, which cannot be interrupted */
-       spin_lock_irqsave(&hisi_hba->lock, flags);
        res = hisi_sas_internal_abort_task_exec(hisi_hba, sas_dev->device_id,
                                                task, abort_flag, tag);
-       spin_unlock_irqrestore(&hisi_hba->lock, flags);
        if (res) {
                del_timer(&task->slow_task->timer);
                dev_err(dev, "internal task abort: executing internal task failed: %d\n",
@@ -1247,6 +1358,17 @@ hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
        wait_for_completion(&task->slow_task->completion);
        res = TMF_RESP_FUNC_FAILED;
 
+       /* Internal abort timed out */
+       if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
+               if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
+                       struct hisi_sas_slot *slot = task->lldd_task;
+
+                       if (slot)
+                               slot->task = NULL;
+                       dev_err(dev, "internal task abort: timeout.\n");
+               }
+       }
+
        if (task->task_status.resp == SAS_TASK_COMPLETE &&
                task->task_status.stat == TMF_RESP_FUNC_COMPLETE) {
                res = TMF_RESP_FUNC_COMPLETE;
@@ -1259,13 +1381,6 @@ hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
                goto exit;
        }
 
-       /* Internal abort timed out */
-       if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
-               if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
-                       dev_err(dev, "internal task abort: timeout.\n");
-               }
-       }
-
 exit:
        dev_dbg(dev, "internal task abort: task to dev %016llx task=%p "
                "resp: 0x%x sts 0x%x\n",
@@ -1353,9 +1468,10 @@ void hisi_sas_rescan_topology(struct hisi_hba *hisi_hba, u32 old_state,
 }
 EXPORT_SYMBOL_GPL(hisi_sas_rescan_topology);
 
-static struct scsi_transport_template *hisi_sas_stt;
+struct scsi_transport_template *hisi_sas_stt;
+EXPORT_SYMBOL_GPL(hisi_sas_stt);
 
-static struct scsi_host_template hisi_sas_sht = {
+static struct scsi_host_template _hisi_sas_sht = {
        .module                 = THIS_MODULE,
        .name                   = DRV_NAME,
        .queuecommand           = sas_queuecommand,
@@ -1375,6 +1491,8 @@ static struct scsi_host_template hisi_sas_sht = {
        .target_destroy         = sas_target_destroy,
        .ioctl                  = sas_ioctl,
 };
+struct scsi_host_template *hisi_sas_sht = &_hisi_sas_sht;
+EXPORT_SYMBOL_GPL(hisi_sas_sht);
 
 static struct sas_domain_function_template hisi_sas_transport_ops = {
        .lldd_dev_found         = hisi_sas_dev_found,
@@ -1422,10 +1540,9 @@ void hisi_sas_init_mem(struct hisi_hba *hisi_hba)
 }
 EXPORT_SYMBOL_GPL(hisi_sas_init_mem);
 
-static int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost)
+int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost)
 {
-       struct platform_device *pdev = hisi_hba->pdev;
-       struct device *dev = &pdev->dev;
+       struct device *dev = hisi_hba->dev;
        int i, s, max_command_entries = hisi_hba->hw->max_command_entries;
 
        spin_lock_init(&hisi_hba->lock);
@@ -1468,16 +1585,9 @@ static int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost)
                        goto err_out;
        }
 
-       s = HISI_SAS_STATUS_BUF_SZ;
-       hisi_hba->status_buffer_pool = dma_pool_create("status_buffer",
-                                                      dev, s, 16, 0);
-       if (!hisi_hba->status_buffer_pool)
-               goto err_out;
-
-       s = HISI_SAS_COMMAND_TABLE_SZ;
-       hisi_hba->command_table_pool = dma_pool_create("command_table",
-                                                      dev, s, 16, 0);
-       if (!hisi_hba->command_table_pool)
+       s = sizeof(struct hisi_sas_slot_buf_table);
+       hisi_hba->buffer_pool = dma_pool_create("dma_buffer", dev, s, 16, 0);
+       if (!hisi_hba->buffer_pool)
                goto err_out;
 
        s = HISI_SAS_MAX_ITCT_ENTRIES * sizeof(struct hisi_sas_itct);
@@ -1512,11 +1622,6 @@ static int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost)
        if (!hisi_hba->slot_index_tags)
                goto err_out;
 
-       hisi_hba->sge_page_pool = dma_pool_create("status_sge", dev,
-                               sizeof(struct hisi_sas_sge_page), 16, 0);
-       if (!hisi_hba->sge_page_pool)
-               goto err_out;
-
        s = sizeof(struct hisi_sas_initial_fis) * HISI_SAS_MAX_PHYS;
        hisi_hba->initial_fis = dma_alloc_coherent(dev, s,
                                &hisi_hba->initial_fis_dma, GFP_KERNEL);
@@ -1542,10 +1647,11 @@ static int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost)
 err_out:
        return -ENOMEM;
 }
+EXPORT_SYMBOL_GPL(hisi_sas_alloc);
 
-static void hisi_sas_free(struct hisi_hba *hisi_hba)
+void hisi_sas_free(struct hisi_hba *hisi_hba)
 {
-       struct device *dev = &hisi_hba->pdev->dev;
+       struct device *dev = hisi_hba->dev;
        int i, s, max_command_entries = hisi_hba->hw->max_command_entries;
 
        for (i = 0; i < hisi_hba->queue_count; i++) {
@@ -1562,9 +1668,7 @@ static void hisi_sas_free(struct hisi_hba *hisi_hba)
                                          hisi_hba->complete_hdr_dma[i]);
        }
 
-       dma_pool_destroy(hisi_hba->status_buffer_pool);
-       dma_pool_destroy(hisi_hba->command_table_pool);
-       dma_pool_destroy(hisi_hba->sge_page_pool);
+       dma_pool_destroy(hisi_hba->buffer_pool);
 
        s = HISI_SAS_MAX_ITCT_ENTRIES * sizeof(struct hisi_sas_itct);
        if (hisi_hba->itct)
@@ -1598,6 +1702,7 @@ static void hisi_sas_free(struct hisi_hba *hisi_hba)
        if (hisi_hba->wq)
                destroy_workqueue(hisi_hba->wq);
 }
+EXPORT_SYMBOL_GPL(hisi_sas_free);
 
 static void hisi_sas_rst_work_handler(struct work_struct *work)
 {
@@ -1607,65 +1712,99 @@ static void hisi_sas_rst_work_handler(struct work_struct *work)
        hisi_sas_controller_reset(hisi_hba);
 }
 
-static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev,
-                                             const struct hisi_sas_hw *hw)
+int hisi_sas_get_fw_info(struct hisi_hba *hisi_hba)
 {
-       struct resource *res;
-       struct Scsi_Host *shost;
-       struct hisi_hba *hisi_hba;
-       struct device *dev = &pdev->dev;
-       struct device_node *np = pdev->dev.of_node;
+       struct device *dev = hisi_hba->dev;
+       struct platform_device *pdev = hisi_hba->platform_dev;
+       struct device_node *np = pdev ? pdev->dev.of_node : NULL;
        struct clk *refclk;
 
-       shost = scsi_host_alloc(&hisi_sas_sht, sizeof(*hisi_hba));
-       if (!shost) {
-               dev_err(dev, "scsi host alloc failed\n");
-               return NULL;
-       }
-       hisi_hba = shost_priv(shost);
-
-       INIT_WORK(&hisi_hba->rst_work, hisi_sas_rst_work_handler);
-       hisi_hba->hw = hw;
-       hisi_hba->pdev = pdev;
-       hisi_hba->shost = shost;
-       SHOST_TO_SAS_HA(shost) = &hisi_hba->sha;
-
-       init_timer(&hisi_hba->timer);
-
        if (device_property_read_u8_array(dev, "sas-addr", hisi_hba->sas_addr,
-                                         SAS_ADDR_SIZE))
-               goto err_out;
+                                         SAS_ADDR_SIZE)) {
+               dev_err(dev, "could not get property sas-addr\n");
+               return -ENOENT;
+       }
 
        if (np) {
+               /*
+                * These properties are only required for platform device-based
+                * controller with DT firmware.
+                */
                hisi_hba->ctrl = syscon_regmap_lookup_by_phandle(np,
                                        "hisilicon,sas-syscon");
-               if (IS_ERR(hisi_hba->ctrl))
-                       goto err_out;
+               if (IS_ERR(hisi_hba->ctrl)) {
+                       dev_err(dev, "could not get syscon\n");
+                       return -ENOENT;
+               }
 
                if (device_property_read_u32(dev, "ctrl-reset-reg",
-                                            &hisi_hba->ctrl_reset_reg))
-                       goto err_out;
+                                            &hisi_hba->ctrl_reset_reg)) {
+                       dev_err(dev,
+                               "could not get property ctrl-reset-reg\n");
+                       return -ENOENT;
+               }
 
                if (device_property_read_u32(dev, "ctrl-reset-sts-reg",
-                                            &hisi_hba->ctrl_reset_sts_reg))
-                       goto err_out;
+                                            &hisi_hba->ctrl_reset_sts_reg)) {
+                       dev_err(dev,
+                               "could not get property ctrl-reset-sts-reg\n");
+                       return -ENOENT;
+               }
 
                if (device_property_read_u32(dev, "ctrl-clock-ena-reg",
-                                            &hisi_hba->ctrl_clock_ena_reg))
-                       goto err_out;
+                                            &hisi_hba->ctrl_clock_ena_reg)) {
+                       dev_err(dev,
+                               "could not get property ctrl-clock-ena-reg\n");
+                       return -ENOENT;
+               }
        }
 
-       refclk = devm_clk_get(&pdev->dev, NULL);
+       refclk = devm_clk_get(dev, NULL);
        if (IS_ERR(refclk))
                dev_dbg(dev, "no ref clk property\n");
        else
                hisi_hba->refclk_frequency_mhz = clk_get_rate(refclk) / 1000000;
 
-       if (device_property_read_u32(dev, "phy-count", &hisi_hba->n_phy))
-               goto err_out;
+       if (device_property_read_u32(dev, "phy-count", &hisi_hba->n_phy)) {
+               dev_err(dev, "could not get property phy-count\n");
+               return -ENOENT;
+       }
 
        if (device_property_read_u32(dev, "queue-count",
-                                    &hisi_hba->queue_count))
+                                    &hisi_hba->queue_count)) {
+               dev_err(dev, "could not get property queue-count\n");
+               return -ENOENT;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(hisi_sas_get_fw_info);
+
+static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev,
+                                             const struct hisi_sas_hw *hw)
+{
+       struct resource *res;
+       struct Scsi_Host *shost;
+       struct hisi_hba *hisi_hba;
+       struct device *dev = &pdev->dev;
+
+       shost = scsi_host_alloc(hisi_sas_sht, sizeof(*hisi_hba));
+       if (!shost) {
+               dev_err(dev, "scsi host alloc failed\n");
+               return NULL;
+       }
+       hisi_hba = shost_priv(shost);
+
+       INIT_WORK(&hisi_hba->rst_work, hisi_sas_rst_work_handler);
+       hisi_hba->hw = hw;
+       hisi_hba->dev = dev;
+       hisi_hba->platform_dev = pdev;
+       hisi_hba->shost = shost;
+       SHOST_TO_SAS_HA(shost) = &hisi_hba->sha;
+
+       init_timer(&hisi_hba->timer);
+
+       if (hisi_sas_get_fw_info(hisi_hba) < 0)
                goto err_out;
 
        if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)) &&
@@ -1691,7 +1830,7 @@ err_out:
        return NULL;
 }
 
-static void hisi_sas_init_add(struct hisi_hba *hisi_hba)
+void hisi_sas_init_add(struct hisi_hba *hisi_hba)
 {
        int i;
 
@@ -1700,6 +1839,7 @@ static void hisi_sas_init_add(struct hisi_hba *hisi_hba)
                       hisi_hba->sas_addr,
                       SAS_ADDR_SIZE);
 }
+EXPORT_SYMBOL_GPL(hisi_sas_init_add);
 
 int hisi_sas_probe(struct platform_device *pdev,
                         const struct hisi_sas_hw *hw)
@@ -1743,7 +1883,7 @@ int hisi_sas_probe(struct platform_device *pdev,
        shost->cmd_per_lun = hisi_hba->hw->max_command_entries;
 
        sha->sas_ha_name = DRV_NAME;
-       sha->dev = &hisi_hba->pdev->dev;
+       sha->dev = hisi_hba->dev;
        sha->lldd_module = THIS_MODULE;
        sha->sas_addr = &hisi_hba->sas_addr[0];
        sha->num_phys = hisi_hba->n_phy;