From: Varun Prakash varun@chelsio.com
commit 6ecdafaec79d4b3388a5b017245f23a0ff9d852d upstream.
Instead of calling dma_unmap_sg() after completing WRITE I/O, call dma_unmap_sg() before calling target_execute_cmd() to sync the DMA buffer.
Link: https://lore.kernel.org/r/1618403949-3443-1-git-send-email-varun@chelsio.com Cc: stable@vger.kernel.org # 5.4+ Signed-off-by: Varun Prakash varun@chelsio.com Signed-off-by: Martin K. Petersen martin.petersen@oracle.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- drivers/target/iscsi/cxgbit/cxgbit_ddp.c | 19 ++++++++++--------- drivers/target/iscsi/cxgbit/cxgbit_target.c | 21 ++++++++++++++++++--- 2 files changed, 28 insertions(+), 12 deletions(-)
--- a/drivers/target/iscsi/cxgbit/cxgbit_ddp.c +++ b/drivers/target/iscsi/cxgbit/cxgbit_ddp.c @@ -265,12 +265,13 @@ void cxgbit_unmap_cmd(struct iscsi_conn struct cxgbit_cmd *ccmd = iscsit_priv_cmd(cmd);
if (ccmd->release) { - struct cxgbi_task_tag_info *ttinfo = &ccmd->ttinfo; - - if (ttinfo->sgl) { + if (cmd->se_cmd.se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC) { + put_page(sg_page(&ccmd->sg)); + } else { struct cxgbit_sock *csk = conn->context; struct cxgbit_device *cdev = csk->com.cdev; struct cxgbi_ppm *ppm = cdev2ppm(cdev); + struct cxgbi_task_tag_info *ttinfo = &ccmd->ttinfo;
/* Abort the TCP conn if DDP is not complete to * avoid any possibility of DDP after freeing @@ -280,14 +281,14 @@ void cxgbit_unmap_cmd(struct iscsi_conn cmd->se_cmd.data_length)) cxgbit_abort_conn(csk);
+ if (unlikely(ttinfo->sgl)) { + dma_unmap_sg(&ppm->pdev->dev, ttinfo->sgl, + ttinfo->nents, DMA_FROM_DEVICE); + ttinfo->nents = 0; + ttinfo->sgl = NULL; + } cxgbi_ppm_ppod_release(ppm, ttinfo->idx); - - dma_unmap_sg(&ppm->pdev->dev, ttinfo->sgl, - ttinfo->nents, DMA_FROM_DEVICE); - } else { - put_page(sg_page(&ccmd->sg)); } - ccmd->release = false; } } --- a/drivers/target/iscsi/cxgbit/cxgbit_target.c +++ b/drivers/target/iscsi/cxgbit/cxgbit_target.c @@ -997,17 +997,18 @@ static int cxgbit_handle_iscsi_dataout(s struct scatterlist *sg_start; struct iscsi_conn *conn = csk->conn; struct iscsi_cmd *cmd = NULL; + struct cxgbit_cmd *ccmd; + struct cxgbi_task_tag_info *ttinfo; struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_rx_pdu_cb(csk->skb); struct iscsi_data *hdr = (struct iscsi_data *)pdu_cb->hdr; u32 data_offset = be32_to_cpu(hdr->offset); - u32 data_len = pdu_cb->dlen; + u32 data_len = ntoh24(hdr->dlength); int rc, sg_nents, sg_off; bool dcrc_err = false;
if (pdu_cb->flags & PDUCBF_RX_DDP_CMP) { u32 offset = be32_to_cpu(hdr->offset); u32 ddp_data_len; - u32 payload_length = ntoh24(hdr->dlength); bool success = false;
cmd = iscsit_find_cmd_from_itt_or_dump(conn, hdr->itt, 0); @@ -1022,7 +1023,7 @@ static int cxgbit_handle_iscsi_dataout(s cmd->data_sn = be32_to_cpu(hdr->datasn);
rc = __iscsit_check_dataout_hdr(conn, (unsigned char *)hdr, - cmd, payload_length, &success); + cmd, data_len, &success); if (rc < 0) return rc; else if (!success) @@ -1060,6 +1061,20 @@ static int cxgbit_handle_iscsi_dataout(s cxgbit_skb_copy_to_sg(csk->skb, sg_start, sg_nents, skip); }
+ ccmd = iscsit_priv_cmd(cmd); + ttinfo = &ccmd->ttinfo; + + if (ccmd->release && ttinfo->sgl && + (cmd->se_cmd.data_length == (cmd->write_data_done + data_len))) { + struct cxgbit_device *cdev = csk->com.cdev; + struct cxgbi_ppm *ppm = cdev2ppm(cdev); + + dma_unmap_sg(&ppm->pdev->dev, ttinfo->sgl, ttinfo->nents, + DMA_FROM_DEVICE); + ttinfo->nents = 0; + ttinfo->sgl = NULL; + } + check_payload:
rc = iscsit_check_dataout_payload(cmd, hdr, dcrc_err);