162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * NVMe over Fabrics TCP target. 462306a36Sopenharmony_ci * Copyright (c) 2018 Lightbits Labs. All rights reserved. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 762306a36Sopenharmony_ci#include <linux/module.h> 862306a36Sopenharmony_ci#include <linux/init.h> 962306a36Sopenharmony_ci#include <linux/slab.h> 1062306a36Sopenharmony_ci#include <linux/err.h> 1162306a36Sopenharmony_ci#include <linux/nvme-tcp.h> 1262306a36Sopenharmony_ci#include <net/sock.h> 1362306a36Sopenharmony_ci#include <net/tcp.h> 1462306a36Sopenharmony_ci#include <linux/inet.h> 1562306a36Sopenharmony_ci#include <linux/llist.h> 1662306a36Sopenharmony_ci#include <crypto/hash.h> 1762306a36Sopenharmony_ci#include <trace/events/sock.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include "nvmet.h" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define NVMET_TCP_DEF_INLINE_DATA_SIZE (4 * PAGE_SIZE) 2262306a36Sopenharmony_ci#define NVMET_TCP_MAXH2CDATA 0x400000 /* 16M arbitrary limit */ 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistatic int param_store_val(const char *str, int *val, int min, int max) 2562306a36Sopenharmony_ci{ 2662306a36Sopenharmony_ci int ret, new_val; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci ret = kstrtoint(str, 10, &new_val); 2962306a36Sopenharmony_ci if (ret) 3062306a36Sopenharmony_ci return -EINVAL; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci if (new_val < min || new_val > max) 3362306a36Sopenharmony_ci return -EINVAL; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci *val = new_val; 3662306a36Sopenharmony_ci return 0; 3762306a36Sopenharmony_ci} 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic int set_params(const char *str, const struct kernel_param *kp) 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci return param_store_val(str, kp->arg, 0, INT_MAX); 4262306a36Sopenharmony_ci} 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistatic const struct kernel_param_ops set_param_ops = { 4562306a36Sopenharmony_ci .set = set_params, 4662306a36Sopenharmony_ci .get = param_get_int, 4762306a36Sopenharmony_ci}; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci/* Define the socket priority to use for connections were it is desirable 5062306a36Sopenharmony_ci * that the NIC consider performing optimized packet processing or filtering. 5162306a36Sopenharmony_ci * A non-zero value being sufficient to indicate general consideration of any 5262306a36Sopenharmony_ci * possible optimization. Making it a module param allows for alternative 5362306a36Sopenharmony_ci * values that may be unique for some NIC implementations. 5462306a36Sopenharmony_ci */ 5562306a36Sopenharmony_cistatic int so_priority; 5662306a36Sopenharmony_cidevice_param_cb(so_priority, &set_param_ops, &so_priority, 0644); 5762306a36Sopenharmony_ciMODULE_PARM_DESC(so_priority, "nvmet tcp socket optimize priority: Default 0"); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci/* Define a time period (in usecs) that io_work() shall sample an activated 6062306a36Sopenharmony_ci * queue before determining it to be idle. This optional module behavior 6162306a36Sopenharmony_ci * can enable NIC solutions that support socket optimized packet processing 6262306a36Sopenharmony_ci * using advanced interrupt moderation techniques. 6362306a36Sopenharmony_ci */ 6462306a36Sopenharmony_cistatic int idle_poll_period_usecs; 6562306a36Sopenharmony_cidevice_param_cb(idle_poll_period_usecs, &set_param_ops, 6662306a36Sopenharmony_ci &idle_poll_period_usecs, 0644); 6762306a36Sopenharmony_ciMODULE_PARM_DESC(idle_poll_period_usecs, 6862306a36Sopenharmony_ci "nvmet tcp io_work poll till idle time period in usecs: Default 0"); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci#define NVMET_TCP_RECV_BUDGET 8 7162306a36Sopenharmony_ci#define NVMET_TCP_SEND_BUDGET 8 7262306a36Sopenharmony_ci#define NVMET_TCP_IO_WORK_BUDGET 64 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cienum nvmet_tcp_send_state { 7562306a36Sopenharmony_ci NVMET_TCP_SEND_DATA_PDU, 7662306a36Sopenharmony_ci NVMET_TCP_SEND_DATA, 7762306a36Sopenharmony_ci NVMET_TCP_SEND_R2T, 7862306a36Sopenharmony_ci NVMET_TCP_SEND_DDGST, 7962306a36Sopenharmony_ci NVMET_TCP_SEND_RESPONSE 8062306a36Sopenharmony_ci}; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cienum nvmet_tcp_recv_state { 8362306a36Sopenharmony_ci NVMET_TCP_RECV_PDU, 8462306a36Sopenharmony_ci NVMET_TCP_RECV_DATA, 8562306a36Sopenharmony_ci NVMET_TCP_RECV_DDGST, 8662306a36Sopenharmony_ci NVMET_TCP_RECV_ERR, 8762306a36Sopenharmony_ci}; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cienum { 9062306a36Sopenharmony_ci NVMET_TCP_F_INIT_FAILED = (1 << 0), 9162306a36Sopenharmony_ci}; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cistruct nvmet_tcp_cmd { 9462306a36Sopenharmony_ci struct nvmet_tcp_queue *queue; 9562306a36Sopenharmony_ci struct nvmet_req req; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci struct nvme_tcp_cmd_pdu *cmd_pdu; 9862306a36Sopenharmony_ci struct nvme_tcp_rsp_pdu *rsp_pdu; 9962306a36Sopenharmony_ci struct nvme_tcp_data_pdu *data_pdu; 10062306a36Sopenharmony_ci struct nvme_tcp_r2t_pdu *r2t_pdu; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci u32 rbytes_done; 10362306a36Sopenharmony_ci u32 wbytes_done; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci u32 pdu_len; 10662306a36Sopenharmony_ci u32 pdu_recv; 10762306a36Sopenharmony_ci int sg_idx; 10862306a36Sopenharmony_ci struct msghdr recv_msg; 10962306a36Sopenharmony_ci struct bio_vec *iov; 11062306a36Sopenharmony_ci u32 flags; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci struct list_head entry; 11362306a36Sopenharmony_ci struct llist_node lentry; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci /* send state */ 11662306a36Sopenharmony_ci u32 offset; 11762306a36Sopenharmony_ci struct scatterlist *cur_sg; 11862306a36Sopenharmony_ci enum nvmet_tcp_send_state state; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci __le32 exp_ddgst; 12162306a36Sopenharmony_ci __le32 recv_ddgst; 12262306a36Sopenharmony_ci}; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cienum nvmet_tcp_queue_state { 12562306a36Sopenharmony_ci NVMET_TCP_Q_CONNECTING, 12662306a36Sopenharmony_ci NVMET_TCP_Q_LIVE, 12762306a36Sopenharmony_ci NVMET_TCP_Q_DISCONNECTING, 12862306a36Sopenharmony_ci}; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistruct nvmet_tcp_queue { 13162306a36Sopenharmony_ci struct socket *sock; 13262306a36Sopenharmony_ci struct nvmet_tcp_port *port; 13362306a36Sopenharmony_ci struct work_struct io_work; 13462306a36Sopenharmony_ci struct nvmet_cq nvme_cq; 13562306a36Sopenharmony_ci struct nvmet_sq nvme_sq; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci /* send state */ 13862306a36Sopenharmony_ci struct nvmet_tcp_cmd *cmds; 13962306a36Sopenharmony_ci unsigned int nr_cmds; 14062306a36Sopenharmony_ci struct list_head free_list; 14162306a36Sopenharmony_ci struct llist_head resp_list; 14262306a36Sopenharmony_ci struct list_head resp_send_list; 14362306a36Sopenharmony_ci int send_list_len; 14462306a36Sopenharmony_ci struct nvmet_tcp_cmd *snd_cmd; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci /* recv state */ 14762306a36Sopenharmony_ci int offset; 14862306a36Sopenharmony_ci int left; 14962306a36Sopenharmony_ci enum nvmet_tcp_recv_state rcv_state; 15062306a36Sopenharmony_ci struct nvmet_tcp_cmd *cmd; 15162306a36Sopenharmony_ci union nvme_tcp_pdu pdu; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci /* digest state */ 15462306a36Sopenharmony_ci bool hdr_digest; 15562306a36Sopenharmony_ci bool data_digest; 15662306a36Sopenharmony_ci struct ahash_request *snd_hash; 15762306a36Sopenharmony_ci struct ahash_request *rcv_hash; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci unsigned long poll_end; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci spinlock_t state_lock; 16262306a36Sopenharmony_ci enum nvmet_tcp_queue_state state; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci struct sockaddr_storage sockaddr; 16562306a36Sopenharmony_ci struct sockaddr_storage sockaddr_peer; 16662306a36Sopenharmony_ci struct work_struct release_work; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci int idx; 16962306a36Sopenharmony_ci struct list_head queue_list; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci struct nvmet_tcp_cmd connect; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci struct page_frag_cache pf_cache; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci void (*data_ready)(struct sock *); 17662306a36Sopenharmony_ci void (*state_change)(struct sock *); 17762306a36Sopenharmony_ci void (*write_space)(struct sock *); 17862306a36Sopenharmony_ci}; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cistruct nvmet_tcp_port { 18162306a36Sopenharmony_ci struct socket *sock; 18262306a36Sopenharmony_ci struct work_struct accept_work; 18362306a36Sopenharmony_ci struct nvmet_port *nport; 18462306a36Sopenharmony_ci struct sockaddr_storage addr; 18562306a36Sopenharmony_ci void (*data_ready)(struct sock *); 18662306a36Sopenharmony_ci}; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistatic DEFINE_IDA(nvmet_tcp_queue_ida); 18962306a36Sopenharmony_cistatic LIST_HEAD(nvmet_tcp_queue_list); 19062306a36Sopenharmony_cistatic DEFINE_MUTEX(nvmet_tcp_queue_mutex); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_cistatic struct workqueue_struct *nvmet_tcp_wq; 19362306a36Sopenharmony_cistatic const struct nvmet_fabrics_ops nvmet_tcp_ops; 19462306a36Sopenharmony_cistatic void nvmet_tcp_free_cmd(struct nvmet_tcp_cmd *c); 19562306a36Sopenharmony_cistatic void nvmet_tcp_free_cmd_buffers(struct nvmet_tcp_cmd *cmd); 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_cistatic inline u16 nvmet_tcp_cmd_tag(struct nvmet_tcp_queue *queue, 19862306a36Sopenharmony_ci struct nvmet_tcp_cmd *cmd) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci if (unlikely(!queue->nr_cmds)) { 20162306a36Sopenharmony_ci /* We didn't allocate cmds yet, send 0xffff */ 20262306a36Sopenharmony_ci return USHRT_MAX; 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci return cmd - queue->cmds; 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_cistatic inline bool nvmet_tcp_has_data_in(struct nvmet_tcp_cmd *cmd) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci return nvme_is_write(cmd->req.cmd) && 21162306a36Sopenharmony_ci cmd->rbytes_done < cmd->req.transfer_len; 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_cistatic inline bool nvmet_tcp_need_data_in(struct nvmet_tcp_cmd *cmd) 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci return nvmet_tcp_has_data_in(cmd) && !cmd->req.cqe->status; 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_cistatic inline bool nvmet_tcp_need_data_out(struct nvmet_tcp_cmd *cmd) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci return !nvme_is_write(cmd->req.cmd) && 22262306a36Sopenharmony_ci cmd->req.transfer_len > 0 && 22362306a36Sopenharmony_ci !cmd->req.cqe->status; 22462306a36Sopenharmony_ci} 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_cistatic inline bool nvmet_tcp_has_inline_data(struct nvmet_tcp_cmd *cmd) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci return nvme_is_write(cmd->req.cmd) && cmd->pdu_len && 22962306a36Sopenharmony_ci !cmd->rbytes_done; 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_cistatic inline struct nvmet_tcp_cmd * 23362306a36Sopenharmony_cinvmet_tcp_get_cmd(struct nvmet_tcp_queue *queue) 23462306a36Sopenharmony_ci{ 23562306a36Sopenharmony_ci struct nvmet_tcp_cmd *cmd; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci cmd = list_first_entry_or_null(&queue->free_list, 23862306a36Sopenharmony_ci struct nvmet_tcp_cmd, entry); 23962306a36Sopenharmony_ci if (!cmd) 24062306a36Sopenharmony_ci return NULL; 24162306a36Sopenharmony_ci list_del_init(&cmd->entry); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci cmd->rbytes_done = cmd->wbytes_done = 0; 24462306a36Sopenharmony_ci cmd->pdu_len = 0; 24562306a36Sopenharmony_ci cmd->pdu_recv = 0; 24662306a36Sopenharmony_ci cmd->iov = NULL; 24762306a36Sopenharmony_ci cmd->flags = 0; 24862306a36Sopenharmony_ci return cmd; 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cistatic inline void nvmet_tcp_put_cmd(struct nvmet_tcp_cmd *cmd) 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci if (unlikely(cmd == &cmd->queue->connect)) 25462306a36Sopenharmony_ci return; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci list_add_tail(&cmd->entry, &cmd->queue->free_list); 25762306a36Sopenharmony_ci} 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_cistatic inline int queue_cpu(struct nvmet_tcp_queue *queue) 26062306a36Sopenharmony_ci{ 26162306a36Sopenharmony_ci return queue->sock->sk->sk_incoming_cpu; 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_cistatic inline u8 nvmet_tcp_hdgst_len(struct nvmet_tcp_queue *queue) 26562306a36Sopenharmony_ci{ 26662306a36Sopenharmony_ci return queue->hdr_digest ? NVME_TCP_DIGEST_LENGTH : 0; 26762306a36Sopenharmony_ci} 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_cistatic inline u8 nvmet_tcp_ddgst_len(struct nvmet_tcp_queue *queue) 27062306a36Sopenharmony_ci{ 27162306a36Sopenharmony_ci return queue->data_digest ? NVME_TCP_DIGEST_LENGTH : 0; 27262306a36Sopenharmony_ci} 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_cistatic inline void nvmet_tcp_hdgst(struct ahash_request *hash, 27562306a36Sopenharmony_ci void *pdu, size_t len) 27662306a36Sopenharmony_ci{ 27762306a36Sopenharmony_ci struct scatterlist sg; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci sg_init_one(&sg, pdu, len); 28062306a36Sopenharmony_ci ahash_request_set_crypt(hash, &sg, pdu + len, len); 28162306a36Sopenharmony_ci crypto_ahash_digest(hash); 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_cistatic int nvmet_tcp_verify_hdgst(struct nvmet_tcp_queue *queue, 28562306a36Sopenharmony_ci void *pdu, size_t len) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci struct nvme_tcp_hdr *hdr = pdu; 28862306a36Sopenharmony_ci __le32 recv_digest; 28962306a36Sopenharmony_ci __le32 exp_digest; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci if (unlikely(!(hdr->flags & NVME_TCP_F_HDGST))) { 29262306a36Sopenharmony_ci pr_err("queue %d: header digest enabled but no header digest\n", 29362306a36Sopenharmony_ci queue->idx); 29462306a36Sopenharmony_ci return -EPROTO; 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci recv_digest = *(__le32 *)(pdu + hdr->hlen); 29862306a36Sopenharmony_ci nvmet_tcp_hdgst(queue->rcv_hash, pdu, len); 29962306a36Sopenharmony_ci exp_digest = *(__le32 *)(pdu + hdr->hlen); 30062306a36Sopenharmony_ci if (recv_digest != exp_digest) { 30162306a36Sopenharmony_ci pr_err("queue %d: header digest error: recv %#x expected %#x\n", 30262306a36Sopenharmony_ci queue->idx, le32_to_cpu(recv_digest), 30362306a36Sopenharmony_ci le32_to_cpu(exp_digest)); 30462306a36Sopenharmony_ci return -EPROTO; 30562306a36Sopenharmony_ci } 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci return 0; 30862306a36Sopenharmony_ci} 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_cistatic int nvmet_tcp_check_ddgst(struct nvmet_tcp_queue *queue, void *pdu) 31162306a36Sopenharmony_ci{ 31262306a36Sopenharmony_ci struct nvme_tcp_hdr *hdr = pdu; 31362306a36Sopenharmony_ci u8 digest_len = nvmet_tcp_hdgst_len(queue); 31462306a36Sopenharmony_ci u32 len; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci len = le32_to_cpu(hdr->plen) - hdr->hlen - 31762306a36Sopenharmony_ci (hdr->flags & NVME_TCP_F_HDGST ? digest_len : 0); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci if (unlikely(len && !(hdr->flags & NVME_TCP_F_DDGST))) { 32062306a36Sopenharmony_ci pr_err("queue %d: data digest flag is cleared\n", queue->idx); 32162306a36Sopenharmony_ci return -EPROTO; 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci return 0; 32562306a36Sopenharmony_ci} 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_cistatic void nvmet_tcp_free_cmd_buffers(struct nvmet_tcp_cmd *cmd) 32862306a36Sopenharmony_ci{ 32962306a36Sopenharmony_ci kfree(cmd->iov); 33062306a36Sopenharmony_ci sgl_free(cmd->req.sg); 33162306a36Sopenharmony_ci cmd->iov = NULL; 33262306a36Sopenharmony_ci cmd->req.sg = NULL; 33362306a36Sopenharmony_ci} 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_cistatic void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd) 33662306a36Sopenharmony_ci{ 33762306a36Sopenharmony_ci struct bio_vec *iov = cmd->iov; 33862306a36Sopenharmony_ci struct scatterlist *sg; 33962306a36Sopenharmony_ci u32 length, offset, sg_offset; 34062306a36Sopenharmony_ci int nr_pages; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci length = cmd->pdu_len; 34362306a36Sopenharmony_ci nr_pages = DIV_ROUND_UP(length, PAGE_SIZE); 34462306a36Sopenharmony_ci offset = cmd->rbytes_done; 34562306a36Sopenharmony_ci cmd->sg_idx = offset / PAGE_SIZE; 34662306a36Sopenharmony_ci sg_offset = offset % PAGE_SIZE; 34762306a36Sopenharmony_ci sg = &cmd->req.sg[cmd->sg_idx]; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci while (length) { 35062306a36Sopenharmony_ci u32 iov_len = min_t(u32, length, sg->length - sg_offset); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci bvec_set_page(iov, sg_page(sg), iov_len, 35362306a36Sopenharmony_ci sg->offset + sg_offset); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci length -= iov_len; 35662306a36Sopenharmony_ci sg = sg_next(sg); 35762306a36Sopenharmony_ci iov++; 35862306a36Sopenharmony_ci sg_offset = 0; 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci iov_iter_bvec(&cmd->recv_msg.msg_iter, ITER_DEST, cmd->iov, 36262306a36Sopenharmony_ci nr_pages, cmd->pdu_len); 36362306a36Sopenharmony_ci} 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_cistatic void nvmet_tcp_fatal_error(struct nvmet_tcp_queue *queue) 36662306a36Sopenharmony_ci{ 36762306a36Sopenharmony_ci queue->rcv_state = NVMET_TCP_RECV_ERR; 36862306a36Sopenharmony_ci if (queue->nvme_sq.ctrl) 36962306a36Sopenharmony_ci nvmet_ctrl_fatal_error(queue->nvme_sq.ctrl); 37062306a36Sopenharmony_ci else 37162306a36Sopenharmony_ci kernel_sock_shutdown(queue->sock, SHUT_RDWR); 37262306a36Sopenharmony_ci} 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_cistatic void nvmet_tcp_socket_error(struct nvmet_tcp_queue *queue, int status) 37562306a36Sopenharmony_ci{ 37662306a36Sopenharmony_ci queue->rcv_state = NVMET_TCP_RECV_ERR; 37762306a36Sopenharmony_ci if (status == -EPIPE || status == -ECONNRESET) 37862306a36Sopenharmony_ci kernel_sock_shutdown(queue->sock, SHUT_RDWR); 37962306a36Sopenharmony_ci else 38062306a36Sopenharmony_ci nvmet_tcp_fatal_error(queue); 38162306a36Sopenharmony_ci} 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_cistatic int nvmet_tcp_map_data(struct nvmet_tcp_cmd *cmd) 38462306a36Sopenharmony_ci{ 38562306a36Sopenharmony_ci struct nvme_sgl_desc *sgl = &cmd->req.cmd->common.dptr.sgl; 38662306a36Sopenharmony_ci u32 len = le32_to_cpu(sgl->length); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci if (!len) 38962306a36Sopenharmony_ci return 0; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci if (sgl->type == ((NVME_SGL_FMT_DATA_DESC << 4) | 39262306a36Sopenharmony_ci NVME_SGL_FMT_OFFSET)) { 39362306a36Sopenharmony_ci if (!nvme_is_write(cmd->req.cmd)) 39462306a36Sopenharmony_ci return NVME_SC_INVALID_FIELD | NVME_SC_DNR; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci if (len > cmd->req.port->inline_data_size) 39762306a36Sopenharmony_ci return NVME_SC_SGL_INVALID_OFFSET | NVME_SC_DNR; 39862306a36Sopenharmony_ci cmd->pdu_len = len; 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci cmd->req.transfer_len += len; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci cmd->req.sg = sgl_alloc(len, GFP_KERNEL, &cmd->req.sg_cnt); 40362306a36Sopenharmony_ci if (!cmd->req.sg) 40462306a36Sopenharmony_ci return NVME_SC_INTERNAL; 40562306a36Sopenharmony_ci cmd->cur_sg = cmd->req.sg; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci if (nvmet_tcp_has_data_in(cmd)) { 40862306a36Sopenharmony_ci cmd->iov = kmalloc_array(cmd->req.sg_cnt, 40962306a36Sopenharmony_ci sizeof(*cmd->iov), GFP_KERNEL); 41062306a36Sopenharmony_ci if (!cmd->iov) 41162306a36Sopenharmony_ci goto err; 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci return 0; 41562306a36Sopenharmony_cierr: 41662306a36Sopenharmony_ci nvmet_tcp_free_cmd_buffers(cmd); 41762306a36Sopenharmony_ci return NVME_SC_INTERNAL; 41862306a36Sopenharmony_ci} 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_cistatic void nvmet_tcp_calc_ddgst(struct ahash_request *hash, 42162306a36Sopenharmony_ci struct nvmet_tcp_cmd *cmd) 42262306a36Sopenharmony_ci{ 42362306a36Sopenharmony_ci ahash_request_set_crypt(hash, cmd->req.sg, 42462306a36Sopenharmony_ci (void *)&cmd->exp_ddgst, cmd->req.transfer_len); 42562306a36Sopenharmony_ci crypto_ahash_digest(hash); 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_cistatic void nvmet_setup_c2h_data_pdu(struct nvmet_tcp_cmd *cmd) 42962306a36Sopenharmony_ci{ 43062306a36Sopenharmony_ci struct nvme_tcp_data_pdu *pdu = cmd->data_pdu; 43162306a36Sopenharmony_ci struct nvmet_tcp_queue *queue = cmd->queue; 43262306a36Sopenharmony_ci u8 hdgst = nvmet_tcp_hdgst_len(cmd->queue); 43362306a36Sopenharmony_ci u8 ddgst = nvmet_tcp_ddgst_len(cmd->queue); 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci cmd->offset = 0; 43662306a36Sopenharmony_ci cmd->state = NVMET_TCP_SEND_DATA_PDU; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci pdu->hdr.type = nvme_tcp_c2h_data; 43962306a36Sopenharmony_ci pdu->hdr.flags = NVME_TCP_F_DATA_LAST | (queue->nvme_sq.sqhd_disabled ? 44062306a36Sopenharmony_ci NVME_TCP_F_DATA_SUCCESS : 0); 44162306a36Sopenharmony_ci pdu->hdr.hlen = sizeof(*pdu); 44262306a36Sopenharmony_ci pdu->hdr.pdo = pdu->hdr.hlen + hdgst; 44362306a36Sopenharmony_ci pdu->hdr.plen = 44462306a36Sopenharmony_ci cpu_to_le32(pdu->hdr.hlen + hdgst + 44562306a36Sopenharmony_ci cmd->req.transfer_len + ddgst); 44662306a36Sopenharmony_ci pdu->command_id = cmd->req.cqe->command_id; 44762306a36Sopenharmony_ci pdu->data_length = cpu_to_le32(cmd->req.transfer_len); 44862306a36Sopenharmony_ci pdu->data_offset = cpu_to_le32(cmd->wbytes_done); 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci if (queue->data_digest) { 45162306a36Sopenharmony_ci pdu->hdr.flags |= NVME_TCP_F_DDGST; 45262306a36Sopenharmony_ci nvmet_tcp_calc_ddgst(queue->snd_hash, cmd); 45362306a36Sopenharmony_ci } 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci if (cmd->queue->hdr_digest) { 45662306a36Sopenharmony_ci pdu->hdr.flags |= NVME_TCP_F_HDGST; 45762306a36Sopenharmony_ci nvmet_tcp_hdgst(queue->snd_hash, pdu, sizeof(*pdu)); 45862306a36Sopenharmony_ci } 45962306a36Sopenharmony_ci} 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_cistatic void nvmet_setup_r2t_pdu(struct nvmet_tcp_cmd *cmd) 46262306a36Sopenharmony_ci{ 46362306a36Sopenharmony_ci struct nvme_tcp_r2t_pdu *pdu = cmd->r2t_pdu; 46462306a36Sopenharmony_ci struct nvmet_tcp_queue *queue = cmd->queue; 46562306a36Sopenharmony_ci u8 hdgst = nvmet_tcp_hdgst_len(cmd->queue); 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci cmd->offset = 0; 46862306a36Sopenharmony_ci cmd->state = NVMET_TCP_SEND_R2T; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci pdu->hdr.type = nvme_tcp_r2t; 47162306a36Sopenharmony_ci pdu->hdr.flags = 0; 47262306a36Sopenharmony_ci pdu->hdr.hlen = sizeof(*pdu); 47362306a36Sopenharmony_ci pdu->hdr.pdo = 0; 47462306a36Sopenharmony_ci pdu->hdr.plen = cpu_to_le32(pdu->hdr.hlen + hdgst); 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci pdu->command_id = cmd->req.cmd->common.command_id; 47762306a36Sopenharmony_ci pdu->ttag = nvmet_tcp_cmd_tag(cmd->queue, cmd); 47862306a36Sopenharmony_ci pdu->r2t_length = cpu_to_le32(cmd->req.transfer_len - cmd->rbytes_done); 47962306a36Sopenharmony_ci pdu->r2t_offset = cpu_to_le32(cmd->rbytes_done); 48062306a36Sopenharmony_ci if (cmd->queue->hdr_digest) { 48162306a36Sopenharmony_ci pdu->hdr.flags |= NVME_TCP_F_HDGST; 48262306a36Sopenharmony_ci nvmet_tcp_hdgst(queue->snd_hash, pdu, sizeof(*pdu)); 48362306a36Sopenharmony_ci } 48462306a36Sopenharmony_ci} 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_cistatic void nvmet_setup_response_pdu(struct nvmet_tcp_cmd *cmd) 48762306a36Sopenharmony_ci{ 48862306a36Sopenharmony_ci struct nvme_tcp_rsp_pdu *pdu = cmd->rsp_pdu; 48962306a36Sopenharmony_ci struct nvmet_tcp_queue *queue = cmd->queue; 49062306a36Sopenharmony_ci u8 hdgst = nvmet_tcp_hdgst_len(cmd->queue); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci cmd->offset = 0; 49362306a36Sopenharmony_ci cmd->state = NVMET_TCP_SEND_RESPONSE; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci pdu->hdr.type = nvme_tcp_rsp; 49662306a36Sopenharmony_ci pdu->hdr.flags = 0; 49762306a36Sopenharmony_ci pdu->hdr.hlen = sizeof(*pdu); 49862306a36Sopenharmony_ci pdu->hdr.pdo = 0; 49962306a36Sopenharmony_ci pdu->hdr.plen = cpu_to_le32(pdu->hdr.hlen + hdgst); 50062306a36Sopenharmony_ci if (cmd->queue->hdr_digest) { 50162306a36Sopenharmony_ci pdu->hdr.flags |= NVME_TCP_F_HDGST; 50262306a36Sopenharmony_ci nvmet_tcp_hdgst(queue->snd_hash, pdu, sizeof(*pdu)); 50362306a36Sopenharmony_ci } 50462306a36Sopenharmony_ci} 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_cistatic void nvmet_tcp_process_resp_list(struct nvmet_tcp_queue *queue) 50762306a36Sopenharmony_ci{ 50862306a36Sopenharmony_ci struct llist_node *node; 50962306a36Sopenharmony_ci struct nvmet_tcp_cmd *cmd; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci for (node = llist_del_all(&queue->resp_list); node; node = node->next) { 51262306a36Sopenharmony_ci cmd = llist_entry(node, struct nvmet_tcp_cmd, lentry); 51362306a36Sopenharmony_ci list_add(&cmd->entry, &queue->resp_send_list); 51462306a36Sopenharmony_ci queue->send_list_len++; 51562306a36Sopenharmony_ci } 51662306a36Sopenharmony_ci} 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_cistatic struct nvmet_tcp_cmd *nvmet_tcp_fetch_cmd(struct nvmet_tcp_queue *queue) 51962306a36Sopenharmony_ci{ 52062306a36Sopenharmony_ci queue->snd_cmd = list_first_entry_or_null(&queue->resp_send_list, 52162306a36Sopenharmony_ci struct nvmet_tcp_cmd, entry); 52262306a36Sopenharmony_ci if (!queue->snd_cmd) { 52362306a36Sopenharmony_ci nvmet_tcp_process_resp_list(queue); 52462306a36Sopenharmony_ci queue->snd_cmd = 52562306a36Sopenharmony_ci list_first_entry_or_null(&queue->resp_send_list, 52662306a36Sopenharmony_ci struct nvmet_tcp_cmd, entry); 52762306a36Sopenharmony_ci if (unlikely(!queue->snd_cmd)) 52862306a36Sopenharmony_ci return NULL; 52962306a36Sopenharmony_ci } 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci list_del_init(&queue->snd_cmd->entry); 53262306a36Sopenharmony_ci queue->send_list_len--; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci if (nvmet_tcp_need_data_out(queue->snd_cmd)) 53562306a36Sopenharmony_ci nvmet_setup_c2h_data_pdu(queue->snd_cmd); 53662306a36Sopenharmony_ci else if (nvmet_tcp_need_data_in(queue->snd_cmd)) 53762306a36Sopenharmony_ci nvmet_setup_r2t_pdu(queue->snd_cmd); 53862306a36Sopenharmony_ci else 53962306a36Sopenharmony_ci nvmet_setup_response_pdu(queue->snd_cmd); 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci return queue->snd_cmd; 54262306a36Sopenharmony_ci} 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_cistatic void nvmet_tcp_queue_response(struct nvmet_req *req) 54562306a36Sopenharmony_ci{ 54662306a36Sopenharmony_ci struct nvmet_tcp_cmd *cmd = 54762306a36Sopenharmony_ci container_of(req, struct nvmet_tcp_cmd, req); 54862306a36Sopenharmony_ci struct nvmet_tcp_queue *queue = cmd->queue; 54962306a36Sopenharmony_ci struct nvme_sgl_desc *sgl; 55062306a36Sopenharmony_ci u32 len; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci if (unlikely(cmd == queue->cmd)) { 55362306a36Sopenharmony_ci sgl = &cmd->req.cmd->common.dptr.sgl; 55462306a36Sopenharmony_ci len = le32_to_cpu(sgl->length); 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci /* 55762306a36Sopenharmony_ci * Wait for inline data before processing the response. 55862306a36Sopenharmony_ci * Avoid using helpers, this might happen before 55962306a36Sopenharmony_ci * nvmet_req_init is completed. 56062306a36Sopenharmony_ci */ 56162306a36Sopenharmony_ci if (queue->rcv_state == NVMET_TCP_RECV_PDU && 56262306a36Sopenharmony_ci len && len <= cmd->req.port->inline_data_size && 56362306a36Sopenharmony_ci nvme_is_write(cmd->req.cmd)) 56462306a36Sopenharmony_ci return; 56562306a36Sopenharmony_ci } 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci llist_add(&cmd->lentry, &queue->resp_list); 56862306a36Sopenharmony_ci queue_work_on(queue_cpu(queue), nvmet_tcp_wq, &cmd->queue->io_work); 56962306a36Sopenharmony_ci} 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_cistatic void nvmet_tcp_execute_request(struct nvmet_tcp_cmd *cmd) 57262306a36Sopenharmony_ci{ 57362306a36Sopenharmony_ci if (unlikely(cmd->flags & NVMET_TCP_F_INIT_FAILED)) 57462306a36Sopenharmony_ci nvmet_tcp_queue_response(&cmd->req); 57562306a36Sopenharmony_ci else 57662306a36Sopenharmony_ci cmd->req.execute(&cmd->req); 57762306a36Sopenharmony_ci} 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_cistatic int nvmet_try_send_data_pdu(struct nvmet_tcp_cmd *cmd) 58062306a36Sopenharmony_ci{ 58162306a36Sopenharmony_ci struct msghdr msg = { 58262306a36Sopenharmony_ci .msg_flags = MSG_DONTWAIT | MSG_MORE | MSG_SPLICE_PAGES, 58362306a36Sopenharmony_ci }; 58462306a36Sopenharmony_ci struct bio_vec bvec; 58562306a36Sopenharmony_ci u8 hdgst = nvmet_tcp_hdgst_len(cmd->queue); 58662306a36Sopenharmony_ci int left = sizeof(*cmd->data_pdu) - cmd->offset + hdgst; 58762306a36Sopenharmony_ci int ret; 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci bvec_set_virt(&bvec, (void *)cmd->data_pdu + cmd->offset, left); 59062306a36Sopenharmony_ci iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, left); 59162306a36Sopenharmony_ci ret = sock_sendmsg(cmd->queue->sock, &msg); 59262306a36Sopenharmony_ci if (ret <= 0) 59362306a36Sopenharmony_ci return ret; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci cmd->offset += ret; 59662306a36Sopenharmony_ci left -= ret; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci if (left) 59962306a36Sopenharmony_ci return -EAGAIN; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci cmd->state = NVMET_TCP_SEND_DATA; 60262306a36Sopenharmony_ci cmd->offset = 0; 60362306a36Sopenharmony_ci return 1; 60462306a36Sopenharmony_ci} 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_cistatic int nvmet_try_send_data(struct nvmet_tcp_cmd *cmd, bool last_in_batch) 60762306a36Sopenharmony_ci{ 60862306a36Sopenharmony_ci struct nvmet_tcp_queue *queue = cmd->queue; 60962306a36Sopenharmony_ci int ret; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci while (cmd->cur_sg) { 61262306a36Sopenharmony_ci struct msghdr msg = { 61362306a36Sopenharmony_ci .msg_flags = MSG_DONTWAIT | MSG_SPLICE_PAGES, 61462306a36Sopenharmony_ci }; 61562306a36Sopenharmony_ci struct page *page = sg_page(cmd->cur_sg); 61662306a36Sopenharmony_ci struct bio_vec bvec; 61762306a36Sopenharmony_ci u32 left = cmd->cur_sg->length - cmd->offset; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci if ((!last_in_batch && cmd->queue->send_list_len) || 62062306a36Sopenharmony_ci cmd->wbytes_done + left < cmd->req.transfer_len || 62162306a36Sopenharmony_ci queue->data_digest || !queue->nvme_sq.sqhd_disabled) 62262306a36Sopenharmony_ci msg.msg_flags |= MSG_MORE; 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci bvec_set_page(&bvec, page, left, cmd->offset); 62562306a36Sopenharmony_ci iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, left); 62662306a36Sopenharmony_ci ret = sock_sendmsg(cmd->queue->sock, &msg); 62762306a36Sopenharmony_ci if (ret <= 0) 62862306a36Sopenharmony_ci return ret; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci cmd->offset += ret; 63162306a36Sopenharmony_ci cmd->wbytes_done += ret; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci /* Done with sg?*/ 63462306a36Sopenharmony_ci if (cmd->offset == cmd->cur_sg->length) { 63562306a36Sopenharmony_ci cmd->cur_sg = sg_next(cmd->cur_sg); 63662306a36Sopenharmony_ci cmd->offset = 0; 63762306a36Sopenharmony_ci } 63862306a36Sopenharmony_ci } 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci if (queue->data_digest) { 64162306a36Sopenharmony_ci cmd->state = NVMET_TCP_SEND_DDGST; 64262306a36Sopenharmony_ci cmd->offset = 0; 64362306a36Sopenharmony_ci } else { 64462306a36Sopenharmony_ci if (queue->nvme_sq.sqhd_disabled) { 64562306a36Sopenharmony_ci cmd->queue->snd_cmd = NULL; 64662306a36Sopenharmony_ci nvmet_tcp_put_cmd(cmd); 64762306a36Sopenharmony_ci } else { 64862306a36Sopenharmony_ci nvmet_setup_response_pdu(cmd); 64962306a36Sopenharmony_ci } 65062306a36Sopenharmony_ci } 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci if (queue->nvme_sq.sqhd_disabled) 65362306a36Sopenharmony_ci nvmet_tcp_free_cmd_buffers(cmd); 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci return 1; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci} 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_cistatic int nvmet_try_send_response(struct nvmet_tcp_cmd *cmd, 66062306a36Sopenharmony_ci bool last_in_batch) 66162306a36Sopenharmony_ci{ 66262306a36Sopenharmony_ci struct msghdr msg = { .msg_flags = MSG_DONTWAIT | MSG_SPLICE_PAGES, }; 66362306a36Sopenharmony_ci struct bio_vec bvec; 66462306a36Sopenharmony_ci u8 hdgst = nvmet_tcp_hdgst_len(cmd->queue); 66562306a36Sopenharmony_ci int left = sizeof(*cmd->rsp_pdu) - cmd->offset + hdgst; 66662306a36Sopenharmony_ci int ret; 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci if (!last_in_batch && cmd->queue->send_list_len) 66962306a36Sopenharmony_ci msg.msg_flags |= MSG_MORE; 67062306a36Sopenharmony_ci else 67162306a36Sopenharmony_ci msg.msg_flags |= MSG_EOR; 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci bvec_set_virt(&bvec, (void *)cmd->rsp_pdu + cmd->offset, left); 67462306a36Sopenharmony_ci iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, left); 67562306a36Sopenharmony_ci ret = sock_sendmsg(cmd->queue->sock, &msg); 67662306a36Sopenharmony_ci if (ret <= 0) 67762306a36Sopenharmony_ci return ret; 67862306a36Sopenharmony_ci cmd->offset += ret; 67962306a36Sopenharmony_ci left -= ret; 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci if (left) 68262306a36Sopenharmony_ci return -EAGAIN; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci nvmet_tcp_free_cmd_buffers(cmd); 68562306a36Sopenharmony_ci cmd->queue->snd_cmd = NULL; 68662306a36Sopenharmony_ci nvmet_tcp_put_cmd(cmd); 68762306a36Sopenharmony_ci return 1; 68862306a36Sopenharmony_ci} 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_cistatic int nvmet_try_send_r2t(struct nvmet_tcp_cmd *cmd, bool last_in_batch) 69162306a36Sopenharmony_ci{ 69262306a36Sopenharmony_ci struct msghdr msg = { .msg_flags = MSG_DONTWAIT | MSG_SPLICE_PAGES, }; 69362306a36Sopenharmony_ci struct bio_vec bvec; 69462306a36Sopenharmony_ci u8 hdgst = nvmet_tcp_hdgst_len(cmd->queue); 69562306a36Sopenharmony_ci int left = sizeof(*cmd->r2t_pdu) - cmd->offset + hdgst; 69662306a36Sopenharmony_ci int ret; 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci if (!last_in_batch && cmd->queue->send_list_len) 69962306a36Sopenharmony_ci msg.msg_flags |= MSG_MORE; 70062306a36Sopenharmony_ci else 70162306a36Sopenharmony_ci msg.msg_flags |= MSG_EOR; 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci bvec_set_virt(&bvec, (void *)cmd->r2t_pdu + cmd->offset, left); 70462306a36Sopenharmony_ci iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, left); 70562306a36Sopenharmony_ci ret = sock_sendmsg(cmd->queue->sock, &msg); 70662306a36Sopenharmony_ci if (ret <= 0) 70762306a36Sopenharmony_ci return ret; 70862306a36Sopenharmony_ci cmd->offset += ret; 70962306a36Sopenharmony_ci left -= ret; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci if (left) 71262306a36Sopenharmony_ci return -EAGAIN; 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci cmd->queue->snd_cmd = NULL; 71562306a36Sopenharmony_ci return 1; 71662306a36Sopenharmony_ci} 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_cistatic int nvmet_try_send_ddgst(struct nvmet_tcp_cmd *cmd, bool last_in_batch) 71962306a36Sopenharmony_ci{ 72062306a36Sopenharmony_ci struct nvmet_tcp_queue *queue = cmd->queue; 72162306a36Sopenharmony_ci int left = NVME_TCP_DIGEST_LENGTH - cmd->offset; 72262306a36Sopenharmony_ci struct msghdr msg = { .msg_flags = MSG_DONTWAIT }; 72362306a36Sopenharmony_ci struct kvec iov = { 72462306a36Sopenharmony_ci .iov_base = (u8 *)&cmd->exp_ddgst + cmd->offset, 72562306a36Sopenharmony_ci .iov_len = left 72662306a36Sopenharmony_ci }; 72762306a36Sopenharmony_ci int ret; 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci if (!last_in_batch && cmd->queue->send_list_len) 73062306a36Sopenharmony_ci msg.msg_flags |= MSG_MORE; 73162306a36Sopenharmony_ci else 73262306a36Sopenharmony_ci msg.msg_flags |= MSG_EOR; 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci ret = kernel_sendmsg(queue->sock, &msg, &iov, 1, iov.iov_len); 73562306a36Sopenharmony_ci if (unlikely(ret <= 0)) 73662306a36Sopenharmony_ci return ret; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci cmd->offset += ret; 73962306a36Sopenharmony_ci left -= ret; 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci if (left) 74262306a36Sopenharmony_ci return -EAGAIN; 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci if (queue->nvme_sq.sqhd_disabled) { 74562306a36Sopenharmony_ci cmd->queue->snd_cmd = NULL; 74662306a36Sopenharmony_ci nvmet_tcp_put_cmd(cmd); 74762306a36Sopenharmony_ci } else { 74862306a36Sopenharmony_ci nvmet_setup_response_pdu(cmd); 74962306a36Sopenharmony_ci } 75062306a36Sopenharmony_ci return 1; 75162306a36Sopenharmony_ci} 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_cistatic int nvmet_tcp_try_send_one(struct nvmet_tcp_queue *queue, 75462306a36Sopenharmony_ci bool last_in_batch) 75562306a36Sopenharmony_ci{ 75662306a36Sopenharmony_ci struct nvmet_tcp_cmd *cmd = queue->snd_cmd; 75762306a36Sopenharmony_ci int ret = 0; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci if (!cmd || queue->state == NVMET_TCP_Q_DISCONNECTING) { 76062306a36Sopenharmony_ci cmd = nvmet_tcp_fetch_cmd(queue); 76162306a36Sopenharmony_ci if (unlikely(!cmd)) 76262306a36Sopenharmony_ci return 0; 76362306a36Sopenharmony_ci } 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci if (cmd->state == NVMET_TCP_SEND_DATA_PDU) { 76662306a36Sopenharmony_ci ret = nvmet_try_send_data_pdu(cmd); 76762306a36Sopenharmony_ci if (ret <= 0) 76862306a36Sopenharmony_ci goto done_send; 76962306a36Sopenharmony_ci } 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci if (cmd->state == NVMET_TCP_SEND_DATA) { 77262306a36Sopenharmony_ci ret = nvmet_try_send_data(cmd, last_in_batch); 77362306a36Sopenharmony_ci if (ret <= 0) 77462306a36Sopenharmony_ci goto done_send; 77562306a36Sopenharmony_ci } 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci if (cmd->state == NVMET_TCP_SEND_DDGST) { 77862306a36Sopenharmony_ci ret = nvmet_try_send_ddgst(cmd, last_in_batch); 77962306a36Sopenharmony_ci if (ret <= 0) 78062306a36Sopenharmony_ci goto done_send; 78162306a36Sopenharmony_ci } 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci if (cmd->state == NVMET_TCP_SEND_R2T) { 78462306a36Sopenharmony_ci ret = nvmet_try_send_r2t(cmd, last_in_batch); 78562306a36Sopenharmony_ci if (ret <= 0) 78662306a36Sopenharmony_ci goto done_send; 78762306a36Sopenharmony_ci } 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci if (cmd->state == NVMET_TCP_SEND_RESPONSE) 79062306a36Sopenharmony_ci ret = nvmet_try_send_response(cmd, last_in_batch); 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_cidone_send: 79362306a36Sopenharmony_ci if (ret < 0) { 79462306a36Sopenharmony_ci if (ret == -EAGAIN) 79562306a36Sopenharmony_ci return 0; 79662306a36Sopenharmony_ci return ret; 79762306a36Sopenharmony_ci } 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci return 1; 80062306a36Sopenharmony_ci} 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_cistatic int nvmet_tcp_try_send(struct nvmet_tcp_queue *queue, 80362306a36Sopenharmony_ci int budget, int *sends) 80462306a36Sopenharmony_ci{ 80562306a36Sopenharmony_ci int i, ret = 0; 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci for (i = 0; i < budget; i++) { 80862306a36Sopenharmony_ci ret = nvmet_tcp_try_send_one(queue, i == budget - 1); 80962306a36Sopenharmony_ci if (unlikely(ret < 0)) { 81062306a36Sopenharmony_ci nvmet_tcp_socket_error(queue, ret); 81162306a36Sopenharmony_ci goto done; 81262306a36Sopenharmony_ci } else if (ret == 0) { 81362306a36Sopenharmony_ci break; 81462306a36Sopenharmony_ci } 81562306a36Sopenharmony_ci (*sends)++; 81662306a36Sopenharmony_ci } 81762306a36Sopenharmony_cidone: 81862306a36Sopenharmony_ci return ret; 81962306a36Sopenharmony_ci} 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_cistatic void nvmet_prepare_receive_pdu(struct nvmet_tcp_queue *queue) 82262306a36Sopenharmony_ci{ 82362306a36Sopenharmony_ci queue->offset = 0; 82462306a36Sopenharmony_ci queue->left = sizeof(struct nvme_tcp_hdr); 82562306a36Sopenharmony_ci queue->cmd = NULL; 82662306a36Sopenharmony_ci queue->rcv_state = NVMET_TCP_RECV_PDU; 82762306a36Sopenharmony_ci} 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_cistatic void nvmet_tcp_free_crypto(struct nvmet_tcp_queue *queue) 83062306a36Sopenharmony_ci{ 83162306a36Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(queue->rcv_hash); 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci ahash_request_free(queue->rcv_hash); 83462306a36Sopenharmony_ci ahash_request_free(queue->snd_hash); 83562306a36Sopenharmony_ci crypto_free_ahash(tfm); 83662306a36Sopenharmony_ci} 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_cistatic int nvmet_tcp_alloc_crypto(struct nvmet_tcp_queue *queue) 83962306a36Sopenharmony_ci{ 84062306a36Sopenharmony_ci struct crypto_ahash *tfm; 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci tfm = crypto_alloc_ahash("crc32c", 0, CRYPTO_ALG_ASYNC); 84362306a36Sopenharmony_ci if (IS_ERR(tfm)) 84462306a36Sopenharmony_ci return PTR_ERR(tfm); 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci queue->snd_hash = ahash_request_alloc(tfm, GFP_KERNEL); 84762306a36Sopenharmony_ci if (!queue->snd_hash) 84862306a36Sopenharmony_ci goto free_tfm; 84962306a36Sopenharmony_ci ahash_request_set_callback(queue->snd_hash, 0, NULL, NULL); 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci queue->rcv_hash = ahash_request_alloc(tfm, GFP_KERNEL); 85262306a36Sopenharmony_ci if (!queue->rcv_hash) 85362306a36Sopenharmony_ci goto free_snd_hash; 85462306a36Sopenharmony_ci ahash_request_set_callback(queue->rcv_hash, 0, NULL, NULL); 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci return 0; 85762306a36Sopenharmony_cifree_snd_hash: 85862306a36Sopenharmony_ci ahash_request_free(queue->snd_hash); 85962306a36Sopenharmony_cifree_tfm: 86062306a36Sopenharmony_ci crypto_free_ahash(tfm); 86162306a36Sopenharmony_ci return -ENOMEM; 86262306a36Sopenharmony_ci} 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_cistatic int nvmet_tcp_handle_icreq(struct nvmet_tcp_queue *queue) 86662306a36Sopenharmony_ci{ 86762306a36Sopenharmony_ci struct nvme_tcp_icreq_pdu *icreq = &queue->pdu.icreq; 86862306a36Sopenharmony_ci struct nvme_tcp_icresp_pdu *icresp = &queue->pdu.icresp; 86962306a36Sopenharmony_ci struct msghdr msg = {}; 87062306a36Sopenharmony_ci struct kvec iov; 87162306a36Sopenharmony_ci int ret; 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci if (le32_to_cpu(icreq->hdr.plen) != sizeof(struct nvme_tcp_icreq_pdu)) { 87462306a36Sopenharmony_ci pr_err("bad nvme-tcp pdu length (%d)\n", 87562306a36Sopenharmony_ci le32_to_cpu(icreq->hdr.plen)); 87662306a36Sopenharmony_ci nvmet_tcp_fatal_error(queue); 87762306a36Sopenharmony_ci } 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci if (icreq->pfv != NVME_TCP_PFV_1_0) { 88062306a36Sopenharmony_ci pr_err("queue %d: bad pfv %d\n", queue->idx, icreq->pfv); 88162306a36Sopenharmony_ci return -EPROTO; 88262306a36Sopenharmony_ci } 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci if (icreq->hpda != 0) { 88562306a36Sopenharmony_ci pr_err("queue %d: unsupported hpda %d\n", queue->idx, 88662306a36Sopenharmony_ci icreq->hpda); 88762306a36Sopenharmony_ci return -EPROTO; 88862306a36Sopenharmony_ci } 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci queue->hdr_digest = !!(icreq->digest & NVME_TCP_HDR_DIGEST_ENABLE); 89162306a36Sopenharmony_ci queue->data_digest = !!(icreq->digest & NVME_TCP_DATA_DIGEST_ENABLE); 89262306a36Sopenharmony_ci if (queue->hdr_digest || queue->data_digest) { 89362306a36Sopenharmony_ci ret = nvmet_tcp_alloc_crypto(queue); 89462306a36Sopenharmony_ci if (ret) 89562306a36Sopenharmony_ci return ret; 89662306a36Sopenharmony_ci } 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci memset(icresp, 0, sizeof(*icresp)); 89962306a36Sopenharmony_ci icresp->hdr.type = nvme_tcp_icresp; 90062306a36Sopenharmony_ci icresp->hdr.hlen = sizeof(*icresp); 90162306a36Sopenharmony_ci icresp->hdr.pdo = 0; 90262306a36Sopenharmony_ci icresp->hdr.plen = cpu_to_le32(icresp->hdr.hlen); 90362306a36Sopenharmony_ci icresp->pfv = cpu_to_le16(NVME_TCP_PFV_1_0); 90462306a36Sopenharmony_ci icresp->maxdata = cpu_to_le32(NVMET_TCP_MAXH2CDATA); 90562306a36Sopenharmony_ci icresp->cpda = 0; 90662306a36Sopenharmony_ci if (queue->hdr_digest) 90762306a36Sopenharmony_ci icresp->digest |= NVME_TCP_HDR_DIGEST_ENABLE; 90862306a36Sopenharmony_ci if (queue->data_digest) 90962306a36Sopenharmony_ci icresp->digest |= NVME_TCP_DATA_DIGEST_ENABLE; 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci iov.iov_base = icresp; 91262306a36Sopenharmony_ci iov.iov_len = sizeof(*icresp); 91362306a36Sopenharmony_ci ret = kernel_sendmsg(queue->sock, &msg, &iov, 1, iov.iov_len); 91462306a36Sopenharmony_ci if (ret < 0) 91562306a36Sopenharmony_ci return ret; /* queue removal will cleanup */ 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci queue->state = NVMET_TCP_Q_LIVE; 91862306a36Sopenharmony_ci nvmet_prepare_receive_pdu(queue); 91962306a36Sopenharmony_ci return 0; 92062306a36Sopenharmony_ci} 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_cistatic void nvmet_tcp_handle_req_failure(struct nvmet_tcp_queue *queue, 92362306a36Sopenharmony_ci struct nvmet_tcp_cmd *cmd, struct nvmet_req *req) 92462306a36Sopenharmony_ci{ 92562306a36Sopenharmony_ci size_t data_len = le32_to_cpu(req->cmd->common.dptr.sgl.length); 92662306a36Sopenharmony_ci int ret; 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci /* 92962306a36Sopenharmony_ci * This command has not been processed yet, hence we are trying to 93062306a36Sopenharmony_ci * figure out if there is still pending data left to receive. If 93162306a36Sopenharmony_ci * we don't, we can simply prepare for the next pdu and bail out, 93262306a36Sopenharmony_ci * otherwise we will need to prepare a buffer and receive the 93362306a36Sopenharmony_ci * stale data before continuing forward. 93462306a36Sopenharmony_ci */ 93562306a36Sopenharmony_ci if (!nvme_is_write(cmd->req.cmd) || !data_len || 93662306a36Sopenharmony_ci data_len > cmd->req.port->inline_data_size) { 93762306a36Sopenharmony_ci nvmet_prepare_receive_pdu(queue); 93862306a36Sopenharmony_ci return; 93962306a36Sopenharmony_ci } 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci ret = nvmet_tcp_map_data(cmd); 94262306a36Sopenharmony_ci if (unlikely(ret)) { 94362306a36Sopenharmony_ci pr_err("queue %d: failed to map data\n", queue->idx); 94462306a36Sopenharmony_ci nvmet_tcp_fatal_error(queue); 94562306a36Sopenharmony_ci return; 94662306a36Sopenharmony_ci } 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci queue->rcv_state = NVMET_TCP_RECV_DATA; 94962306a36Sopenharmony_ci nvmet_tcp_build_pdu_iovec(cmd); 95062306a36Sopenharmony_ci cmd->flags |= NVMET_TCP_F_INIT_FAILED; 95162306a36Sopenharmony_ci} 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_cistatic int nvmet_tcp_handle_h2c_data_pdu(struct nvmet_tcp_queue *queue) 95462306a36Sopenharmony_ci{ 95562306a36Sopenharmony_ci struct nvme_tcp_data_pdu *data = &queue->pdu.data; 95662306a36Sopenharmony_ci struct nvmet_tcp_cmd *cmd; 95762306a36Sopenharmony_ci unsigned int exp_data_len; 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci if (likely(queue->nr_cmds)) { 96062306a36Sopenharmony_ci if (unlikely(data->ttag >= queue->nr_cmds)) { 96162306a36Sopenharmony_ci pr_err("queue %d: received out of bound ttag %u, nr_cmds %u\n", 96262306a36Sopenharmony_ci queue->idx, data->ttag, queue->nr_cmds); 96362306a36Sopenharmony_ci nvmet_tcp_fatal_error(queue); 96462306a36Sopenharmony_ci return -EPROTO; 96562306a36Sopenharmony_ci } 96662306a36Sopenharmony_ci cmd = &queue->cmds[data->ttag]; 96762306a36Sopenharmony_ci } else { 96862306a36Sopenharmony_ci cmd = &queue->connect; 96962306a36Sopenharmony_ci } 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci if (le32_to_cpu(data->data_offset) != cmd->rbytes_done) { 97262306a36Sopenharmony_ci pr_err("ttag %u unexpected data offset %u (expected %u)\n", 97362306a36Sopenharmony_ci data->ttag, le32_to_cpu(data->data_offset), 97462306a36Sopenharmony_ci cmd->rbytes_done); 97562306a36Sopenharmony_ci /* FIXME: use path and transport errors */ 97662306a36Sopenharmony_ci nvmet_tcp_fatal_error(queue); 97762306a36Sopenharmony_ci return -EPROTO; 97862306a36Sopenharmony_ci } 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci exp_data_len = le32_to_cpu(data->hdr.plen) - 98162306a36Sopenharmony_ci nvmet_tcp_hdgst_len(queue) - 98262306a36Sopenharmony_ci nvmet_tcp_ddgst_len(queue) - 98362306a36Sopenharmony_ci sizeof(*data); 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci cmd->pdu_len = le32_to_cpu(data->data_length); 98662306a36Sopenharmony_ci if (unlikely(cmd->pdu_len != exp_data_len || 98762306a36Sopenharmony_ci cmd->pdu_len == 0 || 98862306a36Sopenharmony_ci cmd->pdu_len > NVMET_TCP_MAXH2CDATA)) { 98962306a36Sopenharmony_ci pr_err("H2CData PDU len %u is invalid\n", cmd->pdu_len); 99062306a36Sopenharmony_ci /* FIXME: use proper transport errors */ 99162306a36Sopenharmony_ci nvmet_tcp_fatal_error(queue); 99262306a36Sopenharmony_ci return -EPROTO; 99362306a36Sopenharmony_ci } 99462306a36Sopenharmony_ci cmd->pdu_recv = 0; 99562306a36Sopenharmony_ci nvmet_tcp_build_pdu_iovec(cmd); 99662306a36Sopenharmony_ci queue->cmd = cmd; 99762306a36Sopenharmony_ci queue->rcv_state = NVMET_TCP_RECV_DATA; 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci return 0; 100062306a36Sopenharmony_ci} 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_cistatic int nvmet_tcp_done_recv_pdu(struct nvmet_tcp_queue *queue) 100362306a36Sopenharmony_ci{ 100462306a36Sopenharmony_ci struct nvme_tcp_hdr *hdr = &queue->pdu.cmd.hdr; 100562306a36Sopenharmony_ci struct nvme_command *nvme_cmd = &queue->pdu.cmd.cmd; 100662306a36Sopenharmony_ci struct nvmet_req *req; 100762306a36Sopenharmony_ci int ret; 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci if (unlikely(queue->state == NVMET_TCP_Q_CONNECTING)) { 101062306a36Sopenharmony_ci if (hdr->type != nvme_tcp_icreq) { 101162306a36Sopenharmony_ci pr_err("unexpected pdu type (%d) before icreq\n", 101262306a36Sopenharmony_ci hdr->type); 101362306a36Sopenharmony_ci nvmet_tcp_fatal_error(queue); 101462306a36Sopenharmony_ci return -EPROTO; 101562306a36Sopenharmony_ci } 101662306a36Sopenharmony_ci return nvmet_tcp_handle_icreq(queue); 101762306a36Sopenharmony_ci } 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci if (unlikely(hdr->type == nvme_tcp_icreq)) { 102062306a36Sopenharmony_ci pr_err("queue %d: received icreq pdu in state %d\n", 102162306a36Sopenharmony_ci queue->idx, queue->state); 102262306a36Sopenharmony_ci nvmet_tcp_fatal_error(queue); 102362306a36Sopenharmony_ci return -EPROTO; 102462306a36Sopenharmony_ci } 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci if (hdr->type == nvme_tcp_h2c_data) { 102762306a36Sopenharmony_ci ret = nvmet_tcp_handle_h2c_data_pdu(queue); 102862306a36Sopenharmony_ci if (unlikely(ret)) 102962306a36Sopenharmony_ci return ret; 103062306a36Sopenharmony_ci return 0; 103162306a36Sopenharmony_ci } 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci queue->cmd = nvmet_tcp_get_cmd(queue); 103462306a36Sopenharmony_ci if (unlikely(!queue->cmd)) { 103562306a36Sopenharmony_ci /* This should never happen */ 103662306a36Sopenharmony_ci pr_err("queue %d: out of commands (%d) send_list_len: %d, opcode: %d", 103762306a36Sopenharmony_ci queue->idx, queue->nr_cmds, queue->send_list_len, 103862306a36Sopenharmony_ci nvme_cmd->common.opcode); 103962306a36Sopenharmony_ci nvmet_tcp_fatal_error(queue); 104062306a36Sopenharmony_ci return -ENOMEM; 104162306a36Sopenharmony_ci } 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci req = &queue->cmd->req; 104462306a36Sopenharmony_ci memcpy(req->cmd, nvme_cmd, sizeof(*nvme_cmd)); 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci if (unlikely(!nvmet_req_init(req, &queue->nvme_cq, 104762306a36Sopenharmony_ci &queue->nvme_sq, &nvmet_tcp_ops))) { 104862306a36Sopenharmony_ci pr_err("failed cmd %p id %d opcode %d, data_len: %d\n", 104962306a36Sopenharmony_ci req->cmd, req->cmd->common.command_id, 105062306a36Sopenharmony_ci req->cmd->common.opcode, 105162306a36Sopenharmony_ci le32_to_cpu(req->cmd->common.dptr.sgl.length)); 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci nvmet_tcp_handle_req_failure(queue, queue->cmd, req); 105462306a36Sopenharmony_ci return 0; 105562306a36Sopenharmony_ci } 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci ret = nvmet_tcp_map_data(queue->cmd); 105862306a36Sopenharmony_ci if (unlikely(ret)) { 105962306a36Sopenharmony_ci pr_err("queue %d: failed to map data\n", queue->idx); 106062306a36Sopenharmony_ci if (nvmet_tcp_has_inline_data(queue->cmd)) 106162306a36Sopenharmony_ci nvmet_tcp_fatal_error(queue); 106262306a36Sopenharmony_ci else 106362306a36Sopenharmony_ci nvmet_req_complete(req, ret); 106462306a36Sopenharmony_ci ret = -EAGAIN; 106562306a36Sopenharmony_ci goto out; 106662306a36Sopenharmony_ci } 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci if (nvmet_tcp_need_data_in(queue->cmd)) { 106962306a36Sopenharmony_ci if (nvmet_tcp_has_inline_data(queue->cmd)) { 107062306a36Sopenharmony_ci queue->rcv_state = NVMET_TCP_RECV_DATA; 107162306a36Sopenharmony_ci nvmet_tcp_build_pdu_iovec(queue->cmd); 107262306a36Sopenharmony_ci return 0; 107362306a36Sopenharmony_ci } 107462306a36Sopenharmony_ci /* send back R2T */ 107562306a36Sopenharmony_ci nvmet_tcp_queue_response(&queue->cmd->req); 107662306a36Sopenharmony_ci goto out; 107762306a36Sopenharmony_ci } 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci queue->cmd->req.execute(&queue->cmd->req); 108062306a36Sopenharmony_ciout: 108162306a36Sopenharmony_ci nvmet_prepare_receive_pdu(queue); 108262306a36Sopenharmony_ci return ret; 108362306a36Sopenharmony_ci} 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_cistatic const u8 nvme_tcp_pdu_sizes[] = { 108662306a36Sopenharmony_ci [nvme_tcp_icreq] = sizeof(struct nvme_tcp_icreq_pdu), 108762306a36Sopenharmony_ci [nvme_tcp_cmd] = sizeof(struct nvme_tcp_cmd_pdu), 108862306a36Sopenharmony_ci [nvme_tcp_h2c_data] = sizeof(struct nvme_tcp_data_pdu), 108962306a36Sopenharmony_ci}; 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_cistatic inline u8 nvmet_tcp_pdu_size(u8 type) 109262306a36Sopenharmony_ci{ 109362306a36Sopenharmony_ci size_t idx = type; 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci return (idx < ARRAY_SIZE(nvme_tcp_pdu_sizes) && 109662306a36Sopenharmony_ci nvme_tcp_pdu_sizes[idx]) ? 109762306a36Sopenharmony_ci nvme_tcp_pdu_sizes[idx] : 0; 109862306a36Sopenharmony_ci} 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_cistatic inline bool nvmet_tcp_pdu_valid(u8 type) 110162306a36Sopenharmony_ci{ 110262306a36Sopenharmony_ci switch (type) { 110362306a36Sopenharmony_ci case nvme_tcp_icreq: 110462306a36Sopenharmony_ci case nvme_tcp_cmd: 110562306a36Sopenharmony_ci case nvme_tcp_h2c_data: 110662306a36Sopenharmony_ci /* fallthru */ 110762306a36Sopenharmony_ci return true; 110862306a36Sopenharmony_ci } 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci return false; 111162306a36Sopenharmony_ci} 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_cistatic int nvmet_tcp_try_recv_pdu(struct nvmet_tcp_queue *queue) 111462306a36Sopenharmony_ci{ 111562306a36Sopenharmony_ci struct nvme_tcp_hdr *hdr = &queue->pdu.cmd.hdr; 111662306a36Sopenharmony_ci int len; 111762306a36Sopenharmony_ci struct kvec iov; 111862306a36Sopenharmony_ci struct msghdr msg = { .msg_flags = MSG_DONTWAIT }; 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_cirecv: 112162306a36Sopenharmony_ci iov.iov_base = (void *)&queue->pdu + queue->offset; 112262306a36Sopenharmony_ci iov.iov_len = queue->left; 112362306a36Sopenharmony_ci len = kernel_recvmsg(queue->sock, &msg, &iov, 1, 112462306a36Sopenharmony_ci iov.iov_len, msg.msg_flags); 112562306a36Sopenharmony_ci if (unlikely(len < 0)) 112662306a36Sopenharmony_ci return len; 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci queue->offset += len; 112962306a36Sopenharmony_ci queue->left -= len; 113062306a36Sopenharmony_ci if (queue->left) 113162306a36Sopenharmony_ci return -EAGAIN; 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ci if (queue->offset == sizeof(struct nvme_tcp_hdr)) { 113462306a36Sopenharmony_ci u8 hdgst = nvmet_tcp_hdgst_len(queue); 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci if (unlikely(!nvmet_tcp_pdu_valid(hdr->type))) { 113762306a36Sopenharmony_ci pr_err("unexpected pdu type %d\n", hdr->type); 113862306a36Sopenharmony_ci nvmet_tcp_fatal_error(queue); 113962306a36Sopenharmony_ci return -EIO; 114062306a36Sopenharmony_ci } 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci if (unlikely(hdr->hlen != nvmet_tcp_pdu_size(hdr->type))) { 114362306a36Sopenharmony_ci pr_err("pdu %d bad hlen %d\n", hdr->type, hdr->hlen); 114462306a36Sopenharmony_ci return -EIO; 114562306a36Sopenharmony_ci } 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci queue->left = hdr->hlen - queue->offset + hdgst; 114862306a36Sopenharmony_ci goto recv; 114962306a36Sopenharmony_ci } 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci if (queue->hdr_digest && 115262306a36Sopenharmony_ci nvmet_tcp_verify_hdgst(queue, &queue->pdu, hdr->hlen)) { 115362306a36Sopenharmony_ci nvmet_tcp_fatal_error(queue); /* fatal */ 115462306a36Sopenharmony_ci return -EPROTO; 115562306a36Sopenharmony_ci } 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci if (queue->data_digest && 115862306a36Sopenharmony_ci nvmet_tcp_check_ddgst(queue, &queue->pdu)) { 115962306a36Sopenharmony_ci nvmet_tcp_fatal_error(queue); /* fatal */ 116062306a36Sopenharmony_ci return -EPROTO; 116162306a36Sopenharmony_ci } 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci return nvmet_tcp_done_recv_pdu(queue); 116462306a36Sopenharmony_ci} 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_cistatic void nvmet_tcp_prep_recv_ddgst(struct nvmet_tcp_cmd *cmd) 116762306a36Sopenharmony_ci{ 116862306a36Sopenharmony_ci struct nvmet_tcp_queue *queue = cmd->queue; 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci nvmet_tcp_calc_ddgst(queue->rcv_hash, cmd); 117162306a36Sopenharmony_ci queue->offset = 0; 117262306a36Sopenharmony_ci queue->left = NVME_TCP_DIGEST_LENGTH; 117362306a36Sopenharmony_ci queue->rcv_state = NVMET_TCP_RECV_DDGST; 117462306a36Sopenharmony_ci} 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_cistatic int nvmet_tcp_try_recv_data(struct nvmet_tcp_queue *queue) 117762306a36Sopenharmony_ci{ 117862306a36Sopenharmony_ci struct nvmet_tcp_cmd *cmd = queue->cmd; 117962306a36Sopenharmony_ci int ret; 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci while (msg_data_left(&cmd->recv_msg)) { 118262306a36Sopenharmony_ci ret = sock_recvmsg(cmd->queue->sock, &cmd->recv_msg, 118362306a36Sopenharmony_ci cmd->recv_msg.msg_flags); 118462306a36Sopenharmony_ci if (ret <= 0) 118562306a36Sopenharmony_ci return ret; 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci cmd->pdu_recv += ret; 118862306a36Sopenharmony_ci cmd->rbytes_done += ret; 118962306a36Sopenharmony_ci } 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci if (queue->data_digest) { 119262306a36Sopenharmony_ci nvmet_tcp_prep_recv_ddgst(cmd); 119362306a36Sopenharmony_ci return 0; 119462306a36Sopenharmony_ci } 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci if (cmd->rbytes_done == cmd->req.transfer_len) 119762306a36Sopenharmony_ci nvmet_tcp_execute_request(cmd); 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci nvmet_prepare_receive_pdu(queue); 120062306a36Sopenharmony_ci return 0; 120162306a36Sopenharmony_ci} 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_cistatic int nvmet_tcp_try_recv_ddgst(struct nvmet_tcp_queue *queue) 120462306a36Sopenharmony_ci{ 120562306a36Sopenharmony_ci struct nvmet_tcp_cmd *cmd = queue->cmd; 120662306a36Sopenharmony_ci int ret; 120762306a36Sopenharmony_ci struct msghdr msg = { .msg_flags = MSG_DONTWAIT }; 120862306a36Sopenharmony_ci struct kvec iov = { 120962306a36Sopenharmony_ci .iov_base = (void *)&cmd->recv_ddgst + queue->offset, 121062306a36Sopenharmony_ci .iov_len = queue->left 121162306a36Sopenharmony_ci }; 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci ret = kernel_recvmsg(queue->sock, &msg, &iov, 1, 121462306a36Sopenharmony_ci iov.iov_len, msg.msg_flags); 121562306a36Sopenharmony_ci if (unlikely(ret < 0)) 121662306a36Sopenharmony_ci return ret; 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci queue->offset += ret; 121962306a36Sopenharmony_ci queue->left -= ret; 122062306a36Sopenharmony_ci if (queue->left) 122162306a36Sopenharmony_ci return -EAGAIN; 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci if (queue->data_digest && cmd->exp_ddgst != cmd->recv_ddgst) { 122462306a36Sopenharmony_ci pr_err("queue %d: cmd %d pdu (%d) data digest error: recv %#x expected %#x\n", 122562306a36Sopenharmony_ci queue->idx, cmd->req.cmd->common.command_id, 122662306a36Sopenharmony_ci queue->pdu.cmd.hdr.type, le32_to_cpu(cmd->recv_ddgst), 122762306a36Sopenharmony_ci le32_to_cpu(cmd->exp_ddgst)); 122862306a36Sopenharmony_ci nvmet_req_uninit(&cmd->req); 122962306a36Sopenharmony_ci nvmet_tcp_free_cmd_buffers(cmd); 123062306a36Sopenharmony_ci nvmet_tcp_fatal_error(queue); 123162306a36Sopenharmony_ci ret = -EPROTO; 123262306a36Sopenharmony_ci goto out; 123362306a36Sopenharmony_ci } 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci if (cmd->rbytes_done == cmd->req.transfer_len) 123662306a36Sopenharmony_ci nvmet_tcp_execute_request(cmd); 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci ret = 0; 123962306a36Sopenharmony_ciout: 124062306a36Sopenharmony_ci nvmet_prepare_receive_pdu(queue); 124162306a36Sopenharmony_ci return ret; 124262306a36Sopenharmony_ci} 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_cistatic int nvmet_tcp_try_recv_one(struct nvmet_tcp_queue *queue) 124562306a36Sopenharmony_ci{ 124662306a36Sopenharmony_ci int result = 0; 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci if (unlikely(queue->rcv_state == NVMET_TCP_RECV_ERR)) 124962306a36Sopenharmony_ci return 0; 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_ci if (queue->rcv_state == NVMET_TCP_RECV_PDU) { 125262306a36Sopenharmony_ci result = nvmet_tcp_try_recv_pdu(queue); 125362306a36Sopenharmony_ci if (result != 0) 125462306a36Sopenharmony_ci goto done_recv; 125562306a36Sopenharmony_ci } 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci if (queue->rcv_state == NVMET_TCP_RECV_DATA) { 125862306a36Sopenharmony_ci result = nvmet_tcp_try_recv_data(queue); 125962306a36Sopenharmony_ci if (result != 0) 126062306a36Sopenharmony_ci goto done_recv; 126162306a36Sopenharmony_ci } 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci if (queue->rcv_state == NVMET_TCP_RECV_DDGST) { 126462306a36Sopenharmony_ci result = nvmet_tcp_try_recv_ddgst(queue); 126562306a36Sopenharmony_ci if (result != 0) 126662306a36Sopenharmony_ci goto done_recv; 126762306a36Sopenharmony_ci } 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_cidone_recv: 127062306a36Sopenharmony_ci if (result < 0) { 127162306a36Sopenharmony_ci if (result == -EAGAIN) 127262306a36Sopenharmony_ci return 0; 127362306a36Sopenharmony_ci return result; 127462306a36Sopenharmony_ci } 127562306a36Sopenharmony_ci return 1; 127662306a36Sopenharmony_ci} 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_cistatic int nvmet_tcp_try_recv(struct nvmet_tcp_queue *queue, 127962306a36Sopenharmony_ci int budget, int *recvs) 128062306a36Sopenharmony_ci{ 128162306a36Sopenharmony_ci int i, ret = 0; 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci for (i = 0; i < budget; i++) { 128462306a36Sopenharmony_ci ret = nvmet_tcp_try_recv_one(queue); 128562306a36Sopenharmony_ci if (unlikely(ret < 0)) { 128662306a36Sopenharmony_ci nvmet_tcp_socket_error(queue, ret); 128762306a36Sopenharmony_ci goto done; 128862306a36Sopenharmony_ci } else if (ret == 0) { 128962306a36Sopenharmony_ci break; 129062306a36Sopenharmony_ci } 129162306a36Sopenharmony_ci (*recvs)++; 129262306a36Sopenharmony_ci } 129362306a36Sopenharmony_cidone: 129462306a36Sopenharmony_ci return ret; 129562306a36Sopenharmony_ci} 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_cistatic void nvmet_tcp_schedule_release_queue(struct nvmet_tcp_queue *queue) 129862306a36Sopenharmony_ci{ 129962306a36Sopenharmony_ci spin_lock(&queue->state_lock); 130062306a36Sopenharmony_ci if (queue->state != NVMET_TCP_Q_DISCONNECTING) { 130162306a36Sopenharmony_ci queue->state = NVMET_TCP_Q_DISCONNECTING; 130262306a36Sopenharmony_ci queue_work(nvmet_wq, &queue->release_work); 130362306a36Sopenharmony_ci } 130462306a36Sopenharmony_ci spin_unlock(&queue->state_lock); 130562306a36Sopenharmony_ci} 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_cistatic inline void nvmet_tcp_arm_queue_deadline(struct nvmet_tcp_queue *queue) 130862306a36Sopenharmony_ci{ 130962306a36Sopenharmony_ci queue->poll_end = jiffies + usecs_to_jiffies(idle_poll_period_usecs); 131062306a36Sopenharmony_ci} 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_cistatic bool nvmet_tcp_check_queue_deadline(struct nvmet_tcp_queue *queue, 131362306a36Sopenharmony_ci int ops) 131462306a36Sopenharmony_ci{ 131562306a36Sopenharmony_ci if (!idle_poll_period_usecs) 131662306a36Sopenharmony_ci return false; 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci if (ops) 131962306a36Sopenharmony_ci nvmet_tcp_arm_queue_deadline(queue); 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci return !time_after(jiffies, queue->poll_end); 132262306a36Sopenharmony_ci} 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_cistatic void nvmet_tcp_io_work(struct work_struct *w) 132562306a36Sopenharmony_ci{ 132662306a36Sopenharmony_ci struct nvmet_tcp_queue *queue = 132762306a36Sopenharmony_ci container_of(w, struct nvmet_tcp_queue, io_work); 132862306a36Sopenharmony_ci bool pending; 132962306a36Sopenharmony_ci int ret, ops = 0; 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci do { 133262306a36Sopenharmony_ci pending = false; 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_ci ret = nvmet_tcp_try_recv(queue, NVMET_TCP_RECV_BUDGET, &ops); 133562306a36Sopenharmony_ci if (ret > 0) 133662306a36Sopenharmony_ci pending = true; 133762306a36Sopenharmony_ci else if (ret < 0) 133862306a36Sopenharmony_ci return; 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci ret = nvmet_tcp_try_send(queue, NVMET_TCP_SEND_BUDGET, &ops); 134162306a36Sopenharmony_ci if (ret > 0) 134262306a36Sopenharmony_ci pending = true; 134362306a36Sopenharmony_ci else if (ret < 0) 134462306a36Sopenharmony_ci return; 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ci } while (pending && ops < NVMET_TCP_IO_WORK_BUDGET); 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci /* 134962306a36Sopenharmony_ci * Requeue the worker if idle deadline period is in progress or any 135062306a36Sopenharmony_ci * ops activity was recorded during the do-while loop above. 135162306a36Sopenharmony_ci */ 135262306a36Sopenharmony_ci if (nvmet_tcp_check_queue_deadline(queue, ops) || pending) 135362306a36Sopenharmony_ci queue_work_on(queue_cpu(queue), nvmet_tcp_wq, &queue->io_work); 135462306a36Sopenharmony_ci} 135562306a36Sopenharmony_ci 135662306a36Sopenharmony_cistatic int nvmet_tcp_alloc_cmd(struct nvmet_tcp_queue *queue, 135762306a36Sopenharmony_ci struct nvmet_tcp_cmd *c) 135862306a36Sopenharmony_ci{ 135962306a36Sopenharmony_ci u8 hdgst = nvmet_tcp_hdgst_len(queue); 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_ci c->queue = queue; 136262306a36Sopenharmony_ci c->req.port = queue->port->nport; 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci c->cmd_pdu = page_frag_alloc(&queue->pf_cache, 136562306a36Sopenharmony_ci sizeof(*c->cmd_pdu) + hdgst, GFP_KERNEL | __GFP_ZERO); 136662306a36Sopenharmony_ci if (!c->cmd_pdu) 136762306a36Sopenharmony_ci return -ENOMEM; 136862306a36Sopenharmony_ci c->req.cmd = &c->cmd_pdu->cmd; 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci c->rsp_pdu = page_frag_alloc(&queue->pf_cache, 137162306a36Sopenharmony_ci sizeof(*c->rsp_pdu) + hdgst, GFP_KERNEL | __GFP_ZERO); 137262306a36Sopenharmony_ci if (!c->rsp_pdu) 137362306a36Sopenharmony_ci goto out_free_cmd; 137462306a36Sopenharmony_ci c->req.cqe = &c->rsp_pdu->cqe; 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci c->data_pdu = page_frag_alloc(&queue->pf_cache, 137762306a36Sopenharmony_ci sizeof(*c->data_pdu) + hdgst, GFP_KERNEL | __GFP_ZERO); 137862306a36Sopenharmony_ci if (!c->data_pdu) 137962306a36Sopenharmony_ci goto out_free_rsp; 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_ci c->r2t_pdu = page_frag_alloc(&queue->pf_cache, 138262306a36Sopenharmony_ci sizeof(*c->r2t_pdu) + hdgst, GFP_KERNEL | __GFP_ZERO); 138362306a36Sopenharmony_ci if (!c->r2t_pdu) 138462306a36Sopenharmony_ci goto out_free_data; 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci c->recv_msg.msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL; 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ci list_add_tail(&c->entry, &queue->free_list); 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci return 0; 139162306a36Sopenharmony_ciout_free_data: 139262306a36Sopenharmony_ci page_frag_free(c->data_pdu); 139362306a36Sopenharmony_ciout_free_rsp: 139462306a36Sopenharmony_ci page_frag_free(c->rsp_pdu); 139562306a36Sopenharmony_ciout_free_cmd: 139662306a36Sopenharmony_ci page_frag_free(c->cmd_pdu); 139762306a36Sopenharmony_ci return -ENOMEM; 139862306a36Sopenharmony_ci} 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_cistatic void nvmet_tcp_free_cmd(struct nvmet_tcp_cmd *c) 140162306a36Sopenharmony_ci{ 140262306a36Sopenharmony_ci page_frag_free(c->r2t_pdu); 140362306a36Sopenharmony_ci page_frag_free(c->data_pdu); 140462306a36Sopenharmony_ci page_frag_free(c->rsp_pdu); 140562306a36Sopenharmony_ci page_frag_free(c->cmd_pdu); 140662306a36Sopenharmony_ci} 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_cistatic int nvmet_tcp_alloc_cmds(struct nvmet_tcp_queue *queue) 140962306a36Sopenharmony_ci{ 141062306a36Sopenharmony_ci struct nvmet_tcp_cmd *cmds; 141162306a36Sopenharmony_ci int i, ret = -EINVAL, nr_cmds = queue->nr_cmds; 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ci cmds = kcalloc(nr_cmds, sizeof(struct nvmet_tcp_cmd), GFP_KERNEL); 141462306a36Sopenharmony_ci if (!cmds) 141562306a36Sopenharmony_ci goto out; 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_ci for (i = 0; i < nr_cmds; i++) { 141862306a36Sopenharmony_ci ret = nvmet_tcp_alloc_cmd(queue, cmds + i); 141962306a36Sopenharmony_ci if (ret) 142062306a36Sopenharmony_ci goto out_free; 142162306a36Sopenharmony_ci } 142262306a36Sopenharmony_ci 142362306a36Sopenharmony_ci queue->cmds = cmds; 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ci return 0; 142662306a36Sopenharmony_ciout_free: 142762306a36Sopenharmony_ci while (--i >= 0) 142862306a36Sopenharmony_ci nvmet_tcp_free_cmd(cmds + i); 142962306a36Sopenharmony_ci kfree(cmds); 143062306a36Sopenharmony_ciout: 143162306a36Sopenharmony_ci return ret; 143262306a36Sopenharmony_ci} 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_cistatic void nvmet_tcp_free_cmds(struct nvmet_tcp_queue *queue) 143562306a36Sopenharmony_ci{ 143662306a36Sopenharmony_ci struct nvmet_tcp_cmd *cmds = queue->cmds; 143762306a36Sopenharmony_ci int i; 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci for (i = 0; i < queue->nr_cmds; i++) 144062306a36Sopenharmony_ci nvmet_tcp_free_cmd(cmds + i); 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci nvmet_tcp_free_cmd(&queue->connect); 144362306a36Sopenharmony_ci kfree(cmds); 144462306a36Sopenharmony_ci} 144562306a36Sopenharmony_ci 144662306a36Sopenharmony_cistatic void nvmet_tcp_restore_socket_callbacks(struct nvmet_tcp_queue *queue) 144762306a36Sopenharmony_ci{ 144862306a36Sopenharmony_ci struct socket *sock = queue->sock; 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci write_lock_bh(&sock->sk->sk_callback_lock); 145162306a36Sopenharmony_ci sock->sk->sk_data_ready = queue->data_ready; 145262306a36Sopenharmony_ci sock->sk->sk_state_change = queue->state_change; 145362306a36Sopenharmony_ci sock->sk->sk_write_space = queue->write_space; 145462306a36Sopenharmony_ci sock->sk->sk_user_data = NULL; 145562306a36Sopenharmony_ci write_unlock_bh(&sock->sk->sk_callback_lock); 145662306a36Sopenharmony_ci} 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_cistatic void nvmet_tcp_uninit_data_in_cmds(struct nvmet_tcp_queue *queue) 145962306a36Sopenharmony_ci{ 146062306a36Sopenharmony_ci struct nvmet_tcp_cmd *cmd = queue->cmds; 146162306a36Sopenharmony_ci int i; 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci for (i = 0; i < queue->nr_cmds; i++, cmd++) { 146462306a36Sopenharmony_ci if (nvmet_tcp_need_data_in(cmd)) 146562306a36Sopenharmony_ci nvmet_req_uninit(&cmd->req); 146662306a36Sopenharmony_ci } 146762306a36Sopenharmony_ci 146862306a36Sopenharmony_ci if (!queue->nr_cmds && nvmet_tcp_need_data_in(&queue->connect)) { 146962306a36Sopenharmony_ci /* failed in connect */ 147062306a36Sopenharmony_ci nvmet_req_uninit(&queue->connect.req); 147162306a36Sopenharmony_ci } 147262306a36Sopenharmony_ci} 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_cistatic void nvmet_tcp_free_cmd_data_in_buffers(struct nvmet_tcp_queue *queue) 147562306a36Sopenharmony_ci{ 147662306a36Sopenharmony_ci struct nvmet_tcp_cmd *cmd = queue->cmds; 147762306a36Sopenharmony_ci int i; 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_ci for (i = 0; i < queue->nr_cmds; i++, cmd++) { 148062306a36Sopenharmony_ci if (nvmet_tcp_need_data_in(cmd)) 148162306a36Sopenharmony_ci nvmet_tcp_free_cmd_buffers(cmd); 148262306a36Sopenharmony_ci } 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_ci if (!queue->nr_cmds && nvmet_tcp_need_data_in(&queue->connect)) 148562306a36Sopenharmony_ci nvmet_tcp_free_cmd_buffers(&queue->connect); 148662306a36Sopenharmony_ci} 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_cistatic void nvmet_tcp_release_queue_work(struct work_struct *w) 148962306a36Sopenharmony_ci{ 149062306a36Sopenharmony_ci struct page *page; 149162306a36Sopenharmony_ci struct nvmet_tcp_queue *queue = 149262306a36Sopenharmony_ci container_of(w, struct nvmet_tcp_queue, release_work); 149362306a36Sopenharmony_ci 149462306a36Sopenharmony_ci mutex_lock(&nvmet_tcp_queue_mutex); 149562306a36Sopenharmony_ci list_del_init(&queue->queue_list); 149662306a36Sopenharmony_ci mutex_unlock(&nvmet_tcp_queue_mutex); 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci nvmet_tcp_restore_socket_callbacks(queue); 149962306a36Sopenharmony_ci cancel_work_sync(&queue->io_work); 150062306a36Sopenharmony_ci /* stop accepting incoming data */ 150162306a36Sopenharmony_ci queue->rcv_state = NVMET_TCP_RECV_ERR; 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci nvmet_tcp_uninit_data_in_cmds(queue); 150462306a36Sopenharmony_ci nvmet_sq_destroy(&queue->nvme_sq); 150562306a36Sopenharmony_ci cancel_work_sync(&queue->io_work); 150662306a36Sopenharmony_ci nvmet_tcp_free_cmd_data_in_buffers(queue); 150762306a36Sopenharmony_ci sock_release(queue->sock); 150862306a36Sopenharmony_ci nvmet_tcp_free_cmds(queue); 150962306a36Sopenharmony_ci if (queue->hdr_digest || queue->data_digest) 151062306a36Sopenharmony_ci nvmet_tcp_free_crypto(queue); 151162306a36Sopenharmony_ci ida_free(&nvmet_tcp_queue_ida, queue->idx); 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci page = virt_to_head_page(queue->pf_cache.va); 151462306a36Sopenharmony_ci __page_frag_cache_drain(page, queue->pf_cache.pagecnt_bias); 151562306a36Sopenharmony_ci kfree(queue); 151662306a36Sopenharmony_ci} 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_cistatic void nvmet_tcp_data_ready(struct sock *sk) 151962306a36Sopenharmony_ci{ 152062306a36Sopenharmony_ci struct nvmet_tcp_queue *queue; 152162306a36Sopenharmony_ci 152262306a36Sopenharmony_ci trace_sk_data_ready(sk); 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_ci read_lock_bh(&sk->sk_callback_lock); 152562306a36Sopenharmony_ci queue = sk->sk_user_data; 152662306a36Sopenharmony_ci if (likely(queue)) 152762306a36Sopenharmony_ci queue_work_on(queue_cpu(queue), nvmet_tcp_wq, &queue->io_work); 152862306a36Sopenharmony_ci read_unlock_bh(&sk->sk_callback_lock); 152962306a36Sopenharmony_ci} 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_cistatic void nvmet_tcp_write_space(struct sock *sk) 153262306a36Sopenharmony_ci{ 153362306a36Sopenharmony_ci struct nvmet_tcp_queue *queue; 153462306a36Sopenharmony_ci 153562306a36Sopenharmony_ci read_lock_bh(&sk->sk_callback_lock); 153662306a36Sopenharmony_ci queue = sk->sk_user_data; 153762306a36Sopenharmony_ci if (unlikely(!queue)) 153862306a36Sopenharmony_ci goto out; 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_ci if (unlikely(queue->state == NVMET_TCP_Q_CONNECTING)) { 154162306a36Sopenharmony_ci queue->write_space(sk); 154262306a36Sopenharmony_ci goto out; 154362306a36Sopenharmony_ci } 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci if (sk_stream_is_writeable(sk)) { 154662306a36Sopenharmony_ci clear_bit(SOCK_NOSPACE, &sk->sk_socket->flags); 154762306a36Sopenharmony_ci queue_work_on(queue_cpu(queue), nvmet_tcp_wq, &queue->io_work); 154862306a36Sopenharmony_ci } 154962306a36Sopenharmony_ciout: 155062306a36Sopenharmony_ci read_unlock_bh(&sk->sk_callback_lock); 155162306a36Sopenharmony_ci} 155262306a36Sopenharmony_ci 155362306a36Sopenharmony_cistatic void nvmet_tcp_state_change(struct sock *sk) 155462306a36Sopenharmony_ci{ 155562306a36Sopenharmony_ci struct nvmet_tcp_queue *queue; 155662306a36Sopenharmony_ci 155762306a36Sopenharmony_ci read_lock_bh(&sk->sk_callback_lock); 155862306a36Sopenharmony_ci queue = sk->sk_user_data; 155962306a36Sopenharmony_ci if (!queue) 156062306a36Sopenharmony_ci goto done; 156162306a36Sopenharmony_ci 156262306a36Sopenharmony_ci switch (sk->sk_state) { 156362306a36Sopenharmony_ci case TCP_FIN_WAIT2: 156462306a36Sopenharmony_ci case TCP_LAST_ACK: 156562306a36Sopenharmony_ci break; 156662306a36Sopenharmony_ci case TCP_FIN_WAIT1: 156762306a36Sopenharmony_ci case TCP_CLOSE_WAIT: 156862306a36Sopenharmony_ci case TCP_CLOSE: 156962306a36Sopenharmony_ci /* FALLTHRU */ 157062306a36Sopenharmony_ci nvmet_tcp_schedule_release_queue(queue); 157162306a36Sopenharmony_ci break; 157262306a36Sopenharmony_ci default: 157362306a36Sopenharmony_ci pr_warn("queue %d unhandled state %d\n", 157462306a36Sopenharmony_ci queue->idx, sk->sk_state); 157562306a36Sopenharmony_ci } 157662306a36Sopenharmony_cidone: 157762306a36Sopenharmony_ci read_unlock_bh(&sk->sk_callback_lock); 157862306a36Sopenharmony_ci} 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_cistatic int nvmet_tcp_set_queue_sock(struct nvmet_tcp_queue *queue) 158162306a36Sopenharmony_ci{ 158262306a36Sopenharmony_ci struct socket *sock = queue->sock; 158362306a36Sopenharmony_ci struct inet_sock *inet = inet_sk(sock->sk); 158462306a36Sopenharmony_ci int ret; 158562306a36Sopenharmony_ci 158662306a36Sopenharmony_ci ret = kernel_getsockname(sock, 158762306a36Sopenharmony_ci (struct sockaddr *)&queue->sockaddr); 158862306a36Sopenharmony_ci if (ret < 0) 158962306a36Sopenharmony_ci return ret; 159062306a36Sopenharmony_ci 159162306a36Sopenharmony_ci ret = kernel_getpeername(sock, 159262306a36Sopenharmony_ci (struct sockaddr *)&queue->sockaddr_peer); 159362306a36Sopenharmony_ci if (ret < 0) 159462306a36Sopenharmony_ci return ret; 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_ci /* 159762306a36Sopenharmony_ci * Cleanup whatever is sitting in the TCP transmit queue on socket 159862306a36Sopenharmony_ci * close. This is done to prevent stale data from being sent should 159962306a36Sopenharmony_ci * the network connection be restored before TCP times out. 160062306a36Sopenharmony_ci */ 160162306a36Sopenharmony_ci sock_no_linger(sock->sk); 160262306a36Sopenharmony_ci 160362306a36Sopenharmony_ci if (so_priority > 0) 160462306a36Sopenharmony_ci sock_set_priority(sock->sk, so_priority); 160562306a36Sopenharmony_ci 160662306a36Sopenharmony_ci /* Set socket type of service */ 160762306a36Sopenharmony_ci if (inet->rcv_tos > 0) 160862306a36Sopenharmony_ci ip_sock_set_tos(sock->sk, inet->rcv_tos); 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ci ret = 0; 161162306a36Sopenharmony_ci write_lock_bh(&sock->sk->sk_callback_lock); 161262306a36Sopenharmony_ci if (sock->sk->sk_state != TCP_ESTABLISHED) { 161362306a36Sopenharmony_ci /* 161462306a36Sopenharmony_ci * If the socket is already closing, don't even start 161562306a36Sopenharmony_ci * consuming it 161662306a36Sopenharmony_ci */ 161762306a36Sopenharmony_ci ret = -ENOTCONN; 161862306a36Sopenharmony_ci } else { 161962306a36Sopenharmony_ci sock->sk->sk_user_data = queue; 162062306a36Sopenharmony_ci queue->data_ready = sock->sk->sk_data_ready; 162162306a36Sopenharmony_ci sock->sk->sk_data_ready = nvmet_tcp_data_ready; 162262306a36Sopenharmony_ci queue->state_change = sock->sk->sk_state_change; 162362306a36Sopenharmony_ci sock->sk->sk_state_change = nvmet_tcp_state_change; 162462306a36Sopenharmony_ci queue->write_space = sock->sk->sk_write_space; 162562306a36Sopenharmony_ci sock->sk->sk_write_space = nvmet_tcp_write_space; 162662306a36Sopenharmony_ci if (idle_poll_period_usecs) 162762306a36Sopenharmony_ci nvmet_tcp_arm_queue_deadline(queue); 162862306a36Sopenharmony_ci queue_work_on(queue_cpu(queue), nvmet_tcp_wq, &queue->io_work); 162962306a36Sopenharmony_ci } 163062306a36Sopenharmony_ci write_unlock_bh(&sock->sk->sk_callback_lock); 163162306a36Sopenharmony_ci 163262306a36Sopenharmony_ci return ret; 163362306a36Sopenharmony_ci} 163462306a36Sopenharmony_ci 163562306a36Sopenharmony_cistatic int nvmet_tcp_alloc_queue(struct nvmet_tcp_port *port, 163662306a36Sopenharmony_ci struct socket *newsock) 163762306a36Sopenharmony_ci{ 163862306a36Sopenharmony_ci struct nvmet_tcp_queue *queue; 163962306a36Sopenharmony_ci int ret; 164062306a36Sopenharmony_ci 164162306a36Sopenharmony_ci queue = kzalloc(sizeof(*queue), GFP_KERNEL); 164262306a36Sopenharmony_ci if (!queue) 164362306a36Sopenharmony_ci return -ENOMEM; 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_ci INIT_WORK(&queue->release_work, nvmet_tcp_release_queue_work); 164662306a36Sopenharmony_ci INIT_WORK(&queue->io_work, nvmet_tcp_io_work); 164762306a36Sopenharmony_ci queue->sock = newsock; 164862306a36Sopenharmony_ci queue->port = port; 164962306a36Sopenharmony_ci queue->nr_cmds = 0; 165062306a36Sopenharmony_ci spin_lock_init(&queue->state_lock); 165162306a36Sopenharmony_ci queue->state = NVMET_TCP_Q_CONNECTING; 165262306a36Sopenharmony_ci INIT_LIST_HEAD(&queue->free_list); 165362306a36Sopenharmony_ci init_llist_head(&queue->resp_list); 165462306a36Sopenharmony_ci INIT_LIST_HEAD(&queue->resp_send_list); 165562306a36Sopenharmony_ci 165662306a36Sopenharmony_ci queue->idx = ida_alloc(&nvmet_tcp_queue_ida, GFP_KERNEL); 165762306a36Sopenharmony_ci if (queue->idx < 0) { 165862306a36Sopenharmony_ci ret = queue->idx; 165962306a36Sopenharmony_ci goto out_free_queue; 166062306a36Sopenharmony_ci } 166162306a36Sopenharmony_ci 166262306a36Sopenharmony_ci ret = nvmet_tcp_alloc_cmd(queue, &queue->connect); 166362306a36Sopenharmony_ci if (ret) 166462306a36Sopenharmony_ci goto out_ida_remove; 166562306a36Sopenharmony_ci 166662306a36Sopenharmony_ci ret = nvmet_sq_init(&queue->nvme_sq); 166762306a36Sopenharmony_ci if (ret) 166862306a36Sopenharmony_ci goto out_free_connect; 166962306a36Sopenharmony_ci 167062306a36Sopenharmony_ci nvmet_prepare_receive_pdu(queue); 167162306a36Sopenharmony_ci 167262306a36Sopenharmony_ci mutex_lock(&nvmet_tcp_queue_mutex); 167362306a36Sopenharmony_ci list_add_tail(&queue->queue_list, &nvmet_tcp_queue_list); 167462306a36Sopenharmony_ci mutex_unlock(&nvmet_tcp_queue_mutex); 167562306a36Sopenharmony_ci 167662306a36Sopenharmony_ci ret = nvmet_tcp_set_queue_sock(queue); 167762306a36Sopenharmony_ci if (ret) 167862306a36Sopenharmony_ci goto out_destroy_sq; 167962306a36Sopenharmony_ci 168062306a36Sopenharmony_ci return 0; 168162306a36Sopenharmony_ciout_destroy_sq: 168262306a36Sopenharmony_ci mutex_lock(&nvmet_tcp_queue_mutex); 168362306a36Sopenharmony_ci list_del_init(&queue->queue_list); 168462306a36Sopenharmony_ci mutex_unlock(&nvmet_tcp_queue_mutex); 168562306a36Sopenharmony_ci nvmet_sq_destroy(&queue->nvme_sq); 168662306a36Sopenharmony_ciout_free_connect: 168762306a36Sopenharmony_ci nvmet_tcp_free_cmd(&queue->connect); 168862306a36Sopenharmony_ciout_ida_remove: 168962306a36Sopenharmony_ci ida_free(&nvmet_tcp_queue_ida, queue->idx); 169062306a36Sopenharmony_ciout_free_queue: 169162306a36Sopenharmony_ci kfree(queue); 169262306a36Sopenharmony_ci return ret; 169362306a36Sopenharmony_ci} 169462306a36Sopenharmony_ci 169562306a36Sopenharmony_cistatic void nvmet_tcp_accept_work(struct work_struct *w) 169662306a36Sopenharmony_ci{ 169762306a36Sopenharmony_ci struct nvmet_tcp_port *port = 169862306a36Sopenharmony_ci container_of(w, struct nvmet_tcp_port, accept_work); 169962306a36Sopenharmony_ci struct socket *newsock; 170062306a36Sopenharmony_ci int ret; 170162306a36Sopenharmony_ci 170262306a36Sopenharmony_ci while (true) { 170362306a36Sopenharmony_ci ret = kernel_accept(port->sock, &newsock, O_NONBLOCK); 170462306a36Sopenharmony_ci if (ret < 0) { 170562306a36Sopenharmony_ci if (ret != -EAGAIN) 170662306a36Sopenharmony_ci pr_warn("failed to accept err=%d\n", ret); 170762306a36Sopenharmony_ci return; 170862306a36Sopenharmony_ci } 170962306a36Sopenharmony_ci ret = nvmet_tcp_alloc_queue(port, newsock); 171062306a36Sopenharmony_ci if (ret) { 171162306a36Sopenharmony_ci pr_err("failed to allocate queue\n"); 171262306a36Sopenharmony_ci sock_release(newsock); 171362306a36Sopenharmony_ci } 171462306a36Sopenharmony_ci } 171562306a36Sopenharmony_ci} 171662306a36Sopenharmony_ci 171762306a36Sopenharmony_cistatic void nvmet_tcp_listen_data_ready(struct sock *sk) 171862306a36Sopenharmony_ci{ 171962306a36Sopenharmony_ci struct nvmet_tcp_port *port; 172062306a36Sopenharmony_ci 172162306a36Sopenharmony_ci trace_sk_data_ready(sk); 172262306a36Sopenharmony_ci 172362306a36Sopenharmony_ci read_lock_bh(&sk->sk_callback_lock); 172462306a36Sopenharmony_ci port = sk->sk_user_data; 172562306a36Sopenharmony_ci if (!port) 172662306a36Sopenharmony_ci goto out; 172762306a36Sopenharmony_ci 172862306a36Sopenharmony_ci if (sk->sk_state == TCP_LISTEN) 172962306a36Sopenharmony_ci queue_work(nvmet_wq, &port->accept_work); 173062306a36Sopenharmony_ciout: 173162306a36Sopenharmony_ci read_unlock_bh(&sk->sk_callback_lock); 173262306a36Sopenharmony_ci} 173362306a36Sopenharmony_ci 173462306a36Sopenharmony_cistatic int nvmet_tcp_add_port(struct nvmet_port *nport) 173562306a36Sopenharmony_ci{ 173662306a36Sopenharmony_ci struct nvmet_tcp_port *port; 173762306a36Sopenharmony_ci __kernel_sa_family_t af; 173862306a36Sopenharmony_ci int ret; 173962306a36Sopenharmony_ci 174062306a36Sopenharmony_ci port = kzalloc(sizeof(*port), GFP_KERNEL); 174162306a36Sopenharmony_ci if (!port) 174262306a36Sopenharmony_ci return -ENOMEM; 174362306a36Sopenharmony_ci 174462306a36Sopenharmony_ci switch (nport->disc_addr.adrfam) { 174562306a36Sopenharmony_ci case NVMF_ADDR_FAMILY_IP4: 174662306a36Sopenharmony_ci af = AF_INET; 174762306a36Sopenharmony_ci break; 174862306a36Sopenharmony_ci case NVMF_ADDR_FAMILY_IP6: 174962306a36Sopenharmony_ci af = AF_INET6; 175062306a36Sopenharmony_ci break; 175162306a36Sopenharmony_ci default: 175262306a36Sopenharmony_ci pr_err("address family %d not supported\n", 175362306a36Sopenharmony_ci nport->disc_addr.adrfam); 175462306a36Sopenharmony_ci ret = -EINVAL; 175562306a36Sopenharmony_ci goto err_port; 175662306a36Sopenharmony_ci } 175762306a36Sopenharmony_ci 175862306a36Sopenharmony_ci ret = inet_pton_with_scope(&init_net, af, nport->disc_addr.traddr, 175962306a36Sopenharmony_ci nport->disc_addr.trsvcid, &port->addr); 176062306a36Sopenharmony_ci if (ret) { 176162306a36Sopenharmony_ci pr_err("malformed ip/port passed: %s:%s\n", 176262306a36Sopenharmony_ci nport->disc_addr.traddr, nport->disc_addr.trsvcid); 176362306a36Sopenharmony_ci goto err_port; 176462306a36Sopenharmony_ci } 176562306a36Sopenharmony_ci 176662306a36Sopenharmony_ci port->nport = nport; 176762306a36Sopenharmony_ci INIT_WORK(&port->accept_work, nvmet_tcp_accept_work); 176862306a36Sopenharmony_ci if (port->nport->inline_data_size < 0) 176962306a36Sopenharmony_ci port->nport->inline_data_size = NVMET_TCP_DEF_INLINE_DATA_SIZE; 177062306a36Sopenharmony_ci 177162306a36Sopenharmony_ci ret = sock_create(port->addr.ss_family, SOCK_STREAM, 177262306a36Sopenharmony_ci IPPROTO_TCP, &port->sock); 177362306a36Sopenharmony_ci if (ret) { 177462306a36Sopenharmony_ci pr_err("failed to create a socket\n"); 177562306a36Sopenharmony_ci goto err_port; 177662306a36Sopenharmony_ci } 177762306a36Sopenharmony_ci 177862306a36Sopenharmony_ci port->sock->sk->sk_user_data = port; 177962306a36Sopenharmony_ci port->data_ready = port->sock->sk->sk_data_ready; 178062306a36Sopenharmony_ci port->sock->sk->sk_data_ready = nvmet_tcp_listen_data_ready; 178162306a36Sopenharmony_ci sock_set_reuseaddr(port->sock->sk); 178262306a36Sopenharmony_ci tcp_sock_set_nodelay(port->sock->sk); 178362306a36Sopenharmony_ci if (so_priority > 0) 178462306a36Sopenharmony_ci sock_set_priority(port->sock->sk, so_priority); 178562306a36Sopenharmony_ci 178662306a36Sopenharmony_ci ret = kernel_bind(port->sock, (struct sockaddr *)&port->addr, 178762306a36Sopenharmony_ci sizeof(port->addr)); 178862306a36Sopenharmony_ci if (ret) { 178962306a36Sopenharmony_ci pr_err("failed to bind port socket %d\n", ret); 179062306a36Sopenharmony_ci goto err_sock; 179162306a36Sopenharmony_ci } 179262306a36Sopenharmony_ci 179362306a36Sopenharmony_ci ret = kernel_listen(port->sock, 128); 179462306a36Sopenharmony_ci if (ret) { 179562306a36Sopenharmony_ci pr_err("failed to listen %d on port sock\n", ret); 179662306a36Sopenharmony_ci goto err_sock; 179762306a36Sopenharmony_ci } 179862306a36Sopenharmony_ci 179962306a36Sopenharmony_ci nport->priv = port; 180062306a36Sopenharmony_ci pr_info("enabling port %d (%pISpc)\n", 180162306a36Sopenharmony_ci le16_to_cpu(nport->disc_addr.portid), &port->addr); 180262306a36Sopenharmony_ci 180362306a36Sopenharmony_ci return 0; 180462306a36Sopenharmony_ci 180562306a36Sopenharmony_cierr_sock: 180662306a36Sopenharmony_ci sock_release(port->sock); 180762306a36Sopenharmony_cierr_port: 180862306a36Sopenharmony_ci kfree(port); 180962306a36Sopenharmony_ci return ret; 181062306a36Sopenharmony_ci} 181162306a36Sopenharmony_ci 181262306a36Sopenharmony_cistatic void nvmet_tcp_destroy_port_queues(struct nvmet_tcp_port *port) 181362306a36Sopenharmony_ci{ 181462306a36Sopenharmony_ci struct nvmet_tcp_queue *queue; 181562306a36Sopenharmony_ci 181662306a36Sopenharmony_ci mutex_lock(&nvmet_tcp_queue_mutex); 181762306a36Sopenharmony_ci list_for_each_entry(queue, &nvmet_tcp_queue_list, queue_list) 181862306a36Sopenharmony_ci if (queue->port == port) 181962306a36Sopenharmony_ci kernel_sock_shutdown(queue->sock, SHUT_RDWR); 182062306a36Sopenharmony_ci mutex_unlock(&nvmet_tcp_queue_mutex); 182162306a36Sopenharmony_ci} 182262306a36Sopenharmony_ci 182362306a36Sopenharmony_cistatic void nvmet_tcp_remove_port(struct nvmet_port *nport) 182462306a36Sopenharmony_ci{ 182562306a36Sopenharmony_ci struct nvmet_tcp_port *port = nport->priv; 182662306a36Sopenharmony_ci 182762306a36Sopenharmony_ci write_lock_bh(&port->sock->sk->sk_callback_lock); 182862306a36Sopenharmony_ci port->sock->sk->sk_data_ready = port->data_ready; 182962306a36Sopenharmony_ci port->sock->sk->sk_user_data = NULL; 183062306a36Sopenharmony_ci write_unlock_bh(&port->sock->sk->sk_callback_lock); 183162306a36Sopenharmony_ci cancel_work_sync(&port->accept_work); 183262306a36Sopenharmony_ci /* 183362306a36Sopenharmony_ci * Destroy the remaining queues, which are not belong to any 183462306a36Sopenharmony_ci * controller yet. 183562306a36Sopenharmony_ci */ 183662306a36Sopenharmony_ci nvmet_tcp_destroy_port_queues(port); 183762306a36Sopenharmony_ci 183862306a36Sopenharmony_ci sock_release(port->sock); 183962306a36Sopenharmony_ci kfree(port); 184062306a36Sopenharmony_ci} 184162306a36Sopenharmony_ci 184262306a36Sopenharmony_cistatic void nvmet_tcp_delete_ctrl(struct nvmet_ctrl *ctrl) 184362306a36Sopenharmony_ci{ 184462306a36Sopenharmony_ci struct nvmet_tcp_queue *queue; 184562306a36Sopenharmony_ci 184662306a36Sopenharmony_ci mutex_lock(&nvmet_tcp_queue_mutex); 184762306a36Sopenharmony_ci list_for_each_entry(queue, &nvmet_tcp_queue_list, queue_list) 184862306a36Sopenharmony_ci if (queue->nvme_sq.ctrl == ctrl) 184962306a36Sopenharmony_ci kernel_sock_shutdown(queue->sock, SHUT_RDWR); 185062306a36Sopenharmony_ci mutex_unlock(&nvmet_tcp_queue_mutex); 185162306a36Sopenharmony_ci} 185262306a36Sopenharmony_ci 185362306a36Sopenharmony_cistatic u16 nvmet_tcp_install_queue(struct nvmet_sq *sq) 185462306a36Sopenharmony_ci{ 185562306a36Sopenharmony_ci struct nvmet_tcp_queue *queue = 185662306a36Sopenharmony_ci container_of(sq, struct nvmet_tcp_queue, nvme_sq); 185762306a36Sopenharmony_ci 185862306a36Sopenharmony_ci if (sq->qid == 0) { 185962306a36Sopenharmony_ci /* Let inflight controller teardown complete */ 186062306a36Sopenharmony_ci flush_workqueue(nvmet_wq); 186162306a36Sopenharmony_ci } 186262306a36Sopenharmony_ci 186362306a36Sopenharmony_ci queue->nr_cmds = sq->size * 2; 186462306a36Sopenharmony_ci if (nvmet_tcp_alloc_cmds(queue)) 186562306a36Sopenharmony_ci return NVME_SC_INTERNAL; 186662306a36Sopenharmony_ci return 0; 186762306a36Sopenharmony_ci} 186862306a36Sopenharmony_ci 186962306a36Sopenharmony_cistatic void nvmet_tcp_disc_port_addr(struct nvmet_req *req, 187062306a36Sopenharmony_ci struct nvmet_port *nport, char *traddr) 187162306a36Sopenharmony_ci{ 187262306a36Sopenharmony_ci struct nvmet_tcp_port *port = nport->priv; 187362306a36Sopenharmony_ci 187462306a36Sopenharmony_ci if (inet_addr_is_any((struct sockaddr *)&port->addr)) { 187562306a36Sopenharmony_ci struct nvmet_tcp_cmd *cmd = 187662306a36Sopenharmony_ci container_of(req, struct nvmet_tcp_cmd, req); 187762306a36Sopenharmony_ci struct nvmet_tcp_queue *queue = cmd->queue; 187862306a36Sopenharmony_ci 187962306a36Sopenharmony_ci sprintf(traddr, "%pISc", (struct sockaddr *)&queue->sockaddr); 188062306a36Sopenharmony_ci } else { 188162306a36Sopenharmony_ci memcpy(traddr, nport->disc_addr.traddr, NVMF_TRADDR_SIZE); 188262306a36Sopenharmony_ci } 188362306a36Sopenharmony_ci} 188462306a36Sopenharmony_ci 188562306a36Sopenharmony_cistatic const struct nvmet_fabrics_ops nvmet_tcp_ops = { 188662306a36Sopenharmony_ci .owner = THIS_MODULE, 188762306a36Sopenharmony_ci .type = NVMF_TRTYPE_TCP, 188862306a36Sopenharmony_ci .msdbd = 1, 188962306a36Sopenharmony_ci .add_port = nvmet_tcp_add_port, 189062306a36Sopenharmony_ci .remove_port = nvmet_tcp_remove_port, 189162306a36Sopenharmony_ci .queue_response = nvmet_tcp_queue_response, 189262306a36Sopenharmony_ci .delete_ctrl = nvmet_tcp_delete_ctrl, 189362306a36Sopenharmony_ci .install_queue = nvmet_tcp_install_queue, 189462306a36Sopenharmony_ci .disc_traddr = nvmet_tcp_disc_port_addr, 189562306a36Sopenharmony_ci}; 189662306a36Sopenharmony_ci 189762306a36Sopenharmony_cistatic int __init nvmet_tcp_init(void) 189862306a36Sopenharmony_ci{ 189962306a36Sopenharmony_ci int ret; 190062306a36Sopenharmony_ci 190162306a36Sopenharmony_ci nvmet_tcp_wq = alloc_workqueue("nvmet_tcp_wq", 190262306a36Sopenharmony_ci WQ_MEM_RECLAIM | WQ_HIGHPRI, 0); 190362306a36Sopenharmony_ci if (!nvmet_tcp_wq) 190462306a36Sopenharmony_ci return -ENOMEM; 190562306a36Sopenharmony_ci 190662306a36Sopenharmony_ci ret = nvmet_register_transport(&nvmet_tcp_ops); 190762306a36Sopenharmony_ci if (ret) 190862306a36Sopenharmony_ci goto err; 190962306a36Sopenharmony_ci 191062306a36Sopenharmony_ci return 0; 191162306a36Sopenharmony_cierr: 191262306a36Sopenharmony_ci destroy_workqueue(nvmet_tcp_wq); 191362306a36Sopenharmony_ci return ret; 191462306a36Sopenharmony_ci} 191562306a36Sopenharmony_ci 191662306a36Sopenharmony_cistatic void __exit nvmet_tcp_exit(void) 191762306a36Sopenharmony_ci{ 191862306a36Sopenharmony_ci struct nvmet_tcp_queue *queue; 191962306a36Sopenharmony_ci 192062306a36Sopenharmony_ci nvmet_unregister_transport(&nvmet_tcp_ops); 192162306a36Sopenharmony_ci 192262306a36Sopenharmony_ci flush_workqueue(nvmet_wq); 192362306a36Sopenharmony_ci mutex_lock(&nvmet_tcp_queue_mutex); 192462306a36Sopenharmony_ci list_for_each_entry(queue, &nvmet_tcp_queue_list, queue_list) 192562306a36Sopenharmony_ci kernel_sock_shutdown(queue->sock, SHUT_RDWR); 192662306a36Sopenharmony_ci mutex_unlock(&nvmet_tcp_queue_mutex); 192762306a36Sopenharmony_ci flush_workqueue(nvmet_wq); 192862306a36Sopenharmony_ci 192962306a36Sopenharmony_ci destroy_workqueue(nvmet_tcp_wq); 193062306a36Sopenharmony_ci ida_destroy(&nvmet_tcp_queue_ida); 193162306a36Sopenharmony_ci} 193262306a36Sopenharmony_ci 193362306a36Sopenharmony_cimodule_init(nvmet_tcp_init); 193462306a36Sopenharmony_cimodule_exit(nvmet_tcp_exit); 193562306a36Sopenharmony_ci 193662306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 193762306a36Sopenharmony_ciMODULE_ALIAS("nvmet-transport-3"); /* 3 == NVMF_TRTYPE_TCP */ 1938