18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * NVMe over Fabrics TCP target. 48c2ecf20Sopenharmony_ci * Copyright (c) 2018 Lightbits Labs. All rights reserved. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 78c2ecf20Sopenharmony_ci#include <linux/module.h> 88c2ecf20Sopenharmony_ci#include <linux/init.h> 98c2ecf20Sopenharmony_ci#include <linux/slab.h> 108c2ecf20Sopenharmony_ci#include <linux/err.h> 118c2ecf20Sopenharmony_ci#include <linux/nvme-tcp.h> 128c2ecf20Sopenharmony_ci#include <net/sock.h> 138c2ecf20Sopenharmony_ci#include <net/tcp.h> 148c2ecf20Sopenharmony_ci#include <linux/inet.h> 158c2ecf20Sopenharmony_ci#include <linux/llist.h> 168c2ecf20Sopenharmony_ci#include <crypto/hash.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include "nvmet.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define NVMET_TCP_DEF_INLINE_DATA_SIZE (4 * PAGE_SIZE) 218c2ecf20Sopenharmony_ci#define NVMET_TCP_MAXH2CDATA 0x400000 /* 16M arbitrary limit */ 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci/* Define the socket priority to use for connections were it is desirable 248c2ecf20Sopenharmony_ci * that the NIC consider performing optimized packet processing or filtering. 258c2ecf20Sopenharmony_ci * A non-zero value being sufficient to indicate general consideration of any 268c2ecf20Sopenharmony_ci * possible optimization. Making it a module param allows for alternative 278c2ecf20Sopenharmony_ci * values that may be unique for some NIC implementations. 288c2ecf20Sopenharmony_ci */ 298c2ecf20Sopenharmony_cistatic int so_priority; 308c2ecf20Sopenharmony_cimodule_param(so_priority, int, 0644); 318c2ecf20Sopenharmony_ciMODULE_PARM_DESC(so_priority, "nvmet tcp socket optimize priority"); 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#define NVMET_TCP_RECV_BUDGET 8 348c2ecf20Sopenharmony_ci#define NVMET_TCP_SEND_BUDGET 8 358c2ecf20Sopenharmony_ci#define NVMET_TCP_IO_WORK_BUDGET 64 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cienum nvmet_tcp_send_state { 388c2ecf20Sopenharmony_ci NVMET_TCP_SEND_DATA_PDU, 398c2ecf20Sopenharmony_ci NVMET_TCP_SEND_DATA, 408c2ecf20Sopenharmony_ci NVMET_TCP_SEND_R2T, 418c2ecf20Sopenharmony_ci NVMET_TCP_SEND_DDGST, 428c2ecf20Sopenharmony_ci NVMET_TCP_SEND_RESPONSE 438c2ecf20Sopenharmony_ci}; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cienum nvmet_tcp_recv_state { 468c2ecf20Sopenharmony_ci NVMET_TCP_RECV_PDU, 478c2ecf20Sopenharmony_ci NVMET_TCP_RECV_DATA, 488c2ecf20Sopenharmony_ci NVMET_TCP_RECV_DDGST, 498c2ecf20Sopenharmony_ci NVMET_TCP_RECV_ERR, 508c2ecf20Sopenharmony_ci}; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cienum { 538c2ecf20Sopenharmony_ci NVMET_TCP_F_INIT_FAILED = (1 << 0), 548c2ecf20Sopenharmony_ci}; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistruct nvmet_tcp_cmd { 578c2ecf20Sopenharmony_ci struct nvmet_tcp_queue *queue; 588c2ecf20Sopenharmony_ci struct nvmet_req req; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci struct nvme_tcp_cmd_pdu *cmd_pdu; 618c2ecf20Sopenharmony_ci struct nvme_tcp_rsp_pdu *rsp_pdu; 628c2ecf20Sopenharmony_ci struct nvme_tcp_data_pdu *data_pdu; 638c2ecf20Sopenharmony_ci struct nvme_tcp_r2t_pdu *r2t_pdu; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci u32 rbytes_done; 668c2ecf20Sopenharmony_ci u32 wbytes_done; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci u32 pdu_len; 698c2ecf20Sopenharmony_ci u32 pdu_recv; 708c2ecf20Sopenharmony_ci int sg_idx; 718c2ecf20Sopenharmony_ci int nr_mapped; 728c2ecf20Sopenharmony_ci struct msghdr recv_msg; 738c2ecf20Sopenharmony_ci struct kvec *iov; 748c2ecf20Sopenharmony_ci u32 flags; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci struct list_head entry; 778c2ecf20Sopenharmony_ci struct llist_node lentry; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci /* send state */ 808c2ecf20Sopenharmony_ci u32 offset; 818c2ecf20Sopenharmony_ci struct scatterlist *cur_sg; 828c2ecf20Sopenharmony_ci enum nvmet_tcp_send_state state; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci __le32 exp_ddgst; 858c2ecf20Sopenharmony_ci __le32 recv_ddgst; 868c2ecf20Sopenharmony_ci}; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cienum nvmet_tcp_queue_state { 898c2ecf20Sopenharmony_ci NVMET_TCP_Q_CONNECTING, 908c2ecf20Sopenharmony_ci NVMET_TCP_Q_LIVE, 918c2ecf20Sopenharmony_ci NVMET_TCP_Q_DISCONNECTING, 928c2ecf20Sopenharmony_ci}; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistruct nvmet_tcp_queue { 958c2ecf20Sopenharmony_ci struct socket *sock; 968c2ecf20Sopenharmony_ci struct nvmet_tcp_port *port; 978c2ecf20Sopenharmony_ci struct work_struct io_work; 988c2ecf20Sopenharmony_ci struct nvmet_cq nvme_cq; 998c2ecf20Sopenharmony_ci struct nvmet_sq nvme_sq; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci /* send state */ 1028c2ecf20Sopenharmony_ci struct nvmet_tcp_cmd *cmds; 1038c2ecf20Sopenharmony_ci unsigned int nr_cmds; 1048c2ecf20Sopenharmony_ci struct list_head free_list; 1058c2ecf20Sopenharmony_ci struct llist_head resp_list; 1068c2ecf20Sopenharmony_ci struct list_head resp_send_list; 1078c2ecf20Sopenharmony_ci int send_list_len; 1088c2ecf20Sopenharmony_ci struct nvmet_tcp_cmd *snd_cmd; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci /* recv state */ 1118c2ecf20Sopenharmony_ci int offset; 1128c2ecf20Sopenharmony_ci int left; 1138c2ecf20Sopenharmony_ci enum nvmet_tcp_recv_state rcv_state; 1148c2ecf20Sopenharmony_ci struct nvmet_tcp_cmd *cmd; 1158c2ecf20Sopenharmony_ci union nvme_tcp_pdu pdu; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci /* digest state */ 1188c2ecf20Sopenharmony_ci bool hdr_digest; 1198c2ecf20Sopenharmony_ci bool data_digest; 1208c2ecf20Sopenharmony_ci struct ahash_request *snd_hash; 1218c2ecf20Sopenharmony_ci struct ahash_request *rcv_hash; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci spinlock_t state_lock; 1248c2ecf20Sopenharmony_ci enum nvmet_tcp_queue_state state; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci struct sockaddr_storage sockaddr; 1278c2ecf20Sopenharmony_ci struct sockaddr_storage sockaddr_peer; 1288c2ecf20Sopenharmony_ci struct work_struct release_work; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci int idx; 1318c2ecf20Sopenharmony_ci struct list_head queue_list; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci struct nvmet_tcp_cmd connect; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci struct page_frag_cache pf_cache; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci void (*data_ready)(struct sock *); 1388c2ecf20Sopenharmony_ci void (*state_change)(struct sock *); 1398c2ecf20Sopenharmony_ci void (*write_space)(struct sock *); 1408c2ecf20Sopenharmony_ci}; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistruct nvmet_tcp_port { 1438c2ecf20Sopenharmony_ci struct socket *sock; 1448c2ecf20Sopenharmony_ci struct work_struct accept_work; 1458c2ecf20Sopenharmony_ci struct nvmet_port *nport; 1468c2ecf20Sopenharmony_ci struct sockaddr_storage addr; 1478c2ecf20Sopenharmony_ci void (*data_ready)(struct sock *); 1488c2ecf20Sopenharmony_ci}; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic DEFINE_IDA(nvmet_tcp_queue_ida); 1518c2ecf20Sopenharmony_cistatic LIST_HEAD(nvmet_tcp_queue_list); 1528c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(nvmet_tcp_queue_mutex); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_cistatic struct workqueue_struct *nvmet_tcp_wq; 1558c2ecf20Sopenharmony_cistatic const struct nvmet_fabrics_ops nvmet_tcp_ops; 1568c2ecf20Sopenharmony_cistatic void nvmet_tcp_free_cmd(struct nvmet_tcp_cmd *c); 1578c2ecf20Sopenharmony_cistatic void nvmet_tcp_finish_cmd(struct nvmet_tcp_cmd *cmd); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_cistatic inline u16 nvmet_tcp_cmd_tag(struct nvmet_tcp_queue *queue, 1608c2ecf20Sopenharmony_ci struct nvmet_tcp_cmd *cmd) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci if (unlikely(!queue->nr_cmds)) { 1638c2ecf20Sopenharmony_ci /* We didn't allocate cmds yet, send 0xffff */ 1648c2ecf20Sopenharmony_ci return USHRT_MAX; 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci return cmd - queue->cmds; 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic inline bool nvmet_tcp_has_data_in(struct nvmet_tcp_cmd *cmd) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci return nvme_is_write(cmd->req.cmd) && 1738c2ecf20Sopenharmony_ci cmd->rbytes_done < cmd->req.transfer_len; 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cistatic inline bool nvmet_tcp_need_data_in(struct nvmet_tcp_cmd *cmd) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci return nvmet_tcp_has_data_in(cmd) && !cmd->req.cqe->status; 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic inline bool nvmet_tcp_need_data_out(struct nvmet_tcp_cmd *cmd) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci return !nvme_is_write(cmd->req.cmd) && 1848c2ecf20Sopenharmony_ci cmd->req.transfer_len > 0 && 1858c2ecf20Sopenharmony_ci !cmd->req.cqe->status; 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic inline bool nvmet_tcp_has_inline_data(struct nvmet_tcp_cmd *cmd) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci return nvme_is_write(cmd->req.cmd) && cmd->pdu_len && 1918c2ecf20Sopenharmony_ci !cmd->rbytes_done; 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cistatic inline struct nvmet_tcp_cmd * 1958c2ecf20Sopenharmony_cinvmet_tcp_get_cmd(struct nvmet_tcp_queue *queue) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci struct nvmet_tcp_cmd *cmd; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci cmd = list_first_entry_or_null(&queue->free_list, 2008c2ecf20Sopenharmony_ci struct nvmet_tcp_cmd, entry); 2018c2ecf20Sopenharmony_ci if (!cmd) 2028c2ecf20Sopenharmony_ci return NULL; 2038c2ecf20Sopenharmony_ci list_del_init(&cmd->entry); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci cmd->rbytes_done = cmd->wbytes_done = 0; 2068c2ecf20Sopenharmony_ci cmd->pdu_len = 0; 2078c2ecf20Sopenharmony_ci cmd->pdu_recv = 0; 2088c2ecf20Sopenharmony_ci cmd->iov = NULL; 2098c2ecf20Sopenharmony_ci cmd->flags = 0; 2108c2ecf20Sopenharmony_ci return cmd; 2118c2ecf20Sopenharmony_ci} 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_cistatic inline void nvmet_tcp_put_cmd(struct nvmet_tcp_cmd *cmd) 2148c2ecf20Sopenharmony_ci{ 2158c2ecf20Sopenharmony_ci if (unlikely(cmd == &cmd->queue->connect)) 2168c2ecf20Sopenharmony_ci return; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci list_add_tail(&cmd->entry, &cmd->queue->free_list); 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic inline int queue_cpu(struct nvmet_tcp_queue *queue) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci return queue->sock->sk->sk_incoming_cpu; 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cistatic inline u8 nvmet_tcp_hdgst_len(struct nvmet_tcp_queue *queue) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci return queue->hdr_digest ? NVME_TCP_DIGEST_LENGTH : 0; 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_cistatic inline u8 nvmet_tcp_ddgst_len(struct nvmet_tcp_queue *queue) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci return queue->data_digest ? NVME_TCP_DIGEST_LENGTH : 0; 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_cistatic inline void nvmet_tcp_hdgst(struct ahash_request *hash, 2378c2ecf20Sopenharmony_ci void *pdu, size_t len) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci struct scatterlist sg; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci sg_init_one(&sg, pdu, len); 2428c2ecf20Sopenharmony_ci ahash_request_set_crypt(hash, &sg, pdu + len, len); 2438c2ecf20Sopenharmony_ci crypto_ahash_digest(hash); 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_cistatic int nvmet_tcp_verify_hdgst(struct nvmet_tcp_queue *queue, 2478c2ecf20Sopenharmony_ci void *pdu, size_t len) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci struct nvme_tcp_hdr *hdr = pdu; 2508c2ecf20Sopenharmony_ci __le32 recv_digest; 2518c2ecf20Sopenharmony_ci __le32 exp_digest; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci if (unlikely(!(hdr->flags & NVME_TCP_F_HDGST))) { 2548c2ecf20Sopenharmony_ci pr_err("queue %d: header digest enabled but no header digest\n", 2558c2ecf20Sopenharmony_ci queue->idx); 2568c2ecf20Sopenharmony_ci return -EPROTO; 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci recv_digest = *(__le32 *)(pdu + hdr->hlen); 2608c2ecf20Sopenharmony_ci nvmet_tcp_hdgst(queue->rcv_hash, pdu, len); 2618c2ecf20Sopenharmony_ci exp_digest = *(__le32 *)(pdu + hdr->hlen); 2628c2ecf20Sopenharmony_ci if (recv_digest != exp_digest) { 2638c2ecf20Sopenharmony_ci pr_err("queue %d: header digest error: recv %#x expected %#x\n", 2648c2ecf20Sopenharmony_ci queue->idx, le32_to_cpu(recv_digest), 2658c2ecf20Sopenharmony_ci le32_to_cpu(exp_digest)); 2668c2ecf20Sopenharmony_ci return -EPROTO; 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci return 0; 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_cistatic int nvmet_tcp_check_ddgst(struct nvmet_tcp_queue *queue, void *pdu) 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci struct nvme_tcp_hdr *hdr = pdu; 2758c2ecf20Sopenharmony_ci u8 digest_len = nvmet_tcp_hdgst_len(queue); 2768c2ecf20Sopenharmony_ci u32 len; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci len = le32_to_cpu(hdr->plen) - hdr->hlen - 2798c2ecf20Sopenharmony_ci (hdr->flags & NVME_TCP_F_HDGST ? digest_len : 0); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci if (unlikely(len && !(hdr->flags & NVME_TCP_F_DDGST))) { 2828c2ecf20Sopenharmony_ci pr_err("queue %d: data digest flag is cleared\n", queue->idx); 2838c2ecf20Sopenharmony_ci return -EPROTO; 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci return 0; 2878c2ecf20Sopenharmony_ci} 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_cistatic void nvmet_tcp_unmap_pdu_iovec(struct nvmet_tcp_cmd *cmd) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci struct scatterlist *sg; 2928c2ecf20Sopenharmony_ci int i; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci sg = &cmd->req.sg[cmd->sg_idx]; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci for (i = 0; i < cmd->nr_mapped; i++) 2978c2ecf20Sopenharmony_ci kunmap(sg_page(&sg[i])); 2988c2ecf20Sopenharmony_ci} 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_cistatic void nvmet_tcp_map_pdu_iovec(struct nvmet_tcp_cmd *cmd) 3018c2ecf20Sopenharmony_ci{ 3028c2ecf20Sopenharmony_ci struct kvec *iov = cmd->iov; 3038c2ecf20Sopenharmony_ci struct scatterlist *sg; 3048c2ecf20Sopenharmony_ci u32 length, offset, sg_offset; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci length = cmd->pdu_len; 3078c2ecf20Sopenharmony_ci cmd->nr_mapped = DIV_ROUND_UP(length, PAGE_SIZE); 3088c2ecf20Sopenharmony_ci offset = cmd->rbytes_done; 3098c2ecf20Sopenharmony_ci cmd->sg_idx = offset / PAGE_SIZE; 3108c2ecf20Sopenharmony_ci sg_offset = offset % PAGE_SIZE; 3118c2ecf20Sopenharmony_ci sg = &cmd->req.sg[cmd->sg_idx]; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci while (length) { 3148c2ecf20Sopenharmony_ci u32 iov_len = min_t(u32, length, sg->length - sg_offset); 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci iov->iov_base = kmap(sg_page(sg)) + sg->offset + sg_offset; 3178c2ecf20Sopenharmony_ci iov->iov_len = iov_len; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci length -= iov_len; 3208c2ecf20Sopenharmony_ci sg = sg_next(sg); 3218c2ecf20Sopenharmony_ci iov++; 3228c2ecf20Sopenharmony_ci sg_offset = 0; 3238c2ecf20Sopenharmony_ci } 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci iov_iter_kvec(&cmd->recv_msg.msg_iter, READ, cmd->iov, 3268c2ecf20Sopenharmony_ci cmd->nr_mapped, cmd->pdu_len); 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_cistatic void nvmet_tcp_fatal_error(struct nvmet_tcp_queue *queue) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci queue->rcv_state = NVMET_TCP_RECV_ERR; 3328c2ecf20Sopenharmony_ci if (queue->nvme_sq.ctrl) 3338c2ecf20Sopenharmony_ci nvmet_ctrl_fatal_error(queue->nvme_sq.ctrl); 3348c2ecf20Sopenharmony_ci else 3358c2ecf20Sopenharmony_ci kernel_sock_shutdown(queue->sock, SHUT_RDWR); 3368c2ecf20Sopenharmony_ci} 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_cistatic void nvmet_tcp_socket_error(struct nvmet_tcp_queue *queue, int status) 3398c2ecf20Sopenharmony_ci{ 3408c2ecf20Sopenharmony_ci queue->rcv_state = NVMET_TCP_RECV_ERR; 3418c2ecf20Sopenharmony_ci if (status == -EPIPE || status == -ECONNRESET) 3428c2ecf20Sopenharmony_ci kernel_sock_shutdown(queue->sock, SHUT_RDWR); 3438c2ecf20Sopenharmony_ci else 3448c2ecf20Sopenharmony_ci nvmet_tcp_fatal_error(queue); 3458c2ecf20Sopenharmony_ci} 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_cistatic int nvmet_tcp_map_data(struct nvmet_tcp_cmd *cmd) 3488c2ecf20Sopenharmony_ci{ 3498c2ecf20Sopenharmony_ci struct nvme_sgl_desc *sgl = &cmd->req.cmd->common.dptr.sgl; 3508c2ecf20Sopenharmony_ci u32 len = le32_to_cpu(sgl->length); 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci if (!len) 3538c2ecf20Sopenharmony_ci return 0; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci if (sgl->type == ((NVME_SGL_FMT_DATA_DESC << 4) | 3568c2ecf20Sopenharmony_ci NVME_SGL_FMT_OFFSET)) { 3578c2ecf20Sopenharmony_ci if (!nvme_is_write(cmd->req.cmd)) 3588c2ecf20Sopenharmony_ci return NVME_SC_INVALID_FIELD | NVME_SC_DNR; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci if (len > cmd->req.port->inline_data_size) 3618c2ecf20Sopenharmony_ci return NVME_SC_SGL_INVALID_OFFSET | NVME_SC_DNR; 3628c2ecf20Sopenharmony_ci cmd->pdu_len = len; 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci cmd->req.transfer_len += len; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci cmd->req.sg = sgl_alloc(len, GFP_KERNEL, &cmd->req.sg_cnt); 3678c2ecf20Sopenharmony_ci if (!cmd->req.sg) 3688c2ecf20Sopenharmony_ci return NVME_SC_INTERNAL; 3698c2ecf20Sopenharmony_ci cmd->cur_sg = cmd->req.sg; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci if (nvmet_tcp_has_data_in(cmd)) { 3728c2ecf20Sopenharmony_ci cmd->iov = kmalloc_array(cmd->req.sg_cnt, 3738c2ecf20Sopenharmony_ci sizeof(*cmd->iov), GFP_KERNEL); 3748c2ecf20Sopenharmony_ci if (!cmd->iov) 3758c2ecf20Sopenharmony_ci goto err; 3768c2ecf20Sopenharmony_ci } 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci return 0; 3798c2ecf20Sopenharmony_cierr: 3808c2ecf20Sopenharmony_ci sgl_free(cmd->req.sg); 3818c2ecf20Sopenharmony_ci return NVME_SC_INTERNAL; 3828c2ecf20Sopenharmony_ci} 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_cistatic void nvmet_tcp_send_ddgst(struct ahash_request *hash, 3858c2ecf20Sopenharmony_ci struct nvmet_tcp_cmd *cmd) 3868c2ecf20Sopenharmony_ci{ 3878c2ecf20Sopenharmony_ci ahash_request_set_crypt(hash, cmd->req.sg, 3888c2ecf20Sopenharmony_ci (void *)&cmd->exp_ddgst, cmd->req.transfer_len); 3898c2ecf20Sopenharmony_ci crypto_ahash_digest(hash); 3908c2ecf20Sopenharmony_ci} 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_cistatic void nvmet_tcp_recv_ddgst(struct ahash_request *hash, 3938c2ecf20Sopenharmony_ci struct nvmet_tcp_cmd *cmd) 3948c2ecf20Sopenharmony_ci{ 3958c2ecf20Sopenharmony_ci struct scatterlist sg; 3968c2ecf20Sopenharmony_ci struct kvec *iov; 3978c2ecf20Sopenharmony_ci int i; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci crypto_ahash_init(hash); 4008c2ecf20Sopenharmony_ci for (i = 0, iov = cmd->iov; i < cmd->nr_mapped; i++, iov++) { 4018c2ecf20Sopenharmony_ci sg_init_one(&sg, iov->iov_base, iov->iov_len); 4028c2ecf20Sopenharmony_ci ahash_request_set_crypt(hash, &sg, NULL, iov->iov_len); 4038c2ecf20Sopenharmony_ci crypto_ahash_update(hash); 4048c2ecf20Sopenharmony_ci } 4058c2ecf20Sopenharmony_ci ahash_request_set_crypt(hash, NULL, (void *)&cmd->exp_ddgst, 0); 4068c2ecf20Sopenharmony_ci crypto_ahash_final(hash); 4078c2ecf20Sopenharmony_ci} 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_cistatic void nvmet_setup_c2h_data_pdu(struct nvmet_tcp_cmd *cmd) 4108c2ecf20Sopenharmony_ci{ 4118c2ecf20Sopenharmony_ci struct nvme_tcp_data_pdu *pdu = cmd->data_pdu; 4128c2ecf20Sopenharmony_ci struct nvmet_tcp_queue *queue = cmd->queue; 4138c2ecf20Sopenharmony_ci u8 hdgst = nvmet_tcp_hdgst_len(cmd->queue); 4148c2ecf20Sopenharmony_ci u8 ddgst = nvmet_tcp_ddgst_len(cmd->queue); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci cmd->offset = 0; 4178c2ecf20Sopenharmony_ci cmd->state = NVMET_TCP_SEND_DATA_PDU; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci pdu->hdr.type = nvme_tcp_c2h_data; 4208c2ecf20Sopenharmony_ci pdu->hdr.flags = NVME_TCP_F_DATA_LAST | (queue->nvme_sq.sqhd_disabled ? 4218c2ecf20Sopenharmony_ci NVME_TCP_F_DATA_SUCCESS : 0); 4228c2ecf20Sopenharmony_ci pdu->hdr.hlen = sizeof(*pdu); 4238c2ecf20Sopenharmony_ci pdu->hdr.pdo = pdu->hdr.hlen + hdgst; 4248c2ecf20Sopenharmony_ci pdu->hdr.plen = 4258c2ecf20Sopenharmony_ci cpu_to_le32(pdu->hdr.hlen + hdgst + 4268c2ecf20Sopenharmony_ci cmd->req.transfer_len + ddgst); 4278c2ecf20Sopenharmony_ci pdu->command_id = cmd->req.cqe->command_id; 4288c2ecf20Sopenharmony_ci pdu->data_length = cpu_to_le32(cmd->req.transfer_len); 4298c2ecf20Sopenharmony_ci pdu->data_offset = cpu_to_le32(cmd->wbytes_done); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci if (queue->data_digest) { 4328c2ecf20Sopenharmony_ci pdu->hdr.flags |= NVME_TCP_F_DDGST; 4338c2ecf20Sopenharmony_ci nvmet_tcp_send_ddgst(queue->snd_hash, cmd); 4348c2ecf20Sopenharmony_ci } 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci if (cmd->queue->hdr_digest) { 4378c2ecf20Sopenharmony_ci pdu->hdr.flags |= NVME_TCP_F_HDGST; 4388c2ecf20Sopenharmony_ci nvmet_tcp_hdgst(queue->snd_hash, pdu, sizeof(*pdu)); 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci} 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_cistatic void nvmet_setup_r2t_pdu(struct nvmet_tcp_cmd *cmd) 4438c2ecf20Sopenharmony_ci{ 4448c2ecf20Sopenharmony_ci struct nvme_tcp_r2t_pdu *pdu = cmd->r2t_pdu; 4458c2ecf20Sopenharmony_ci struct nvmet_tcp_queue *queue = cmd->queue; 4468c2ecf20Sopenharmony_ci u8 hdgst = nvmet_tcp_hdgst_len(cmd->queue); 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci cmd->offset = 0; 4498c2ecf20Sopenharmony_ci cmd->state = NVMET_TCP_SEND_R2T; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci pdu->hdr.type = nvme_tcp_r2t; 4528c2ecf20Sopenharmony_ci pdu->hdr.flags = 0; 4538c2ecf20Sopenharmony_ci pdu->hdr.hlen = sizeof(*pdu); 4548c2ecf20Sopenharmony_ci pdu->hdr.pdo = 0; 4558c2ecf20Sopenharmony_ci pdu->hdr.plen = cpu_to_le32(pdu->hdr.hlen + hdgst); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci pdu->command_id = cmd->req.cmd->common.command_id; 4588c2ecf20Sopenharmony_ci pdu->ttag = nvmet_tcp_cmd_tag(cmd->queue, cmd); 4598c2ecf20Sopenharmony_ci pdu->r2t_length = cpu_to_le32(cmd->req.transfer_len - cmd->rbytes_done); 4608c2ecf20Sopenharmony_ci pdu->r2t_offset = cpu_to_le32(cmd->rbytes_done); 4618c2ecf20Sopenharmony_ci if (cmd->queue->hdr_digest) { 4628c2ecf20Sopenharmony_ci pdu->hdr.flags |= NVME_TCP_F_HDGST; 4638c2ecf20Sopenharmony_ci nvmet_tcp_hdgst(queue->snd_hash, pdu, sizeof(*pdu)); 4648c2ecf20Sopenharmony_ci } 4658c2ecf20Sopenharmony_ci} 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_cistatic void nvmet_setup_response_pdu(struct nvmet_tcp_cmd *cmd) 4688c2ecf20Sopenharmony_ci{ 4698c2ecf20Sopenharmony_ci struct nvme_tcp_rsp_pdu *pdu = cmd->rsp_pdu; 4708c2ecf20Sopenharmony_ci struct nvmet_tcp_queue *queue = cmd->queue; 4718c2ecf20Sopenharmony_ci u8 hdgst = nvmet_tcp_hdgst_len(cmd->queue); 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci cmd->offset = 0; 4748c2ecf20Sopenharmony_ci cmd->state = NVMET_TCP_SEND_RESPONSE; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci pdu->hdr.type = nvme_tcp_rsp; 4778c2ecf20Sopenharmony_ci pdu->hdr.flags = 0; 4788c2ecf20Sopenharmony_ci pdu->hdr.hlen = sizeof(*pdu); 4798c2ecf20Sopenharmony_ci pdu->hdr.pdo = 0; 4808c2ecf20Sopenharmony_ci pdu->hdr.plen = cpu_to_le32(pdu->hdr.hlen + hdgst); 4818c2ecf20Sopenharmony_ci if (cmd->queue->hdr_digest) { 4828c2ecf20Sopenharmony_ci pdu->hdr.flags |= NVME_TCP_F_HDGST; 4838c2ecf20Sopenharmony_ci nvmet_tcp_hdgst(queue->snd_hash, pdu, sizeof(*pdu)); 4848c2ecf20Sopenharmony_ci } 4858c2ecf20Sopenharmony_ci} 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_cistatic void nvmet_tcp_process_resp_list(struct nvmet_tcp_queue *queue) 4888c2ecf20Sopenharmony_ci{ 4898c2ecf20Sopenharmony_ci struct llist_node *node; 4908c2ecf20Sopenharmony_ci struct nvmet_tcp_cmd *cmd; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci for (node = llist_del_all(&queue->resp_list); node; node = node->next) { 4938c2ecf20Sopenharmony_ci cmd = llist_entry(node, struct nvmet_tcp_cmd, lentry); 4948c2ecf20Sopenharmony_ci list_add(&cmd->entry, &queue->resp_send_list); 4958c2ecf20Sopenharmony_ci queue->send_list_len++; 4968c2ecf20Sopenharmony_ci } 4978c2ecf20Sopenharmony_ci} 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_cistatic struct nvmet_tcp_cmd *nvmet_tcp_fetch_cmd(struct nvmet_tcp_queue *queue) 5008c2ecf20Sopenharmony_ci{ 5018c2ecf20Sopenharmony_ci queue->snd_cmd = list_first_entry_or_null(&queue->resp_send_list, 5028c2ecf20Sopenharmony_ci struct nvmet_tcp_cmd, entry); 5038c2ecf20Sopenharmony_ci if (!queue->snd_cmd) { 5048c2ecf20Sopenharmony_ci nvmet_tcp_process_resp_list(queue); 5058c2ecf20Sopenharmony_ci queue->snd_cmd = 5068c2ecf20Sopenharmony_ci list_first_entry_or_null(&queue->resp_send_list, 5078c2ecf20Sopenharmony_ci struct nvmet_tcp_cmd, entry); 5088c2ecf20Sopenharmony_ci if (unlikely(!queue->snd_cmd)) 5098c2ecf20Sopenharmony_ci return NULL; 5108c2ecf20Sopenharmony_ci } 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci list_del_init(&queue->snd_cmd->entry); 5138c2ecf20Sopenharmony_ci queue->send_list_len--; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci if (nvmet_tcp_need_data_out(queue->snd_cmd)) 5168c2ecf20Sopenharmony_ci nvmet_setup_c2h_data_pdu(queue->snd_cmd); 5178c2ecf20Sopenharmony_ci else if (nvmet_tcp_need_data_in(queue->snd_cmd)) 5188c2ecf20Sopenharmony_ci nvmet_setup_r2t_pdu(queue->snd_cmd); 5198c2ecf20Sopenharmony_ci else 5208c2ecf20Sopenharmony_ci nvmet_setup_response_pdu(queue->snd_cmd); 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci return queue->snd_cmd; 5238c2ecf20Sopenharmony_ci} 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_cistatic void nvmet_tcp_queue_response(struct nvmet_req *req) 5268c2ecf20Sopenharmony_ci{ 5278c2ecf20Sopenharmony_ci struct nvmet_tcp_cmd *cmd = 5288c2ecf20Sopenharmony_ci container_of(req, struct nvmet_tcp_cmd, req); 5298c2ecf20Sopenharmony_ci struct nvmet_tcp_queue *queue = cmd->queue; 5308c2ecf20Sopenharmony_ci struct nvme_sgl_desc *sgl; 5318c2ecf20Sopenharmony_ci u32 len; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci if (unlikely(cmd == queue->cmd)) { 5348c2ecf20Sopenharmony_ci sgl = &cmd->req.cmd->common.dptr.sgl; 5358c2ecf20Sopenharmony_ci len = le32_to_cpu(sgl->length); 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci /* 5388c2ecf20Sopenharmony_ci * Wait for inline data before processing the response. 5398c2ecf20Sopenharmony_ci * Avoid using helpers, this might happen before 5408c2ecf20Sopenharmony_ci * nvmet_req_init is completed. 5418c2ecf20Sopenharmony_ci */ 5428c2ecf20Sopenharmony_ci if (queue->rcv_state == NVMET_TCP_RECV_PDU && 5438c2ecf20Sopenharmony_ci len && len <= cmd->req.port->inline_data_size && 5448c2ecf20Sopenharmony_ci nvme_is_write(cmd->req.cmd)) 5458c2ecf20Sopenharmony_ci return; 5468c2ecf20Sopenharmony_ci } 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci llist_add(&cmd->lentry, &queue->resp_list); 5498c2ecf20Sopenharmony_ci queue_work_on(queue_cpu(queue), nvmet_tcp_wq, &cmd->queue->io_work); 5508c2ecf20Sopenharmony_ci} 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_cistatic void nvmet_tcp_execute_request(struct nvmet_tcp_cmd *cmd) 5538c2ecf20Sopenharmony_ci{ 5548c2ecf20Sopenharmony_ci if (unlikely(cmd->flags & NVMET_TCP_F_INIT_FAILED)) 5558c2ecf20Sopenharmony_ci nvmet_tcp_queue_response(&cmd->req); 5568c2ecf20Sopenharmony_ci else 5578c2ecf20Sopenharmony_ci cmd->req.execute(&cmd->req); 5588c2ecf20Sopenharmony_ci} 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_cistatic int nvmet_try_send_data_pdu(struct nvmet_tcp_cmd *cmd) 5618c2ecf20Sopenharmony_ci{ 5628c2ecf20Sopenharmony_ci u8 hdgst = nvmet_tcp_hdgst_len(cmd->queue); 5638c2ecf20Sopenharmony_ci int left = sizeof(*cmd->data_pdu) - cmd->offset + hdgst; 5648c2ecf20Sopenharmony_ci int ret; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci ret = kernel_sendpage(cmd->queue->sock, virt_to_page(cmd->data_pdu), 5678c2ecf20Sopenharmony_ci offset_in_page(cmd->data_pdu) + cmd->offset, 5688c2ecf20Sopenharmony_ci left, MSG_DONTWAIT | MSG_MORE | MSG_SENDPAGE_NOTLAST); 5698c2ecf20Sopenharmony_ci if (ret <= 0) 5708c2ecf20Sopenharmony_ci return ret; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci cmd->offset += ret; 5738c2ecf20Sopenharmony_ci left -= ret; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci if (left) 5768c2ecf20Sopenharmony_ci return -EAGAIN; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci cmd->state = NVMET_TCP_SEND_DATA; 5798c2ecf20Sopenharmony_ci cmd->offset = 0; 5808c2ecf20Sopenharmony_ci return 1; 5818c2ecf20Sopenharmony_ci} 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_cistatic int nvmet_try_send_data(struct nvmet_tcp_cmd *cmd, bool last_in_batch) 5848c2ecf20Sopenharmony_ci{ 5858c2ecf20Sopenharmony_ci struct nvmet_tcp_queue *queue = cmd->queue; 5868c2ecf20Sopenharmony_ci int ret; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci while (cmd->cur_sg) { 5898c2ecf20Sopenharmony_ci struct page *page = sg_page(cmd->cur_sg); 5908c2ecf20Sopenharmony_ci u32 left = cmd->cur_sg->length - cmd->offset; 5918c2ecf20Sopenharmony_ci int flags = MSG_DONTWAIT; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci if ((!last_in_batch && cmd->queue->send_list_len) || 5948c2ecf20Sopenharmony_ci cmd->wbytes_done + left < cmd->req.transfer_len || 5958c2ecf20Sopenharmony_ci queue->data_digest || !queue->nvme_sq.sqhd_disabled) 5968c2ecf20Sopenharmony_ci flags |= MSG_MORE | MSG_SENDPAGE_NOTLAST; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci ret = kernel_sendpage(cmd->queue->sock, page, cmd->offset, 5998c2ecf20Sopenharmony_ci left, flags); 6008c2ecf20Sopenharmony_ci if (ret <= 0) 6018c2ecf20Sopenharmony_ci return ret; 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci cmd->offset += ret; 6048c2ecf20Sopenharmony_ci cmd->wbytes_done += ret; 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci /* Done with sg?*/ 6078c2ecf20Sopenharmony_ci if (cmd->offset == cmd->cur_sg->length) { 6088c2ecf20Sopenharmony_ci cmd->cur_sg = sg_next(cmd->cur_sg); 6098c2ecf20Sopenharmony_ci cmd->offset = 0; 6108c2ecf20Sopenharmony_ci } 6118c2ecf20Sopenharmony_ci } 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci if (queue->data_digest) { 6148c2ecf20Sopenharmony_ci cmd->state = NVMET_TCP_SEND_DDGST; 6158c2ecf20Sopenharmony_ci cmd->offset = 0; 6168c2ecf20Sopenharmony_ci } else { 6178c2ecf20Sopenharmony_ci if (queue->nvme_sq.sqhd_disabled) { 6188c2ecf20Sopenharmony_ci cmd->queue->snd_cmd = NULL; 6198c2ecf20Sopenharmony_ci nvmet_tcp_put_cmd(cmd); 6208c2ecf20Sopenharmony_ci } else { 6218c2ecf20Sopenharmony_ci nvmet_setup_response_pdu(cmd); 6228c2ecf20Sopenharmony_ci } 6238c2ecf20Sopenharmony_ci } 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci if (queue->nvme_sq.sqhd_disabled) { 6268c2ecf20Sopenharmony_ci kfree(cmd->iov); 6278c2ecf20Sopenharmony_ci sgl_free(cmd->req.sg); 6288c2ecf20Sopenharmony_ci } 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci return 1; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci} 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_cistatic int nvmet_try_send_response(struct nvmet_tcp_cmd *cmd, 6358c2ecf20Sopenharmony_ci bool last_in_batch) 6368c2ecf20Sopenharmony_ci{ 6378c2ecf20Sopenharmony_ci u8 hdgst = nvmet_tcp_hdgst_len(cmd->queue); 6388c2ecf20Sopenharmony_ci int left = sizeof(*cmd->rsp_pdu) - cmd->offset + hdgst; 6398c2ecf20Sopenharmony_ci int flags = MSG_DONTWAIT; 6408c2ecf20Sopenharmony_ci int ret; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci if (!last_in_batch && cmd->queue->send_list_len) 6438c2ecf20Sopenharmony_ci flags |= MSG_MORE | MSG_SENDPAGE_NOTLAST; 6448c2ecf20Sopenharmony_ci else 6458c2ecf20Sopenharmony_ci flags |= MSG_EOR; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci ret = kernel_sendpage(cmd->queue->sock, virt_to_page(cmd->rsp_pdu), 6488c2ecf20Sopenharmony_ci offset_in_page(cmd->rsp_pdu) + cmd->offset, left, flags); 6498c2ecf20Sopenharmony_ci if (ret <= 0) 6508c2ecf20Sopenharmony_ci return ret; 6518c2ecf20Sopenharmony_ci cmd->offset += ret; 6528c2ecf20Sopenharmony_ci left -= ret; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci if (left) 6558c2ecf20Sopenharmony_ci return -EAGAIN; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci kfree(cmd->iov); 6588c2ecf20Sopenharmony_ci sgl_free(cmd->req.sg); 6598c2ecf20Sopenharmony_ci cmd->queue->snd_cmd = NULL; 6608c2ecf20Sopenharmony_ci nvmet_tcp_put_cmd(cmd); 6618c2ecf20Sopenharmony_ci return 1; 6628c2ecf20Sopenharmony_ci} 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_cistatic int nvmet_try_send_r2t(struct nvmet_tcp_cmd *cmd, bool last_in_batch) 6658c2ecf20Sopenharmony_ci{ 6668c2ecf20Sopenharmony_ci u8 hdgst = nvmet_tcp_hdgst_len(cmd->queue); 6678c2ecf20Sopenharmony_ci int left = sizeof(*cmd->r2t_pdu) - cmd->offset + hdgst; 6688c2ecf20Sopenharmony_ci int flags = MSG_DONTWAIT; 6698c2ecf20Sopenharmony_ci int ret; 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci if (!last_in_batch && cmd->queue->send_list_len) 6728c2ecf20Sopenharmony_ci flags |= MSG_MORE | MSG_SENDPAGE_NOTLAST; 6738c2ecf20Sopenharmony_ci else 6748c2ecf20Sopenharmony_ci flags |= MSG_EOR; 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci ret = kernel_sendpage(cmd->queue->sock, virt_to_page(cmd->r2t_pdu), 6778c2ecf20Sopenharmony_ci offset_in_page(cmd->r2t_pdu) + cmd->offset, left, flags); 6788c2ecf20Sopenharmony_ci if (ret <= 0) 6798c2ecf20Sopenharmony_ci return ret; 6808c2ecf20Sopenharmony_ci cmd->offset += ret; 6818c2ecf20Sopenharmony_ci left -= ret; 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci if (left) 6848c2ecf20Sopenharmony_ci return -EAGAIN; 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci cmd->queue->snd_cmd = NULL; 6878c2ecf20Sopenharmony_ci return 1; 6888c2ecf20Sopenharmony_ci} 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_cistatic int nvmet_try_send_ddgst(struct nvmet_tcp_cmd *cmd, bool last_in_batch) 6918c2ecf20Sopenharmony_ci{ 6928c2ecf20Sopenharmony_ci struct nvmet_tcp_queue *queue = cmd->queue; 6938c2ecf20Sopenharmony_ci int left = NVME_TCP_DIGEST_LENGTH - cmd->offset; 6948c2ecf20Sopenharmony_ci struct msghdr msg = { .msg_flags = MSG_DONTWAIT }; 6958c2ecf20Sopenharmony_ci struct kvec iov = { 6968c2ecf20Sopenharmony_ci .iov_base = (u8 *)&cmd->exp_ddgst + cmd->offset, 6978c2ecf20Sopenharmony_ci .iov_len = left 6988c2ecf20Sopenharmony_ci }; 6998c2ecf20Sopenharmony_ci int ret; 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci if (!last_in_batch && cmd->queue->send_list_len) 7028c2ecf20Sopenharmony_ci msg.msg_flags |= MSG_MORE; 7038c2ecf20Sopenharmony_ci else 7048c2ecf20Sopenharmony_ci msg.msg_flags |= MSG_EOR; 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci ret = kernel_sendmsg(queue->sock, &msg, &iov, 1, iov.iov_len); 7078c2ecf20Sopenharmony_ci if (unlikely(ret <= 0)) 7088c2ecf20Sopenharmony_ci return ret; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci cmd->offset += ret; 7118c2ecf20Sopenharmony_ci left -= ret; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci if (left) 7148c2ecf20Sopenharmony_ci return -EAGAIN; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci if (queue->nvme_sq.sqhd_disabled) { 7178c2ecf20Sopenharmony_ci cmd->queue->snd_cmd = NULL; 7188c2ecf20Sopenharmony_ci nvmet_tcp_put_cmd(cmd); 7198c2ecf20Sopenharmony_ci } else { 7208c2ecf20Sopenharmony_ci nvmet_setup_response_pdu(cmd); 7218c2ecf20Sopenharmony_ci } 7228c2ecf20Sopenharmony_ci return 1; 7238c2ecf20Sopenharmony_ci} 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_cistatic int nvmet_tcp_try_send_one(struct nvmet_tcp_queue *queue, 7268c2ecf20Sopenharmony_ci bool last_in_batch) 7278c2ecf20Sopenharmony_ci{ 7288c2ecf20Sopenharmony_ci struct nvmet_tcp_cmd *cmd = queue->snd_cmd; 7298c2ecf20Sopenharmony_ci int ret = 0; 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci if (!cmd || queue->state == NVMET_TCP_Q_DISCONNECTING) { 7328c2ecf20Sopenharmony_ci cmd = nvmet_tcp_fetch_cmd(queue); 7338c2ecf20Sopenharmony_ci if (unlikely(!cmd)) 7348c2ecf20Sopenharmony_ci return 0; 7358c2ecf20Sopenharmony_ci } 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci if (cmd->state == NVMET_TCP_SEND_DATA_PDU) { 7388c2ecf20Sopenharmony_ci ret = nvmet_try_send_data_pdu(cmd); 7398c2ecf20Sopenharmony_ci if (ret <= 0) 7408c2ecf20Sopenharmony_ci goto done_send; 7418c2ecf20Sopenharmony_ci } 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci if (cmd->state == NVMET_TCP_SEND_DATA) { 7448c2ecf20Sopenharmony_ci ret = nvmet_try_send_data(cmd, last_in_batch); 7458c2ecf20Sopenharmony_ci if (ret <= 0) 7468c2ecf20Sopenharmony_ci goto done_send; 7478c2ecf20Sopenharmony_ci } 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci if (cmd->state == NVMET_TCP_SEND_DDGST) { 7508c2ecf20Sopenharmony_ci ret = nvmet_try_send_ddgst(cmd, last_in_batch); 7518c2ecf20Sopenharmony_ci if (ret <= 0) 7528c2ecf20Sopenharmony_ci goto done_send; 7538c2ecf20Sopenharmony_ci } 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci if (cmd->state == NVMET_TCP_SEND_R2T) { 7568c2ecf20Sopenharmony_ci ret = nvmet_try_send_r2t(cmd, last_in_batch); 7578c2ecf20Sopenharmony_ci if (ret <= 0) 7588c2ecf20Sopenharmony_ci goto done_send; 7598c2ecf20Sopenharmony_ci } 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci if (cmd->state == NVMET_TCP_SEND_RESPONSE) 7628c2ecf20Sopenharmony_ci ret = nvmet_try_send_response(cmd, last_in_batch); 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_cidone_send: 7658c2ecf20Sopenharmony_ci if (ret < 0) { 7668c2ecf20Sopenharmony_ci if (ret == -EAGAIN) 7678c2ecf20Sopenharmony_ci return 0; 7688c2ecf20Sopenharmony_ci return ret; 7698c2ecf20Sopenharmony_ci } 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci return 1; 7728c2ecf20Sopenharmony_ci} 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_cistatic int nvmet_tcp_try_send(struct nvmet_tcp_queue *queue, 7758c2ecf20Sopenharmony_ci int budget, int *sends) 7768c2ecf20Sopenharmony_ci{ 7778c2ecf20Sopenharmony_ci int i, ret = 0; 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci for (i = 0; i < budget; i++) { 7808c2ecf20Sopenharmony_ci ret = nvmet_tcp_try_send_one(queue, i == budget - 1); 7818c2ecf20Sopenharmony_ci if (unlikely(ret < 0)) { 7828c2ecf20Sopenharmony_ci nvmet_tcp_socket_error(queue, ret); 7838c2ecf20Sopenharmony_ci goto done; 7848c2ecf20Sopenharmony_ci } else if (ret == 0) { 7858c2ecf20Sopenharmony_ci break; 7868c2ecf20Sopenharmony_ci } 7878c2ecf20Sopenharmony_ci (*sends)++; 7888c2ecf20Sopenharmony_ci } 7898c2ecf20Sopenharmony_cidone: 7908c2ecf20Sopenharmony_ci return ret; 7918c2ecf20Sopenharmony_ci} 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_cistatic void nvmet_prepare_receive_pdu(struct nvmet_tcp_queue *queue) 7948c2ecf20Sopenharmony_ci{ 7958c2ecf20Sopenharmony_ci queue->offset = 0; 7968c2ecf20Sopenharmony_ci queue->left = sizeof(struct nvme_tcp_hdr); 7978c2ecf20Sopenharmony_ci queue->cmd = NULL; 7988c2ecf20Sopenharmony_ci queue->rcv_state = NVMET_TCP_RECV_PDU; 7998c2ecf20Sopenharmony_ci} 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_cistatic void nvmet_tcp_free_crypto(struct nvmet_tcp_queue *queue) 8028c2ecf20Sopenharmony_ci{ 8038c2ecf20Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(queue->rcv_hash); 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci ahash_request_free(queue->rcv_hash); 8068c2ecf20Sopenharmony_ci ahash_request_free(queue->snd_hash); 8078c2ecf20Sopenharmony_ci crypto_free_ahash(tfm); 8088c2ecf20Sopenharmony_ci} 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_cistatic int nvmet_tcp_alloc_crypto(struct nvmet_tcp_queue *queue) 8118c2ecf20Sopenharmony_ci{ 8128c2ecf20Sopenharmony_ci struct crypto_ahash *tfm; 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci tfm = crypto_alloc_ahash("crc32c", 0, CRYPTO_ALG_ASYNC); 8158c2ecf20Sopenharmony_ci if (IS_ERR(tfm)) 8168c2ecf20Sopenharmony_ci return PTR_ERR(tfm); 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci queue->snd_hash = ahash_request_alloc(tfm, GFP_KERNEL); 8198c2ecf20Sopenharmony_ci if (!queue->snd_hash) 8208c2ecf20Sopenharmony_ci goto free_tfm; 8218c2ecf20Sopenharmony_ci ahash_request_set_callback(queue->snd_hash, 0, NULL, NULL); 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci queue->rcv_hash = ahash_request_alloc(tfm, GFP_KERNEL); 8248c2ecf20Sopenharmony_ci if (!queue->rcv_hash) 8258c2ecf20Sopenharmony_ci goto free_snd_hash; 8268c2ecf20Sopenharmony_ci ahash_request_set_callback(queue->rcv_hash, 0, NULL, NULL); 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci return 0; 8298c2ecf20Sopenharmony_cifree_snd_hash: 8308c2ecf20Sopenharmony_ci ahash_request_free(queue->snd_hash); 8318c2ecf20Sopenharmony_cifree_tfm: 8328c2ecf20Sopenharmony_ci crypto_free_ahash(tfm); 8338c2ecf20Sopenharmony_ci return -ENOMEM; 8348c2ecf20Sopenharmony_ci} 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_cistatic int nvmet_tcp_handle_icreq(struct nvmet_tcp_queue *queue) 8388c2ecf20Sopenharmony_ci{ 8398c2ecf20Sopenharmony_ci struct nvme_tcp_icreq_pdu *icreq = &queue->pdu.icreq; 8408c2ecf20Sopenharmony_ci struct nvme_tcp_icresp_pdu *icresp = &queue->pdu.icresp; 8418c2ecf20Sopenharmony_ci struct msghdr msg = {}; 8428c2ecf20Sopenharmony_ci struct kvec iov; 8438c2ecf20Sopenharmony_ci int ret; 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci if (le32_to_cpu(icreq->hdr.plen) != sizeof(struct nvme_tcp_icreq_pdu)) { 8468c2ecf20Sopenharmony_ci pr_err("bad nvme-tcp pdu length (%d)\n", 8478c2ecf20Sopenharmony_ci le32_to_cpu(icreq->hdr.plen)); 8488c2ecf20Sopenharmony_ci nvmet_tcp_fatal_error(queue); 8498c2ecf20Sopenharmony_ci } 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci if (icreq->pfv != NVME_TCP_PFV_1_0) { 8528c2ecf20Sopenharmony_ci pr_err("queue %d: bad pfv %d\n", queue->idx, icreq->pfv); 8538c2ecf20Sopenharmony_ci return -EPROTO; 8548c2ecf20Sopenharmony_ci } 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci if (icreq->hpda != 0) { 8578c2ecf20Sopenharmony_ci pr_err("queue %d: unsupported hpda %d\n", queue->idx, 8588c2ecf20Sopenharmony_ci icreq->hpda); 8598c2ecf20Sopenharmony_ci return -EPROTO; 8608c2ecf20Sopenharmony_ci } 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci queue->hdr_digest = !!(icreq->digest & NVME_TCP_HDR_DIGEST_ENABLE); 8638c2ecf20Sopenharmony_ci queue->data_digest = !!(icreq->digest & NVME_TCP_DATA_DIGEST_ENABLE); 8648c2ecf20Sopenharmony_ci if (queue->hdr_digest || queue->data_digest) { 8658c2ecf20Sopenharmony_ci ret = nvmet_tcp_alloc_crypto(queue); 8668c2ecf20Sopenharmony_ci if (ret) 8678c2ecf20Sopenharmony_ci return ret; 8688c2ecf20Sopenharmony_ci } 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci memset(icresp, 0, sizeof(*icresp)); 8718c2ecf20Sopenharmony_ci icresp->hdr.type = nvme_tcp_icresp; 8728c2ecf20Sopenharmony_ci icresp->hdr.hlen = sizeof(*icresp); 8738c2ecf20Sopenharmony_ci icresp->hdr.pdo = 0; 8748c2ecf20Sopenharmony_ci icresp->hdr.plen = cpu_to_le32(icresp->hdr.hlen); 8758c2ecf20Sopenharmony_ci icresp->pfv = cpu_to_le16(NVME_TCP_PFV_1_0); 8768c2ecf20Sopenharmony_ci icresp->maxdata = cpu_to_le32(NVMET_TCP_MAXH2CDATA); 8778c2ecf20Sopenharmony_ci icresp->cpda = 0; 8788c2ecf20Sopenharmony_ci if (queue->hdr_digest) 8798c2ecf20Sopenharmony_ci icresp->digest |= NVME_TCP_HDR_DIGEST_ENABLE; 8808c2ecf20Sopenharmony_ci if (queue->data_digest) 8818c2ecf20Sopenharmony_ci icresp->digest |= NVME_TCP_DATA_DIGEST_ENABLE; 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci iov.iov_base = icresp; 8848c2ecf20Sopenharmony_ci iov.iov_len = sizeof(*icresp); 8858c2ecf20Sopenharmony_ci ret = kernel_sendmsg(queue->sock, &msg, &iov, 1, iov.iov_len); 8868c2ecf20Sopenharmony_ci if (ret < 0) 8878c2ecf20Sopenharmony_ci return ret; /* queue removal will cleanup */ 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci queue->state = NVMET_TCP_Q_LIVE; 8908c2ecf20Sopenharmony_ci nvmet_prepare_receive_pdu(queue); 8918c2ecf20Sopenharmony_ci return 0; 8928c2ecf20Sopenharmony_ci} 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_cistatic void nvmet_tcp_handle_req_failure(struct nvmet_tcp_queue *queue, 8958c2ecf20Sopenharmony_ci struct nvmet_tcp_cmd *cmd, struct nvmet_req *req) 8968c2ecf20Sopenharmony_ci{ 8978c2ecf20Sopenharmony_ci size_t data_len = le32_to_cpu(req->cmd->common.dptr.sgl.length); 8988c2ecf20Sopenharmony_ci int ret; 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci if (!nvme_is_write(cmd->req.cmd) || 9018c2ecf20Sopenharmony_ci data_len > cmd->req.port->inline_data_size) { 9028c2ecf20Sopenharmony_ci nvmet_prepare_receive_pdu(queue); 9038c2ecf20Sopenharmony_ci return; 9048c2ecf20Sopenharmony_ci } 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci ret = nvmet_tcp_map_data(cmd); 9078c2ecf20Sopenharmony_ci if (unlikely(ret)) { 9088c2ecf20Sopenharmony_ci pr_err("queue %d: failed to map data\n", queue->idx); 9098c2ecf20Sopenharmony_ci nvmet_tcp_fatal_error(queue); 9108c2ecf20Sopenharmony_ci return; 9118c2ecf20Sopenharmony_ci } 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci queue->rcv_state = NVMET_TCP_RECV_DATA; 9148c2ecf20Sopenharmony_ci nvmet_tcp_map_pdu_iovec(cmd); 9158c2ecf20Sopenharmony_ci cmd->flags |= NVMET_TCP_F_INIT_FAILED; 9168c2ecf20Sopenharmony_ci} 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_cistatic int nvmet_tcp_handle_h2c_data_pdu(struct nvmet_tcp_queue *queue) 9198c2ecf20Sopenharmony_ci{ 9208c2ecf20Sopenharmony_ci struct nvme_tcp_data_pdu *data = &queue->pdu.data; 9218c2ecf20Sopenharmony_ci struct nvmet_tcp_cmd *cmd; 9228c2ecf20Sopenharmony_ci unsigned int exp_data_len; 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci if (likely(queue->nr_cmds)) { 9258c2ecf20Sopenharmony_ci if (unlikely(data->ttag >= queue->nr_cmds)) { 9268c2ecf20Sopenharmony_ci pr_err("queue %d: received out of bound ttag %u, nr_cmds %u\n", 9278c2ecf20Sopenharmony_ci queue->idx, data->ttag, queue->nr_cmds); 9288c2ecf20Sopenharmony_ci nvmet_tcp_fatal_error(queue); 9298c2ecf20Sopenharmony_ci return -EPROTO; 9308c2ecf20Sopenharmony_ci } 9318c2ecf20Sopenharmony_ci cmd = &queue->cmds[data->ttag]; 9328c2ecf20Sopenharmony_ci } else { 9338c2ecf20Sopenharmony_ci cmd = &queue->connect; 9348c2ecf20Sopenharmony_ci } 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci if (le32_to_cpu(data->data_offset) != cmd->rbytes_done) { 9378c2ecf20Sopenharmony_ci pr_err("ttag %u unexpected data offset %u (expected %u)\n", 9388c2ecf20Sopenharmony_ci data->ttag, le32_to_cpu(data->data_offset), 9398c2ecf20Sopenharmony_ci cmd->rbytes_done); 9408c2ecf20Sopenharmony_ci /* FIXME: use path and transport errors */ 9418c2ecf20Sopenharmony_ci nvmet_tcp_fatal_error(queue); 9428c2ecf20Sopenharmony_ci return -EPROTO; 9438c2ecf20Sopenharmony_ci } 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci exp_data_len = le32_to_cpu(data->hdr.plen) - 9468c2ecf20Sopenharmony_ci nvmet_tcp_hdgst_len(queue) - 9478c2ecf20Sopenharmony_ci nvmet_tcp_ddgst_len(queue) - 9488c2ecf20Sopenharmony_ci sizeof(*data); 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci cmd->pdu_len = le32_to_cpu(data->data_length); 9518c2ecf20Sopenharmony_ci if (unlikely(cmd->pdu_len != exp_data_len || 9528c2ecf20Sopenharmony_ci cmd->pdu_len == 0 || 9538c2ecf20Sopenharmony_ci cmd->pdu_len > NVMET_TCP_MAXH2CDATA)) { 9548c2ecf20Sopenharmony_ci pr_err("H2CData PDU len %u is invalid\n", cmd->pdu_len); 9558c2ecf20Sopenharmony_ci /* FIXME: use proper transport errors */ 9568c2ecf20Sopenharmony_ci nvmet_tcp_fatal_error(queue); 9578c2ecf20Sopenharmony_ci return -EPROTO; 9588c2ecf20Sopenharmony_ci } 9598c2ecf20Sopenharmony_ci cmd->pdu_recv = 0; 9608c2ecf20Sopenharmony_ci nvmet_tcp_map_pdu_iovec(cmd); 9618c2ecf20Sopenharmony_ci queue->cmd = cmd; 9628c2ecf20Sopenharmony_ci queue->rcv_state = NVMET_TCP_RECV_DATA; 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci return 0; 9658c2ecf20Sopenharmony_ci} 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_cistatic int nvmet_tcp_done_recv_pdu(struct nvmet_tcp_queue *queue) 9688c2ecf20Sopenharmony_ci{ 9698c2ecf20Sopenharmony_ci struct nvme_tcp_hdr *hdr = &queue->pdu.cmd.hdr; 9708c2ecf20Sopenharmony_ci struct nvme_command *nvme_cmd = &queue->pdu.cmd.cmd; 9718c2ecf20Sopenharmony_ci struct nvmet_req *req; 9728c2ecf20Sopenharmony_ci int ret; 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci if (unlikely(queue->state == NVMET_TCP_Q_CONNECTING)) { 9758c2ecf20Sopenharmony_ci if (hdr->type != nvme_tcp_icreq) { 9768c2ecf20Sopenharmony_ci pr_err("unexpected pdu type (%d) before icreq\n", 9778c2ecf20Sopenharmony_ci hdr->type); 9788c2ecf20Sopenharmony_ci nvmet_tcp_fatal_error(queue); 9798c2ecf20Sopenharmony_ci return -EPROTO; 9808c2ecf20Sopenharmony_ci } 9818c2ecf20Sopenharmony_ci return nvmet_tcp_handle_icreq(queue); 9828c2ecf20Sopenharmony_ci } 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci if (hdr->type == nvme_tcp_h2c_data) { 9858c2ecf20Sopenharmony_ci ret = nvmet_tcp_handle_h2c_data_pdu(queue); 9868c2ecf20Sopenharmony_ci if (unlikely(ret)) 9878c2ecf20Sopenharmony_ci return ret; 9888c2ecf20Sopenharmony_ci return 0; 9898c2ecf20Sopenharmony_ci } 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci queue->cmd = nvmet_tcp_get_cmd(queue); 9928c2ecf20Sopenharmony_ci if (unlikely(!queue->cmd)) { 9938c2ecf20Sopenharmony_ci /* This should never happen */ 9948c2ecf20Sopenharmony_ci pr_err("queue %d: out of commands (%d) send_list_len: %d, opcode: %d", 9958c2ecf20Sopenharmony_ci queue->idx, queue->nr_cmds, queue->send_list_len, 9968c2ecf20Sopenharmony_ci nvme_cmd->common.opcode); 9978c2ecf20Sopenharmony_ci nvmet_tcp_fatal_error(queue); 9988c2ecf20Sopenharmony_ci return -ENOMEM; 9998c2ecf20Sopenharmony_ci } 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci req = &queue->cmd->req; 10028c2ecf20Sopenharmony_ci memcpy(req->cmd, nvme_cmd, sizeof(*nvme_cmd)); 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci if (unlikely(!nvmet_req_init(req, &queue->nvme_cq, 10058c2ecf20Sopenharmony_ci &queue->nvme_sq, &nvmet_tcp_ops))) { 10068c2ecf20Sopenharmony_ci pr_err("failed cmd %p id %d opcode %d, data_len: %d\n", 10078c2ecf20Sopenharmony_ci req->cmd, req->cmd->common.command_id, 10088c2ecf20Sopenharmony_ci req->cmd->common.opcode, 10098c2ecf20Sopenharmony_ci le32_to_cpu(req->cmd->common.dptr.sgl.length)); 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci nvmet_tcp_handle_req_failure(queue, queue->cmd, req); 10128c2ecf20Sopenharmony_ci return 0; 10138c2ecf20Sopenharmony_ci } 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci ret = nvmet_tcp_map_data(queue->cmd); 10168c2ecf20Sopenharmony_ci if (unlikely(ret)) { 10178c2ecf20Sopenharmony_ci pr_err("queue %d: failed to map data\n", queue->idx); 10188c2ecf20Sopenharmony_ci if (nvmet_tcp_has_inline_data(queue->cmd)) 10198c2ecf20Sopenharmony_ci nvmet_tcp_fatal_error(queue); 10208c2ecf20Sopenharmony_ci else 10218c2ecf20Sopenharmony_ci nvmet_req_complete(req, ret); 10228c2ecf20Sopenharmony_ci ret = -EAGAIN; 10238c2ecf20Sopenharmony_ci goto out; 10248c2ecf20Sopenharmony_ci } 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci if (nvmet_tcp_need_data_in(queue->cmd)) { 10278c2ecf20Sopenharmony_ci if (nvmet_tcp_has_inline_data(queue->cmd)) { 10288c2ecf20Sopenharmony_ci queue->rcv_state = NVMET_TCP_RECV_DATA; 10298c2ecf20Sopenharmony_ci nvmet_tcp_map_pdu_iovec(queue->cmd); 10308c2ecf20Sopenharmony_ci return 0; 10318c2ecf20Sopenharmony_ci } 10328c2ecf20Sopenharmony_ci /* send back R2T */ 10338c2ecf20Sopenharmony_ci nvmet_tcp_queue_response(&queue->cmd->req); 10348c2ecf20Sopenharmony_ci goto out; 10358c2ecf20Sopenharmony_ci } 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci queue->cmd->req.execute(&queue->cmd->req); 10388c2ecf20Sopenharmony_ciout: 10398c2ecf20Sopenharmony_ci nvmet_prepare_receive_pdu(queue); 10408c2ecf20Sopenharmony_ci return ret; 10418c2ecf20Sopenharmony_ci} 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_cistatic const u8 nvme_tcp_pdu_sizes[] = { 10448c2ecf20Sopenharmony_ci [nvme_tcp_icreq] = sizeof(struct nvme_tcp_icreq_pdu), 10458c2ecf20Sopenharmony_ci [nvme_tcp_cmd] = sizeof(struct nvme_tcp_cmd_pdu), 10468c2ecf20Sopenharmony_ci [nvme_tcp_h2c_data] = sizeof(struct nvme_tcp_data_pdu), 10478c2ecf20Sopenharmony_ci}; 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_cistatic inline u8 nvmet_tcp_pdu_size(u8 type) 10508c2ecf20Sopenharmony_ci{ 10518c2ecf20Sopenharmony_ci size_t idx = type; 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci return (idx < ARRAY_SIZE(nvme_tcp_pdu_sizes) && 10548c2ecf20Sopenharmony_ci nvme_tcp_pdu_sizes[idx]) ? 10558c2ecf20Sopenharmony_ci nvme_tcp_pdu_sizes[idx] : 0; 10568c2ecf20Sopenharmony_ci} 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_cistatic inline bool nvmet_tcp_pdu_valid(u8 type) 10598c2ecf20Sopenharmony_ci{ 10608c2ecf20Sopenharmony_ci switch (type) { 10618c2ecf20Sopenharmony_ci case nvme_tcp_icreq: 10628c2ecf20Sopenharmony_ci case nvme_tcp_cmd: 10638c2ecf20Sopenharmony_ci case nvme_tcp_h2c_data: 10648c2ecf20Sopenharmony_ci /* fallthru */ 10658c2ecf20Sopenharmony_ci return true; 10668c2ecf20Sopenharmony_ci } 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci return false; 10698c2ecf20Sopenharmony_ci} 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_cistatic int nvmet_tcp_try_recv_pdu(struct nvmet_tcp_queue *queue) 10728c2ecf20Sopenharmony_ci{ 10738c2ecf20Sopenharmony_ci struct nvme_tcp_hdr *hdr = &queue->pdu.cmd.hdr; 10748c2ecf20Sopenharmony_ci int len; 10758c2ecf20Sopenharmony_ci struct kvec iov; 10768c2ecf20Sopenharmony_ci struct msghdr msg = { .msg_flags = MSG_DONTWAIT }; 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_cirecv: 10798c2ecf20Sopenharmony_ci iov.iov_base = (void *)&queue->pdu + queue->offset; 10808c2ecf20Sopenharmony_ci iov.iov_len = queue->left; 10818c2ecf20Sopenharmony_ci len = kernel_recvmsg(queue->sock, &msg, &iov, 1, 10828c2ecf20Sopenharmony_ci iov.iov_len, msg.msg_flags); 10838c2ecf20Sopenharmony_ci if (unlikely(len < 0)) 10848c2ecf20Sopenharmony_ci return len; 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci queue->offset += len; 10878c2ecf20Sopenharmony_ci queue->left -= len; 10888c2ecf20Sopenharmony_ci if (queue->left) 10898c2ecf20Sopenharmony_ci return -EAGAIN; 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci if (queue->offset == sizeof(struct nvme_tcp_hdr)) { 10928c2ecf20Sopenharmony_ci u8 hdgst = nvmet_tcp_hdgst_len(queue); 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci if (unlikely(!nvmet_tcp_pdu_valid(hdr->type))) { 10958c2ecf20Sopenharmony_ci pr_err("unexpected pdu type %d\n", hdr->type); 10968c2ecf20Sopenharmony_ci nvmet_tcp_fatal_error(queue); 10978c2ecf20Sopenharmony_ci return -EIO; 10988c2ecf20Sopenharmony_ci } 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci if (unlikely(hdr->hlen != nvmet_tcp_pdu_size(hdr->type))) { 11018c2ecf20Sopenharmony_ci pr_err("pdu %d bad hlen %d\n", hdr->type, hdr->hlen); 11028c2ecf20Sopenharmony_ci return -EIO; 11038c2ecf20Sopenharmony_ci } 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci queue->left = hdr->hlen - queue->offset + hdgst; 11068c2ecf20Sopenharmony_ci goto recv; 11078c2ecf20Sopenharmony_ci } 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci if (queue->hdr_digest && 11108c2ecf20Sopenharmony_ci nvmet_tcp_verify_hdgst(queue, &queue->pdu, hdr->hlen)) { 11118c2ecf20Sopenharmony_ci nvmet_tcp_fatal_error(queue); /* fatal */ 11128c2ecf20Sopenharmony_ci return -EPROTO; 11138c2ecf20Sopenharmony_ci } 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci if (queue->data_digest && 11168c2ecf20Sopenharmony_ci nvmet_tcp_check_ddgst(queue, &queue->pdu)) { 11178c2ecf20Sopenharmony_ci nvmet_tcp_fatal_error(queue); /* fatal */ 11188c2ecf20Sopenharmony_ci return -EPROTO; 11198c2ecf20Sopenharmony_ci } 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci return nvmet_tcp_done_recv_pdu(queue); 11228c2ecf20Sopenharmony_ci} 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_cistatic void nvmet_tcp_prep_recv_ddgst(struct nvmet_tcp_cmd *cmd) 11258c2ecf20Sopenharmony_ci{ 11268c2ecf20Sopenharmony_ci struct nvmet_tcp_queue *queue = cmd->queue; 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci nvmet_tcp_recv_ddgst(queue->rcv_hash, cmd); 11298c2ecf20Sopenharmony_ci queue->offset = 0; 11308c2ecf20Sopenharmony_ci queue->left = NVME_TCP_DIGEST_LENGTH; 11318c2ecf20Sopenharmony_ci queue->rcv_state = NVMET_TCP_RECV_DDGST; 11328c2ecf20Sopenharmony_ci} 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_cistatic int nvmet_tcp_try_recv_data(struct nvmet_tcp_queue *queue) 11358c2ecf20Sopenharmony_ci{ 11368c2ecf20Sopenharmony_ci struct nvmet_tcp_cmd *cmd = queue->cmd; 11378c2ecf20Sopenharmony_ci int ret; 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci while (msg_data_left(&cmd->recv_msg)) { 11408c2ecf20Sopenharmony_ci ret = sock_recvmsg(cmd->queue->sock, &cmd->recv_msg, 11418c2ecf20Sopenharmony_ci cmd->recv_msg.msg_flags); 11428c2ecf20Sopenharmony_ci if (ret <= 0) 11438c2ecf20Sopenharmony_ci return ret; 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci cmd->pdu_recv += ret; 11468c2ecf20Sopenharmony_ci cmd->rbytes_done += ret; 11478c2ecf20Sopenharmony_ci } 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci nvmet_tcp_unmap_pdu_iovec(cmd); 11508c2ecf20Sopenharmony_ci if (queue->data_digest) { 11518c2ecf20Sopenharmony_ci nvmet_tcp_prep_recv_ddgst(cmd); 11528c2ecf20Sopenharmony_ci return 0; 11538c2ecf20Sopenharmony_ci } 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci if (cmd->rbytes_done == cmd->req.transfer_len) 11568c2ecf20Sopenharmony_ci nvmet_tcp_execute_request(cmd); 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci nvmet_prepare_receive_pdu(queue); 11598c2ecf20Sopenharmony_ci return 0; 11608c2ecf20Sopenharmony_ci} 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_cistatic int nvmet_tcp_try_recv_ddgst(struct nvmet_tcp_queue *queue) 11638c2ecf20Sopenharmony_ci{ 11648c2ecf20Sopenharmony_ci struct nvmet_tcp_cmd *cmd = queue->cmd; 11658c2ecf20Sopenharmony_ci int ret; 11668c2ecf20Sopenharmony_ci struct msghdr msg = { .msg_flags = MSG_DONTWAIT }; 11678c2ecf20Sopenharmony_ci struct kvec iov = { 11688c2ecf20Sopenharmony_ci .iov_base = (void *)&cmd->recv_ddgst + queue->offset, 11698c2ecf20Sopenharmony_ci .iov_len = queue->left 11708c2ecf20Sopenharmony_ci }; 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci ret = kernel_recvmsg(queue->sock, &msg, &iov, 1, 11738c2ecf20Sopenharmony_ci iov.iov_len, msg.msg_flags); 11748c2ecf20Sopenharmony_ci if (unlikely(ret < 0)) 11758c2ecf20Sopenharmony_ci return ret; 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci queue->offset += ret; 11788c2ecf20Sopenharmony_ci queue->left -= ret; 11798c2ecf20Sopenharmony_ci if (queue->left) 11808c2ecf20Sopenharmony_ci return -EAGAIN; 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci if (queue->data_digest && cmd->exp_ddgst != cmd->recv_ddgst) { 11838c2ecf20Sopenharmony_ci pr_err("queue %d: cmd %d pdu (%d) data digest error: recv %#x expected %#x\n", 11848c2ecf20Sopenharmony_ci queue->idx, cmd->req.cmd->common.command_id, 11858c2ecf20Sopenharmony_ci queue->pdu.cmd.hdr.type, le32_to_cpu(cmd->recv_ddgst), 11868c2ecf20Sopenharmony_ci le32_to_cpu(cmd->exp_ddgst)); 11878c2ecf20Sopenharmony_ci nvmet_tcp_finish_cmd(cmd); 11888c2ecf20Sopenharmony_ci nvmet_tcp_fatal_error(queue); 11898c2ecf20Sopenharmony_ci ret = -EPROTO; 11908c2ecf20Sopenharmony_ci goto out; 11918c2ecf20Sopenharmony_ci } 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci if (cmd->rbytes_done == cmd->req.transfer_len) 11948c2ecf20Sopenharmony_ci nvmet_tcp_execute_request(cmd); 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ci ret = 0; 11978c2ecf20Sopenharmony_ciout: 11988c2ecf20Sopenharmony_ci nvmet_prepare_receive_pdu(queue); 11998c2ecf20Sopenharmony_ci return ret; 12008c2ecf20Sopenharmony_ci} 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_cistatic int nvmet_tcp_try_recv_one(struct nvmet_tcp_queue *queue) 12038c2ecf20Sopenharmony_ci{ 12048c2ecf20Sopenharmony_ci int result = 0; 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci if (unlikely(queue->rcv_state == NVMET_TCP_RECV_ERR)) 12078c2ecf20Sopenharmony_ci return 0; 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci if (queue->rcv_state == NVMET_TCP_RECV_PDU) { 12108c2ecf20Sopenharmony_ci result = nvmet_tcp_try_recv_pdu(queue); 12118c2ecf20Sopenharmony_ci if (result != 0) 12128c2ecf20Sopenharmony_ci goto done_recv; 12138c2ecf20Sopenharmony_ci } 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci if (queue->rcv_state == NVMET_TCP_RECV_DATA) { 12168c2ecf20Sopenharmony_ci result = nvmet_tcp_try_recv_data(queue); 12178c2ecf20Sopenharmony_ci if (result != 0) 12188c2ecf20Sopenharmony_ci goto done_recv; 12198c2ecf20Sopenharmony_ci } 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci if (queue->rcv_state == NVMET_TCP_RECV_DDGST) { 12228c2ecf20Sopenharmony_ci result = nvmet_tcp_try_recv_ddgst(queue); 12238c2ecf20Sopenharmony_ci if (result != 0) 12248c2ecf20Sopenharmony_ci goto done_recv; 12258c2ecf20Sopenharmony_ci } 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_cidone_recv: 12288c2ecf20Sopenharmony_ci if (result < 0) { 12298c2ecf20Sopenharmony_ci if (result == -EAGAIN) 12308c2ecf20Sopenharmony_ci return 0; 12318c2ecf20Sopenharmony_ci return result; 12328c2ecf20Sopenharmony_ci } 12338c2ecf20Sopenharmony_ci return 1; 12348c2ecf20Sopenharmony_ci} 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_cistatic int nvmet_tcp_try_recv(struct nvmet_tcp_queue *queue, 12378c2ecf20Sopenharmony_ci int budget, int *recvs) 12388c2ecf20Sopenharmony_ci{ 12398c2ecf20Sopenharmony_ci int i, ret = 0; 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci for (i = 0; i < budget; i++) { 12428c2ecf20Sopenharmony_ci ret = nvmet_tcp_try_recv_one(queue); 12438c2ecf20Sopenharmony_ci if (unlikely(ret < 0)) { 12448c2ecf20Sopenharmony_ci nvmet_tcp_socket_error(queue, ret); 12458c2ecf20Sopenharmony_ci goto done; 12468c2ecf20Sopenharmony_ci } else if (ret == 0) { 12478c2ecf20Sopenharmony_ci break; 12488c2ecf20Sopenharmony_ci } 12498c2ecf20Sopenharmony_ci (*recvs)++; 12508c2ecf20Sopenharmony_ci } 12518c2ecf20Sopenharmony_cidone: 12528c2ecf20Sopenharmony_ci return ret; 12538c2ecf20Sopenharmony_ci} 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_cistatic void nvmet_tcp_schedule_release_queue(struct nvmet_tcp_queue *queue) 12568c2ecf20Sopenharmony_ci{ 12578c2ecf20Sopenharmony_ci spin_lock(&queue->state_lock); 12588c2ecf20Sopenharmony_ci if (queue->state != NVMET_TCP_Q_DISCONNECTING) { 12598c2ecf20Sopenharmony_ci queue->state = NVMET_TCP_Q_DISCONNECTING; 12608c2ecf20Sopenharmony_ci schedule_work(&queue->release_work); 12618c2ecf20Sopenharmony_ci } 12628c2ecf20Sopenharmony_ci spin_unlock(&queue->state_lock); 12638c2ecf20Sopenharmony_ci} 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_cistatic void nvmet_tcp_io_work(struct work_struct *w) 12668c2ecf20Sopenharmony_ci{ 12678c2ecf20Sopenharmony_ci struct nvmet_tcp_queue *queue = 12688c2ecf20Sopenharmony_ci container_of(w, struct nvmet_tcp_queue, io_work); 12698c2ecf20Sopenharmony_ci bool pending; 12708c2ecf20Sopenharmony_ci int ret, ops = 0; 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci do { 12738c2ecf20Sopenharmony_ci pending = false; 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci ret = nvmet_tcp_try_recv(queue, NVMET_TCP_RECV_BUDGET, &ops); 12768c2ecf20Sopenharmony_ci if (ret > 0) 12778c2ecf20Sopenharmony_ci pending = true; 12788c2ecf20Sopenharmony_ci else if (ret < 0) 12798c2ecf20Sopenharmony_ci return; 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci ret = nvmet_tcp_try_send(queue, NVMET_TCP_SEND_BUDGET, &ops); 12828c2ecf20Sopenharmony_ci if (ret > 0) 12838c2ecf20Sopenharmony_ci pending = true; 12848c2ecf20Sopenharmony_ci else if (ret < 0) 12858c2ecf20Sopenharmony_ci return; 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ci } while (pending && ops < NVMET_TCP_IO_WORK_BUDGET); 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci /* 12908c2ecf20Sopenharmony_ci * We exahusted our budget, requeue our selves 12918c2ecf20Sopenharmony_ci */ 12928c2ecf20Sopenharmony_ci if (pending) 12938c2ecf20Sopenharmony_ci queue_work_on(queue_cpu(queue), nvmet_tcp_wq, &queue->io_work); 12948c2ecf20Sopenharmony_ci} 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_cistatic int nvmet_tcp_alloc_cmd(struct nvmet_tcp_queue *queue, 12978c2ecf20Sopenharmony_ci struct nvmet_tcp_cmd *c) 12988c2ecf20Sopenharmony_ci{ 12998c2ecf20Sopenharmony_ci u8 hdgst = nvmet_tcp_hdgst_len(queue); 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci c->queue = queue; 13028c2ecf20Sopenharmony_ci c->req.port = queue->port->nport; 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci c->cmd_pdu = page_frag_alloc(&queue->pf_cache, 13058c2ecf20Sopenharmony_ci sizeof(*c->cmd_pdu) + hdgst, GFP_KERNEL | __GFP_ZERO); 13068c2ecf20Sopenharmony_ci if (!c->cmd_pdu) 13078c2ecf20Sopenharmony_ci return -ENOMEM; 13088c2ecf20Sopenharmony_ci c->req.cmd = &c->cmd_pdu->cmd; 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci c->rsp_pdu = page_frag_alloc(&queue->pf_cache, 13118c2ecf20Sopenharmony_ci sizeof(*c->rsp_pdu) + hdgst, GFP_KERNEL | __GFP_ZERO); 13128c2ecf20Sopenharmony_ci if (!c->rsp_pdu) 13138c2ecf20Sopenharmony_ci goto out_free_cmd; 13148c2ecf20Sopenharmony_ci c->req.cqe = &c->rsp_pdu->cqe; 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci c->data_pdu = page_frag_alloc(&queue->pf_cache, 13178c2ecf20Sopenharmony_ci sizeof(*c->data_pdu) + hdgst, GFP_KERNEL | __GFP_ZERO); 13188c2ecf20Sopenharmony_ci if (!c->data_pdu) 13198c2ecf20Sopenharmony_ci goto out_free_rsp; 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci c->r2t_pdu = page_frag_alloc(&queue->pf_cache, 13228c2ecf20Sopenharmony_ci sizeof(*c->r2t_pdu) + hdgst, GFP_KERNEL | __GFP_ZERO); 13238c2ecf20Sopenharmony_ci if (!c->r2t_pdu) 13248c2ecf20Sopenharmony_ci goto out_free_data; 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci c->recv_msg.msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL; 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci list_add_tail(&c->entry, &queue->free_list); 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci return 0; 13318c2ecf20Sopenharmony_ciout_free_data: 13328c2ecf20Sopenharmony_ci page_frag_free(c->data_pdu); 13338c2ecf20Sopenharmony_ciout_free_rsp: 13348c2ecf20Sopenharmony_ci page_frag_free(c->rsp_pdu); 13358c2ecf20Sopenharmony_ciout_free_cmd: 13368c2ecf20Sopenharmony_ci page_frag_free(c->cmd_pdu); 13378c2ecf20Sopenharmony_ci return -ENOMEM; 13388c2ecf20Sopenharmony_ci} 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_cistatic void nvmet_tcp_free_cmd(struct nvmet_tcp_cmd *c) 13418c2ecf20Sopenharmony_ci{ 13428c2ecf20Sopenharmony_ci page_frag_free(c->r2t_pdu); 13438c2ecf20Sopenharmony_ci page_frag_free(c->data_pdu); 13448c2ecf20Sopenharmony_ci page_frag_free(c->rsp_pdu); 13458c2ecf20Sopenharmony_ci page_frag_free(c->cmd_pdu); 13468c2ecf20Sopenharmony_ci} 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_cistatic int nvmet_tcp_alloc_cmds(struct nvmet_tcp_queue *queue) 13498c2ecf20Sopenharmony_ci{ 13508c2ecf20Sopenharmony_ci struct nvmet_tcp_cmd *cmds; 13518c2ecf20Sopenharmony_ci int i, ret = -EINVAL, nr_cmds = queue->nr_cmds; 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_ci cmds = kcalloc(nr_cmds, sizeof(struct nvmet_tcp_cmd), GFP_KERNEL); 13548c2ecf20Sopenharmony_ci if (!cmds) 13558c2ecf20Sopenharmony_ci goto out; 13568c2ecf20Sopenharmony_ci 13578c2ecf20Sopenharmony_ci for (i = 0; i < nr_cmds; i++) { 13588c2ecf20Sopenharmony_ci ret = nvmet_tcp_alloc_cmd(queue, cmds + i); 13598c2ecf20Sopenharmony_ci if (ret) 13608c2ecf20Sopenharmony_ci goto out_free; 13618c2ecf20Sopenharmony_ci } 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_ci queue->cmds = cmds; 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci return 0; 13668c2ecf20Sopenharmony_ciout_free: 13678c2ecf20Sopenharmony_ci while (--i >= 0) 13688c2ecf20Sopenharmony_ci nvmet_tcp_free_cmd(cmds + i); 13698c2ecf20Sopenharmony_ci kfree(cmds); 13708c2ecf20Sopenharmony_ciout: 13718c2ecf20Sopenharmony_ci return ret; 13728c2ecf20Sopenharmony_ci} 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_cistatic void nvmet_tcp_free_cmds(struct nvmet_tcp_queue *queue) 13758c2ecf20Sopenharmony_ci{ 13768c2ecf20Sopenharmony_ci struct nvmet_tcp_cmd *cmds = queue->cmds; 13778c2ecf20Sopenharmony_ci int i; 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci for (i = 0; i < queue->nr_cmds; i++) 13808c2ecf20Sopenharmony_ci nvmet_tcp_free_cmd(cmds + i); 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci nvmet_tcp_free_cmd(&queue->connect); 13838c2ecf20Sopenharmony_ci kfree(cmds); 13848c2ecf20Sopenharmony_ci} 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_cistatic void nvmet_tcp_restore_socket_callbacks(struct nvmet_tcp_queue *queue) 13878c2ecf20Sopenharmony_ci{ 13888c2ecf20Sopenharmony_ci struct socket *sock = queue->sock; 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_ci write_lock_bh(&sock->sk->sk_callback_lock); 13918c2ecf20Sopenharmony_ci sock->sk->sk_data_ready = queue->data_ready; 13928c2ecf20Sopenharmony_ci sock->sk->sk_state_change = queue->state_change; 13938c2ecf20Sopenharmony_ci sock->sk->sk_write_space = queue->write_space; 13948c2ecf20Sopenharmony_ci sock->sk->sk_user_data = NULL; 13958c2ecf20Sopenharmony_ci write_unlock_bh(&sock->sk->sk_callback_lock); 13968c2ecf20Sopenharmony_ci} 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_cistatic void nvmet_tcp_finish_cmd(struct nvmet_tcp_cmd *cmd) 13998c2ecf20Sopenharmony_ci{ 14008c2ecf20Sopenharmony_ci nvmet_req_uninit(&cmd->req); 14018c2ecf20Sopenharmony_ci nvmet_tcp_unmap_pdu_iovec(cmd); 14028c2ecf20Sopenharmony_ci kfree(cmd->iov); 14038c2ecf20Sopenharmony_ci sgl_free(cmd->req.sg); 14048c2ecf20Sopenharmony_ci} 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_cistatic void nvmet_tcp_uninit_data_in_cmds(struct nvmet_tcp_queue *queue) 14078c2ecf20Sopenharmony_ci{ 14088c2ecf20Sopenharmony_ci struct nvmet_tcp_cmd *cmd = queue->cmds; 14098c2ecf20Sopenharmony_ci int i; 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_ci for (i = 0; i < queue->nr_cmds; i++, cmd++) { 14128c2ecf20Sopenharmony_ci if (nvmet_tcp_need_data_in(cmd)) 14138c2ecf20Sopenharmony_ci nvmet_tcp_finish_cmd(cmd); 14148c2ecf20Sopenharmony_ci } 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_ci if (!queue->nr_cmds && nvmet_tcp_need_data_in(&queue->connect)) { 14178c2ecf20Sopenharmony_ci /* failed in connect */ 14188c2ecf20Sopenharmony_ci nvmet_tcp_finish_cmd(&queue->connect); 14198c2ecf20Sopenharmony_ci } 14208c2ecf20Sopenharmony_ci} 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_cistatic void nvmet_tcp_release_queue_work(struct work_struct *w) 14238c2ecf20Sopenharmony_ci{ 14248c2ecf20Sopenharmony_ci struct page *page; 14258c2ecf20Sopenharmony_ci struct nvmet_tcp_queue *queue = 14268c2ecf20Sopenharmony_ci container_of(w, struct nvmet_tcp_queue, release_work); 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci mutex_lock(&nvmet_tcp_queue_mutex); 14298c2ecf20Sopenharmony_ci list_del_init(&queue->queue_list); 14308c2ecf20Sopenharmony_ci mutex_unlock(&nvmet_tcp_queue_mutex); 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_ci nvmet_tcp_restore_socket_callbacks(queue); 14338c2ecf20Sopenharmony_ci flush_work(&queue->io_work); 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci nvmet_tcp_uninit_data_in_cmds(queue); 14368c2ecf20Sopenharmony_ci nvmet_sq_destroy(&queue->nvme_sq); 14378c2ecf20Sopenharmony_ci cancel_work_sync(&queue->io_work); 14388c2ecf20Sopenharmony_ci sock_release(queue->sock); 14398c2ecf20Sopenharmony_ci nvmet_tcp_free_cmds(queue); 14408c2ecf20Sopenharmony_ci if (queue->hdr_digest || queue->data_digest) 14418c2ecf20Sopenharmony_ci nvmet_tcp_free_crypto(queue); 14428c2ecf20Sopenharmony_ci ida_simple_remove(&nvmet_tcp_queue_ida, queue->idx); 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ci page = virt_to_head_page(queue->pf_cache.va); 14458c2ecf20Sopenharmony_ci __page_frag_cache_drain(page, queue->pf_cache.pagecnt_bias); 14468c2ecf20Sopenharmony_ci kfree(queue); 14478c2ecf20Sopenharmony_ci} 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_cistatic void nvmet_tcp_data_ready(struct sock *sk) 14508c2ecf20Sopenharmony_ci{ 14518c2ecf20Sopenharmony_ci struct nvmet_tcp_queue *queue; 14528c2ecf20Sopenharmony_ci 14538c2ecf20Sopenharmony_ci read_lock_bh(&sk->sk_callback_lock); 14548c2ecf20Sopenharmony_ci queue = sk->sk_user_data; 14558c2ecf20Sopenharmony_ci if (likely(queue)) 14568c2ecf20Sopenharmony_ci queue_work_on(queue_cpu(queue), nvmet_tcp_wq, &queue->io_work); 14578c2ecf20Sopenharmony_ci read_unlock_bh(&sk->sk_callback_lock); 14588c2ecf20Sopenharmony_ci} 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_cistatic void nvmet_tcp_write_space(struct sock *sk) 14618c2ecf20Sopenharmony_ci{ 14628c2ecf20Sopenharmony_ci struct nvmet_tcp_queue *queue; 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_ci read_lock_bh(&sk->sk_callback_lock); 14658c2ecf20Sopenharmony_ci queue = sk->sk_user_data; 14668c2ecf20Sopenharmony_ci if (unlikely(!queue)) 14678c2ecf20Sopenharmony_ci goto out; 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_ci if (unlikely(queue->state == NVMET_TCP_Q_CONNECTING)) { 14708c2ecf20Sopenharmony_ci queue->write_space(sk); 14718c2ecf20Sopenharmony_ci goto out; 14728c2ecf20Sopenharmony_ci } 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci if (sk_stream_is_writeable(sk)) { 14758c2ecf20Sopenharmony_ci clear_bit(SOCK_NOSPACE, &sk->sk_socket->flags); 14768c2ecf20Sopenharmony_ci queue_work_on(queue_cpu(queue), nvmet_tcp_wq, &queue->io_work); 14778c2ecf20Sopenharmony_ci } 14788c2ecf20Sopenharmony_ciout: 14798c2ecf20Sopenharmony_ci read_unlock_bh(&sk->sk_callback_lock); 14808c2ecf20Sopenharmony_ci} 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_cistatic void nvmet_tcp_state_change(struct sock *sk) 14838c2ecf20Sopenharmony_ci{ 14848c2ecf20Sopenharmony_ci struct nvmet_tcp_queue *queue; 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci read_lock_bh(&sk->sk_callback_lock); 14878c2ecf20Sopenharmony_ci queue = sk->sk_user_data; 14888c2ecf20Sopenharmony_ci if (!queue) 14898c2ecf20Sopenharmony_ci goto done; 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci switch (sk->sk_state) { 14928c2ecf20Sopenharmony_ci case TCP_FIN_WAIT2: 14938c2ecf20Sopenharmony_ci case TCP_LAST_ACK: 14948c2ecf20Sopenharmony_ci break; 14958c2ecf20Sopenharmony_ci case TCP_FIN_WAIT1: 14968c2ecf20Sopenharmony_ci case TCP_CLOSE_WAIT: 14978c2ecf20Sopenharmony_ci case TCP_CLOSE: 14988c2ecf20Sopenharmony_ci /* FALLTHRU */ 14998c2ecf20Sopenharmony_ci nvmet_tcp_schedule_release_queue(queue); 15008c2ecf20Sopenharmony_ci break; 15018c2ecf20Sopenharmony_ci default: 15028c2ecf20Sopenharmony_ci pr_warn("queue %d unhandled state %d\n", 15038c2ecf20Sopenharmony_ci queue->idx, sk->sk_state); 15048c2ecf20Sopenharmony_ci } 15058c2ecf20Sopenharmony_cidone: 15068c2ecf20Sopenharmony_ci read_unlock_bh(&sk->sk_callback_lock); 15078c2ecf20Sopenharmony_ci} 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_cistatic int nvmet_tcp_set_queue_sock(struct nvmet_tcp_queue *queue) 15108c2ecf20Sopenharmony_ci{ 15118c2ecf20Sopenharmony_ci struct socket *sock = queue->sock; 15128c2ecf20Sopenharmony_ci struct inet_sock *inet = inet_sk(sock->sk); 15138c2ecf20Sopenharmony_ci int ret; 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci ret = kernel_getsockname(sock, 15168c2ecf20Sopenharmony_ci (struct sockaddr *)&queue->sockaddr); 15178c2ecf20Sopenharmony_ci if (ret < 0) 15188c2ecf20Sopenharmony_ci return ret; 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_ci ret = kernel_getpeername(sock, 15218c2ecf20Sopenharmony_ci (struct sockaddr *)&queue->sockaddr_peer); 15228c2ecf20Sopenharmony_ci if (ret < 0) 15238c2ecf20Sopenharmony_ci return ret; 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ci /* 15268c2ecf20Sopenharmony_ci * Cleanup whatever is sitting in the TCP transmit queue on socket 15278c2ecf20Sopenharmony_ci * close. This is done to prevent stale data from being sent should 15288c2ecf20Sopenharmony_ci * the network connection be restored before TCP times out. 15298c2ecf20Sopenharmony_ci */ 15308c2ecf20Sopenharmony_ci sock_no_linger(sock->sk); 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci if (so_priority > 0) 15338c2ecf20Sopenharmony_ci sock_set_priority(sock->sk, so_priority); 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_ci /* Set socket type of service */ 15368c2ecf20Sopenharmony_ci if (inet->rcv_tos > 0) 15378c2ecf20Sopenharmony_ci ip_sock_set_tos(sock->sk, inet->rcv_tos); 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci ret = 0; 15408c2ecf20Sopenharmony_ci write_lock_bh(&sock->sk->sk_callback_lock); 15418c2ecf20Sopenharmony_ci if (sock->sk->sk_state != TCP_ESTABLISHED) { 15428c2ecf20Sopenharmony_ci /* 15438c2ecf20Sopenharmony_ci * If the socket is already closing, don't even start 15448c2ecf20Sopenharmony_ci * consuming it 15458c2ecf20Sopenharmony_ci */ 15468c2ecf20Sopenharmony_ci ret = -ENOTCONN; 15478c2ecf20Sopenharmony_ci } else { 15488c2ecf20Sopenharmony_ci sock->sk->sk_user_data = queue; 15498c2ecf20Sopenharmony_ci queue->data_ready = sock->sk->sk_data_ready; 15508c2ecf20Sopenharmony_ci sock->sk->sk_data_ready = nvmet_tcp_data_ready; 15518c2ecf20Sopenharmony_ci queue->state_change = sock->sk->sk_state_change; 15528c2ecf20Sopenharmony_ci sock->sk->sk_state_change = nvmet_tcp_state_change; 15538c2ecf20Sopenharmony_ci queue->write_space = sock->sk->sk_write_space; 15548c2ecf20Sopenharmony_ci sock->sk->sk_write_space = nvmet_tcp_write_space; 15558c2ecf20Sopenharmony_ci queue_work_on(queue_cpu(queue), nvmet_tcp_wq, &queue->io_work); 15568c2ecf20Sopenharmony_ci } 15578c2ecf20Sopenharmony_ci write_unlock_bh(&sock->sk->sk_callback_lock); 15588c2ecf20Sopenharmony_ci 15598c2ecf20Sopenharmony_ci return ret; 15608c2ecf20Sopenharmony_ci} 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_cistatic int nvmet_tcp_alloc_queue(struct nvmet_tcp_port *port, 15638c2ecf20Sopenharmony_ci struct socket *newsock) 15648c2ecf20Sopenharmony_ci{ 15658c2ecf20Sopenharmony_ci struct nvmet_tcp_queue *queue; 15668c2ecf20Sopenharmony_ci int ret; 15678c2ecf20Sopenharmony_ci 15688c2ecf20Sopenharmony_ci queue = kzalloc(sizeof(*queue), GFP_KERNEL); 15698c2ecf20Sopenharmony_ci if (!queue) 15708c2ecf20Sopenharmony_ci return -ENOMEM; 15718c2ecf20Sopenharmony_ci 15728c2ecf20Sopenharmony_ci INIT_WORK(&queue->release_work, nvmet_tcp_release_queue_work); 15738c2ecf20Sopenharmony_ci INIT_WORK(&queue->io_work, nvmet_tcp_io_work); 15748c2ecf20Sopenharmony_ci queue->sock = newsock; 15758c2ecf20Sopenharmony_ci queue->port = port; 15768c2ecf20Sopenharmony_ci queue->nr_cmds = 0; 15778c2ecf20Sopenharmony_ci spin_lock_init(&queue->state_lock); 15788c2ecf20Sopenharmony_ci queue->state = NVMET_TCP_Q_CONNECTING; 15798c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&queue->free_list); 15808c2ecf20Sopenharmony_ci init_llist_head(&queue->resp_list); 15818c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&queue->resp_send_list); 15828c2ecf20Sopenharmony_ci 15838c2ecf20Sopenharmony_ci queue->idx = ida_simple_get(&nvmet_tcp_queue_ida, 0, 0, GFP_KERNEL); 15848c2ecf20Sopenharmony_ci if (queue->idx < 0) { 15858c2ecf20Sopenharmony_ci ret = queue->idx; 15868c2ecf20Sopenharmony_ci goto out_free_queue; 15878c2ecf20Sopenharmony_ci } 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_ci ret = nvmet_tcp_alloc_cmd(queue, &queue->connect); 15908c2ecf20Sopenharmony_ci if (ret) 15918c2ecf20Sopenharmony_ci goto out_ida_remove; 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_ci ret = nvmet_sq_init(&queue->nvme_sq); 15948c2ecf20Sopenharmony_ci if (ret) 15958c2ecf20Sopenharmony_ci goto out_free_connect; 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci nvmet_prepare_receive_pdu(queue); 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci mutex_lock(&nvmet_tcp_queue_mutex); 16008c2ecf20Sopenharmony_ci list_add_tail(&queue->queue_list, &nvmet_tcp_queue_list); 16018c2ecf20Sopenharmony_ci mutex_unlock(&nvmet_tcp_queue_mutex); 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci ret = nvmet_tcp_set_queue_sock(queue); 16048c2ecf20Sopenharmony_ci if (ret) 16058c2ecf20Sopenharmony_ci goto out_destroy_sq; 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ci return 0; 16088c2ecf20Sopenharmony_ciout_destroy_sq: 16098c2ecf20Sopenharmony_ci mutex_lock(&nvmet_tcp_queue_mutex); 16108c2ecf20Sopenharmony_ci list_del_init(&queue->queue_list); 16118c2ecf20Sopenharmony_ci mutex_unlock(&nvmet_tcp_queue_mutex); 16128c2ecf20Sopenharmony_ci nvmet_sq_destroy(&queue->nvme_sq); 16138c2ecf20Sopenharmony_ciout_free_connect: 16148c2ecf20Sopenharmony_ci nvmet_tcp_free_cmd(&queue->connect); 16158c2ecf20Sopenharmony_ciout_ida_remove: 16168c2ecf20Sopenharmony_ci ida_simple_remove(&nvmet_tcp_queue_ida, queue->idx); 16178c2ecf20Sopenharmony_ciout_free_queue: 16188c2ecf20Sopenharmony_ci kfree(queue); 16198c2ecf20Sopenharmony_ci return ret; 16208c2ecf20Sopenharmony_ci} 16218c2ecf20Sopenharmony_ci 16228c2ecf20Sopenharmony_cistatic void nvmet_tcp_accept_work(struct work_struct *w) 16238c2ecf20Sopenharmony_ci{ 16248c2ecf20Sopenharmony_ci struct nvmet_tcp_port *port = 16258c2ecf20Sopenharmony_ci container_of(w, struct nvmet_tcp_port, accept_work); 16268c2ecf20Sopenharmony_ci struct socket *newsock; 16278c2ecf20Sopenharmony_ci int ret; 16288c2ecf20Sopenharmony_ci 16298c2ecf20Sopenharmony_ci while (true) { 16308c2ecf20Sopenharmony_ci ret = kernel_accept(port->sock, &newsock, O_NONBLOCK); 16318c2ecf20Sopenharmony_ci if (ret < 0) { 16328c2ecf20Sopenharmony_ci if (ret != -EAGAIN) 16338c2ecf20Sopenharmony_ci pr_warn("failed to accept err=%d\n", ret); 16348c2ecf20Sopenharmony_ci return; 16358c2ecf20Sopenharmony_ci } 16368c2ecf20Sopenharmony_ci ret = nvmet_tcp_alloc_queue(port, newsock); 16378c2ecf20Sopenharmony_ci if (ret) { 16388c2ecf20Sopenharmony_ci pr_err("failed to allocate queue\n"); 16398c2ecf20Sopenharmony_ci sock_release(newsock); 16408c2ecf20Sopenharmony_ci } 16418c2ecf20Sopenharmony_ci } 16428c2ecf20Sopenharmony_ci} 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_cistatic void nvmet_tcp_listen_data_ready(struct sock *sk) 16458c2ecf20Sopenharmony_ci{ 16468c2ecf20Sopenharmony_ci struct nvmet_tcp_port *port; 16478c2ecf20Sopenharmony_ci 16488c2ecf20Sopenharmony_ci read_lock_bh(&sk->sk_callback_lock); 16498c2ecf20Sopenharmony_ci port = sk->sk_user_data; 16508c2ecf20Sopenharmony_ci if (!port) 16518c2ecf20Sopenharmony_ci goto out; 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_ci if (sk->sk_state == TCP_LISTEN) 16548c2ecf20Sopenharmony_ci schedule_work(&port->accept_work); 16558c2ecf20Sopenharmony_ciout: 16568c2ecf20Sopenharmony_ci read_unlock_bh(&sk->sk_callback_lock); 16578c2ecf20Sopenharmony_ci} 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_cistatic int nvmet_tcp_add_port(struct nvmet_port *nport) 16608c2ecf20Sopenharmony_ci{ 16618c2ecf20Sopenharmony_ci struct nvmet_tcp_port *port; 16628c2ecf20Sopenharmony_ci __kernel_sa_family_t af; 16638c2ecf20Sopenharmony_ci int ret; 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_ci port = kzalloc(sizeof(*port), GFP_KERNEL); 16668c2ecf20Sopenharmony_ci if (!port) 16678c2ecf20Sopenharmony_ci return -ENOMEM; 16688c2ecf20Sopenharmony_ci 16698c2ecf20Sopenharmony_ci switch (nport->disc_addr.adrfam) { 16708c2ecf20Sopenharmony_ci case NVMF_ADDR_FAMILY_IP4: 16718c2ecf20Sopenharmony_ci af = AF_INET; 16728c2ecf20Sopenharmony_ci break; 16738c2ecf20Sopenharmony_ci case NVMF_ADDR_FAMILY_IP6: 16748c2ecf20Sopenharmony_ci af = AF_INET6; 16758c2ecf20Sopenharmony_ci break; 16768c2ecf20Sopenharmony_ci default: 16778c2ecf20Sopenharmony_ci pr_err("address family %d not supported\n", 16788c2ecf20Sopenharmony_ci nport->disc_addr.adrfam); 16798c2ecf20Sopenharmony_ci ret = -EINVAL; 16808c2ecf20Sopenharmony_ci goto err_port; 16818c2ecf20Sopenharmony_ci } 16828c2ecf20Sopenharmony_ci 16838c2ecf20Sopenharmony_ci ret = inet_pton_with_scope(&init_net, af, nport->disc_addr.traddr, 16848c2ecf20Sopenharmony_ci nport->disc_addr.trsvcid, &port->addr); 16858c2ecf20Sopenharmony_ci if (ret) { 16868c2ecf20Sopenharmony_ci pr_err("malformed ip/port passed: %s:%s\n", 16878c2ecf20Sopenharmony_ci nport->disc_addr.traddr, nport->disc_addr.trsvcid); 16888c2ecf20Sopenharmony_ci goto err_port; 16898c2ecf20Sopenharmony_ci } 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_ci port->nport = nport; 16928c2ecf20Sopenharmony_ci INIT_WORK(&port->accept_work, nvmet_tcp_accept_work); 16938c2ecf20Sopenharmony_ci if (port->nport->inline_data_size < 0) 16948c2ecf20Sopenharmony_ci port->nport->inline_data_size = NVMET_TCP_DEF_INLINE_DATA_SIZE; 16958c2ecf20Sopenharmony_ci 16968c2ecf20Sopenharmony_ci ret = sock_create(port->addr.ss_family, SOCK_STREAM, 16978c2ecf20Sopenharmony_ci IPPROTO_TCP, &port->sock); 16988c2ecf20Sopenharmony_ci if (ret) { 16998c2ecf20Sopenharmony_ci pr_err("failed to create a socket\n"); 17008c2ecf20Sopenharmony_ci goto err_port; 17018c2ecf20Sopenharmony_ci } 17028c2ecf20Sopenharmony_ci 17038c2ecf20Sopenharmony_ci port->sock->sk->sk_user_data = port; 17048c2ecf20Sopenharmony_ci port->data_ready = port->sock->sk->sk_data_ready; 17058c2ecf20Sopenharmony_ci port->sock->sk->sk_data_ready = nvmet_tcp_listen_data_ready; 17068c2ecf20Sopenharmony_ci sock_set_reuseaddr(port->sock->sk); 17078c2ecf20Sopenharmony_ci tcp_sock_set_nodelay(port->sock->sk); 17088c2ecf20Sopenharmony_ci if (so_priority > 0) 17098c2ecf20Sopenharmony_ci sock_set_priority(port->sock->sk, so_priority); 17108c2ecf20Sopenharmony_ci 17118c2ecf20Sopenharmony_ci ret = kernel_bind(port->sock, (struct sockaddr *)&port->addr, 17128c2ecf20Sopenharmony_ci sizeof(port->addr)); 17138c2ecf20Sopenharmony_ci if (ret) { 17148c2ecf20Sopenharmony_ci pr_err("failed to bind port socket %d\n", ret); 17158c2ecf20Sopenharmony_ci goto err_sock; 17168c2ecf20Sopenharmony_ci } 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_ci ret = kernel_listen(port->sock, 128); 17198c2ecf20Sopenharmony_ci if (ret) { 17208c2ecf20Sopenharmony_ci pr_err("failed to listen %d on port sock\n", ret); 17218c2ecf20Sopenharmony_ci goto err_sock; 17228c2ecf20Sopenharmony_ci } 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ci nport->priv = port; 17258c2ecf20Sopenharmony_ci pr_info("enabling port %d (%pISpc)\n", 17268c2ecf20Sopenharmony_ci le16_to_cpu(nport->disc_addr.portid), &port->addr); 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_ci return 0; 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_cierr_sock: 17318c2ecf20Sopenharmony_ci sock_release(port->sock); 17328c2ecf20Sopenharmony_cierr_port: 17338c2ecf20Sopenharmony_ci kfree(port); 17348c2ecf20Sopenharmony_ci return ret; 17358c2ecf20Sopenharmony_ci} 17368c2ecf20Sopenharmony_ci 17378c2ecf20Sopenharmony_cistatic void nvmet_tcp_destroy_port_queues(struct nvmet_tcp_port *port) 17388c2ecf20Sopenharmony_ci{ 17398c2ecf20Sopenharmony_ci struct nvmet_tcp_queue *queue; 17408c2ecf20Sopenharmony_ci 17418c2ecf20Sopenharmony_ci mutex_lock(&nvmet_tcp_queue_mutex); 17428c2ecf20Sopenharmony_ci list_for_each_entry(queue, &nvmet_tcp_queue_list, queue_list) 17438c2ecf20Sopenharmony_ci if (queue->port == port) 17448c2ecf20Sopenharmony_ci kernel_sock_shutdown(queue->sock, SHUT_RDWR); 17458c2ecf20Sopenharmony_ci mutex_unlock(&nvmet_tcp_queue_mutex); 17468c2ecf20Sopenharmony_ci} 17478c2ecf20Sopenharmony_ci 17488c2ecf20Sopenharmony_cistatic void nvmet_tcp_remove_port(struct nvmet_port *nport) 17498c2ecf20Sopenharmony_ci{ 17508c2ecf20Sopenharmony_ci struct nvmet_tcp_port *port = nport->priv; 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_ci write_lock_bh(&port->sock->sk->sk_callback_lock); 17538c2ecf20Sopenharmony_ci port->sock->sk->sk_data_ready = port->data_ready; 17548c2ecf20Sopenharmony_ci port->sock->sk->sk_user_data = NULL; 17558c2ecf20Sopenharmony_ci write_unlock_bh(&port->sock->sk->sk_callback_lock); 17568c2ecf20Sopenharmony_ci cancel_work_sync(&port->accept_work); 17578c2ecf20Sopenharmony_ci /* 17588c2ecf20Sopenharmony_ci * Destroy the remaining queues, which are not belong to any 17598c2ecf20Sopenharmony_ci * controller yet. 17608c2ecf20Sopenharmony_ci */ 17618c2ecf20Sopenharmony_ci nvmet_tcp_destroy_port_queues(port); 17628c2ecf20Sopenharmony_ci 17638c2ecf20Sopenharmony_ci sock_release(port->sock); 17648c2ecf20Sopenharmony_ci kfree(port); 17658c2ecf20Sopenharmony_ci} 17668c2ecf20Sopenharmony_ci 17678c2ecf20Sopenharmony_cistatic void nvmet_tcp_delete_ctrl(struct nvmet_ctrl *ctrl) 17688c2ecf20Sopenharmony_ci{ 17698c2ecf20Sopenharmony_ci struct nvmet_tcp_queue *queue; 17708c2ecf20Sopenharmony_ci 17718c2ecf20Sopenharmony_ci mutex_lock(&nvmet_tcp_queue_mutex); 17728c2ecf20Sopenharmony_ci list_for_each_entry(queue, &nvmet_tcp_queue_list, queue_list) 17738c2ecf20Sopenharmony_ci if (queue->nvme_sq.ctrl == ctrl) 17748c2ecf20Sopenharmony_ci kernel_sock_shutdown(queue->sock, SHUT_RDWR); 17758c2ecf20Sopenharmony_ci mutex_unlock(&nvmet_tcp_queue_mutex); 17768c2ecf20Sopenharmony_ci} 17778c2ecf20Sopenharmony_ci 17788c2ecf20Sopenharmony_cistatic u16 nvmet_tcp_install_queue(struct nvmet_sq *sq) 17798c2ecf20Sopenharmony_ci{ 17808c2ecf20Sopenharmony_ci struct nvmet_tcp_queue *queue = 17818c2ecf20Sopenharmony_ci container_of(sq, struct nvmet_tcp_queue, nvme_sq); 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_ci if (sq->qid == 0) { 17848c2ecf20Sopenharmony_ci /* Let inflight controller teardown complete */ 17858c2ecf20Sopenharmony_ci flush_scheduled_work(); 17868c2ecf20Sopenharmony_ci } 17878c2ecf20Sopenharmony_ci 17888c2ecf20Sopenharmony_ci queue->nr_cmds = sq->size * 2; 17898c2ecf20Sopenharmony_ci if (nvmet_tcp_alloc_cmds(queue)) { 17908c2ecf20Sopenharmony_ci queue->nr_cmds = 0; 17918c2ecf20Sopenharmony_ci return NVME_SC_INTERNAL; 17928c2ecf20Sopenharmony_ci } 17938c2ecf20Sopenharmony_ci return 0; 17948c2ecf20Sopenharmony_ci} 17958c2ecf20Sopenharmony_ci 17968c2ecf20Sopenharmony_cistatic void nvmet_tcp_disc_port_addr(struct nvmet_req *req, 17978c2ecf20Sopenharmony_ci struct nvmet_port *nport, char *traddr) 17988c2ecf20Sopenharmony_ci{ 17998c2ecf20Sopenharmony_ci struct nvmet_tcp_port *port = nport->priv; 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_ci if (inet_addr_is_any((struct sockaddr *)&port->addr)) { 18028c2ecf20Sopenharmony_ci struct nvmet_tcp_cmd *cmd = 18038c2ecf20Sopenharmony_ci container_of(req, struct nvmet_tcp_cmd, req); 18048c2ecf20Sopenharmony_ci struct nvmet_tcp_queue *queue = cmd->queue; 18058c2ecf20Sopenharmony_ci 18068c2ecf20Sopenharmony_ci sprintf(traddr, "%pISc", (struct sockaddr *)&queue->sockaddr); 18078c2ecf20Sopenharmony_ci } else { 18088c2ecf20Sopenharmony_ci memcpy(traddr, nport->disc_addr.traddr, NVMF_TRADDR_SIZE); 18098c2ecf20Sopenharmony_ci } 18108c2ecf20Sopenharmony_ci} 18118c2ecf20Sopenharmony_ci 18128c2ecf20Sopenharmony_cistatic const struct nvmet_fabrics_ops nvmet_tcp_ops = { 18138c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 18148c2ecf20Sopenharmony_ci .type = NVMF_TRTYPE_TCP, 18158c2ecf20Sopenharmony_ci .msdbd = 1, 18168c2ecf20Sopenharmony_ci .add_port = nvmet_tcp_add_port, 18178c2ecf20Sopenharmony_ci .remove_port = nvmet_tcp_remove_port, 18188c2ecf20Sopenharmony_ci .queue_response = nvmet_tcp_queue_response, 18198c2ecf20Sopenharmony_ci .delete_ctrl = nvmet_tcp_delete_ctrl, 18208c2ecf20Sopenharmony_ci .install_queue = nvmet_tcp_install_queue, 18218c2ecf20Sopenharmony_ci .disc_traddr = nvmet_tcp_disc_port_addr, 18228c2ecf20Sopenharmony_ci}; 18238c2ecf20Sopenharmony_ci 18248c2ecf20Sopenharmony_cistatic int __init nvmet_tcp_init(void) 18258c2ecf20Sopenharmony_ci{ 18268c2ecf20Sopenharmony_ci int ret; 18278c2ecf20Sopenharmony_ci 18288c2ecf20Sopenharmony_ci nvmet_tcp_wq = alloc_workqueue("nvmet_tcp_wq", 18298c2ecf20Sopenharmony_ci WQ_MEM_RECLAIM | WQ_HIGHPRI, 0); 18308c2ecf20Sopenharmony_ci if (!nvmet_tcp_wq) 18318c2ecf20Sopenharmony_ci return -ENOMEM; 18328c2ecf20Sopenharmony_ci 18338c2ecf20Sopenharmony_ci ret = nvmet_register_transport(&nvmet_tcp_ops); 18348c2ecf20Sopenharmony_ci if (ret) 18358c2ecf20Sopenharmony_ci goto err; 18368c2ecf20Sopenharmony_ci 18378c2ecf20Sopenharmony_ci return 0; 18388c2ecf20Sopenharmony_cierr: 18398c2ecf20Sopenharmony_ci destroy_workqueue(nvmet_tcp_wq); 18408c2ecf20Sopenharmony_ci return ret; 18418c2ecf20Sopenharmony_ci} 18428c2ecf20Sopenharmony_ci 18438c2ecf20Sopenharmony_cistatic void __exit nvmet_tcp_exit(void) 18448c2ecf20Sopenharmony_ci{ 18458c2ecf20Sopenharmony_ci struct nvmet_tcp_queue *queue; 18468c2ecf20Sopenharmony_ci 18478c2ecf20Sopenharmony_ci nvmet_unregister_transport(&nvmet_tcp_ops); 18488c2ecf20Sopenharmony_ci 18498c2ecf20Sopenharmony_ci flush_scheduled_work(); 18508c2ecf20Sopenharmony_ci mutex_lock(&nvmet_tcp_queue_mutex); 18518c2ecf20Sopenharmony_ci list_for_each_entry(queue, &nvmet_tcp_queue_list, queue_list) 18528c2ecf20Sopenharmony_ci kernel_sock_shutdown(queue->sock, SHUT_RDWR); 18538c2ecf20Sopenharmony_ci mutex_unlock(&nvmet_tcp_queue_mutex); 18548c2ecf20Sopenharmony_ci flush_scheduled_work(); 18558c2ecf20Sopenharmony_ci 18568c2ecf20Sopenharmony_ci destroy_workqueue(nvmet_tcp_wq); 18578c2ecf20Sopenharmony_ci} 18588c2ecf20Sopenharmony_ci 18598c2ecf20Sopenharmony_cimodule_init(nvmet_tcp_init); 18608c2ecf20Sopenharmony_cimodule_exit(nvmet_tcp_exit); 18618c2ecf20Sopenharmony_ci 18628c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 18638c2ecf20Sopenharmony_ciMODULE_ALIAS("nvmet-transport-3"); /* 3 == NVMF_TRTYPE_TCP */ 1864