in iscsi/iscsi_target_util.c [1076:1172]
int iscsit_fe_sendpage_sg(
struct iscsi_cmd *cmd,
struct iscsi_conn *conn)
{
struct scatterlist *sg = cmd->first_data_sg;
struct kvec iov;
u32 tx_hdr_size, data_len;
u32 offset = cmd->first_data_sg_off;
int tx_sent, iov_off;
send_hdr:
tx_hdr_size = ISCSI_HDR_LEN;
if (conn->conn_ops->HeaderDigest)
tx_hdr_size += ISCSI_CRC_LEN;
iov.iov_base = cmd->pdu;
iov.iov_len = tx_hdr_size;
tx_sent = tx_data(conn, &iov, 1, tx_hdr_size);
if (tx_hdr_size != tx_sent) {
if (tx_sent == -EAGAIN) {
pr_err("tx_data() returned -EAGAIN\n");
goto send_hdr;
}
return -1;
}
data_len = cmd->tx_size - tx_hdr_size - cmd->padding;
/*
* Set iov_off used by padding and data digest tx_data() calls below
* in order to determine proper offset into cmd->iov_data[]
*/
if (conn->conn_ops->DataDigest) {
data_len -= ISCSI_CRC_LEN;
if (cmd->padding)
iov_off = (cmd->iov_data_count - 2);
else
iov_off = (cmd->iov_data_count - 1);
} else {
iov_off = (cmd->iov_data_count - 1);
}
/*
* Perform sendpage() for each page in the scatterlist
*/
while (data_len) {
u32 space = (sg->length - offset);
u32 sub_len = min_t(u32, data_len, space);
send_pg:
tx_sent = conn->sock->ops->sendpage(conn->sock,
sg_page(sg), sg->offset + offset, sub_len, 0);
if (tx_sent != sub_len) {
if (tx_sent == -EAGAIN) {
pr_err("tcp_sendpage() returned"
" -EAGAIN\n");
goto send_pg;
}
pr_err("tcp_sendpage() failure: %d\n",
tx_sent);
return -1;
}
data_len -= sub_len;
offset = 0;
sg = sg_next(sg);
}
send_padding:
if (cmd->padding) {
struct kvec *iov_p = &cmd->iov_data[iov_off++];
tx_sent = tx_data(conn, iov_p, 1, cmd->padding);
if (cmd->padding != tx_sent) {
if (tx_sent == -EAGAIN) {
pr_err("tx_data() returned -EAGAIN\n");
goto send_padding;
}
return -1;
}
}
send_datacrc:
if (conn->conn_ops->DataDigest) {
struct kvec *iov_d = &cmd->iov_data[iov_off];
tx_sent = tx_data(conn, iov_d, 1, ISCSI_CRC_LEN);
if (ISCSI_CRC_LEN != tx_sent) {
if (tx_sent == -EAGAIN) {
pr_err("tx_data() returned -EAGAIN\n");
goto send_datacrc;
}
return -1;
}
}
return 0;
}