Commit 7eee4b92 authored by Xiang Chen's avatar Xiang Chen Committed by Martin K. Petersen

scsi: hisi_sas: relocate smp sg map

Currently we use DQ lock to protect delivery of DQ entry one by one.

To optimise to allow more than one slot to be built for a single DQ in
parallel, we need to remove the DQ lock when preparing slots, prior to
delivery.

To achieve this, we rearrange the slot build order to ensure that once
we allocate a slot for a task, we do cannot fail to deliver the task.

In this patch, we rearrange the slot building for SMP tasks to ensure
that sg mapping part (which can fail) happens before we allocate the
slot in the DQ.
Signed-off-by: default avatarXiang Chen <chenxiang66@hisilicon.com>
Signed-off-by: default avatarJohn Garry <john.garry@huawei.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 0d846e70
...@@ -319,7 +319,8 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_sas_dq ...@@ -319,7 +319,8 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_sas_dq
struct hisi_sas_cmd_hdr *cmd_hdr_base; struct hisi_sas_cmd_hdr *cmd_hdr_base;
struct asd_sas_port *sas_port = device->port; struct asd_sas_port *sas_port = device->port;
struct device *dev = hisi_hba->dev; struct device *dev = hisi_hba->dev;
int dlvry_queue_slot, dlvry_queue, n_elem = 0, rc, slot_idx; int dlvry_queue_slot, dlvry_queue, rc, slot_idx;
int n_elem = 0, n_elem_req = 0, n_elem_resp = 0;
unsigned long flags; unsigned long flags;
if (!sas_port) { if (!sas_port) {
...@@ -358,6 +359,8 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_sas_dq ...@@ -358,6 +359,8 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_sas_dq
} }
if (!sas_protocol_ata(task->task_proto)) { if (!sas_protocol_ata(task->task_proto)) {
unsigned int req_len, resp_len;
if (task->num_scatter) { if (task->num_scatter) {
n_elem = dma_map_sg(dev, task->scatter, n_elem = dma_map_sg(dev, task->scatter,
task->num_scatter, task->data_dir); task->num_scatter, task->data_dir);
...@@ -365,6 +368,29 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_sas_dq ...@@ -365,6 +368,29 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_sas_dq
rc = -ENOMEM; rc = -ENOMEM;
goto prep_out; goto prep_out;
} }
} else if (task->task_proto & SAS_PROTOCOL_SMP) {
n_elem_req = dma_map_sg(dev, &task->smp_task.smp_req,
1, DMA_TO_DEVICE);
if (!n_elem_req) {
rc = -ENOMEM;
goto prep_out;
}
req_len = sg_dma_len(&task->smp_task.smp_req);
if (req_len & 0x3) {
rc = -EINVAL;
goto err_out_dma_unmap;
}
n_elem_resp = dma_map_sg(dev, &task->smp_task.smp_resp,
1, DMA_FROM_DEVICE);
if (!n_elem_req) {
rc = -ENOMEM;
goto err_out_dma_unmap;
}
resp_len = sg_dma_len(&task->smp_task.smp_resp);
if (resp_len & 0x3) {
rc = -EINVAL;
goto err_out_dma_unmap;
}
} }
} else } else
n_elem = task->num_scatter; n_elem = task->num_scatter;
...@@ -375,11 +401,9 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_sas_dq ...@@ -375,11 +401,9 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_sas_dq
device); device);
else else
rc = hisi_sas_slot_index_alloc(hisi_hba, &slot_idx); rc = hisi_sas_slot_index_alloc(hisi_hba, &slot_idx);
if (rc) {
spin_unlock_irqrestore(&hisi_hba->lock, flags);
goto err_out;
}
spin_unlock_irqrestore(&hisi_hba->lock, flags); spin_unlock_irqrestore(&hisi_hba->lock, flags);
if (rc)
goto err_out_dma_unmap;
rc = hisi_hba->hw->get_free_slot(hisi_hba, dq); rc = hisi_hba->hw->get_free_slot(hisi_hba, dq);
if (rc) if (rc)
...@@ -458,14 +482,22 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_sas_dq ...@@ -458,14 +482,22 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_sas_dq
spin_lock_irqsave(&hisi_hba->lock, flags); spin_lock_irqsave(&hisi_hba->lock, flags);
hisi_sas_slot_index_free(hisi_hba, slot_idx); hisi_sas_slot_index_free(hisi_hba, slot_idx);
spin_unlock_irqrestore(&hisi_hba->lock, flags); spin_unlock_irqrestore(&hisi_hba->lock, flags);
err_out: err_out_dma_unmap:
dev_err(dev, "task prep: failed[%d]!\n", rc); if (!sas_protocol_ata(task->task_proto)) {
if (!sas_protocol_ata(task->task_proto)) if (task->num_scatter) {
if (n_elem) dma_unmap_sg(dev, task->scatter, task->num_scatter,
dma_unmap_sg(dev, task->scatter, task->data_dir);
task->num_scatter, } else if (task->task_proto & SAS_PROTOCOL_SMP) {
task->data_dir); if (n_elem_req)
dma_unmap_sg(dev, &task->smp_task.smp_req,
1, DMA_TO_DEVICE);
if (n_elem_resp)
dma_unmap_sg(dev, &task->smp_task.smp_resp,
1, DMA_FROM_DEVICE);
}
}
prep_out: prep_out:
dev_err(dev, "task prep: failed[%d]!\n", rc);
return rc; return rc;
} }
......
...@@ -974,38 +974,17 @@ static int prep_smp_v1_hw(struct hisi_hba *hisi_hba, ...@@ -974,38 +974,17 @@ static int prep_smp_v1_hw(struct hisi_hba *hisi_hba,
struct sas_task *task = slot->task; struct sas_task *task = slot->task;
struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr; struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
struct domain_device *device = task->dev; struct domain_device *device = task->dev;
struct device *dev = hisi_hba->dev;
struct hisi_sas_port *port = slot->port; 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; struct hisi_sas_device *sas_dev = device->lldd_dev;
dma_addr_t req_dma_addr; dma_addr_t req_dma_addr;
unsigned int req_len, resp_len; unsigned int req_len;
int elem, rc;
/*
* DMA-map SMP request, response buffers
*/
/* req */ /* req */
sg_req = &task->smp_task.smp_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_len = sg_dma_len(sg_req);
req_dma_addr = sg_dma_address(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;
}
/* create header */ /* create header */
/* dw0 */ /* dw0 */
hdr->dw0 = cpu_to_le32((port->id << CMD_HDR_PORT_OFF) | hdr->dw0 = cpu_to_le32((port->id << CMD_HDR_PORT_OFF) |
...@@ -1027,14 +1006,6 @@ static int prep_smp_v1_hw(struct hisi_hba *hisi_hba, ...@@ -1027,14 +1006,6 @@ static int prep_smp_v1_hw(struct hisi_hba *hisi_hba,
hdr->sts_buffer_addr = cpu_to_le64(hisi_sas_status_buf_addr_dma(slot)); hdr->sts_buffer_addr = cpu_to_le64(hisi_sas_status_buf_addr_dma(slot));
return 0; 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_v1_hw(struct hisi_hba *hisi_hba, static int prep_ssp_v1_hw(struct hisi_hba *hisi_hba,
......
...@@ -1721,37 +1721,16 @@ static int prep_smp_v2_hw(struct hisi_hba *hisi_hba, ...@@ -1721,37 +1721,16 @@ static int prep_smp_v2_hw(struct hisi_hba *hisi_hba,
struct sas_task *task = slot->task; struct sas_task *task = slot->task;
struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr; struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
struct domain_device *device = task->dev; struct domain_device *device = task->dev;
struct device *dev = hisi_hba->dev;
struct hisi_sas_port *port = slot->port; 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; struct hisi_sas_device *sas_dev = device->lldd_dev;
dma_addr_t req_dma_addr; dma_addr_t req_dma_addr;
unsigned int req_len, resp_len; unsigned int req_len;
int elem, rc;
/*
* DMA-map SMP request, response buffers
*/
/* req */ /* req */
sg_req = &task->smp_task.smp_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); req_dma_addr = sg_dma_address(sg_req);
req_len = sg_dma_len(&task->smp_task.smp_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;
}
/* create header */ /* create header */
/* dw0 */ /* dw0 */
...@@ -1775,14 +1754,6 @@ static int prep_smp_v2_hw(struct hisi_hba *hisi_hba, ...@@ -1775,14 +1754,6 @@ static int prep_smp_v2_hw(struct hisi_hba *hisi_hba,
hdr->sts_buffer_addr = cpu_to_le64(hisi_sas_status_buf_addr_dma(slot)); hdr->sts_buffer_addr = cpu_to_le64(hisi_sas_status_buf_addr_dma(slot));
return 0; 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, static int prep_ssp_v2_hw(struct hisi_hba *hisi_hba,
......
...@@ -986,38 +986,17 @@ static int prep_smp_v3_hw(struct hisi_hba *hisi_hba, ...@@ -986,38 +986,17 @@ static int prep_smp_v3_hw(struct hisi_hba *hisi_hba,
struct sas_task *task = slot->task; struct sas_task *task = slot->task;
struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr; struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
struct domain_device *device = task->dev; struct domain_device *device = task->dev;
struct device *dev = hisi_hba->dev;
struct hisi_sas_port *port = slot->port; 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; struct hisi_sas_device *sas_dev = device->lldd_dev;
dma_addr_t req_dma_addr; dma_addr_t req_dma_addr;
unsigned int req_len, resp_len; unsigned int req_len;
int elem, rc;
/*
* DMA-map SMP request, response buffers
*/
/* req */ /* req */
sg_req = &task->smp_task.smp_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_len = sg_dma_len(sg_req);
req_dma_addr = sg_dma_address(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;
}
/* create header */ /* create header */
/* dw0 */ /* dw0 */
hdr->dw0 = cpu_to_le32((port->id << CMD_HDR_PORT_OFF) | hdr->dw0 = cpu_to_le32((port->id << CMD_HDR_PORT_OFF) |
...@@ -1040,14 +1019,6 @@ static int prep_smp_v3_hw(struct hisi_hba *hisi_hba, ...@@ -1040,14 +1019,6 @@ static int prep_smp_v3_hw(struct hisi_hba *hisi_hba,
hdr->sts_buffer_addr = cpu_to_le64(hisi_sas_status_buf_addr_dma(slot)); hdr->sts_buffer_addr = cpu_to_le64(hisi_sas_status_buf_addr_dma(slot));
return 0; 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_ata_v3_hw(struct hisi_hba *hisi_hba, static int prep_ata_v3_hw(struct hisi_hba *hisi_hba,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment