static int cxgbit_handle_iscsi_dataout()

in iscsi/cxgbit/cxgbit_target.c [995:1085]


static int cxgbit_handle_iscsi_dataout(struct cxgbit_sock *csk)
{
	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 = 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;
		bool success = false;

		cmd = iscsit_find_cmd_from_itt_or_dump(conn, hdr->itt, 0);
		if (!cmd)
			return 0;

		ddp_data_len = offset - cmd->write_data_done;
		atomic_long_add(ddp_data_len, &conn->sess->rx_data_octets);

		cmd->write_data_done = offset;
		cmd->next_burst_len = ddp_data_len;
		cmd->data_sn = be32_to_cpu(hdr->datasn);

		rc = __iscsit_check_dataout_hdr(conn, (unsigned char *)hdr,
						cmd, data_len, &success);
		if (rc < 0)
			return rc;
		else if (!success)
			return 0;
	} else {
		rc = iscsit_check_dataout_hdr(conn, (unsigned char *)hdr, &cmd);
		if (rc < 0)
			return rc;
		else if (!cmd)
			return 0;
	}

	if (pdu_cb->flags & PDUCBF_RX_DCRC_ERR) {
		pr_err("ITT: 0x%08x, Offset: %u, Length: %u,"
		       " DataSN: 0x%08x\n",
		       hdr->itt, hdr->offset, data_len,
		       hdr->datasn);

		dcrc_err = true;
		goto check_payload;
	}

	pr_debug("DataOut data_len: %u, "
		"write_data_done: %u, data_length: %u\n",
		  data_len,  cmd->write_data_done,
		  cmd->se_cmd.data_length);

	if (!(pdu_cb->flags & PDUCBF_RX_DATA_DDPD)) {
		u32 skip = data_offset % PAGE_SIZE;

		sg_off = data_offset / PAGE_SIZE;
		sg_start = &cmd->se_cmd.t_data_sg[sg_off];
		sg_nents = max(1UL, DIV_ROUND_UP(skip + data_len, PAGE_SIZE));

		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);
	if (rc < 0)
		return rc;

	return 0;
}