in host/tcp.c [1249:1345]
static int nvme_tcp_init_connection(struct nvme_tcp_queue *queue)
{
struct nvme_tcp_icreq_pdu *icreq;
struct nvme_tcp_icresp_pdu *icresp;
struct msghdr msg = {};
struct kvec iov;
bool ctrl_hdgst, ctrl_ddgst;
int ret;
icreq = kzalloc(sizeof(*icreq), GFP_KERNEL);
if (!icreq)
return -ENOMEM;
icresp = kzalloc(sizeof(*icresp), GFP_KERNEL);
if (!icresp) {
ret = -ENOMEM;
goto free_icreq;
}
icreq->hdr.type = nvme_tcp_icreq;
icreq->hdr.hlen = sizeof(*icreq);
icreq->hdr.pdo = 0;
icreq->hdr.plen = cpu_to_le32(icreq->hdr.hlen);
icreq->pfv = cpu_to_le16(NVME_TCP_PFV_1_0);
icreq->maxr2t = 0; /* single inflight r2t supported */
icreq->hpda = 0; /* no alignment constraint */
if (queue->hdr_digest)
icreq->digest |= NVME_TCP_HDR_DIGEST_ENABLE;
if (queue->data_digest)
icreq->digest |= NVME_TCP_DATA_DIGEST_ENABLE;
iov.iov_base = icreq;
iov.iov_len = sizeof(*icreq);
ret = kernel_sendmsg(queue->sock, &msg, &iov, 1, iov.iov_len);
if (ret < 0)
goto free_icresp;
memset(&msg, 0, sizeof(msg));
iov.iov_base = icresp;
iov.iov_len = sizeof(*icresp);
ret = kernel_recvmsg(queue->sock, &msg, &iov, 1,
iov.iov_len, msg.msg_flags);
if (ret < 0)
goto free_icresp;
ret = -EINVAL;
if (icresp->hdr.type != nvme_tcp_icresp) {
pr_err("queue %d: bad type returned %d\n",
nvme_tcp_queue_id(queue), icresp->hdr.type);
goto free_icresp;
}
if (le32_to_cpu(icresp->hdr.plen) != sizeof(*icresp)) {
pr_err("queue %d: bad pdu length returned %d\n",
nvme_tcp_queue_id(queue), icresp->hdr.plen);
goto free_icresp;
}
if (icresp->pfv != NVME_TCP_PFV_1_0) {
pr_err("queue %d: bad pfv returned %d\n",
nvme_tcp_queue_id(queue), icresp->pfv);
goto free_icresp;
}
ctrl_ddgst = !!(icresp->digest & NVME_TCP_DATA_DIGEST_ENABLE);
if ((queue->data_digest && !ctrl_ddgst) ||
(!queue->data_digest && ctrl_ddgst)) {
pr_err("queue %d: data digest mismatch host: %s ctrl: %s\n",
nvme_tcp_queue_id(queue),
queue->data_digest ? "enabled" : "disabled",
ctrl_ddgst ? "enabled" : "disabled");
goto free_icresp;
}
ctrl_hdgst = !!(icresp->digest & NVME_TCP_HDR_DIGEST_ENABLE);
if ((queue->hdr_digest && !ctrl_hdgst) ||
(!queue->hdr_digest && ctrl_hdgst)) {
pr_err("queue %d: header digest mismatch host: %s ctrl: %s\n",
nvme_tcp_queue_id(queue),
queue->hdr_digest ? "enabled" : "disabled",
ctrl_hdgst ? "enabled" : "disabled");
goto free_icresp;
}
if (icresp->cpda != 0) {
pr_err("queue %d: unsupported cpda returned %d\n",
nvme_tcp_queue_id(queue), icresp->cpda);
goto free_icresp;
}
ret = 0;
free_icresp:
kfree(icresp);
free_icreq:
kfree(icreq);
return ret;
}