18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * NVMe over Fabrics TCP host.
48c2ecf20Sopenharmony_ci * Copyright (c) 2018 Lightbits Labs. All rights reserved.
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
78c2ecf20Sopenharmony_ci#include <linux/module.h>
88c2ecf20Sopenharmony_ci#include <linux/init.h>
98c2ecf20Sopenharmony_ci#include <linux/slab.h>
108c2ecf20Sopenharmony_ci#include <linux/err.h>
118c2ecf20Sopenharmony_ci#include <linux/nvme-tcp.h>
128c2ecf20Sopenharmony_ci#include <net/sock.h>
138c2ecf20Sopenharmony_ci#include <net/tcp.h>
148c2ecf20Sopenharmony_ci#include <linux/blk-mq.h>
158c2ecf20Sopenharmony_ci#include <crypto/hash.h>
168c2ecf20Sopenharmony_ci#include <net/busy_poll.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include "nvme.h"
198c2ecf20Sopenharmony_ci#include "fabrics.h"
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_cistruct nvme_tcp_queue;
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci/* Define the socket priority to use for connections were it is desirable
248c2ecf20Sopenharmony_ci * that the NIC consider performing optimized packet processing or filtering.
258c2ecf20Sopenharmony_ci * A non-zero value being sufficient to indicate general consideration of any
268c2ecf20Sopenharmony_ci * possible optimization.  Making it a module param allows for alternative
278c2ecf20Sopenharmony_ci * values that may be unique for some NIC implementations.
288c2ecf20Sopenharmony_ci */
298c2ecf20Sopenharmony_cistatic int so_priority;
308c2ecf20Sopenharmony_cimodule_param(so_priority, int, 0644);
318c2ecf20Sopenharmony_ciMODULE_PARM_DESC(so_priority, "nvme tcp socket optimize priority");
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_LOCK_ALLOC
348c2ecf20Sopenharmony_ci/* lockdep can detect a circular dependency of the form
358c2ecf20Sopenharmony_ci *   sk_lock -> mmap_lock (page fault) -> fs locks -> sk_lock
368c2ecf20Sopenharmony_ci * because dependencies are tracked for both nvme-tcp and user contexts. Using
378c2ecf20Sopenharmony_ci * a separate class prevents lockdep from conflating nvme-tcp socket use with
388c2ecf20Sopenharmony_ci * user-space socket API use.
398c2ecf20Sopenharmony_ci */
408c2ecf20Sopenharmony_cistatic struct lock_class_key nvme_tcp_sk_key[2];
418c2ecf20Sopenharmony_cistatic struct lock_class_key nvme_tcp_slock_key[2];
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_cistatic void nvme_tcp_reclassify_socket(struct socket *sock)
448c2ecf20Sopenharmony_ci{
458c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	if (WARN_ON_ONCE(!sock_allow_reclassification(sk)))
488c2ecf20Sopenharmony_ci		return;
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	switch (sk->sk_family) {
518c2ecf20Sopenharmony_ci	case AF_INET:
528c2ecf20Sopenharmony_ci		sock_lock_init_class_and_name(sk, "slock-AF_INET-NVME",
538c2ecf20Sopenharmony_ci					      &nvme_tcp_slock_key[0],
548c2ecf20Sopenharmony_ci					      "sk_lock-AF_INET-NVME",
558c2ecf20Sopenharmony_ci					      &nvme_tcp_sk_key[0]);
568c2ecf20Sopenharmony_ci		break;
578c2ecf20Sopenharmony_ci	case AF_INET6:
588c2ecf20Sopenharmony_ci		sock_lock_init_class_and_name(sk, "slock-AF_INET6-NVME",
598c2ecf20Sopenharmony_ci					      &nvme_tcp_slock_key[1],
608c2ecf20Sopenharmony_ci					      "sk_lock-AF_INET6-NVME",
618c2ecf20Sopenharmony_ci					      &nvme_tcp_sk_key[1]);
628c2ecf20Sopenharmony_ci		break;
638c2ecf20Sopenharmony_ci	default:
648c2ecf20Sopenharmony_ci		WARN_ON_ONCE(1);
658c2ecf20Sopenharmony_ci	}
668c2ecf20Sopenharmony_ci}
678c2ecf20Sopenharmony_ci#else
688c2ecf20Sopenharmony_cistatic void nvme_tcp_reclassify_socket(struct socket *sock) { }
698c2ecf20Sopenharmony_ci#endif
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_cienum nvme_tcp_send_state {
728c2ecf20Sopenharmony_ci	NVME_TCP_SEND_CMD_PDU = 0,
738c2ecf20Sopenharmony_ci	NVME_TCP_SEND_H2C_PDU,
748c2ecf20Sopenharmony_ci	NVME_TCP_SEND_DATA,
758c2ecf20Sopenharmony_ci	NVME_TCP_SEND_DDGST,
768c2ecf20Sopenharmony_ci};
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_cistruct nvme_tcp_request {
798c2ecf20Sopenharmony_ci	struct nvme_request	req;
808c2ecf20Sopenharmony_ci	void			*pdu;
818c2ecf20Sopenharmony_ci	struct nvme_tcp_queue	*queue;
828c2ecf20Sopenharmony_ci	u32			data_len;
838c2ecf20Sopenharmony_ci	u32			pdu_len;
848c2ecf20Sopenharmony_ci	u32			pdu_sent;
858c2ecf20Sopenharmony_ci	u16			ttag;
868c2ecf20Sopenharmony_ci	struct list_head	entry;
878c2ecf20Sopenharmony_ci	struct llist_node	lentry;
888c2ecf20Sopenharmony_ci	__le32			ddgst;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	struct bio		*curr_bio;
918c2ecf20Sopenharmony_ci	struct iov_iter		iter;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	/* send state */
948c2ecf20Sopenharmony_ci	size_t			offset;
958c2ecf20Sopenharmony_ci	size_t			data_sent;
968c2ecf20Sopenharmony_ci	enum nvme_tcp_send_state state;
978c2ecf20Sopenharmony_ci};
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_cienum nvme_tcp_queue_flags {
1008c2ecf20Sopenharmony_ci	NVME_TCP_Q_ALLOCATED	= 0,
1018c2ecf20Sopenharmony_ci	NVME_TCP_Q_LIVE		= 1,
1028c2ecf20Sopenharmony_ci	NVME_TCP_Q_POLLING	= 2,
1038c2ecf20Sopenharmony_ci};
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_cienum nvme_tcp_recv_state {
1068c2ecf20Sopenharmony_ci	NVME_TCP_RECV_PDU = 0,
1078c2ecf20Sopenharmony_ci	NVME_TCP_RECV_DATA,
1088c2ecf20Sopenharmony_ci	NVME_TCP_RECV_DDGST,
1098c2ecf20Sopenharmony_ci};
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_cistruct nvme_tcp_ctrl;
1128c2ecf20Sopenharmony_cistruct nvme_tcp_queue {
1138c2ecf20Sopenharmony_ci	struct socket		*sock;
1148c2ecf20Sopenharmony_ci	struct work_struct	io_work;
1158c2ecf20Sopenharmony_ci	int			io_cpu;
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	struct mutex		queue_lock;
1188c2ecf20Sopenharmony_ci	struct mutex		send_mutex;
1198c2ecf20Sopenharmony_ci	struct llist_head	req_list;
1208c2ecf20Sopenharmony_ci	struct list_head	send_list;
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	/* recv state */
1238c2ecf20Sopenharmony_ci	void			*pdu;
1248c2ecf20Sopenharmony_ci	int			pdu_remaining;
1258c2ecf20Sopenharmony_ci	int			pdu_offset;
1268c2ecf20Sopenharmony_ci	size_t			data_remaining;
1278c2ecf20Sopenharmony_ci	size_t			ddgst_remaining;
1288c2ecf20Sopenharmony_ci	unsigned int		nr_cqe;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	/* send state */
1318c2ecf20Sopenharmony_ci	struct nvme_tcp_request *request;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	int			queue_size;
1348c2ecf20Sopenharmony_ci	size_t			cmnd_capsule_len;
1358c2ecf20Sopenharmony_ci	struct nvme_tcp_ctrl	*ctrl;
1368c2ecf20Sopenharmony_ci	unsigned long		flags;
1378c2ecf20Sopenharmony_ci	bool			rd_enabled;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	bool			hdr_digest;
1408c2ecf20Sopenharmony_ci	bool			data_digest;
1418c2ecf20Sopenharmony_ci	struct ahash_request	*rcv_hash;
1428c2ecf20Sopenharmony_ci	struct ahash_request	*snd_hash;
1438c2ecf20Sopenharmony_ci	__le32			exp_ddgst;
1448c2ecf20Sopenharmony_ci	__le32			recv_ddgst;
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	struct page_frag_cache	pf_cache;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	void (*state_change)(struct sock *);
1498c2ecf20Sopenharmony_ci	void (*data_ready)(struct sock *);
1508c2ecf20Sopenharmony_ci	void (*write_space)(struct sock *);
1518c2ecf20Sopenharmony_ci};
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_cistruct nvme_tcp_ctrl {
1548c2ecf20Sopenharmony_ci	/* read only in the hot path */
1558c2ecf20Sopenharmony_ci	struct nvme_tcp_queue	*queues;
1568c2ecf20Sopenharmony_ci	struct blk_mq_tag_set	tag_set;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	/* other member variables */
1598c2ecf20Sopenharmony_ci	struct list_head	list;
1608c2ecf20Sopenharmony_ci	struct blk_mq_tag_set	admin_tag_set;
1618c2ecf20Sopenharmony_ci	struct sockaddr_storage addr;
1628c2ecf20Sopenharmony_ci	struct sockaddr_storage src_addr;
1638c2ecf20Sopenharmony_ci	struct nvme_ctrl	ctrl;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	struct work_struct	err_work;
1668c2ecf20Sopenharmony_ci	struct delayed_work	connect_work;
1678c2ecf20Sopenharmony_ci	struct nvme_tcp_request async_req;
1688c2ecf20Sopenharmony_ci	u32			io_queues[HCTX_MAX_TYPES];
1698c2ecf20Sopenharmony_ci};
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_cistatic LIST_HEAD(nvme_tcp_ctrl_list);
1728c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(nvme_tcp_ctrl_mutex);
1738c2ecf20Sopenharmony_cistatic struct workqueue_struct *nvme_tcp_wq;
1748c2ecf20Sopenharmony_cistatic const struct blk_mq_ops nvme_tcp_mq_ops;
1758c2ecf20Sopenharmony_cistatic const struct blk_mq_ops nvme_tcp_admin_mq_ops;
1768c2ecf20Sopenharmony_cistatic int nvme_tcp_try_send(struct nvme_tcp_queue *queue);
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_cistatic inline struct nvme_tcp_ctrl *to_tcp_ctrl(struct nvme_ctrl *ctrl)
1798c2ecf20Sopenharmony_ci{
1808c2ecf20Sopenharmony_ci	return container_of(ctrl, struct nvme_tcp_ctrl, ctrl);
1818c2ecf20Sopenharmony_ci}
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_cistatic inline int nvme_tcp_queue_id(struct nvme_tcp_queue *queue)
1848c2ecf20Sopenharmony_ci{
1858c2ecf20Sopenharmony_ci	return queue - queue->ctrl->queues;
1868c2ecf20Sopenharmony_ci}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_cistatic inline struct blk_mq_tags *nvme_tcp_tagset(struct nvme_tcp_queue *queue)
1898c2ecf20Sopenharmony_ci{
1908c2ecf20Sopenharmony_ci	u32 queue_idx = nvme_tcp_queue_id(queue);
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	if (queue_idx == 0)
1938c2ecf20Sopenharmony_ci		return queue->ctrl->admin_tag_set.tags[queue_idx];
1948c2ecf20Sopenharmony_ci	return queue->ctrl->tag_set.tags[queue_idx - 1];
1958c2ecf20Sopenharmony_ci}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_cistatic inline u8 nvme_tcp_hdgst_len(struct nvme_tcp_queue *queue)
1988c2ecf20Sopenharmony_ci{
1998c2ecf20Sopenharmony_ci	return queue->hdr_digest ? NVME_TCP_DIGEST_LENGTH : 0;
2008c2ecf20Sopenharmony_ci}
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_cistatic inline u8 nvme_tcp_ddgst_len(struct nvme_tcp_queue *queue)
2038c2ecf20Sopenharmony_ci{
2048c2ecf20Sopenharmony_ci	return queue->data_digest ? NVME_TCP_DIGEST_LENGTH : 0;
2058c2ecf20Sopenharmony_ci}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_cistatic inline size_t nvme_tcp_inline_data_size(struct nvme_tcp_queue *queue)
2088c2ecf20Sopenharmony_ci{
2098c2ecf20Sopenharmony_ci	return queue->cmnd_capsule_len - sizeof(struct nvme_command);
2108c2ecf20Sopenharmony_ci}
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_cistatic inline bool nvme_tcp_async_req(struct nvme_tcp_request *req)
2138c2ecf20Sopenharmony_ci{
2148c2ecf20Sopenharmony_ci	return req == &req->queue->ctrl->async_req;
2158c2ecf20Sopenharmony_ci}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_cistatic inline bool nvme_tcp_has_inline_data(struct nvme_tcp_request *req)
2188c2ecf20Sopenharmony_ci{
2198c2ecf20Sopenharmony_ci	struct request *rq;
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	if (unlikely(nvme_tcp_async_req(req)))
2228c2ecf20Sopenharmony_ci		return false; /* async events don't have a request */
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	rq = blk_mq_rq_from_pdu(req);
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	return rq_data_dir(rq) == WRITE && req->data_len &&
2278c2ecf20Sopenharmony_ci		req->data_len <= nvme_tcp_inline_data_size(req->queue);
2288c2ecf20Sopenharmony_ci}
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_cistatic inline struct page *nvme_tcp_req_cur_page(struct nvme_tcp_request *req)
2318c2ecf20Sopenharmony_ci{
2328c2ecf20Sopenharmony_ci	return req->iter.bvec->bv_page;
2338c2ecf20Sopenharmony_ci}
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_cistatic inline size_t nvme_tcp_req_cur_offset(struct nvme_tcp_request *req)
2368c2ecf20Sopenharmony_ci{
2378c2ecf20Sopenharmony_ci	return req->iter.bvec->bv_offset + req->iter.iov_offset;
2388c2ecf20Sopenharmony_ci}
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_cistatic inline size_t nvme_tcp_req_cur_length(struct nvme_tcp_request *req)
2418c2ecf20Sopenharmony_ci{
2428c2ecf20Sopenharmony_ci	return min_t(size_t, iov_iter_single_seg_count(&req->iter),
2438c2ecf20Sopenharmony_ci			req->pdu_len - req->pdu_sent);
2448c2ecf20Sopenharmony_ci}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_cistatic inline size_t nvme_tcp_req_offset(struct nvme_tcp_request *req)
2478c2ecf20Sopenharmony_ci{
2488c2ecf20Sopenharmony_ci	return req->iter.iov_offset;
2498c2ecf20Sopenharmony_ci}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_cistatic inline size_t nvme_tcp_pdu_data_left(struct nvme_tcp_request *req)
2528c2ecf20Sopenharmony_ci{
2538c2ecf20Sopenharmony_ci	return rq_data_dir(blk_mq_rq_from_pdu(req)) == WRITE ?
2548c2ecf20Sopenharmony_ci			req->pdu_len - req->pdu_sent : 0;
2558c2ecf20Sopenharmony_ci}
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_cistatic inline size_t nvme_tcp_pdu_last_send(struct nvme_tcp_request *req,
2588c2ecf20Sopenharmony_ci		int len)
2598c2ecf20Sopenharmony_ci{
2608c2ecf20Sopenharmony_ci	return nvme_tcp_pdu_data_left(req) <= len;
2618c2ecf20Sopenharmony_ci}
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_cistatic void nvme_tcp_init_iter(struct nvme_tcp_request *req,
2648c2ecf20Sopenharmony_ci		unsigned int dir)
2658c2ecf20Sopenharmony_ci{
2668c2ecf20Sopenharmony_ci	struct request *rq = blk_mq_rq_from_pdu(req);
2678c2ecf20Sopenharmony_ci	struct bio_vec *vec;
2688c2ecf20Sopenharmony_ci	unsigned int size;
2698c2ecf20Sopenharmony_ci	int nsegs;
2708c2ecf20Sopenharmony_ci	size_t offset;
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	if (rq->rq_flags & RQF_SPECIAL_PAYLOAD) {
2738c2ecf20Sopenharmony_ci		vec = &rq->special_vec;
2748c2ecf20Sopenharmony_ci		nsegs = 1;
2758c2ecf20Sopenharmony_ci		size = blk_rq_payload_bytes(rq);
2768c2ecf20Sopenharmony_ci		offset = 0;
2778c2ecf20Sopenharmony_ci	} else {
2788c2ecf20Sopenharmony_ci		struct bio *bio = req->curr_bio;
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci		vec = __bvec_iter_bvec(bio->bi_io_vec, bio->bi_iter);
2818c2ecf20Sopenharmony_ci		nsegs = bio_segments(bio);
2828c2ecf20Sopenharmony_ci		size = bio->bi_iter.bi_size;
2838c2ecf20Sopenharmony_ci		offset = bio->bi_iter.bi_bvec_done;
2848c2ecf20Sopenharmony_ci	}
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	iov_iter_bvec(&req->iter, dir, vec, nsegs, size);
2878c2ecf20Sopenharmony_ci	req->iter.iov_offset = offset;
2888c2ecf20Sopenharmony_ci}
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_cistatic inline void nvme_tcp_advance_req(struct nvme_tcp_request *req,
2918c2ecf20Sopenharmony_ci		int len)
2928c2ecf20Sopenharmony_ci{
2938c2ecf20Sopenharmony_ci	req->data_sent += len;
2948c2ecf20Sopenharmony_ci	req->pdu_sent += len;
2958c2ecf20Sopenharmony_ci	iov_iter_advance(&req->iter, len);
2968c2ecf20Sopenharmony_ci	if (!iov_iter_count(&req->iter) &&
2978c2ecf20Sopenharmony_ci	    req->data_sent < req->data_len) {
2988c2ecf20Sopenharmony_ci		req->curr_bio = req->curr_bio->bi_next;
2998c2ecf20Sopenharmony_ci		nvme_tcp_init_iter(req, WRITE);
3008c2ecf20Sopenharmony_ci	}
3018c2ecf20Sopenharmony_ci}
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_cistatic inline void nvme_tcp_send_all(struct nvme_tcp_queue *queue)
3048c2ecf20Sopenharmony_ci{
3058c2ecf20Sopenharmony_ci	int ret;
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	/* drain the send queue as much as we can... */
3088c2ecf20Sopenharmony_ci	do {
3098c2ecf20Sopenharmony_ci		ret = nvme_tcp_try_send(queue);
3108c2ecf20Sopenharmony_ci	} while (ret > 0);
3118c2ecf20Sopenharmony_ci}
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_cistatic inline bool nvme_tcp_queue_more(struct nvme_tcp_queue *queue)
3148c2ecf20Sopenharmony_ci{
3158c2ecf20Sopenharmony_ci	return !list_empty(&queue->send_list) ||
3168c2ecf20Sopenharmony_ci		!llist_empty(&queue->req_list);
3178c2ecf20Sopenharmony_ci}
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_cistatic inline void nvme_tcp_queue_request(struct nvme_tcp_request *req,
3208c2ecf20Sopenharmony_ci		bool sync, bool last)
3218c2ecf20Sopenharmony_ci{
3228c2ecf20Sopenharmony_ci	struct nvme_tcp_queue *queue = req->queue;
3238c2ecf20Sopenharmony_ci	bool empty;
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	empty = llist_add(&req->lentry, &queue->req_list) &&
3268c2ecf20Sopenharmony_ci		list_empty(&queue->send_list) && !queue->request;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	/*
3298c2ecf20Sopenharmony_ci	 * if we're the first on the send_list and we can try to send
3308c2ecf20Sopenharmony_ci	 * directly, otherwise queue io_work. Also, only do that if we
3318c2ecf20Sopenharmony_ci	 * are on the same cpu, so we don't introduce contention.
3328c2ecf20Sopenharmony_ci	 */
3338c2ecf20Sopenharmony_ci	if (queue->io_cpu == raw_smp_processor_id() &&
3348c2ecf20Sopenharmony_ci	    sync && empty && mutex_trylock(&queue->send_mutex)) {
3358c2ecf20Sopenharmony_ci		nvme_tcp_send_all(queue);
3368c2ecf20Sopenharmony_ci		mutex_unlock(&queue->send_mutex);
3378c2ecf20Sopenharmony_ci	}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	if (last && nvme_tcp_queue_more(queue))
3408c2ecf20Sopenharmony_ci		queue_work_on(queue->io_cpu, nvme_tcp_wq, &queue->io_work);
3418c2ecf20Sopenharmony_ci}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_cistatic void nvme_tcp_process_req_list(struct nvme_tcp_queue *queue)
3448c2ecf20Sopenharmony_ci{
3458c2ecf20Sopenharmony_ci	struct nvme_tcp_request *req;
3468c2ecf20Sopenharmony_ci	struct llist_node *node;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	for (node = llist_del_all(&queue->req_list); node; node = node->next) {
3498c2ecf20Sopenharmony_ci		req = llist_entry(node, struct nvme_tcp_request, lentry);
3508c2ecf20Sopenharmony_ci		list_add(&req->entry, &queue->send_list);
3518c2ecf20Sopenharmony_ci	}
3528c2ecf20Sopenharmony_ci}
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_cistatic inline struct nvme_tcp_request *
3558c2ecf20Sopenharmony_cinvme_tcp_fetch_request(struct nvme_tcp_queue *queue)
3568c2ecf20Sopenharmony_ci{
3578c2ecf20Sopenharmony_ci	struct nvme_tcp_request *req;
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	req = list_first_entry_or_null(&queue->send_list,
3608c2ecf20Sopenharmony_ci			struct nvme_tcp_request, entry);
3618c2ecf20Sopenharmony_ci	if (!req) {
3628c2ecf20Sopenharmony_ci		nvme_tcp_process_req_list(queue);
3638c2ecf20Sopenharmony_ci		req = list_first_entry_or_null(&queue->send_list,
3648c2ecf20Sopenharmony_ci				struct nvme_tcp_request, entry);
3658c2ecf20Sopenharmony_ci		if (unlikely(!req))
3668c2ecf20Sopenharmony_ci			return NULL;
3678c2ecf20Sopenharmony_ci	}
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	list_del(&req->entry);
3708c2ecf20Sopenharmony_ci	return req;
3718c2ecf20Sopenharmony_ci}
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_cistatic inline void nvme_tcp_ddgst_final(struct ahash_request *hash,
3748c2ecf20Sopenharmony_ci		__le32 *dgst)
3758c2ecf20Sopenharmony_ci{
3768c2ecf20Sopenharmony_ci	ahash_request_set_crypt(hash, NULL, (u8 *)dgst, 0);
3778c2ecf20Sopenharmony_ci	crypto_ahash_final(hash);
3788c2ecf20Sopenharmony_ci}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_cistatic inline void nvme_tcp_ddgst_update(struct ahash_request *hash,
3818c2ecf20Sopenharmony_ci		struct page *page, off_t off, size_t len)
3828c2ecf20Sopenharmony_ci{
3838c2ecf20Sopenharmony_ci	struct scatterlist sg;
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	sg_init_marker(&sg, 1);
3868c2ecf20Sopenharmony_ci	sg_set_page(&sg, page, len, off);
3878c2ecf20Sopenharmony_ci	ahash_request_set_crypt(hash, &sg, NULL, len);
3888c2ecf20Sopenharmony_ci	crypto_ahash_update(hash);
3898c2ecf20Sopenharmony_ci}
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_cistatic inline void nvme_tcp_hdgst(struct ahash_request *hash,
3928c2ecf20Sopenharmony_ci		void *pdu, size_t len)
3938c2ecf20Sopenharmony_ci{
3948c2ecf20Sopenharmony_ci	struct scatterlist sg;
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	sg_init_one(&sg, pdu, len);
3978c2ecf20Sopenharmony_ci	ahash_request_set_crypt(hash, &sg, pdu + len, len);
3988c2ecf20Sopenharmony_ci	crypto_ahash_digest(hash);
3998c2ecf20Sopenharmony_ci}
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_cistatic int nvme_tcp_verify_hdgst(struct nvme_tcp_queue *queue,
4028c2ecf20Sopenharmony_ci		void *pdu, size_t pdu_len)
4038c2ecf20Sopenharmony_ci{
4048c2ecf20Sopenharmony_ci	struct nvme_tcp_hdr *hdr = pdu;
4058c2ecf20Sopenharmony_ci	__le32 recv_digest;
4068c2ecf20Sopenharmony_ci	__le32 exp_digest;
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	if (unlikely(!(hdr->flags & NVME_TCP_F_HDGST))) {
4098c2ecf20Sopenharmony_ci		dev_err(queue->ctrl->ctrl.device,
4108c2ecf20Sopenharmony_ci			"queue %d: header digest flag is cleared\n",
4118c2ecf20Sopenharmony_ci			nvme_tcp_queue_id(queue));
4128c2ecf20Sopenharmony_ci		return -EPROTO;
4138c2ecf20Sopenharmony_ci	}
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	recv_digest = *(__le32 *)(pdu + hdr->hlen);
4168c2ecf20Sopenharmony_ci	nvme_tcp_hdgst(queue->rcv_hash, pdu, pdu_len);
4178c2ecf20Sopenharmony_ci	exp_digest = *(__le32 *)(pdu + hdr->hlen);
4188c2ecf20Sopenharmony_ci	if (recv_digest != exp_digest) {
4198c2ecf20Sopenharmony_ci		dev_err(queue->ctrl->ctrl.device,
4208c2ecf20Sopenharmony_ci			"header digest error: recv %#x expected %#x\n",
4218c2ecf20Sopenharmony_ci			le32_to_cpu(recv_digest), le32_to_cpu(exp_digest));
4228c2ecf20Sopenharmony_ci		return -EIO;
4238c2ecf20Sopenharmony_ci	}
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci	return 0;
4268c2ecf20Sopenharmony_ci}
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_cistatic int nvme_tcp_check_ddgst(struct nvme_tcp_queue *queue, void *pdu)
4298c2ecf20Sopenharmony_ci{
4308c2ecf20Sopenharmony_ci	struct nvme_tcp_hdr *hdr = pdu;
4318c2ecf20Sopenharmony_ci	u8 digest_len = nvme_tcp_hdgst_len(queue);
4328c2ecf20Sopenharmony_ci	u32 len;
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	len = le32_to_cpu(hdr->plen) - hdr->hlen -
4358c2ecf20Sopenharmony_ci		((hdr->flags & NVME_TCP_F_HDGST) ? digest_len : 0);
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	if (unlikely(len && !(hdr->flags & NVME_TCP_F_DDGST))) {
4388c2ecf20Sopenharmony_ci		dev_err(queue->ctrl->ctrl.device,
4398c2ecf20Sopenharmony_ci			"queue %d: data digest flag is cleared\n",
4408c2ecf20Sopenharmony_ci		nvme_tcp_queue_id(queue));
4418c2ecf20Sopenharmony_ci		return -EPROTO;
4428c2ecf20Sopenharmony_ci	}
4438c2ecf20Sopenharmony_ci	crypto_ahash_init(queue->rcv_hash);
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	return 0;
4468c2ecf20Sopenharmony_ci}
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_cistatic void nvme_tcp_exit_request(struct blk_mq_tag_set *set,
4498c2ecf20Sopenharmony_ci		struct request *rq, unsigned int hctx_idx)
4508c2ecf20Sopenharmony_ci{
4518c2ecf20Sopenharmony_ci	struct nvme_tcp_request *req = blk_mq_rq_to_pdu(rq);
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	page_frag_free(req->pdu);
4548c2ecf20Sopenharmony_ci}
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_cistatic int nvme_tcp_init_request(struct blk_mq_tag_set *set,
4578c2ecf20Sopenharmony_ci		struct request *rq, unsigned int hctx_idx,
4588c2ecf20Sopenharmony_ci		unsigned int numa_node)
4598c2ecf20Sopenharmony_ci{
4608c2ecf20Sopenharmony_ci	struct nvme_tcp_ctrl *ctrl = set->driver_data;
4618c2ecf20Sopenharmony_ci	struct nvme_tcp_request *req = blk_mq_rq_to_pdu(rq);
4628c2ecf20Sopenharmony_ci	int queue_idx = (set == &ctrl->tag_set) ? hctx_idx + 1 : 0;
4638c2ecf20Sopenharmony_ci	struct nvme_tcp_queue *queue = &ctrl->queues[queue_idx];
4648c2ecf20Sopenharmony_ci	u8 hdgst = nvme_tcp_hdgst_len(queue);
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	req->pdu = page_frag_alloc(&queue->pf_cache,
4678c2ecf20Sopenharmony_ci		sizeof(struct nvme_tcp_cmd_pdu) + hdgst,
4688c2ecf20Sopenharmony_ci		GFP_KERNEL | __GFP_ZERO);
4698c2ecf20Sopenharmony_ci	if (!req->pdu)
4708c2ecf20Sopenharmony_ci		return -ENOMEM;
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	req->queue = queue;
4738c2ecf20Sopenharmony_ci	nvme_req(rq)->ctrl = &ctrl->ctrl;
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	return 0;
4768c2ecf20Sopenharmony_ci}
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_cistatic int nvme_tcp_init_hctx(struct blk_mq_hw_ctx *hctx, void *data,
4798c2ecf20Sopenharmony_ci		unsigned int hctx_idx)
4808c2ecf20Sopenharmony_ci{
4818c2ecf20Sopenharmony_ci	struct nvme_tcp_ctrl *ctrl = data;
4828c2ecf20Sopenharmony_ci	struct nvme_tcp_queue *queue = &ctrl->queues[hctx_idx + 1];
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	hctx->driver_data = queue;
4858c2ecf20Sopenharmony_ci	return 0;
4868c2ecf20Sopenharmony_ci}
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_cistatic int nvme_tcp_init_admin_hctx(struct blk_mq_hw_ctx *hctx, void *data,
4898c2ecf20Sopenharmony_ci		unsigned int hctx_idx)
4908c2ecf20Sopenharmony_ci{
4918c2ecf20Sopenharmony_ci	struct nvme_tcp_ctrl *ctrl = data;
4928c2ecf20Sopenharmony_ci	struct nvme_tcp_queue *queue = &ctrl->queues[0];
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci	hctx->driver_data = queue;
4958c2ecf20Sopenharmony_ci	return 0;
4968c2ecf20Sopenharmony_ci}
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_cistatic enum nvme_tcp_recv_state
4998c2ecf20Sopenharmony_cinvme_tcp_recv_state(struct nvme_tcp_queue *queue)
5008c2ecf20Sopenharmony_ci{
5018c2ecf20Sopenharmony_ci	return  (queue->pdu_remaining) ? NVME_TCP_RECV_PDU :
5028c2ecf20Sopenharmony_ci		(queue->ddgst_remaining) ? NVME_TCP_RECV_DDGST :
5038c2ecf20Sopenharmony_ci		NVME_TCP_RECV_DATA;
5048c2ecf20Sopenharmony_ci}
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_cistatic void nvme_tcp_init_recv_ctx(struct nvme_tcp_queue *queue)
5078c2ecf20Sopenharmony_ci{
5088c2ecf20Sopenharmony_ci	queue->pdu_remaining = sizeof(struct nvme_tcp_rsp_pdu) +
5098c2ecf20Sopenharmony_ci				nvme_tcp_hdgst_len(queue);
5108c2ecf20Sopenharmony_ci	queue->pdu_offset = 0;
5118c2ecf20Sopenharmony_ci	queue->data_remaining = -1;
5128c2ecf20Sopenharmony_ci	queue->ddgst_remaining = 0;
5138c2ecf20Sopenharmony_ci}
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_cistatic void nvme_tcp_error_recovery(struct nvme_ctrl *ctrl)
5168c2ecf20Sopenharmony_ci{
5178c2ecf20Sopenharmony_ci	if (!nvme_change_ctrl_state(ctrl, NVME_CTRL_RESETTING))
5188c2ecf20Sopenharmony_ci		return;
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci	dev_warn(ctrl->device, "starting error recovery\n");
5218c2ecf20Sopenharmony_ci	queue_work(nvme_reset_wq, &to_tcp_ctrl(ctrl)->err_work);
5228c2ecf20Sopenharmony_ci}
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_cistatic int nvme_tcp_process_nvme_cqe(struct nvme_tcp_queue *queue,
5258c2ecf20Sopenharmony_ci		struct nvme_completion *cqe)
5268c2ecf20Sopenharmony_ci{
5278c2ecf20Sopenharmony_ci	struct request *rq;
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	rq = nvme_find_rq(nvme_tcp_tagset(queue), cqe->command_id);
5308c2ecf20Sopenharmony_ci	if (!rq) {
5318c2ecf20Sopenharmony_ci		dev_err(queue->ctrl->ctrl.device,
5328c2ecf20Sopenharmony_ci			"got bad cqe.command_id %#x on queue %d\n",
5338c2ecf20Sopenharmony_ci			cqe->command_id, nvme_tcp_queue_id(queue));
5348c2ecf20Sopenharmony_ci		nvme_tcp_error_recovery(&queue->ctrl->ctrl);
5358c2ecf20Sopenharmony_ci		return -EINVAL;
5368c2ecf20Sopenharmony_ci	}
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci	if (!nvme_try_complete_req(rq, cqe->status, cqe->result))
5398c2ecf20Sopenharmony_ci		nvme_complete_rq(rq);
5408c2ecf20Sopenharmony_ci	queue->nr_cqe++;
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci	return 0;
5438c2ecf20Sopenharmony_ci}
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_cistatic int nvme_tcp_handle_c2h_data(struct nvme_tcp_queue *queue,
5468c2ecf20Sopenharmony_ci		struct nvme_tcp_data_pdu *pdu)
5478c2ecf20Sopenharmony_ci{
5488c2ecf20Sopenharmony_ci	struct request *rq;
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	rq = nvme_find_rq(nvme_tcp_tagset(queue), pdu->command_id);
5518c2ecf20Sopenharmony_ci	if (!rq) {
5528c2ecf20Sopenharmony_ci		dev_err(queue->ctrl->ctrl.device,
5538c2ecf20Sopenharmony_ci			"got bad c2hdata.command_id %#x on queue %d\n",
5548c2ecf20Sopenharmony_ci			pdu->command_id, nvme_tcp_queue_id(queue));
5558c2ecf20Sopenharmony_ci		return -ENOENT;
5568c2ecf20Sopenharmony_ci	}
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci	if (!blk_rq_payload_bytes(rq)) {
5598c2ecf20Sopenharmony_ci		dev_err(queue->ctrl->ctrl.device,
5608c2ecf20Sopenharmony_ci			"queue %d tag %#x unexpected data\n",
5618c2ecf20Sopenharmony_ci			nvme_tcp_queue_id(queue), rq->tag);
5628c2ecf20Sopenharmony_ci		return -EIO;
5638c2ecf20Sopenharmony_ci	}
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	queue->data_remaining = le32_to_cpu(pdu->data_length);
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	if (pdu->hdr.flags & NVME_TCP_F_DATA_SUCCESS &&
5688c2ecf20Sopenharmony_ci	    unlikely(!(pdu->hdr.flags & NVME_TCP_F_DATA_LAST))) {
5698c2ecf20Sopenharmony_ci		dev_err(queue->ctrl->ctrl.device,
5708c2ecf20Sopenharmony_ci			"queue %d tag %#x SUCCESS set but not last PDU\n",
5718c2ecf20Sopenharmony_ci			nvme_tcp_queue_id(queue), rq->tag);
5728c2ecf20Sopenharmony_ci		nvme_tcp_error_recovery(&queue->ctrl->ctrl);
5738c2ecf20Sopenharmony_ci		return -EPROTO;
5748c2ecf20Sopenharmony_ci	}
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	return 0;
5778c2ecf20Sopenharmony_ci}
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_cistatic int nvme_tcp_handle_comp(struct nvme_tcp_queue *queue,
5808c2ecf20Sopenharmony_ci		struct nvme_tcp_rsp_pdu *pdu)
5818c2ecf20Sopenharmony_ci{
5828c2ecf20Sopenharmony_ci	struct nvme_completion *cqe = &pdu->cqe;
5838c2ecf20Sopenharmony_ci	int ret = 0;
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	/*
5868c2ecf20Sopenharmony_ci	 * AEN requests are special as they don't time out and can
5878c2ecf20Sopenharmony_ci	 * survive any kind of queue freeze and often don't respond to
5888c2ecf20Sopenharmony_ci	 * aborts.  We don't even bother to allocate a struct request
5898c2ecf20Sopenharmony_ci	 * for them but rather special case them here.
5908c2ecf20Sopenharmony_ci	 */
5918c2ecf20Sopenharmony_ci	if (unlikely(nvme_is_aen_req(nvme_tcp_queue_id(queue),
5928c2ecf20Sopenharmony_ci				     cqe->command_id)))
5938c2ecf20Sopenharmony_ci		nvme_complete_async_event(&queue->ctrl->ctrl, cqe->status,
5948c2ecf20Sopenharmony_ci				&cqe->result);
5958c2ecf20Sopenharmony_ci	else
5968c2ecf20Sopenharmony_ci		ret = nvme_tcp_process_nvme_cqe(queue, cqe);
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci	return ret;
5998c2ecf20Sopenharmony_ci}
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_cistatic int nvme_tcp_setup_h2c_data_pdu(struct nvme_tcp_request *req,
6028c2ecf20Sopenharmony_ci		struct nvme_tcp_r2t_pdu *pdu)
6038c2ecf20Sopenharmony_ci{
6048c2ecf20Sopenharmony_ci	struct nvme_tcp_data_pdu *data = req->pdu;
6058c2ecf20Sopenharmony_ci	struct nvme_tcp_queue *queue = req->queue;
6068c2ecf20Sopenharmony_ci	struct request *rq = blk_mq_rq_from_pdu(req);
6078c2ecf20Sopenharmony_ci	u8 hdgst = nvme_tcp_hdgst_len(queue);
6088c2ecf20Sopenharmony_ci	u8 ddgst = nvme_tcp_ddgst_len(queue);
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	req->pdu_len = le32_to_cpu(pdu->r2t_length);
6118c2ecf20Sopenharmony_ci	req->pdu_sent = 0;
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci	if (unlikely(!req->pdu_len)) {
6148c2ecf20Sopenharmony_ci		dev_err(queue->ctrl->ctrl.device,
6158c2ecf20Sopenharmony_ci			"req %d r2t len is %u, probably a bug...\n",
6168c2ecf20Sopenharmony_ci			rq->tag, req->pdu_len);
6178c2ecf20Sopenharmony_ci		return -EPROTO;
6188c2ecf20Sopenharmony_ci	}
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci	if (unlikely(req->data_sent + req->pdu_len > req->data_len)) {
6218c2ecf20Sopenharmony_ci		dev_err(queue->ctrl->ctrl.device,
6228c2ecf20Sopenharmony_ci			"req %d r2t len %u exceeded data len %u (%zu sent)\n",
6238c2ecf20Sopenharmony_ci			rq->tag, req->pdu_len, req->data_len,
6248c2ecf20Sopenharmony_ci			req->data_sent);
6258c2ecf20Sopenharmony_ci		return -EPROTO;
6268c2ecf20Sopenharmony_ci	}
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci	if (unlikely(le32_to_cpu(pdu->r2t_offset) < req->data_sent)) {
6298c2ecf20Sopenharmony_ci		dev_err(queue->ctrl->ctrl.device,
6308c2ecf20Sopenharmony_ci			"req %d unexpected r2t offset %u (expected %zu)\n",
6318c2ecf20Sopenharmony_ci			rq->tag, le32_to_cpu(pdu->r2t_offset),
6328c2ecf20Sopenharmony_ci			req->data_sent);
6338c2ecf20Sopenharmony_ci		return -EPROTO;
6348c2ecf20Sopenharmony_ci	}
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci	memset(data, 0, sizeof(*data));
6378c2ecf20Sopenharmony_ci	data->hdr.type = nvme_tcp_h2c_data;
6388c2ecf20Sopenharmony_ci	data->hdr.flags = NVME_TCP_F_DATA_LAST;
6398c2ecf20Sopenharmony_ci	if (queue->hdr_digest)
6408c2ecf20Sopenharmony_ci		data->hdr.flags |= NVME_TCP_F_HDGST;
6418c2ecf20Sopenharmony_ci	if (queue->data_digest)
6428c2ecf20Sopenharmony_ci		data->hdr.flags |= NVME_TCP_F_DDGST;
6438c2ecf20Sopenharmony_ci	data->hdr.hlen = sizeof(*data);
6448c2ecf20Sopenharmony_ci	data->hdr.pdo = data->hdr.hlen + hdgst;
6458c2ecf20Sopenharmony_ci	data->hdr.plen =
6468c2ecf20Sopenharmony_ci		cpu_to_le32(data->hdr.hlen + hdgst + req->pdu_len + ddgst);
6478c2ecf20Sopenharmony_ci	data->ttag = pdu->ttag;
6488c2ecf20Sopenharmony_ci	data->command_id = nvme_cid(rq);
6498c2ecf20Sopenharmony_ci	data->data_offset = pdu->r2t_offset;
6508c2ecf20Sopenharmony_ci	data->data_length = cpu_to_le32(req->pdu_len);
6518c2ecf20Sopenharmony_ci	return 0;
6528c2ecf20Sopenharmony_ci}
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_cistatic int nvme_tcp_handle_r2t(struct nvme_tcp_queue *queue,
6558c2ecf20Sopenharmony_ci		struct nvme_tcp_r2t_pdu *pdu)
6568c2ecf20Sopenharmony_ci{
6578c2ecf20Sopenharmony_ci	struct nvme_tcp_request *req;
6588c2ecf20Sopenharmony_ci	struct request *rq;
6598c2ecf20Sopenharmony_ci	int ret;
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_ci	rq = nvme_find_rq(nvme_tcp_tagset(queue), pdu->command_id);
6628c2ecf20Sopenharmony_ci	if (!rq) {
6638c2ecf20Sopenharmony_ci		dev_err(queue->ctrl->ctrl.device,
6648c2ecf20Sopenharmony_ci			"got bad r2t.command_id %#x on queue %d\n",
6658c2ecf20Sopenharmony_ci			pdu->command_id, nvme_tcp_queue_id(queue));
6668c2ecf20Sopenharmony_ci		return -ENOENT;
6678c2ecf20Sopenharmony_ci	}
6688c2ecf20Sopenharmony_ci	req = blk_mq_rq_to_pdu(rq);
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci	ret = nvme_tcp_setup_h2c_data_pdu(req, pdu);
6718c2ecf20Sopenharmony_ci	if (unlikely(ret))
6728c2ecf20Sopenharmony_ci		return ret;
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_ci	req->state = NVME_TCP_SEND_H2C_PDU;
6758c2ecf20Sopenharmony_ci	req->offset = 0;
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci	nvme_tcp_queue_request(req, false, true);
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci	return 0;
6808c2ecf20Sopenharmony_ci}
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_cistatic int nvme_tcp_recv_pdu(struct nvme_tcp_queue *queue, struct sk_buff *skb,
6838c2ecf20Sopenharmony_ci		unsigned int *offset, size_t *len)
6848c2ecf20Sopenharmony_ci{
6858c2ecf20Sopenharmony_ci	struct nvme_tcp_hdr *hdr;
6868c2ecf20Sopenharmony_ci	char *pdu = queue->pdu;
6878c2ecf20Sopenharmony_ci	size_t rcv_len = min_t(size_t, *len, queue->pdu_remaining);
6888c2ecf20Sopenharmony_ci	int ret;
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_ci	ret = skb_copy_bits(skb, *offset,
6918c2ecf20Sopenharmony_ci		&pdu[queue->pdu_offset], rcv_len);
6928c2ecf20Sopenharmony_ci	if (unlikely(ret))
6938c2ecf20Sopenharmony_ci		return ret;
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci	queue->pdu_remaining -= rcv_len;
6968c2ecf20Sopenharmony_ci	queue->pdu_offset += rcv_len;
6978c2ecf20Sopenharmony_ci	*offset += rcv_len;
6988c2ecf20Sopenharmony_ci	*len -= rcv_len;
6998c2ecf20Sopenharmony_ci	if (queue->pdu_remaining)
7008c2ecf20Sopenharmony_ci		return 0;
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci	hdr = queue->pdu;
7038c2ecf20Sopenharmony_ci	if (queue->hdr_digest) {
7048c2ecf20Sopenharmony_ci		ret = nvme_tcp_verify_hdgst(queue, queue->pdu, hdr->hlen);
7058c2ecf20Sopenharmony_ci		if (unlikely(ret))
7068c2ecf20Sopenharmony_ci			return ret;
7078c2ecf20Sopenharmony_ci	}
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci	if (queue->data_digest) {
7118c2ecf20Sopenharmony_ci		ret = nvme_tcp_check_ddgst(queue, queue->pdu);
7128c2ecf20Sopenharmony_ci		if (unlikely(ret))
7138c2ecf20Sopenharmony_ci			return ret;
7148c2ecf20Sopenharmony_ci	}
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_ci	switch (hdr->type) {
7178c2ecf20Sopenharmony_ci	case nvme_tcp_c2h_data:
7188c2ecf20Sopenharmony_ci		return nvme_tcp_handle_c2h_data(queue, (void *)queue->pdu);
7198c2ecf20Sopenharmony_ci	case nvme_tcp_rsp:
7208c2ecf20Sopenharmony_ci		nvme_tcp_init_recv_ctx(queue);
7218c2ecf20Sopenharmony_ci		return nvme_tcp_handle_comp(queue, (void *)queue->pdu);
7228c2ecf20Sopenharmony_ci	case nvme_tcp_r2t:
7238c2ecf20Sopenharmony_ci		nvme_tcp_init_recv_ctx(queue);
7248c2ecf20Sopenharmony_ci		return nvme_tcp_handle_r2t(queue, (void *)queue->pdu);
7258c2ecf20Sopenharmony_ci	default:
7268c2ecf20Sopenharmony_ci		dev_err(queue->ctrl->ctrl.device,
7278c2ecf20Sopenharmony_ci			"unsupported pdu type (%d)\n", hdr->type);
7288c2ecf20Sopenharmony_ci		return -EINVAL;
7298c2ecf20Sopenharmony_ci	}
7308c2ecf20Sopenharmony_ci}
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_cistatic inline void nvme_tcp_end_request(struct request *rq, u16 status)
7338c2ecf20Sopenharmony_ci{
7348c2ecf20Sopenharmony_ci	union nvme_result res = {};
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci	if (!nvme_try_complete_req(rq, cpu_to_le16(status << 1), res))
7378c2ecf20Sopenharmony_ci		nvme_complete_rq(rq);
7388c2ecf20Sopenharmony_ci}
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_cistatic int nvme_tcp_recv_data(struct nvme_tcp_queue *queue, struct sk_buff *skb,
7418c2ecf20Sopenharmony_ci			      unsigned int *offset, size_t *len)
7428c2ecf20Sopenharmony_ci{
7438c2ecf20Sopenharmony_ci	struct nvme_tcp_data_pdu *pdu = (void *)queue->pdu;
7448c2ecf20Sopenharmony_ci	struct request *rq =
7458c2ecf20Sopenharmony_ci		nvme_cid_to_rq(nvme_tcp_tagset(queue), pdu->command_id);
7468c2ecf20Sopenharmony_ci	struct nvme_tcp_request *req = blk_mq_rq_to_pdu(rq);
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci	while (true) {
7498c2ecf20Sopenharmony_ci		int recv_len, ret;
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci		recv_len = min_t(size_t, *len, queue->data_remaining);
7528c2ecf20Sopenharmony_ci		if (!recv_len)
7538c2ecf20Sopenharmony_ci			break;
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_ci		if (!iov_iter_count(&req->iter)) {
7568c2ecf20Sopenharmony_ci			req->curr_bio = req->curr_bio->bi_next;
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci			/*
7598c2ecf20Sopenharmony_ci			 * If we don`t have any bios it means that controller
7608c2ecf20Sopenharmony_ci			 * sent more data than we requested, hence error
7618c2ecf20Sopenharmony_ci			 */
7628c2ecf20Sopenharmony_ci			if (!req->curr_bio) {
7638c2ecf20Sopenharmony_ci				dev_err(queue->ctrl->ctrl.device,
7648c2ecf20Sopenharmony_ci					"queue %d no space in request %#x",
7658c2ecf20Sopenharmony_ci					nvme_tcp_queue_id(queue), rq->tag);
7668c2ecf20Sopenharmony_ci				nvme_tcp_init_recv_ctx(queue);
7678c2ecf20Sopenharmony_ci				return -EIO;
7688c2ecf20Sopenharmony_ci			}
7698c2ecf20Sopenharmony_ci			nvme_tcp_init_iter(req, READ);
7708c2ecf20Sopenharmony_ci		}
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_ci		/* we can read only from what is left in this bio */
7738c2ecf20Sopenharmony_ci		recv_len = min_t(size_t, recv_len,
7748c2ecf20Sopenharmony_ci				iov_iter_count(&req->iter));
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci		if (queue->data_digest)
7778c2ecf20Sopenharmony_ci			ret = skb_copy_and_hash_datagram_iter(skb, *offset,
7788c2ecf20Sopenharmony_ci				&req->iter, recv_len, queue->rcv_hash);
7798c2ecf20Sopenharmony_ci		else
7808c2ecf20Sopenharmony_ci			ret = skb_copy_datagram_iter(skb, *offset,
7818c2ecf20Sopenharmony_ci					&req->iter, recv_len);
7828c2ecf20Sopenharmony_ci		if (ret) {
7838c2ecf20Sopenharmony_ci			dev_err(queue->ctrl->ctrl.device,
7848c2ecf20Sopenharmony_ci				"queue %d failed to copy request %#x data",
7858c2ecf20Sopenharmony_ci				nvme_tcp_queue_id(queue), rq->tag);
7868c2ecf20Sopenharmony_ci			return ret;
7878c2ecf20Sopenharmony_ci		}
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci		*len -= recv_len;
7908c2ecf20Sopenharmony_ci		*offset += recv_len;
7918c2ecf20Sopenharmony_ci		queue->data_remaining -= recv_len;
7928c2ecf20Sopenharmony_ci	}
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci	if (!queue->data_remaining) {
7958c2ecf20Sopenharmony_ci		if (queue->data_digest) {
7968c2ecf20Sopenharmony_ci			nvme_tcp_ddgst_final(queue->rcv_hash, &queue->exp_ddgst);
7978c2ecf20Sopenharmony_ci			queue->ddgst_remaining = NVME_TCP_DIGEST_LENGTH;
7988c2ecf20Sopenharmony_ci		} else {
7998c2ecf20Sopenharmony_ci			if (pdu->hdr.flags & NVME_TCP_F_DATA_SUCCESS) {
8008c2ecf20Sopenharmony_ci				nvme_tcp_end_request(rq, NVME_SC_SUCCESS);
8018c2ecf20Sopenharmony_ci				queue->nr_cqe++;
8028c2ecf20Sopenharmony_ci			}
8038c2ecf20Sopenharmony_ci			nvme_tcp_init_recv_ctx(queue);
8048c2ecf20Sopenharmony_ci		}
8058c2ecf20Sopenharmony_ci	}
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ci	return 0;
8088c2ecf20Sopenharmony_ci}
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_cistatic int nvme_tcp_recv_ddgst(struct nvme_tcp_queue *queue,
8118c2ecf20Sopenharmony_ci		struct sk_buff *skb, unsigned int *offset, size_t *len)
8128c2ecf20Sopenharmony_ci{
8138c2ecf20Sopenharmony_ci	struct nvme_tcp_data_pdu *pdu = (void *)queue->pdu;
8148c2ecf20Sopenharmony_ci	char *ddgst = (char *)&queue->recv_ddgst;
8158c2ecf20Sopenharmony_ci	size_t recv_len = min_t(size_t, *len, queue->ddgst_remaining);
8168c2ecf20Sopenharmony_ci	off_t off = NVME_TCP_DIGEST_LENGTH - queue->ddgst_remaining;
8178c2ecf20Sopenharmony_ci	int ret;
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_ci	ret = skb_copy_bits(skb, *offset, &ddgst[off], recv_len);
8208c2ecf20Sopenharmony_ci	if (unlikely(ret))
8218c2ecf20Sopenharmony_ci		return ret;
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci	queue->ddgst_remaining -= recv_len;
8248c2ecf20Sopenharmony_ci	*offset += recv_len;
8258c2ecf20Sopenharmony_ci	*len -= recv_len;
8268c2ecf20Sopenharmony_ci	if (queue->ddgst_remaining)
8278c2ecf20Sopenharmony_ci		return 0;
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci	if (queue->recv_ddgst != queue->exp_ddgst) {
8308c2ecf20Sopenharmony_ci		dev_err(queue->ctrl->ctrl.device,
8318c2ecf20Sopenharmony_ci			"data digest error: recv %#x expected %#x\n",
8328c2ecf20Sopenharmony_ci			le32_to_cpu(queue->recv_ddgst),
8338c2ecf20Sopenharmony_ci			le32_to_cpu(queue->exp_ddgst));
8348c2ecf20Sopenharmony_ci		return -EIO;
8358c2ecf20Sopenharmony_ci	}
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci	if (pdu->hdr.flags & NVME_TCP_F_DATA_SUCCESS) {
8388c2ecf20Sopenharmony_ci		struct request *rq = nvme_cid_to_rq(nvme_tcp_tagset(queue),
8398c2ecf20Sopenharmony_ci					pdu->command_id);
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci		nvme_tcp_end_request(rq, NVME_SC_SUCCESS);
8428c2ecf20Sopenharmony_ci		queue->nr_cqe++;
8438c2ecf20Sopenharmony_ci	}
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci	nvme_tcp_init_recv_ctx(queue);
8468c2ecf20Sopenharmony_ci	return 0;
8478c2ecf20Sopenharmony_ci}
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_cistatic int nvme_tcp_recv_skb(read_descriptor_t *desc, struct sk_buff *skb,
8508c2ecf20Sopenharmony_ci			     unsigned int offset, size_t len)
8518c2ecf20Sopenharmony_ci{
8528c2ecf20Sopenharmony_ci	struct nvme_tcp_queue *queue = desc->arg.data;
8538c2ecf20Sopenharmony_ci	size_t consumed = len;
8548c2ecf20Sopenharmony_ci	int result;
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_ci	while (len) {
8578c2ecf20Sopenharmony_ci		switch (nvme_tcp_recv_state(queue)) {
8588c2ecf20Sopenharmony_ci		case NVME_TCP_RECV_PDU:
8598c2ecf20Sopenharmony_ci			result = nvme_tcp_recv_pdu(queue, skb, &offset, &len);
8608c2ecf20Sopenharmony_ci			break;
8618c2ecf20Sopenharmony_ci		case NVME_TCP_RECV_DATA:
8628c2ecf20Sopenharmony_ci			result = nvme_tcp_recv_data(queue, skb, &offset, &len);
8638c2ecf20Sopenharmony_ci			break;
8648c2ecf20Sopenharmony_ci		case NVME_TCP_RECV_DDGST:
8658c2ecf20Sopenharmony_ci			result = nvme_tcp_recv_ddgst(queue, skb, &offset, &len);
8668c2ecf20Sopenharmony_ci			break;
8678c2ecf20Sopenharmony_ci		default:
8688c2ecf20Sopenharmony_ci			result = -EFAULT;
8698c2ecf20Sopenharmony_ci		}
8708c2ecf20Sopenharmony_ci		if (result) {
8718c2ecf20Sopenharmony_ci			dev_err(queue->ctrl->ctrl.device,
8728c2ecf20Sopenharmony_ci				"receive failed:  %d\n", result);
8738c2ecf20Sopenharmony_ci			queue->rd_enabled = false;
8748c2ecf20Sopenharmony_ci			nvme_tcp_error_recovery(&queue->ctrl->ctrl);
8758c2ecf20Sopenharmony_ci			return result;
8768c2ecf20Sopenharmony_ci		}
8778c2ecf20Sopenharmony_ci	}
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci	return consumed;
8808c2ecf20Sopenharmony_ci}
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_cistatic void nvme_tcp_data_ready(struct sock *sk)
8838c2ecf20Sopenharmony_ci{
8848c2ecf20Sopenharmony_ci	struct nvme_tcp_queue *queue;
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_ci	read_lock_bh(&sk->sk_callback_lock);
8878c2ecf20Sopenharmony_ci	queue = sk->sk_user_data;
8888c2ecf20Sopenharmony_ci	if (likely(queue && queue->rd_enabled) &&
8898c2ecf20Sopenharmony_ci	    !test_bit(NVME_TCP_Q_POLLING, &queue->flags))
8908c2ecf20Sopenharmony_ci		queue_work_on(queue->io_cpu, nvme_tcp_wq, &queue->io_work);
8918c2ecf20Sopenharmony_ci	read_unlock_bh(&sk->sk_callback_lock);
8928c2ecf20Sopenharmony_ci}
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_cistatic void nvme_tcp_write_space(struct sock *sk)
8958c2ecf20Sopenharmony_ci{
8968c2ecf20Sopenharmony_ci	struct nvme_tcp_queue *queue;
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci	read_lock_bh(&sk->sk_callback_lock);
8998c2ecf20Sopenharmony_ci	queue = sk->sk_user_data;
9008c2ecf20Sopenharmony_ci	if (likely(queue && sk_stream_is_writeable(sk))) {
9018c2ecf20Sopenharmony_ci		clear_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
9028c2ecf20Sopenharmony_ci		queue_work_on(queue->io_cpu, nvme_tcp_wq, &queue->io_work);
9038c2ecf20Sopenharmony_ci	}
9048c2ecf20Sopenharmony_ci	read_unlock_bh(&sk->sk_callback_lock);
9058c2ecf20Sopenharmony_ci}
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_cistatic void nvme_tcp_state_change(struct sock *sk)
9088c2ecf20Sopenharmony_ci{
9098c2ecf20Sopenharmony_ci	struct nvme_tcp_queue *queue;
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_ci	read_lock_bh(&sk->sk_callback_lock);
9128c2ecf20Sopenharmony_ci	queue = sk->sk_user_data;
9138c2ecf20Sopenharmony_ci	if (!queue)
9148c2ecf20Sopenharmony_ci		goto done;
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ci	switch (sk->sk_state) {
9178c2ecf20Sopenharmony_ci	case TCP_CLOSE:
9188c2ecf20Sopenharmony_ci	case TCP_CLOSE_WAIT:
9198c2ecf20Sopenharmony_ci	case TCP_LAST_ACK:
9208c2ecf20Sopenharmony_ci	case TCP_FIN_WAIT1:
9218c2ecf20Sopenharmony_ci	case TCP_FIN_WAIT2:
9228c2ecf20Sopenharmony_ci		nvme_tcp_error_recovery(&queue->ctrl->ctrl);
9238c2ecf20Sopenharmony_ci		break;
9248c2ecf20Sopenharmony_ci	default:
9258c2ecf20Sopenharmony_ci		dev_info(queue->ctrl->ctrl.device,
9268c2ecf20Sopenharmony_ci			"queue %d socket state %d\n",
9278c2ecf20Sopenharmony_ci			nvme_tcp_queue_id(queue), sk->sk_state);
9288c2ecf20Sopenharmony_ci	}
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci	queue->state_change(sk);
9318c2ecf20Sopenharmony_cidone:
9328c2ecf20Sopenharmony_ci	read_unlock_bh(&sk->sk_callback_lock);
9338c2ecf20Sopenharmony_ci}
9348c2ecf20Sopenharmony_ci
9358c2ecf20Sopenharmony_cistatic inline void nvme_tcp_done_send_req(struct nvme_tcp_queue *queue)
9368c2ecf20Sopenharmony_ci{
9378c2ecf20Sopenharmony_ci	queue->request = NULL;
9388c2ecf20Sopenharmony_ci}
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_cistatic void nvme_tcp_fail_request(struct nvme_tcp_request *req)
9418c2ecf20Sopenharmony_ci{
9428c2ecf20Sopenharmony_ci	if (nvme_tcp_async_req(req)) {
9438c2ecf20Sopenharmony_ci		union nvme_result res = {};
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_ci		nvme_complete_async_event(&req->queue->ctrl->ctrl,
9468c2ecf20Sopenharmony_ci				cpu_to_le16(NVME_SC_HOST_PATH_ERROR), &res);
9478c2ecf20Sopenharmony_ci	} else {
9488c2ecf20Sopenharmony_ci		nvme_tcp_end_request(blk_mq_rq_from_pdu(req),
9498c2ecf20Sopenharmony_ci				NVME_SC_HOST_PATH_ERROR);
9508c2ecf20Sopenharmony_ci	}
9518c2ecf20Sopenharmony_ci}
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_cistatic int nvme_tcp_try_send_data(struct nvme_tcp_request *req)
9548c2ecf20Sopenharmony_ci{
9558c2ecf20Sopenharmony_ci	struct nvme_tcp_queue *queue = req->queue;
9568c2ecf20Sopenharmony_ci	int req_data_len = req->data_len;
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci	while (true) {
9598c2ecf20Sopenharmony_ci		struct page *page = nvme_tcp_req_cur_page(req);
9608c2ecf20Sopenharmony_ci		size_t offset = nvme_tcp_req_cur_offset(req);
9618c2ecf20Sopenharmony_ci		size_t len = nvme_tcp_req_cur_length(req);
9628c2ecf20Sopenharmony_ci		bool last = nvme_tcp_pdu_last_send(req, len);
9638c2ecf20Sopenharmony_ci		int req_data_sent = req->data_sent;
9648c2ecf20Sopenharmony_ci		int ret, flags = MSG_DONTWAIT;
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_ci		if (last && !queue->data_digest && !nvme_tcp_queue_more(queue))
9678c2ecf20Sopenharmony_ci			flags |= MSG_EOR;
9688c2ecf20Sopenharmony_ci		else
9698c2ecf20Sopenharmony_ci			flags |= MSG_MORE | MSG_SENDPAGE_NOTLAST;
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci		if (sendpage_ok(page)) {
9728c2ecf20Sopenharmony_ci			ret = kernel_sendpage(queue->sock, page, offset, len,
9738c2ecf20Sopenharmony_ci					flags);
9748c2ecf20Sopenharmony_ci		} else {
9758c2ecf20Sopenharmony_ci			ret = sock_no_sendpage(queue->sock, page, offset, len,
9768c2ecf20Sopenharmony_ci					flags);
9778c2ecf20Sopenharmony_ci		}
9788c2ecf20Sopenharmony_ci		if (ret <= 0)
9798c2ecf20Sopenharmony_ci			return ret;
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci		if (queue->data_digest)
9828c2ecf20Sopenharmony_ci			nvme_tcp_ddgst_update(queue->snd_hash, page,
9838c2ecf20Sopenharmony_ci					offset, ret);
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci		/*
9868c2ecf20Sopenharmony_ci		 * update the request iterator except for the last payload send
9878c2ecf20Sopenharmony_ci		 * in the request where we don't want to modify it as we may
9888c2ecf20Sopenharmony_ci		 * compete with the RX path completing the request.
9898c2ecf20Sopenharmony_ci		 */
9908c2ecf20Sopenharmony_ci		if (req_data_sent + ret < req_data_len)
9918c2ecf20Sopenharmony_ci			nvme_tcp_advance_req(req, ret);
9928c2ecf20Sopenharmony_ci
9938c2ecf20Sopenharmony_ci		/* fully successful last send in current PDU */
9948c2ecf20Sopenharmony_ci		if (last && ret == len) {
9958c2ecf20Sopenharmony_ci			if (queue->data_digest) {
9968c2ecf20Sopenharmony_ci				nvme_tcp_ddgst_final(queue->snd_hash,
9978c2ecf20Sopenharmony_ci					&req->ddgst);
9988c2ecf20Sopenharmony_ci				req->state = NVME_TCP_SEND_DDGST;
9998c2ecf20Sopenharmony_ci				req->offset = 0;
10008c2ecf20Sopenharmony_ci			} else {
10018c2ecf20Sopenharmony_ci				nvme_tcp_done_send_req(queue);
10028c2ecf20Sopenharmony_ci			}
10038c2ecf20Sopenharmony_ci			return 1;
10048c2ecf20Sopenharmony_ci		}
10058c2ecf20Sopenharmony_ci	}
10068c2ecf20Sopenharmony_ci	return -EAGAIN;
10078c2ecf20Sopenharmony_ci}
10088c2ecf20Sopenharmony_ci
10098c2ecf20Sopenharmony_cistatic int nvme_tcp_try_send_cmd_pdu(struct nvme_tcp_request *req)
10108c2ecf20Sopenharmony_ci{
10118c2ecf20Sopenharmony_ci	struct nvme_tcp_queue *queue = req->queue;
10128c2ecf20Sopenharmony_ci	struct nvme_tcp_cmd_pdu *pdu = req->pdu;
10138c2ecf20Sopenharmony_ci	bool inline_data = nvme_tcp_has_inline_data(req);
10148c2ecf20Sopenharmony_ci	u8 hdgst = nvme_tcp_hdgst_len(queue);
10158c2ecf20Sopenharmony_ci	int len = sizeof(*pdu) + hdgst - req->offset;
10168c2ecf20Sopenharmony_ci	int flags = MSG_DONTWAIT;
10178c2ecf20Sopenharmony_ci	int ret;
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_ci	if (inline_data || nvme_tcp_queue_more(queue))
10208c2ecf20Sopenharmony_ci		flags |= MSG_MORE | MSG_SENDPAGE_NOTLAST;
10218c2ecf20Sopenharmony_ci	else
10228c2ecf20Sopenharmony_ci		flags |= MSG_EOR;
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_ci	if (queue->hdr_digest && !req->offset)
10258c2ecf20Sopenharmony_ci		nvme_tcp_hdgst(queue->snd_hash, pdu, sizeof(*pdu));
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci	ret = kernel_sendpage(queue->sock, virt_to_page(pdu),
10288c2ecf20Sopenharmony_ci			offset_in_page(pdu) + req->offset, len,  flags);
10298c2ecf20Sopenharmony_ci	if (unlikely(ret <= 0))
10308c2ecf20Sopenharmony_ci		return ret;
10318c2ecf20Sopenharmony_ci
10328c2ecf20Sopenharmony_ci	len -= ret;
10338c2ecf20Sopenharmony_ci	if (!len) {
10348c2ecf20Sopenharmony_ci		if (inline_data) {
10358c2ecf20Sopenharmony_ci			req->state = NVME_TCP_SEND_DATA;
10368c2ecf20Sopenharmony_ci			if (queue->data_digest)
10378c2ecf20Sopenharmony_ci				crypto_ahash_init(queue->snd_hash);
10388c2ecf20Sopenharmony_ci			nvme_tcp_init_iter(req, WRITE);
10398c2ecf20Sopenharmony_ci		} else {
10408c2ecf20Sopenharmony_ci			nvme_tcp_done_send_req(queue);
10418c2ecf20Sopenharmony_ci		}
10428c2ecf20Sopenharmony_ci		return 1;
10438c2ecf20Sopenharmony_ci	}
10448c2ecf20Sopenharmony_ci	req->offset += ret;
10458c2ecf20Sopenharmony_ci
10468c2ecf20Sopenharmony_ci	return -EAGAIN;
10478c2ecf20Sopenharmony_ci}
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_cistatic int nvme_tcp_try_send_data_pdu(struct nvme_tcp_request *req)
10508c2ecf20Sopenharmony_ci{
10518c2ecf20Sopenharmony_ci	struct nvme_tcp_queue *queue = req->queue;
10528c2ecf20Sopenharmony_ci	struct nvme_tcp_data_pdu *pdu = req->pdu;
10538c2ecf20Sopenharmony_ci	u8 hdgst = nvme_tcp_hdgst_len(queue);
10548c2ecf20Sopenharmony_ci	int len = sizeof(*pdu) - req->offset + hdgst;
10558c2ecf20Sopenharmony_ci	int ret;
10568c2ecf20Sopenharmony_ci
10578c2ecf20Sopenharmony_ci	if (queue->hdr_digest && !req->offset)
10588c2ecf20Sopenharmony_ci		nvme_tcp_hdgst(queue->snd_hash, pdu, sizeof(*pdu));
10598c2ecf20Sopenharmony_ci
10608c2ecf20Sopenharmony_ci	ret = kernel_sendpage(queue->sock, virt_to_page(pdu),
10618c2ecf20Sopenharmony_ci			offset_in_page(pdu) + req->offset, len,
10628c2ecf20Sopenharmony_ci			MSG_DONTWAIT | MSG_MORE | MSG_SENDPAGE_NOTLAST);
10638c2ecf20Sopenharmony_ci	if (unlikely(ret <= 0))
10648c2ecf20Sopenharmony_ci		return ret;
10658c2ecf20Sopenharmony_ci
10668c2ecf20Sopenharmony_ci	len -= ret;
10678c2ecf20Sopenharmony_ci	if (!len) {
10688c2ecf20Sopenharmony_ci		req->state = NVME_TCP_SEND_DATA;
10698c2ecf20Sopenharmony_ci		if (queue->data_digest)
10708c2ecf20Sopenharmony_ci			crypto_ahash_init(queue->snd_hash);
10718c2ecf20Sopenharmony_ci		if (!req->data_sent)
10728c2ecf20Sopenharmony_ci			nvme_tcp_init_iter(req, WRITE);
10738c2ecf20Sopenharmony_ci		return 1;
10748c2ecf20Sopenharmony_ci	}
10758c2ecf20Sopenharmony_ci	req->offset += ret;
10768c2ecf20Sopenharmony_ci
10778c2ecf20Sopenharmony_ci	return -EAGAIN;
10788c2ecf20Sopenharmony_ci}
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_cistatic int nvme_tcp_try_send_ddgst(struct nvme_tcp_request *req)
10818c2ecf20Sopenharmony_ci{
10828c2ecf20Sopenharmony_ci	struct nvme_tcp_queue *queue = req->queue;
10838c2ecf20Sopenharmony_ci	size_t offset = req->offset;
10848c2ecf20Sopenharmony_ci	int ret;
10858c2ecf20Sopenharmony_ci	struct msghdr msg = { .msg_flags = MSG_DONTWAIT };
10868c2ecf20Sopenharmony_ci	struct kvec iov = {
10878c2ecf20Sopenharmony_ci		.iov_base = (u8 *)&req->ddgst + req->offset,
10888c2ecf20Sopenharmony_ci		.iov_len = NVME_TCP_DIGEST_LENGTH - req->offset
10898c2ecf20Sopenharmony_ci	};
10908c2ecf20Sopenharmony_ci
10918c2ecf20Sopenharmony_ci	if (nvme_tcp_queue_more(queue))
10928c2ecf20Sopenharmony_ci		msg.msg_flags |= MSG_MORE;
10938c2ecf20Sopenharmony_ci	else
10948c2ecf20Sopenharmony_ci		msg.msg_flags |= MSG_EOR;
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_ci	ret = kernel_sendmsg(queue->sock, &msg, &iov, 1, iov.iov_len);
10978c2ecf20Sopenharmony_ci	if (unlikely(ret <= 0))
10988c2ecf20Sopenharmony_ci		return ret;
10998c2ecf20Sopenharmony_ci
11008c2ecf20Sopenharmony_ci	if (offset + ret == NVME_TCP_DIGEST_LENGTH) {
11018c2ecf20Sopenharmony_ci		nvme_tcp_done_send_req(queue);
11028c2ecf20Sopenharmony_ci		return 1;
11038c2ecf20Sopenharmony_ci	}
11048c2ecf20Sopenharmony_ci
11058c2ecf20Sopenharmony_ci	req->offset += ret;
11068c2ecf20Sopenharmony_ci	return -EAGAIN;
11078c2ecf20Sopenharmony_ci}
11088c2ecf20Sopenharmony_ci
11098c2ecf20Sopenharmony_cistatic int nvme_tcp_try_send(struct nvme_tcp_queue *queue)
11108c2ecf20Sopenharmony_ci{
11118c2ecf20Sopenharmony_ci	struct nvme_tcp_request *req;
11128c2ecf20Sopenharmony_ci	int ret = 1;
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_ci	if (!queue->request) {
11158c2ecf20Sopenharmony_ci		queue->request = nvme_tcp_fetch_request(queue);
11168c2ecf20Sopenharmony_ci		if (!queue->request)
11178c2ecf20Sopenharmony_ci			return 0;
11188c2ecf20Sopenharmony_ci	}
11198c2ecf20Sopenharmony_ci	req = queue->request;
11208c2ecf20Sopenharmony_ci
11218c2ecf20Sopenharmony_ci	if (req->state == NVME_TCP_SEND_CMD_PDU) {
11228c2ecf20Sopenharmony_ci		ret = nvme_tcp_try_send_cmd_pdu(req);
11238c2ecf20Sopenharmony_ci		if (ret <= 0)
11248c2ecf20Sopenharmony_ci			goto done;
11258c2ecf20Sopenharmony_ci		if (!nvme_tcp_has_inline_data(req))
11268c2ecf20Sopenharmony_ci			return ret;
11278c2ecf20Sopenharmony_ci	}
11288c2ecf20Sopenharmony_ci
11298c2ecf20Sopenharmony_ci	if (req->state == NVME_TCP_SEND_H2C_PDU) {
11308c2ecf20Sopenharmony_ci		ret = nvme_tcp_try_send_data_pdu(req);
11318c2ecf20Sopenharmony_ci		if (ret <= 0)
11328c2ecf20Sopenharmony_ci			goto done;
11338c2ecf20Sopenharmony_ci	}
11348c2ecf20Sopenharmony_ci
11358c2ecf20Sopenharmony_ci	if (req->state == NVME_TCP_SEND_DATA) {
11368c2ecf20Sopenharmony_ci		ret = nvme_tcp_try_send_data(req);
11378c2ecf20Sopenharmony_ci		if (ret <= 0)
11388c2ecf20Sopenharmony_ci			goto done;
11398c2ecf20Sopenharmony_ci	}
11408c2ecf20Sopenharmony_ci
11418c2ecf20Sopenharmony_ci	if (req->state == NVME_TCP_SEND_DDGST)
11428c2ecf20Sopenharmony_ci		ret = nvme_tcp_try_send_ddgst(req);
11438c2ecf20Sopenharmony_cidone:
11448c2ecf20Sopenharmony_ci	if (ret == -EAGAIN) {
11458c2ecf20Sopenharmony_ci		ret = 0;
11468c2ecf20Sopenharmony_ci	} else if (ret < 0) {
11478c2ecf20Sopenharmony_ci		dev_err(queue->ctrl->ctrl.device,
11488c2ecf20Sopenharmony_ci			"failed to send request %d\n", ret);
11498c2ecf20Sopenharmony_ci		nvme_tcp_fail_request(queue->request);
11508c2ecf20Sopenharmony_ci		nvme_tcp_done_send_req(queue);
11518c2ecf20Sopenharmony_ci	}
11528c2ecf20Sopenharmony_ci	return ret;
11538c2ecf20Sopenharmony_ci}
11548c2ecf20Sopenharmony_ci
11558c2ecf20Sopenharmony_cistatic int nvme_tcp_try_recv(struct nvme_tcp_queue *queue)
11568c2ecf20Sopenharmony_ci{
11578c2ecf20Sopenharmony_ci	struct socket *sock = queue->sock;
11588c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
11598c2ecf20Sopenharmony_ci	read_descriptor_t rd_desc;
11608c2ecf20Sopenharmony_ci	int consumed;
11618c2ecf20Sopenharmony_ci
11628c2ecf20Sopenharmony_ci	rd_desc.arg.data = queue;
11638c2ecf20Sopenharmony_ci	rd_desc.count = 1;
11648c2ecf20Sopenharmony_ci	lock_sock(sk);
11658c2ecf20Sopenharmony_ci	queue->nr_cqe = 0;
11668c2ecf20Sopenharmony_ci	consumed = sock->ops->read_sock(sk, &rd_desc, nvme_tcp_recv_skb);
11678c2ecf20Sopenharmony_ci	release_sock(sk);
11688c2ecf20Sopenharmony_ci	return consumed;
11698c2ecf20Sopenharmony_ci}
11708c2ecf20Sopenharmony_ci
11718c2ecf20Sopenharmony_cistatic void nvme_tcp_io_work(struct work_struct *w)
11728c2ecf20Sopenharmony_ci{
11738c2ecf20Sopenharmony_ci	struct nvme_tcp_queue *queue =
11748c2ecf20Sopenharmony_ci		container_of(w, struct nvme_tcp_queue, io_work);
11758c2ecf20Sopenharmony_ci	unsigned long deadline = jiffies + msecs_to_jiffies(1);
11768c2ecf20Sopenharmony_ci
11778c2ecf20Sopenharmony_ci	do {
11788c2ecf20Sopenharmony_ci		bool pending = false;
11798c2ecf20Sopenharmony_ci		int result;
11808c2ecf20Sopenharmony_ci
11818c2ecf20Sopenharmony_ci		if (mutex_trylock(&queue->send_mutex)) {
11828c2ecf20Sopenharmony_ci			result = nvme_tcp_try_send(queue);
11838c2ecf20Sopenharmony_ci			mutex_unlock(&queue->send_mutex);
11848c2ecf20Sopenharmony_ci			if (result > 0)
11858c2ecf20Sopenharmony_ci				pending = true;
11868c2ecf20Sopenharmony_ci			else if (unlikely(result < 0))
11878c2ecf20Sopenharmony_ci				break;
11888c2ecf20Sopenharmony_ci		}
11898c2ecf20Sopenharmony_ci
11908c2ecf20Sopenharmony_ci		result = nvme_tcp_try_recv(queue);
11918c2ecf20Sopenharmony_ci		if (result > 0)
11928c2ecf20Sopenharmony_ci			pending = true;
11938c2ecf20Sopenharmony_ci		else if (unlikely(result < 0))
11948c2ecf20Sopenharmony_ci			return;
11958c2ecf20Sopenharmony_ci
11968c2ecf20Sopenharmony_ci		if (!pending || !queue->rd_enabled)
11978c2ecf20Sopenharmony_ci			return;
11988c2ecf20Sopenharmony_ci
11998c2ecf20Sopenharmony_ci	} while (!time_after(jiffies, deadline)); /* quota is exhausted */
12008c2ecf20Sopenharmony_ci
12018c2ecf20Sopenharmony_ci	queue_work_on(queue->io_cpu, nvme_tcp_wq, &queue->io_work);
12028c2ecf20Sopenharmony_ci}
12038c2ecf20Sopenharmony_ci
12048c2ecf20Sopenharmony_cistatic void nvme_tcp_free_crypto(struct nvme_tcp_queue *queue)
12058c2ecf20Sopenharmony_ci{
12068c2ecf20Sopenharmony_ci	struct crypto_ahash *tfm = crypto_ahash_reqtfm(queue->rcv_hash);
12078c2ecf20Sopenharmony_ci
12088c2ecf20Sopenharmony_ci	ahash_request_free(queue->rcv_hash);
12098c2ecf20Sopenharmony_ci	ahash_request_free(queue->snd_hash);
12108c2ecf20Sopenharmony_ci	crypto_free_ahash(tfm);
12118c2ecf20Sopenharmony_ci}
12128c2ecf20Sopenharmony_ci
12138c2ecf20Sopenharmony_cistatic int nvme_tcp_alloc_crypto(struct nvme_tcp_queue *queue)
12148c2ecf20Sopenharmony_ci{
12158c2ecf20Sopenharmony_ci	struct crypto_ahash *tfm;
12168c2ecf20Sopenharmony_ci
12178c2ecf20Sopenharmony_ci	tfm = crypto_alloc_ahash("crc32c", 0, CRYPTO_ALG_ASYNC);
12188c2ecf20Sopenharmony_ci	if (IS_ERR(tfm))
12198c2ecf20Sopenharmony_ci		return PTR_ERR(tfm);
12208c2ecf20Sopenharmony_ci
12218c2ecf20Sopenharmony_ci	queue->snd_hash = ahash_request_alloc(tfm, GFP_KERNEL);
12228c2ecf20Sopenharmony_ci	if (!queue->snd_hash)
12238c2ecf20Sopenharmony_ci		goto free_tfm;
12248c2ecf20Sopenharmony_ci	ahash_request_set_callback(queue->snd_hash, 0, NULL, NULL);
12258c2ecf20Sopenharmony_ci
12268c2ecf20Sopenharmony_ci	queue->rcv_hash = ahash_request_alloc(tfm, GFP_KERNEL);
12278c2ecf20Sopenharmony_ci	if (!queue->rcv_hash)
12288c2ecf20Sopenharmony_ci		goto free_snd_hash;
12298c2ecf20Sopenharmony_ci	ahash_request_set_callback(queue->rcv_hash, 0, NULL, NULL);
12308c2ecf20Sopenharmony_ci
12318c2ecf20Sopenharmony_ci	return 0;
12328c2ecf20Sopenharmony_cifree_snd_hash:
12338c2ecf20Sopenharmony_ci	ahash_request_free(queue->snd_hash);
12348c2ecf20Sopenharmony_cifree_tfm:
12358c2ecf20Sopenharmony_ci	crypto_free_ahash(tfm);
12368c2ecf20Sopenharmony_ci	return -ENOMEM;
12378c2ecf20Sopenharmony_ci}
12388c2ecf20Sopenharmony_ci
12398c2ecf20Sopenharmony_cistatic void nvme_tcp_free_async_req(struct nvme_tcp_ctrl *ctrl)
12408c2ecf20Sopenharmony_ci{
12418c2ecf20Sopenharmony_ci	struct nvme_tcp_request *async = &ctrl->async_req;
12428c2ecf20Sopenharmony_ci
12438c2ecf20Sopenharmony_ci	page_frag_free(async->pdu);
12448c2ecf20Sopenharmony_ci}
12458c2ecf20Sopenharmony_ci
12468c2ecf20Sopenharmony_cistatic int nvme_tcp_alloc_async_req(struct nvme_tcp_ctrl *ctrl)
12478c2ecf20Sopenharmony_ci{
12488c2ecf20Sopenharmony_ci	struct nvme_tcp_queue *queue = &ctrl->queues[0];
12498c2ecf20Sopenharmony_ci	struct nvme_tcp_request *async = &ctrl->async_req;
12508c2ecf20Sopenharmony_ci	u8 hdgst = nvme_tcp_hdgst_len(queue);
12518c2ecf20Sopenharmony_ci
12528c2ecf20Sopenharmony_ci	async->pdu = page_frag_alloc(&queue->pf_cache,
12538c2ecf20Sopenharmony_ci		sizeof(struct nvme_tcp_cmd_pdu) + hdgst,
12548c2ecf20Sopenharmony_ci		GFP_KERNEL | __GFP_ZERO);
12558c2ecf20Sopenharmony_ci	if (!async->pdu)
12568c2ecf20Sopenharmony_ci		return -ENOMEM;
12578c2ecf20Sopenharmony_ci
12588c2ecf20Sopenharmony_ci	async->queue = &ctrl->queues[0];
12598c2ecf20Sopenharmony_ci	return 0;
12608c2ecf20Sopenharmony_ci}
12618c2ecf20Sopenharmony_ci
12628c2ecf20Sopenharmony_cistatic void nvme_tcp_free_queue(struct nvme_ctrl *nctrl, int qid)
12638c2ecf20Sopenharmony_ci{
12648c2ecf20Sopenharmony_ci	struct nvme_tcp_ctrl *ctrl = to_tcp_ctrl(nctrl);
12658c2ecf20Sopenharmony_ci	struct nvme_tcp_queue *queue = &ctrl->queues[qid];
12668c2ecf20Sopenharmony_ci
12678c2ecf20Sopenharmony_ci	if (!test_and_clear_bit(NVME_TCP_Q_ALLOCATED, &queue->flags))
12688c2ecf20Sopenharmony_ci		return;
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_ci	if (queue->hdr_digest || queue->data_digest)
12718c2ecf20Sopenharmony_ci		nvme_tcp_free_crypto(queue);
12728c2ecf20Sopenharmony_ci
12738c2ecf20Sopenharmony_ci	sock_release(queue->sock);
12748c2ecf20Sopenharmony_ci	kfree(queue->pdu);
12758c2ecf20Sopenharmony_ci	mutex_destroy(&queue->queue_lock);
12768c2ecf20Sopenharmony_ci}
12778c2ecf20Sopenharmony_ci
12788c2ecf20Sopenharmony_cistatic int nvme_tcp_init_connection(struct nvme_tcp_queue *queue)
12798c2ecf20Sopenharmony_ci{
12808c2ecf20Sopenharmony_ci	struct nvme_tcp_icreq_pdu *icreq;
12818c2ecf20Sopenharmony_ci	struct nvme_tcp_icresp_pdu *icresp;
12828c2ecf20Sopenharmony_ci	struct msghdr msg = {};
12838c2ecf20Sopenharmony_ci	struct kvec iov;
12848c2ecf20Sopenharmony_ci	bool ctrl_hdgst, ctrl_ddgst;
12858c2ecf20Sopenharmony_ci	int ret;
12868c2ecf20Sopenharmony_ci
12878c2ecf20Sopenharmony_ci	icreq = kzalloc(sizeof(*icreq), GFP_KERNEL);
12888c2ecf20Sopenharmony_ci	if (!icreq)
12898c2ecf20Sopenharmony_ci		return -ENOMEM;
12908c2ecf20Sopenharmony_ci
12918c2ecf20Sopenharmony_ci	icresp = kzalloc(sizeof(*icresp), GFP_KERNEL);
12928c2ecf20Sopenharmony_ci	if (!icresp) {
12938c2ecf20Sopenharmony_ci		ret = -ENOMEM;
12948c2ecf20Sopenharmony_ci		goto free_icreq;
12958c2ecf20Sopenharmony_ci	}
12968c2ecf20Sopenharmony_ci
12978c2ecf20Sopenharmony_ci	icreq->hdr.type = nvme_tcp_icreq;
12988c2ecf20Sopenharmony_ci	icreq->hdr.hlen = sizeof(*icreq);
12998c2ecf20Sopenharmony_ci	icreq->hdr.pdo = 0;
13008c2ecf20Sopenharmony_ci	icreq->hdr.plen = cpu_to_le32(icreq->hdr.hlen);
13018c2ecf20Sopenharmony_ci	icreq->pfv = cpu_to_le16(NVME_TCP_PFV_1_0);
13028c2ecf20Sopenharmony_ci	icreq->maxr2t = 0; /* single inflight r2t supported */
13038c2ecf20Sopenharmony_ci	icreq->hpda = 0; /* no alignment constraint */
13048c2ecf20Sopenharmony_ci	if (queue->hdr_digest)
13058c2ecf20Sopenharmony_ci		icreq->digest |= NVME_TCP_HDR_DIGEST_ENABLE;
13068c2ecf20Sopenharmony_ci	if (queue->data_digest)
13078c2ecf20Sopenharmony_ci		icreq->digest |= NVME_TCP_DATA_DIGEST_ENABLE;
13088c2ecf20Sopenharmony_ci
13098c2ecf20Sopenharmony_ci	iov.iov_base = icreq;
13108c2ecf20Sopenharmony_ci	iov.iov_len = sizeof(*icreq);
13118c2ecf20Sopenharmony_ci	ret = kernel_sendmsg(queue->sock, &msg, &iov, 1, iov.iov_len);
13128c2ecf20Sopenharmony_ci	if (ret < 0)
13138c2ecf20Sopenharmony_ci		goto free_icresp;
13148c2ecf20Sopenharmony_ci
13158c2ecf20Sopenharmony_ci	memset(&msg, 0, sizeof(msg));
13168c2ecf20Sopenharmony_ci	iov.iov_base = icresp;
13178c2ecf20Sopenharmony_ci	iov.iov_len = sizeof(*icresp);
13188c2ecf20Sopenharmony_ci	ret = kernel_recvmsg(queue->sock, &msg, &iov, 1,
13198c2ecf20Sopenharmony_ci			iov.iov_len, msg.msg_flags);
13208c2ecf20Sopenharmony_ci	if (ret < 0)
13218c2ecf20Sopenharmony_ci		goto free_icresp;
13228c2ecf20Sopenharmony_ci
13238c2ecf20Sopenharmony_ci	ret = -EINVAL;
13248c2ecf20Sopenharmony_ci	if (icresp->hdr.type != nvme_tcp_icresp) {
13258c2ecf20Sopenharmony_ci		pr_err("queue %d: bad type returned %d\n",
13268c2ecf20Sopenharmony_ci			nvme_tcp_queue_id(queue), icresp->hdr.type);
13278c2ecf20Sopenharmony_ci		goto free_icresp;
13288c2ecf20Sopenharmony_ci	}
13298c2ecf20Sopenharmony_ci
13308c2ecf20Sopenharmony_ci	if (le32_to_cpu(icresp->hdr.plen) != sizeof(*icresp)) {
13318c2ecf20Sopenharmony_ci		pr_err("queue %d: bad pdu length returned %d\n",
13328c2ecf20Sopenharmony_ci			nvme_tcp_queue_id(queue), icresp->hdr.plen);
13338c2ecf20Sopenharmony_ci		goto free_icresp;
13348c2ecf20Sopenharmony_ci	}
13358c2ecf20Sopenharmony_ci
13368c2ecf20Sopenharmony_ci	if (icresp->pfv != NVME_TCP_PFV_1_0) {
13378c2ecf20Sopenharmony_ci		pr_err("queue %d: bad pfv returned %d\n",
13388c2ecf20Sopenharmony_ci			nvme_tcp_queue_id(queue), icresp->pfv);
13398c2ecf20Sopenharmony_ci		goto free_icresp;
13408c2ecf20Sopenharmony_ci	}
13418c2ecf20Sopenharmony_ci
13428c2ecf20Sopenharmony_ci	ctrl_ddgst = !!(icresp->digest & NVME_TCP_DATA_DIGEST_ENABLE);
13438c2ecf20Sopenharmony_ci	if ((queue->data_digest && !ctrl_ddgst) ||
13448c2ecf20Sopenharmony_ci	    (!queue->data_digest && ctrl_ddgst)) {
13458c2ecf20Sopenharmony_ci		pr_err("queue %d: data digest mismatch host: %s ctrl: %s\n",
13468c2ecf20Sopenharmony_ci			nvme_tcp_queue_id(queue),
13478c2ecf20Sopenharmony_ci			queue->data_digest ? "enabled" : "disabled",
13488c2ecf20Sopenharmony_ci			ctrl_ddgst ? "enabled" : "disabled");
13498c2ecf20Sopenharmony_ci		goto free_icresp;
13508c2ecf20Sopenharmony_ci	}
13518c2ecf20Sopenharmony_ci
13528c2ecf20Sopenharmony_ci	ctrl_hdgst = !!(icresp->digest & NVME_TCP_HDR_DIGEST_ENABLE);
13538c2ecf20Sopenharmony_ci	if ((queue->hdr_digest && !ctrl_hdgst) ||
13548c2ecf20Sopenharmony_ci	    (!queue->hdr_digest && ctrl_hdgst)) {
13558c2ecf20Sopenharmony_ci		pr_err("queue %d: header digest mismatch host: %s ctrl: %s\n",
13568c2ecf20Sopenharmony_ci			nvme_tcp_queue_id(queue),
13578c2ecf20Sopenharmony_ci			queue->hdr_digest ? "enabled" : "disabled",
13588c2ecf20Sopenharmony_ci			ctrl_hdgst ? "enabled" : "disabled");
13598c2ecf20Sopenharmony_ci		goto free_icresp;
13608c2ecf20Sopenharmony_ci	}
13618c2ecf20Sopenharmony_ci
13628c2ecf20Sopenharmony_ci	if (icresp->cpda != 0) {
13638c2ecf20Sopenharmony_ci		pr_err("queue %d: unsupported cpda returned %d\n",
13648c2ecf20Sopenharmony_ci			nvme_tcp_queue_id(queue), icresp->cpda);
13658c2ecf20Sopenharmony_ci		goto free_icresp;
13668c2ecf20Sopenharmony_ci	}
13678c2ecf20Sopenharmony_ci
13688c2ecf20Sopenharmony_ci	ret = 0;
13698c2ecf20Sopenharmony_cifree_icresp:
13708c2ecf20Sopenharmony_ci	kfree(icresp);
13718c2ecf20Sopenharmony_cifree_icreq:
13728c2ecf20Sopenharmony_ci	kfree(icreq);
13738c2ecf20Sopenharmony_ci	return ret;
13748c2ecf20Sopenharmony_ci}
13758c2ecf20Sopenharmony_ci
13768c2ecf20Sopenharmony_cistatic bool nvme_tcp_admin_queue(struct nvme_tcp_queue *queue)
13778c2ecf20Sopenharmony_ci{
13788c2ecf20Sopenharmony_ci	return nvme_tcp_queue_id(queue) == 0;
13798c2ecf20Sopenharmony_ci}
13808c2ecf20Sopenharmony_ci
13818c2ecf20Sopenharmony_cistatic bool nvme_tcp_default_queue(struct nvme_tcp_queue *queue)
13828c2ecf20Sopenharmony_ci{
13838c2ecf20Sopenharmony_ci	struct nvme_tcp_ctrl *ctrl = queue->ctrl;
13848c2ecf20Sopenharmony_ci	int qid = nvme_tcp_queue_id(queue);
13858c2ecf20Sopenharmony_ci
13868c2ecf20Sopenharmony_ci	return !nvme_tcp_admin_queue(queue) &&
13878c2ecf20Sopenharmony_ci		qid < 1 + ctrl->io_queues[HCTX_TYPE_DEFAULT];
13888c2ecf20Sopenharmony_ci}
13898c2ecf20Sopenharmony_ci
13908c2ecf20Sopenharmony_cistatic bool nvme_tcp_read_queue(struct nvme_tcp_queue *queue)
13918c2ecf20Sopenharmony_ci{
13928c2ecf20Sopenharmony_ci	struct nvme_tcp_ctrl *ctrl = queue->ctrl;
13938c2ecf20Sopenharmony_ci	int qid = nvme_tcp_queue_id(queue);
13948c2ecf20Sopenharmony_ci
13958c2ecf20Sopenharmony_ci	return !nvme_tcp_admin_queue(queue) &&
13968c2ecf20Sopenharmony_ci		!nvme_tcp_default_queue(queue) &&
13978c2ecf20Sopenharmony_ci		qid < 1 + ctrl->io_queues[HCTX_TYPE_DEFAULT] +
13988c2ecf20Sopenharmony_ci			  ctrl->io_queues[HCTX_TYPE_READ];
13998c2ecf20Sopenharmony_ci}
14008c2ecf20Sopenharmony_ci
14018c2ecf20Sopenharmony_cistatic bool nvme_tcp_poll_queue(struct nvme_tcp_queue *queue)
14028c2ecf20Sopenharmony_ci{
14038c2ecf20Sopenharmony_ci	struct nvme_tcp_ctrl *ctrl = queue->ctrl;
14048c2ecf20Sopenharmony_ci	int qid = nvme_tcp_queue_id(queue);
14058c2ecf20Sopenharmony_ci
14068c2ecf20Sopenharmony_ci	return !nvme_tcp_admin_queue(queue) &&
14078c2ecf20Sopenharmony_ci		!nvme_tcp_default_queue(queue) &&
14088c2ecf20Sopenharmony_ci		!nvme_tcp_read_queue(queue) &&
14098c2ecf20Sopenharmony_ci		qid < 1 + ctrl->io_queues[HCTX_TYPE_DEFAULT] +
14108c2ecf20Sopenharmony_ci			  ctrl->io_queues[HCTX_TYPE_READ] +
14118c2ecf20Sopenharmony_ci			  ctrl->io_queues[HCTX_TYPE_POLL];
14128c2ecf20Sopenharmony_ci}
14138c2ecf20Sopenharmony_ci
14148c2ecf20Sopenharmony_cistatic void nvme_tcp_set_queue_io_cpu(struct nvme_tcp_queue *queue)
14158c2ecf20Sopenharmony_ci{
14168c2ecf20Sopenharmony_ci	struct nvme_tcp_ctrl *ctrl = queue->ctrl;
14178c2ecf20Sopenharmony_ci	int qid = nvme_tcp_queue_id(queue);
14188c2ecf20Sopenharmony_ci	int n = 0;
14198c2ecf20Sopenharmony_ci
14208c2ecf20Sopenharmony_ci	if (nvme_tcp_default_queue(queue))
14218c2ecf20Sopenharmony_ci		n = qid - 1;
14228c2ecf20Sopenharmony_ci	else if (nvme_tcp_read_queue(queue))
14238c2ecf20Sopenharmony_ci		n = qid - ctrl->io_queues[HCTX_TYPE_DEFAULT] - 1;
14248c2ecf20Sopenharmony_ci	else if (nvme_tcp_poll_queue(queue))
14258c2ecf20Sopenharmony_ci		n = qid - ctrl->io_queues[HCTX_TYPE_DEFAULT] -
14268c2ecf20Sopenharmony_ci				ctrl->io_queues[HCTX_TYPE_READ] - 1;
14278c2ecf20Sopenharmony_ci	queue->io_cpu = cpumask_next_wrap(n - 1, cpu_online_mask, -1, false);
14288c2ecf20Sopenharmony_ci}
14298c2ecf20Sopenharmony_ci
14308c2ecf20Sopenharmony_cistatic int nvme_tcp_alloc_queue(struct nvme_ctrl *nctrl,
14318c2ecf20Sopenharmony_ci		int qid, size_t queue_size)
14328c2ecf20Sopenharmony_ci{
14338c2ecf20Sopenharmony_ci	struct nvme_tcp_ctrl *ctrl = to_tcp_ctrl(nctrl);
14348c2ecf20Sopenharmony_ci	struct nvme_tcp_queue *queue = &ctrl->queues[qid];
14358c2ecf20Sopenharmony_ci	int ret, rcv_pdu_size;
14368c2ecf20Sopenharmony_ci
14378c2ecf20Sopenharmony_ci	mutex_init(&queue->queue_lock);
14388c2ecf20Sopenharmony_ci	queue->ctrl = ctrl;
14398c2ecf20Sopenharmony_ci	init_llist_head(&queue->req_list);
14408c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&queue->send_list);
14418c2ecf20Sopenharmony_ci	mutex_init(&queue->send_mutex);
14428c2ecf20Sopenharmony_ci	INIT_WORK(&queue->io_work, nvme_tcp_io_work);
14438c2ecf20Sopenharmony_ci	queue->queue_size = queue_size;
14448c2ecf20Sopenharmony_ci
14458c2ecf20Sopenharmony_ci	if (qid > 0)
14468c2ecf20Sopenharmony_ci		queue->cmnd_capsule_len = nctrl->ioccsz * 16;
14478c2ecf20Sopenharmony_ci	else
14488c2ecf20Sopenharmony_ci		queue->cmnd_capsule_len = sizeof(struct nvme_command) +
14498c2ecf20Sopenharmony_ci						NVME_TCP_ADMIN_CCSZ;
14508c2ecf20Sopenharmony_ci
14518c2ecf20Sopenharmony_ci	ret = sock_create(ctrl->addr.ss_family, SOCK_STREAM,
14528c2ecf20Sopenharmony_ci			IPPROTO_TCP, &queue->sock);
14538c2ecf20Sopenharmony_ci	if (ret) {
14548c2ecf20Sopenharmony_ci		dev_err(nctrl->device,
14558c2ecf20Sopenharmony_ci			"failed to create socket: %d\n", ret);
14568c2ecf20Sopenharmony_ci		goto err_destroy_mutex;
14578c2ecf20Sopenharmony_ci	}
14588c2ecf20Sopenharmony_ci
14598c2ecf20Sopenharmony_ci	nvme_tcp_reclassify_socket(queue->sock);
14608c2ecf20Sopenharmony_ci
14618c2ecf20Sopenharmony_ci	/* Single syn retry */
14628c2ecf20Sopenharmony_ci	tcp_sock_set_syncnt(queue->sock->sk, 1);
14638c2ecf20Sopenharmony_ci
14648c2ecf20Sopenharmony_ci	/* Set TCP no delay */
14658c2ecf20Sopenharmony_ci	tcp_sock_set_nodelay(queue->sock->sk);
14668c2ecf20Sopenharmony_ci
14678c2ecf20Sopenharmony_ci	/*
14688c2ecf20Sopenharmony_ci	 * Cleanup whatever is sitting in the TCP transmit queue on socket
14698c2ecf20Sopenharmony_ci	 * close. This is done to prevent stale data from being sent should
14708c2ecf20Sopenharmony_ci	 * the network connection be restored before TCP times out.
14718c2ecf20Sopenharmony_ci	 */
14728c2ecf20Sopenharmony_ci	sock_no_linger(queue->sock->sk);
14738c2ecf20Sopenharmony_ci
14748c2ecf20Sopenharmony_ci	if (so_priority > 0)
14758c2ecf20Sopenharmony_ci		sock_set_priority(queue->sock->sk, so_priority);
14768c2ecf20Sopenharmony_ci
14778c2ecf20Sopenharmony_ci	/* Set socket type of service */
14788c2ecf20Sopenharmony_ci	if (nctrl->opts->tos >= 0)
14798c2ecf20Sopenharmony_ci		ip_sock_set_tos(queue->sock->sk, nctrl->opts->tos);
14808c2ecf20Sopenharmony_ci
14818c2ecf20Sopenharmony_ci	/* Set 10 seconds timeout for icresp recvmsg */
14828c2ecf20Sopenharmony_ci	queue->sock->sk->sk_rcvtimeo = 10 * HZ;
14838c2ecf20Sopenharmony_ci
14848c2ecf20Sopenharmony_ci	queue->sock->sk->sk_allocation = GFP_ATOMIC;
14858c2ecf20Sopenharmony_ci	nvme_tcp_set_queue_io_cpu(queue);
14868c2ecf20Sopenharmony_ci	queue->request = NULL;
14878c2ecf20Sopenharmony_ci	queue->data_remaining = 0;
14888c2ecf20Sopenharmony_ci	queue->ddgst_remaining = 0;
14898c2ecf20Sopenharmony_ci	queue->pdu_remaining = 0;
14908c2ecf20Sopenharmony_ci	queue->pdu_offset = 0;
14918c2ecf20Sopenharmony_ci	sk_set_memalloc(queue->sock->sk);
14928c2ecf20Sopenharmony_ci
14938c2ecf20Sopenharmony_ci	if (nctrl->opts->mask & NVMF_OPT_HOST_TRADDR) {
14948c2ecf20Sopenharmony_ci		ret = kernel_bind(queue->sock, (struct sockaddr *)&ctrl->src_addr,
14958c2ecf20Sopenharmony_ci			sizeof(ctrl->src_addr));
14968c2ecf20Sopenharmony_ci		if (ret) {
14978c2ecf20Sopenharmony_ci			dev_err(nctrl->device,
14988c2ecf20Sopenharmony_ci				"failed to bind queue %d socket %d\n",
14998c2ecf20Sopenharmony_ci				qid, ret);
15008c2ecf20Sopenharmony_ci			goto err_sock;
15018c2ecf20Sopenharmony_ci		}
15028c2ecf20Sopenharmony_ci	}
15038c2ecf20Sopenharmony_ci
15048c2ecf20Sopenharmony_ci	queue->hdr_digest = nctrl->opts->hdr_digest;
15058c2ecf20Sopenharmony_ci	queue->data_digest = nctrl->opts->data_digest;
15068c2ecf20Sopenharmony_ci	if (queue->hdr_digest || queue->data_digest) {
15078c2ecf20Sopenharmony_ci		ret = nvme_tcp_alloc_crypto(queue);
15088c2ecf20Sopenharmony_ci		if (ret) {
15098c2ecf20Sopenharmony_ci			dev_err(nctrl->device,
15108c2ecf20Sopenharmony_ci				"failed to allocate queue %d crypto\n", qid);
15118c2ecf20Sopenharmony_ci			goto err_sock;
15128c2ecf20Sopenharmony_ci		}
15138c2ecf20Sopenharmony_ci	}
15148c2ecf20Sopenharmony_ci
15158c2ecf20Sopenharmony_ci	rcv_pdu_size = sizeof(struct nvme_tcp_rsp_pdu) +
15168c2ecf20Sopenharmony_ci			nvme_tcp_hdgst_len(queue);
15178c2ecf20Sopenharmony_ci	queue->pdu = kmalloc(rcv_pdu_size, GFP_KERNEL);
15188c2ecf20Sopenharmony_ci	if (!queue->pdu) {
15198c2ecf20Sopenharmony_ci		ret = -ENOMEM;
15208c2ecf20Sopenharmony_ci		goto err_crypto;
15218c2ecf20Sopenharmony_ci	}
15228c2ecf20Sopenharmony_ci
15238c2ecf20Sopenharmony_ci	dev_dbg(nctrl->device, "connecting queue %d\n",
15248c2ecf20Sopenharmony_ci			nvme_tcp_queue_id(queue));
15258c2ecf20Sopenharmony_ci
15268c2ecf20Sopenharmony_ci	ret = kernel_connect(queue->sock, (struct sockaddr *)&ctrl->addr,
15278c2ecf20Sopenharmony_ci		sizeof(ctrl->addr), 0);
15288c2ecf20Sopenharmony_ci	if (ret) {
15298c2ecf20Sopenharmony_ci		dev_err(nctrl->device,
15308c2ecf20Sopenharmony_ci			"failed to connect socket: %d\n", ret);
15318c2ecf20Sopenharmony_ci		goto err_rcv_pdu;
15328c2ecf20Sopenharmony_ci	}
15338c2ecf20Sopenharmony_ci
15348c2ecf20Sopenharmony_ci	ret = nvme_tcp_init_connection(queue);
15358c2ecf20Sopenharmony_ci	if (ret)
15368c2ecf20Sopenharmony_ci		goto err_init_connect;
15378c2ecf20Sopenharmony_ci
15388c2ecf20Sopenharmony_ci	set_bit(NVME_TCP_Q_ALLOCATED, &queue->flags);
15398c2ecf20Sopenharmony_ci
15408c2ecf20Sopenharmony_ci	return 0;
15418c2ecf20Sopenharmony_ci
15428c2ecf20Sopenharmony_cierr_init_connect:
15438c2ecf20Sopenharmony_ci	kernel_sock_shutdown(queue->sock, SHUT_RDWR);
15448c2ecf20Sopenharmony_cierr_rcv_pdu:
15458c2ecf20Sopenharmony_ci	kfree(queue->pdu);
15468c2ecf20Sopenharmony_cierr_crypto:
15478c2ecf20Sopenharmony_ci	if (queue->hdr_digest || queue->data_digest)
15488c2ecf20Sopenharmony_ci		nvme_tcp_free_crypto(queue);
15498c2ecf20Sopenharmony_cierr_sock:
15508c2ecf20Sopenharmony_ci	sock_release(queue->sock);
15518c2ecf20Sopenharmony_ci	queue->sock = NULL;
15528c2ecf20Sopenharmony_cierr_destroy_mutex:
15538c2ecf20Sopenharmony_ci	mutex_destroy(&queue->queue_lock);
15548c2ecf20Sopenharmony_ci	return ret;
15558c2ecf20Sopenharmony_ci}
15568c2ecf20Sopenharmony_ci
15578c2ecf20Sopenharmony_cistatic void nvme_tcp_restore_sock_ops(struct nvme_tcp_queue *queue)
15588c2ecf20Sopenharmony_ci{
15598c2ecf20Sopenharmony_ci	struct socket *sock = queue->sock;
15608c2ecf20Sopenharmony_ci
15618c2ecf20Sopenharmony_ci	write_lock_bh(&sock->sk->sk_callback_lock);
15628c2ecf20Sopenharmony_ci	sock->sk->sk_user_data  = NULL;
15638c2ecf20Sopenharmony_ci	sock->sk->sk_data_ready = queue->data_ready;
15648c2ecf20Sopenharmony_ci	sock->sk->sk_state_change = queue->state_change;
15658c2ecf20Sopenharmony_ci	sock->sk->sk_write_space  = queue->write_space;
15668c2ecf20Sopenharmony_ci	write_unlock_bh(&sock->sk->sk_callback_lock);
15678c2ecf20Sopenharmony_ci}
15688c2ecf20Sopenharmony_ci
15698c2ecf20Sopenharmony_cistatic void __nvme_tcp_stop_queue(struct nvme_tcp_queue *queue)
15708c2ecf20Sopenharmony_ci{
15718c2ecf20Sopenharmony_ci	kernel_sock_shutdown(queue->sock, SHUT_RDWR);
15728c2ecf20Sopenharmony_ci	nvme_tcp_restore_sock_ops(queue);
15738c2ecf20Sopenharmony_ci	cancel_work_sync(&queue->io_work);
15748c2ecf20Sopenharmony_ci}
15758c2ecf20Sopenharmony_ci
15768c2ecf20Sopenharmony_cistatic void nvme_tcp_stop_queue(struct nvme_ctrl *nctrl, int qid)
15778c2ecf20Sopenharmony_ci{
15788c2ecf20Sopenharmony_ci	struct nvme_tcp_ctrl *ctrl = to_tcp_ctrl(nctrl);
15798c2ecf20Sopenharmony_ci	struct nvme_tcp_queue *queue = &ctrl->queues[qid];
15808c2ecf20Sopenharmony_ci
15818c2ecf20Sopenharmony_ci	mutex_lock(&queue->queue_lock);
15828c2ecf20Sopenharmony_ci	if (test_and_clear_bit(NVME_TCP_Q_LIVE, &queue->flags))
15838c2ecf20Sopenharmony_ci		__nvme_tcp_stop_queue(queue);
15848c2ecf20Sopenharmony_ci	mutex_unlock(&queue->queue_lock);
15858c2ecf20Sopenharmony_ci}
15868c2ecf20Sopenharmony_ci
15878c2ecf20Sopenharmony_cistatic void nvme_tcp_setup_sock_ops(struct nvme_tcp_queue *queue)
15888c2ecf20Sopenharmony_ci{
15898c2ecf20Sopenharmony_ci	write_lock_bh(&queue->sock->sk->sk_callback_lock);
15908c2ecf20Sopenharmony_ci	queue->sock->sk->sk_user_data = queue;
15918c2ecf20Sopenharmony_ci	queue->state_change = queue->sock->sk->sk_state_change;
15928c2ecf20Sopenharmony_ci	queue->data_ready = queue->sock->sk->sk_data_ready;
15938c2ecf20Sopenharmony_ci	queue->write_space = queue->sock->sk->sk_write_space;
15948c2ecf20Sopenharmony_ci	queue->sock->sk->sk_data_ready = nvme_tcp_data_ready;
15958c2ecf20Sopenharmony_ci	queue->sock->sk->sk_state_change = nvme_tcp_state_change;
15968c2ecf20Sopenharmony_ci	queue->sock->sk->sk_write_space = nvme_tcp_write_space;
15978c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_RX_BUSY_POLL
15988c2ecf20Sopenharmony_ci	queue->sock->sk->sk_ll_usec = 1;
15998c2ecf20Sopenharmony_ci#endif
16008c2ecf20Sopenharmony_ci	write_unlock_bh(&queue->sock->sk->sk_callback_lock);
16018c2ecf20Sopenharmony_ci}
16028c2ecf20Sopenharmony_ci
16038c2ecf20Sopenharmony_cistatic int nvme_tcp_start_queue(struct nvme_ctrl *nctrl, int idx)
16048c2ecf20Sopenharmony_ci{
16058c2ecf20Sopenharmony_ci	struct nvme_tcp_ctrl *ctrl = to_tcp_ctrl(nctrl);
16068c2ecf20Sopenharmony_ci	struct nvme_tcp_queue *queue = &ctrl->queues[idx];
16078c2ecf20Sopenharmony_ci	int ret;
16088c2ecf20Sopenharmony_ci
16098c2ecf20Sopenharmony_ci	queue->rd_enabled = true;
16108c2ecf20Sopenharmony_ci	nvme_tcp_init_recv_ctx(queue);
16118c2ecf20Sopenharmony_ci	nvme_tcp_setup_sock_ops(queue);
16128c2ecf20Sopenharmony_ci
16138c2ecf20Sopenharmony_ci	if (idx)
16148c2ecf20Sopenharmony_ci		ret = nvmf_connect_io_queue(nctrl, idx, false);
16158c2ecf20Sopenharmony_ci	else
16168c2ecf20Sopenharmony_ci		ret = nvmf_connect_admin_queue(nctrl);
16178c2ecf20Sopenharmony_ci
16188c2ecf20Sopenharmony_ci	if (!ret) {
16198c2ecf20Sopenharmony_ci		set_bit(NVME_TCP_Q_LIVE, &queue->flags);
16208c2ecf20Sopenharmony_ci	} else {
16218c2ecf20Sopenharmony_ci		if (test_bit(NVME_TCP_Q_ALLOCATED, &queue->flags))
16228c2ecf20Sopenharmony_ci			__nvme_tcp_stop_queue(queue);
16238c2ecf20Sopenharmony_ci		dev_err(nctrl->device,
16248c2ecf20Sopenharmony_ci			"failed to connect queue: %d ret=%d\n", idx, ret);
16258c2ecf20Sopenharmony_ci	}
16268c2ecf20Sopenharmony_ci	return ret;
16278c2ecf20Sopenharmony_ci}
16288c2ecf20Sopenharmony_ci
16298c2ecf20Sopenharmony_cistatic struct blk_mq_tag_set *nvme_tcp_alloc_tagset(struct nvme_ctrl *nctrl,
16308c2ecf20Sopenharmony_ci		bool admin)
16318c2ecf20Sopenharmony_ci{
16328c2ecf20Sopenharmony_ci	struct nvme_tcp_ctrl *ctrl = to_tcp_ctrl(nctrl);
16338c2ecf20Sopenharmony_ci	struct blk_mq_tag_set *set;
16348c2ecf20Sopenharmony_ci	int ret;
16358c2ecf20Sopenharmony_ci
16368c2ecf20Sopenharmony_ci	if (admin) {
16378c2ecf20Sopenharmony_ci		set = &ctrl->admin_tag_set;
16388c2ecf20Sopenharmony_ci		memset(set, 0, sizeof(*set));
16398c2ecf20Sopenharmony_ci		set->ops = &nvme_tcp_admin_mq_ops;
16408c2ecf20Sopenharmony_ci		set->queue_depth = NVME_AQ_MQ_TAG_DEPTH;
16418c2ecf20Sopenharmony_ci		set->reserved_tags = 2; /* connect + keep-alive */
16428c2ecf20Sopenharmony_ci		set->numa_node = nctrl->numa_node;
16438c2ecf20Sopenharmony_ci		set->flags = BLK_MQ_F_BLOCKING;
16448c2ecf20Sopenharmony_ci		set->cmd_size = sizeof(struct nvme_tcp_request);
16458c2ecf20Sopenharmony_ci		set->driver_data = ctrl;
16468c2ecf20Sopenharmony_ci		set->nr_hw_queues = 1;
16478c2ecf20Sopenharmony_ci		set->timeout = ADMIN_TIMEOUT;
16488c2ecf20Sopenharmony_ci	} else {
16498c2ecf20Sopenharmony_ci		set = &ctrl->tag_set;
16508c2ecf20Sopenharmony_ci		memset(set, 0, sizeof(*set));
16518c2ecf20Sopenharmony_ci		set->ops = &nvme_tcp_mq_ops;
16528c2ecf20Sopenharmony_ci		set->queue_depth = nctrl->sqsize + 1;
16538c2ecf20Sopenharmony_ci		set->reserved_tags = 1; /* fabric connect */
16548c2ecf20Sopenharmony_ci		set->numa_node = nctrl->numa_node;
16558c2ecf20Sopenharmony_ci		set->flags = BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_BLOCKING;
16568c2ecf20Sopenharmony_ci		set->cmd_size = sizeof(struct nvme_tcp_request);
16578c2ecf20Sopenharmony_ci		set->driver_data = ctrl;
16588c2ecf20Sopenharmony_ci		set->nr_hw_queues = nctrl->queue_count - 1;
16598c2ecf20Sopenharmony_ci		set->timeout = NVME_IO_TIMEOUT;
16608c2ecf20Sopenharmony_ci		set->nr_maps = nctrl->opts->nr_poll_queues ? HCTX_MAX_TYPES : 2;
16618c2ecf20Sopenharmony_ci	}
16628c2ecf20Sopenharmony_ci
16638c2ecf20Sopenharmony_ci	ret = blk_mq_alloc_tag_set(set);
16648c2ecf20Sopenharmony_ci	if (ret)
16658c2ecf20Sopenharmony_ci		return ERR_PTR(ret);
16668c2ecf20Sopenharmony_ci
16678c2ecf20Sopenharmony_ci	return set;
16688c2ecf20Sopenharmony_ci}
16698c2ecf20Sopenharmony_ci
16708c2ecf20Sopenharmony_cistatic void nvme_tcp_free_admin_queue(struct nvme_ctrl *ctrl)
16718c2ecf20Sopenharmony_ci{
16728c2ecf20Sopenharmony_ci	if (to_tcp_ctrl(ctrl)->async_req.pdu) {
16738c2ecf20Sopenharmony_ci		cancel_work_sync(&ctrl->async_event_work);
16748c2ecf20Sopenharmony_ci		nvme_tcp_free_async_req(to_tcp_ctrl(ctrl));
16758c2ecf20Sopenharmony_ci		to_tcp_ctrl(ctrl)->async_req.pdu = NULL;
16768c2ecf20Sopenharmony_ci	}
16778c2ecf20Sopenharmony_ci
16788c2ecf20Sopenharmony_ci	nvme_tcp_free_queue(ctrl, 0);
16798c2ecf20Sopenharmony_ci}
16808c2ecf20Sopenharmony_ci
16818c2ecf20Sopenharmony_cistatic void nvme_tcp_free_io_queues(struct nvme_ctrl *ctrl)
16828c2ecf20Sopenharmony_ci{
16838c2ecf20Sopenharmony_ci	int i;
16848c2ecf20Sopenharmony_ci
16858c2ecf20Sopenharmony_ci	for (i = 1; i < ctrl->queue_count; i++)
16868c2ecf20Sopenharmony_ci		nvme_tcp_free_queue(ctrl, i);
16878c2ecf20Sopenharmony_ci}
16888c2ecf20Sopenharmony_ci
16898c2ecf20Sopenharmony_cistatic void nvme_tcp_stop_io_queues(struct nvme_ctrl *ctrl)
16908c2ecf20Sopenharmony_ci{
16918c2ecf20Sopenharmony_ci	int i;
16928c2ecf20Sopenharmony_ci
16938c2ecf20Sopenharmony_ci	for (i = 1; i < ctrl->queue_count; i++)
16948c2ecf20Sopenharmony_ci		nvme_tcp_stop_queue(ctrl, i);
16958c2ecf20Sopenharmony_ci}
16968c2ecf20Sopenharmony_ci
16978c2ecf20Sopenharmony_cistatic int nvme_tcp_start_io_queues(struct nvme_ctrl *ctrl)
16988c2ecf20Sopenharmony_ci{
16998c2ecf20Sopenharmony_ci	int i, ret = 0;
17008c2ecf20Sopenharmony_ci
17018c2ecf20Sopenharmony_ci	for (i = 1; i < ctrl->queue_count; i++) {
17028c2ecf20Sopenharmony_ci		ret = nvme_tcp_start_queue(ctrl, i);
17038c2ecf20Sopenharmony_ci		if (ret)
17048c2ecf20Sopenharmony_ci			goto out_stop_queues;
17058c2ecf20Sopenharmony_ci	}
17068c2ecf20Sopenharmony_ci
17078c2ecf20Sopenharmony_ci	return 0;
17088c2ecf20Sopenharmony_ci
17098c2ecf20Sopenharmony_ciout_stop_queues:
17108c2ecf20Sopenharmony_ci	for (i--; i >= 1; i--)
17118c2ecf20Sopenharmony_ci		nvme_tcp_stop_queue(ctrl, i);
17128c2ecf20Sopenharmony_ci	return ret;
17138c2ecf20Sopenharmony_ci}
17148c2ecf20Sopenharmony_ci
17158c2ecf20Sopenharmony_cistatic int nvme_tcp_alloc_admin_queue(struct nvme_ctrl *ctrl)
17168c2ecf20Sopenharmony_ci{
17178c2ecf20Sopenharmony_ci	int ret;
17188c2ecf20Sopenharmony_ci
17198c2ecf20Sopenharmony_ci	ret = nvme_tcp_alloc_queue(ctrl, 0, NVME_AQ_DEPTH);
17208c2ecf20Sopenharmony_ci	if (ret)
17218c2ecf20Sopenharmony_ci		return ret;
17228c2ecf20Sopenharmony_ci
17238c2ecf20Sopenharmony_ci	ret = nvme_tcp_alloc_async_req(to_tcp_ctrl(ctrl));
17248c2ecf20Sopenharmony_ci	if (ret)
17258c2ecf20Sopenharmony_ci		goto out_free_queue;
17268c2ecf20Sopenharmony_ci
17278c2ecf20Sopenharmony_ci	return 0;
17288c2ecf20Sopenharmony_ci
17298c2ecf20Sopenharmony_ciout_free_queue:
17308c2ecf20Sopenharmony_ci	nvme_tcp_free_queue(ctrl, 0);
17318c2ecf20Sopenharmony_ci	return ret;
17328c2ecf20Sopenharmony_ci}
17338c2ecf20Sopenharmony_ci
17348c2ecf20Sopenharmony_cistatic int __nvme_tcp_alloc_io_queues(struct nvme_ctrl *ctrl)
17358c2ecf20Sopenharmony_ci{
17368c2ecf20Sopenharmony_ci	int i, ret;
17378c2ecf20Sopenharmony_ci
17388c2ecf20Sopenharmony_ci	for (i = 1; i < ctrl->queue_count; i++) {
17398c2ecf20Sopenharmony_ci		ret = nvme_tcp_alloc_queue(ctrl, i,
17408c2ecf20Sopenharmony_ci				ctrl->sqsize + 1);
17418c2ecf20Sopenharmony_ci		if (ret)
17428c2ecf20Sopenharmony_ci			goto out_free_queues;
17438c2ecf20Sopenharmony_ci	}
17448c2ecf20Sopenharmony_ci
17458c2ecf20Sopenharmony_ci	return 0;
17468c2ecf20Sopenharmony_ci
17478c2ecf20Sopenharmony_ciout_free_queues:
17488c2ecf20Sopenharmony_ci	for (i--; i >= 1; i--)
17498c2ecf20Sopenharmony_ci		nvme_tcp_free_queue(ctrl, i);
17508c2ecf20Sopenharmony_ci
17518c2ecf20Sopenharmony_ci	return ret;
17528c2ecf20Sopenharmony_ci}
17538c2ecf20Sopenharmony_ci
17548c2ecf20Sopenharmony_cistatic unsigned int nvme_tcp_nr_io_queues(struct nvme_ctrl *ctrl)
17558c2ecf20Sopenharmony_ci{
17568c2ecf20Sopenharmony_ci	unsigned int nr_io_queues;
17578c2ecf20Sopenharmony_ci
17588c2ecf20Sopenharmony_ci	nr_io_queues = min(ctrl->opts->nr_io_queues, num_online_cpus());
17598c2ecf20Sopenharmony_ci	nr_io_queues += min(ctrl->opts->nr_write_queues, num_online_cpus());
17608c2ecf20Sopenharmony_ci	nr_io_queues += min(ctrl->opts->nr_poll_queues, num_online_cpus());
17618c2ecf20Sopenharmony_ci
17628c2ecf20Sopenharmony_ci	return nr_io_queues;
17638c2ecf20Sopenharmony_ci}
17648c2ecf20Sopenharmony_ci
17658c2ecf20Sopenharmony_cistatic void nvme_tcp_set_io_queues(struct nvme_ctrl *nctrl,
17668c2ecf20Sopenharmony_ci		unsigned int nr_io_queues)
17678c2ecf20Sopenharmony_ci{
17688c2ecf20Sopenharmony_ci	struct nvme_tcp_ctrl *ctrl = to_tcp_ctrl(nctrl);
17698c2ecf20Sopenharmony_ci	struct nvmf_ctrl_options *opts = nctrl->opts;
17708c2ecf20Sopenharmony_ci
17718c2ecf20Sopenharmony_ci	if (opts->nr_write_queues && opts->nr_io_queues < nr_io_queues) {
17728c2ecf20Sopenharmony_ci		/*
17738c2ecf20Sopenharmony_ci		 * separate read/write queues
17748c2ecf20Sopenharmony_ci		 * hand out dedicated default queues only after we have
17758c2ecf20Sopenharmony_ci		 * sufficient read queues.
17768c2ecf20Sopenharmony_ci		 */
17778c2ecf20Sopenharmony_ci		ctrl->io_queues[HCTX_TYPE_READ] = opts->nr_io_queues;
17788c2ecf20Sopenharmony_ci		nr_io_queues -= ctrl->io_queues[HCTX_TYPE_READ];
17798c2ecf20Sopenharmony_ci		ctrl->io_queues[HCTX_TYPE_DEFAULT] =
17808c2ecf20Sopenharmony_ci			min(opts->nr_write_queues, nr_io_queues);
17818c2ecf20Sopenharmony_ci		nr_io_queues -= ctrl->io_queues[HCTX_TYPE_DEFAULT];
17828c2ecf20Sopenharmony_ci	} else {
17838c2ecf20Sopenharmony_ci		/*
17848c2ecf20Sopenharmony_ci		 * shared read/write queues
17858c2ecf20Sopenharmony_ci		 * either no write queues were requested, or we don't have
17868c2ecf20Sopenharmony_ci		 * sufficient queue count to have dedicated default queues.
17878c2ecf20Sopenharmony_ci		 */
17888c2ecf20Sopenharmony_ci		ctrl->io_queues[HCTX_TYPE_DEFAULT] =
17898c2ecf20Sopenharmony_ci			min(opts->nr_io_queues, nr_io_queues);
17908c2ecf20Sopenharmony_ci		nr_io_queues -= ctrl->io_queues[HCTX_TYPE_DEFAULT];
17918c2ecf20Sopenharmony_ci	}
17928c2ecf20Sopenharmony_ci
17938c2ecf20Sopenharmony_ci	if (opts->nr_poll_queues && nr_io_queues) {
17948c2ecf20Sopenharmony_ci		/* map dedicated poll queues only if we have queues left */
17958c2ecf20Sopenharmony_ci		ctrl->io_queues[HCTX_TYPE_POLL] =
17968c2ecf20Sopenharmony_ci			min(opts->nr_poll_queues, nr_io_queues);
17978c2ecf20Sopenharmony_ci	}
17988c2ecf20Sopenharmony_ci}
17998c2ecf20Sopenharmony_ci
18008c2ecf20Sopenharmony_cistatic int nvme_tcp_alloc_io_queues(struct nvme_ctrl *ctrl)
18018c2ecf20Sopenharmony_ci{
18028c2ecf20Sopenharmony_ci	unsigned int nr_io_queues;
18038c2ecf20Sopenharmony_ci	int ret;
18048c2ecf20Sopenharmony_ci
18058c2ecf20Sopenharmony_ci	nr_io_queues = nvme_tcp_nr_io_queues(ctrl);
18068c2ecf20Sopenharmony_ci	ret = nvme_set_queue_count(ctrl, &nr_io_queues);
18078c2ecf20Sopenharmony_ci	if (ret)
18088c2ecf20Sopenharmony_ci		return ret;
18098c2ecf20Sopenharmony_ci
18108c2ecf20Sopenharmony_ci	if (nr_io_queues == 0) {
18118c2ecf20Sopenharmony_ci		dev_err(ctrl->device,
18128c2ecf20Sopenharmony_ci			"unable to set any I/O queues\n");
18138c2ecf20Sopenharmony_ci		return -ENOMEM;
18148c2ecf20Sopenharmony_ci	}
18158c2ecf20Sopenharmony_ci
18168c2ecf20Sopenharmony_ci	ctrl->queue_count = nr_io_queues + 1;
18178c2ecf20Sopenharmony_ci	dev_info(ctrl->device,
18188c2ecf20Sopenharmony_ci		"creating %d I/O queues.\n", nr_io_queues);
18198c2ecf20Sopenharmony_ci
18208c2ecf20Sopenharmony_ci	nvme_tcp_set_io_queues(ctrl, nr_io_queues);
18218c2ecf20Sopenharmony_ci
18228c2ecf20Sopenharmony_ci	return __nvme_tcp_alloc_io_queues(ctrl);
18238c2ecf20Sopenharmony_ci}
18248c2ecf20Sopenharmony_ci
18258c2ecf20Sopenharmony_cistatic void nvme_tcp_destroy_io_queues(struct nvme_ctrl *ctrl, bool remove)
18268c2ecf20Sopenharmony_ci{
18278c2ecf20Sopenharmony_ci	nvme_tcp_stop_io_queues(ctrl);
18288c2ecf20Sopenharmony_ci	if (remove) {
18298c2ecf20Sopenharmony_ci		blk_cleanup_queue(ctrl->connect_q);
18308c2ecf20Sopenharmony_ci		blk_mq_free_tag_set(ctrl->tagset);
18318c2ecf20Sopenharmony_ci	}
18328c2ecf20Sopenharmony_ci	nvme_tcp_free_io_queues(ctrl);
18338c2ecf20Sopenharmony_ci}
18348c2ecf20Sopenharmony_ci
18358c2ecf20Sopenharmony_cistatic int nvme_tcp_configure_io_queues(struct nvme_ctrl *ctrl, bool new)
18368c2ecf20Sopenharmony_ci{
18378c2ecf20Sopenharmony_ci	int ret;
18388c2ecf20Sopenharmony_ci
18398c2ecf20Sopenharmony_ci	ret = nvme_tcp_alloc_io_queues(ctrl);
18408c2ecf20Sopenharmony_ci	if (ret)
18418c2ecf20Sopenharmony_ci		return ret;
18428c2ecf20Sopenharmony_ci
18438c2ecf20Sopenharmony_ci	if (new) {
18448c2ecf20Sopenharmony_ci		ctrl->tagset = nvme_tcp_alloc_tagset(ctrl, false);
18458c2ecf20Sopenharmony_ci		if (IS_ERR(ctrl->tagset)) {
18468c2ecf20Sopenharmony_ci			ret = PTR_ERR(ctrl->tagset);
18478c2ecf20Sopenharmony_ci			goto out_free_io_queues;
18488c2ecf20Sopenharmony_ci		}
18498c2ecf20Sopenharmony_ci
18508c2ecf20Sopenharmony_ci		ctrl->connect_q = blk_mq_init_queue(ctrl->tagset);
18518c2ecf20Sopenharmony_ci		if (IS_ERR(ctrl->connect_q)) {
18528c2ecf20Sopenharmony_ci			ret = PTR_ERR(ctrl->connect_q);
18538c2ecf20Sopenharmony_ci			goto out_free_tag_set;
18548c2ecf20Sopenharmony_ci		}
18558c2ecf20Sopenharmony_ci	}
18568c2ecf20Sopenharmony_ci
18578c2ecf20Sopenharmony_ci	ret = nvme_tcp_start_io_queues(ctrl);
18588c2ecf20Sopenharmony_ci	if (ret)
18598c2ecf20Sopenharmony_ci		goto out_cleanup_connect_q;
18608c2ecf20Sopenharmony_ci
18618c2ecf20Sopenharmony_ci	if (!new) {
18628c2ecf20Sopenharmony_ci		nvme_start_freeze(ctrl);
18638c2ecf20Sopenharmony_ci		nvme_start_queues(ctrl);
18648c2ecf20Sopenharmony_ci		if (!nvme_wait_freeze_timeout(ctrl, NVME_IO_TIMEOUT)) {
18658c2ecf20Sopenharmony_ci			/*
18668c2ecf20Sopenharmony_ci			 * If we timed out waiting for freeze we are likely to
18678c2ecf20Sopenharmony_ci			 * be stuck.  Fail the controller initialization just
18688c2ecf20Sopenharmony_ci			 * to be safe.
18698c2ecf20Sopenharmony_ci			 */
18708c2ecf20Sopenharmony_ci			ret = -ENODEV;
18718c2ecf20Sopenharmony_ci			nvme_unfreeze(ctrl);
18728c2ecf20Sopenharmony_ci			goto out_wait_freeze_timed_out;
18738c2ecf20Sopenharmony_ci		}
18748c2ecf20Sopenharmony_ci		blk_mq_update_nr_hw_queues(ctrl->tagset,
18758c2ecf20Sopenharmony_ci			ctrl->queue_count - 1);
18768c2ecf20Sopenharmony_ci		nvme_unfreeze(ctrl);
18778c2ecf20Sopenharmony_ci	}
18788c2ecf20Sopenharmony_ci
18798c2ecf20Sopenharmony_ci	return 0;
18808c2ecf20Sopenharmony_ci
18818c2ecf20Sopenharmony_ciout_wait_freeze_timed_out:
18828c2ecf20Sopenharmony_ci	nvme_stop_queues(ctrl);
18838c2ecf20Sopenharmony_ci	nvme_sync_io_queues(ctrl);
18848c2ecf20Sopenharmony_ci	nvme_tcp_stop_io_queues(ctrl);
18858c2ecf20Sopenharmony_ciout_cleanup_connect_q:
18868c2ecf20Sopenharmony_ci	nvme_cancel_tagset(ctrl);
18878c2ecf20Sopenharmony_ci	if (new)
18888c2ecf20Sopenharmony_ci		blk_cleanup_queue(ctrl->connect_q);
18898c2ecf20Sopenharmony_ciout_free_tag_set:
18908c2ecf20Sopenharmony_ci	if (new)
18918c2ecf20Sopenharmony_ci		blk_mq_free_tag_set(ctrl->tagset);
18928c2ecf20Sopenharmony_ciout_free_io_queues:
18938c2ecf20Sopenharmony_ci	nvme_tcp_free_io_queues(ctrl);
18948c2ecf20Sopenharmony_ci	return ret;
18958c2ecf20Sopenharmony_ci}
18968c2ecf20Sopenharmony_ci
18978c2ecf20Sopenharmony_cistatic void nvme_tcp_destroy_admin_queue(struct nvme_ctrl *ctrl, bool remove)
18988c2ecf20Sopenharmony_ci{
18998c2ecf20Sopenharmony_ci	nvme_tcp_stop_queue(ctrl, 0);
19008c2ecf20Sopenharmony_ci	if (remove) {
19018c2ecf20Sopenharmony_ci		blk_cleanup_queue(ctrl->admin_q);
19028c2ecf20Sopenharmony_ci		blk_cleanup_queue(ctrl->fabrics_q);
19038c2ecf20Sopenharmony_ci		blk_mq_free_tag_set(ctrl->admin_tagset);
19048c2ecf20Sopenharmony_ci	}
19058c2ecf20Sopenharmony_ci	nvme_tcp_free_admin_queue(ctrl);
19068c2ecf20Sopenharmony_ci}
19078c2ecf20Sopenharmony_ci
19088c2ecf20Sopenharmony_cistatic int nvme_tcp_configure_admin_queue(struct nvme_ctrl *ctrl, bool new)
19098c2ecf20Sopenharmony_ci{
19108c2ecf20Sopenharmony_ci	int error;
19118c2ecf20Sopenharmony_ci
19128c2ecf20Sopenharmony_ci	error = nvme_tcp_alloc_admin_queue(ctrl);
19138c2ecf20Sopenharmony_ci	if (error)
19148c2ecf20Sopenharmony_ci		return error;
19158c2ecf20Sopenharmony_ci
19168c2ecf20Sopenharmony_ci	if (new) {
19178c2ecf20Sopenharmony_ci		ctrl->admin_tagset = nvme_tcp_alloc_tagset(ctrl, true);
19188c2ecf20Sopenharmony_ci		if (IS_ERR(ctrl->admin_tagset)) {
19198c2ecf20Sopenharmony_ci			error = PTR_ERR(ctrl->admin_tagset);
19208c2ecf20Sopenharmony_ci			goto out_free_queue;
19218c2ecf20Sopenharmony_ci		}
19228c2ecf20Sopenharmony_ci
19238c2ecf20Sopenharmony_ci		ctrl->fabrics_q = blk_mq_init_queue(ctrl->admin_tagset);
19248c2ecf20Sopenharmony_ci		if (IS_ERR(ctrl->fabrics_q)) {
19258c2ecf20Sopenharmony_ci			error = PTR_ERR(ctrl->fabrics_q);
19268c2ecf20Sopenharmony_ci			goto out_free_tagset;
19278c2ecf20Sopenharmony_ci		}
19288c2ecf20Sopenharmony_ci
19298c2ecf20Sopenharmony_ci		ctrl->admin_q = blk_mq_init_queue(ctrl->admin_tagset);
19308c2ecf20Sopenharmony_ci		if (IS_ERR(ctrl->admin_q)) {
19318c2ecf20Sopenharmony_ci			error = PTR_ERR(ctrl->admin_q);
19328c2ecf20Sopenharmony_ci			goto out_cleanup_fabrics_q;
19338c2ecf20Sopenharmony_ci		}
19348c2ecf20Sopenharmony_ci	}
19358c2ecf20Sopenharmony_ci
19368c2ecf20Sopenharmony_ci	error = nvme_tcp_start_queue(ctrl, 0);
19378c2ecf20Sopenharmony_ci	if (error)
19388c2ecf20Sopenharmony_ci		goto out_cleanup_queue;
19398c2ecf20Sopenharmony_ci
19408c2ecf20Sopenharmony_ci	error = nvme_enable_ctrl(ctrl);
19418c2ecf20Sopenharmony_ci	if (error)
19428c2ecf20Sopenharmony_ci		goto out_stop_queue;
19438c2ecf20Sopenharmony_ci
19448c2ecf20Sopenharmony_ci	nvme_start_admin_queue(ctrl);
19458c2ecf20Sopenharmony_ci
19468c2ecf20Sopenharmony_ci	error = nvme_init_identify(ctrl);
19478c2ecf20Sopenharmony_ci	if (error)
19488c2ecf20Sopenharmony_ci		goto out_quiesce_queue;
19498c2ecf20Sopenharmony_ci
19508c2ecf20Sopenharmony_ci	return 0;
19518c2ecf20Sopenharmony_ci
19528c2ecf20Sopenharmony_ciout_quiesce_queue:
19538c2ecf20Sopenharmony_ci	nvme_stop_admin_queue(ctrl);
19548c2ecf20Sopenharmony_ci	blk_sync_queue(ctrl->admin_q);
19558c2ecf20Sopenharmony_ciout_stop_queue:
19568c2ecf20Sopenharmony_ci	nvme_tcp_stop_queue(ctrl, 0);
19578c2ecf20Sopenharmony_ci	nvme_cancel_admin_tagset(ctrl);
19588c2ecf20Sopenharmony_ciout_cleanup_queue:
19598c2ecf20Sopenharmony_ci	if (new)
19608c2ecf20Sopenharmony_ci		blk_cleanup_queue(ctrl->admin_q);
19618c2ecf20Sopenharmony_ciout_cleanup_fabrics_q:
19628c2ecf20Sopenharmony_ci	if (new)
19638c2ecf20Sopenharmony_ci		blk_cleanup_queue(ctrl->fabrics_q);
19648c2ecf20Sopenharmony_ciout_free_tagset:
19658c2ecf20Sopenharmony_ci	if (new)
19668c2ecf20Sopenharmony_ci		blk_mq_free_tag_set(ctrl->admin_tagset);
19678c2ecf20Sopenharmony_ciout_free_queue:
19688c2ecf20Sopenharmony_ci	nvme_tcp_free_admin_queue(ctrl);
19698c2ecf20Sopenharmony_ci	return error;
19708c2ecf20Sopenharmony_ci}
19718c2ecf20Sopenharmony_ci
19728c2ecf20Sopenharmony_cistatic void nvme_tcp_teardown_admin_queue(struct nvme_ctrl *ctrl,
19738c2ecf20Sopenharmony_ci		bool remove)
19748c2ecf20Sopenharmony_ci{
19758c2ecf20Sopenharmony_ci	nvme_stop_admin_queue(ctrl);
19768c2ecf20Sopenharmony_ci	blk_sync_queue(ctrl->admin_q);
19778c2ecf20Sopenharmony_ci	nvme_tcp_stop_queue(ctrl, 0);
19788c2ecf20Sopenharmony_ci	if (ctrl->admin_tagset) {
19798c2ecf20Sopenharmony_ci		blk_mq_tagset_busy_iter(ctrl->admin_tagset,
19808c2ecf20Sopenharmony_ci			nvme_cancel_request, ctrl);
19818c2ecf20Sopenharmony_ci		blk_mq_tagset_wait_completed_request(ctrl->admin_tagset);
19828c2ecf20Sopenharmony_ci	}
19838c2ecf20Sopenharmony_ci	if (remove)
19848c2ecf20Sopenharmony_ci		nvme_start_admin_queue(ctrl);
19858c2ecf20Sopenharmony_ci	nvme_tcp_destroy_admin_queue(ctrl, remove);
19868c2ecf20Sopenharmony_ci}
19878c2ecf20Sopenharmony_ci
19888c2ecf20Sopenharmony_cistatic void nvme_tcp_teardown_io_queues(struct nvme_ctrl *ctrl,
19898c2ecf20Sopenharmony_ci		bool remove)
19908c2ecf20Sopenharmony_ci{
19918c2ecf20Sopenharmony_ci	if (ctrl->queue_count <= 1)
19928c2ecf20Sopenharmony_ci		return;
19938c2ecf20Sopenharmony_ci	nvme_stop_admin_queue(ctrl);
19948c2ecf20Sopenharmony_ci	nvme_stop_queues(ctrl);
19958c2ecf20Sopenharmony_ci	nvme_sync_io_queues(ctrl);
19968c2ecf20Sopenharmony_ci	nvme_tcp_stop_io_queues(ctrl);
19978c2ecf20Sopenharmony_ci	if (ctrl->tagset) {
19988c2ecf20Sopenharmony_ci		blk_mq_tagset_busy_iter(ctrl->tagset,
19998c2ecf20Sopenharmony_ci			nvme_cancel_request, ctrl);
20008c2ecf20Sopenharmony_ci		blk_mq_tagset_wait_completed_request(ctrl->tagset);
20018c2ecf20Sopenharmony_ci	}
20028c2ecf20Sopenharmony_ci	if (remove)
20038c2ecf20Sopenharmony_ci		nvme_start_queues(ctrl);
20048c2ecf20Sopenharmony_ci	nvme_tcp_destroy_io_queues(ctrl, remove);
20058c2ecf20Sopenharmony_ci}
20068c2ecf20Sopenharmony_ci
20078c2ecf20Sopenharmony_cistatic void nvme_tcp_reconnect_or_remove(struct nvme_ctrl *ctrl)
20088c2ecf20Sopenharmony_ci{
20098c2ecf20Sopenharmony_ci	/* If we are resetting/deleting then do nothing */
20108c2ecf20Sopenharmony_ci	if (ctrl->state != NVME_CTRL_CONNECTING) {
20118c2ecf20Sopenharmony_ci		WARN_ON_ONCE(ctrl->state == NVME_CTRL_NEW ||
20128c2ecf20Sopenharmony_ci			ctrl->state == NVME_CTRL_LIVE);
20138c2ecf20Sopenharmony_ci		return;
20148c2ecf20Sopenharmony_ci	}
20158c2ecf20Sopenharmony_ci
20168c2ecf20Sopenharmony_ci	if (nvmf_should_reconnect(ctrl)) {
20178c2ecf20Sopenharmony_ci		dev_info(ctrl->device, "Reconnecting in %d seconds...\n",
20188c2ecf20Sopenharmony_ci			ctrl->opts->reconnect_delay);
20198c2ecf20Sopenharmony_ci		queue_delayed_work(nvme_wq, &to_tcp_ctrl(ctrl)->connect_work,
20208c2ecf20Sopenharmony_ci				ctrl->opts->reconnect_delay * HZ);
20218c2ecf20Sopenharmony_ci	} else {
20228c2ecf20Sopenharmony_ci		dev_info(ctrl->device, "Removing controller...\n");
20238c2ecf20Sopenharmony_ci		nvme_delete_ctrl(ctrl);
20248c2ecf20Sopenharmony_ci	}
20258c2ecf20Sopenharmony_ci}
20268c2ecf20Sopenharmony_ci
20278c2ecf20Sopenharmony_cistatic int nvme_tcp_setup_ctrl(struct nvme_ctrl *ctrl, bool new)
20288c2ecf20Sopenharmony_ci{
20298c2ecf20Sopenharmony_ci	struct nvmf_ctrl_options *opts = ctrl->opts;
20308c2ecf20Sopenharmony_ci	int ret;
20318c2ecf20Sopenharmony_ci
20328c2ecf20Sopenharmony_ci	ret = nvme_tcp_configure_admin_queue(ctrl, new);
20338c2ecf20Sopenharmony_ci	if (ret)
20348c2ecf20Sopenharmony_ci		return ret;
20358c2ecf20Sopenharmony_ci
20368c2ecf20Sopenharmony_ci	if (ctrl->icdoff) {
20378c2ecf20Sopenharmony_ci		dev_err(ctrl->device, "icdoff is not supported!\n");
20388c2ecf20Sopenharmony_ci		goto destroy_admin;
20398c2ecf20Sopenharmony_ci	}
20408c2ecf20Sopenharmony_ci
20418c2ecf20Sopenharmony_ci	if (opts->queue_size > ctrl->sqsize + 1)
20428c2ecf20Sopenharmony_ci		dev_warn(ctrl->device,
20438c2ecf20Sopenharmony_ci			"queue_size %zu > ctrl sqsize %u, clamping down\n",
20448c2ecf20Sopenharmony_ci			opts->queue_size, ctrl->sqsize + 1);
20458c2ecf20Sopenharmony_ci
20468c2ecf20Sopenharmony_ci	if (ctrl->sqsize + 1 > ctrl->maxcmd) {
20478c2ecf20Sopenharmony_ci		dev_warn(ctrl->device,
20488c2ecf20Sopenharmony_ci			"sqsize %u > ctrl maxcmd %u, clamping down\n",
20498c2ecf20Sopenharmony_ci			ctrl->sqsize + 1, ctrl->maxcmd);
20508c2ecf20Sopenharmony_ci		ctrl->sqsize = ctrl->maxcmd - 1;
20518c2ecf20Sopenharmony_ci	}
20528c2ecf20Sopenharmony_ci
20538c2ecf20Sopenharmony_ci	if (ctrl->queue_count > 1) {
20548c2ecf20Sopenharmony_ci		ret = nvme_tcp_configure_io_queues(ctrl, new);
20558c2ecf20Sopenharmony_ci		if (ret)
20568c2ecf20Sopenharmony_ci			goto destroy_admin;
20578c2ecf20Sopenharmony_ci	}
20588c2ecf20Sopenharmony_ci
20598c2ecf20Sopenharmony_ci	if (!nvme_change_ctrl_state(ctrl, NVME_CTRL_LIVE)) {
20608c2ecf20Sopenharmony_ci		/*
20618c2ecf20Sopenharmony_ci		 * state change failure is ok if we started ctrl delete,
20628c2ecf20Sopenharmony_ci		 * unless we're during creation of a new controller to
20638c2ecf20Sopenharmony_ci		 * avoid races with teardown flow.
20648c2ecf20Sopenharmony_ci		 */
20658c2ecf20Sopenharmony_ci		WARN_ON_ONCE(ctrl->state != NVME_CTRL_DELETING &&
20668c2ecf20Sopenharmony_ci			     ctrl->state != NVME_CTRL_DELETING_NOIO);
20678c2ecf20Sopenharmony_ci		WARN_ON_ONCE(new);
20688c2ecf20Sopenharmony_ci		ret = -EINVAL;
20698c2ecf20Sopenharmony_ci		goto destroy_io;
20708c2ecf20Sopenharmony_ci	}
20718c2ecf20Sopenharmony_ci
20728c2ecf20Sopenharmony_ci	nvme_start_ctrl(ctrl);
20738c2ecf20Sopenharmony_ci	return 0;
20748c2ecf20Sopenharmony_ci
20758c2ecf20Sopenharmony_cidestroy_io:
20768c2ecf20Sopenharmony_ci	if (ctrl->queue_count > 1) {
20778c2ecf20Sopenharmony_ci		nvme_stop_queues(ctrl);
20788c2ecf20Sopenharmony_ci		nvme_sync_io_queues(ctrl);
20798c2ecf20Sopenharmony_ci		nvme_tcp_stop_io_queues(ctrl);
20808c2ecf20Sopenharmony_ci		nvme_cancel_tagset(ctrl);
20818c2ecf20Sopenharmony_ci		nvme_tcp_destroy_io_queues(ctrl, new);
20828c2ecf20Sopenharmony_ci	}
20838c2ecf20Sopenharmony_cidestroy_admin:
20848c2ecf20Sopenharmony_ci	nvme_stop_admin_queue(ctrl);
20858c2ecf20Sopenharmony_ci	blk_sync_queue(ctrl->admin_q);
20868c2ecf20Sopenharmony_ci	nvme_tcp_stop_queue(ctrl, 0);
20878c2ecf20Sopenharmony_ci	nvme_cancel_admin_tagset(ctrl);
20888c2ecf20Sopenharmony_ci	nvme_tcp_destroy_admin_queue(ctrl, new);
20898c2ecf20Sopenharmony_ci	return ret;
20908c2ecf20Sopenharmony_ci}
20918c2ecf20Sopenharmony_ci
20928c2ecf20Sopenharmony_cistatic void nvme_tcp_reconnect_ctrl_work(struct work_struct *work)
20938c2ecf20Sopenharmony_ci{
20948c2ecf20Sopenharmony_ci	struct nvme_tcp_ctrl *tcp_ctrl = container_of(to_delayed_work(work),
20958c2ecf20Sopenharmony_ci			struct nvme_tcp_ctrl, connect_work);
20968c2ecf20Sopenharmony_ci	struct nvme_ctrl *ctrl = &tcp_ctrl->ctrl;
20978c2ecf20Sopenharmony_ci
20988c2ecf20Sopenharmony_ci	++ctrl->nr_reconnects;
20998c2ecf20Sopenharmony_ci
21008c2ecf20Sopenharmony_ci	if (nvme_tcp_setup_ctrl(ctrl, false))
21018c2ecf20Sopenharmony_ci		goto requeue;
21028c2ecf20Sopenharmony_ci
21038c2ecf20Sopenharmony_ci	dev_info(ctrl->device, "Successfully reconnected (%d attempt)\n",
21048c2ecf20Sopenharmony_ci			ctrl->nr_reconnects);
21058c2ecf20Sopenharmony_ci
21068c2ecf20Sopenharmony_ci	ctrl->nr_reconnects = 0;
21078c2ecf20Sopenharmony_ci
21088c2ecf20Sopenharmony_ci	return;
21098c2ecf20Sopenharmony_ci
21108c2ecf20Sopenharmony_cirequeue:
21118c2ecf20Sopenharmony_ci	dev_info(ctrl->device, "Failed reconnect attempt %d\n",
21128c2ecf20Sopenharmony_ci			ctrl->nr_reconnects);
21138c2ecf20Sopenharmony_ci	nvme_tcp_reconnect_or_remove(ctrl);
21148c2ecf20Sopenharmony_ci}
21158c2ecf20Sopenharmony_ci
21168c2ecf20Sopenharmony_cistatic void nvme_tcp_error_recovery_work(struct work_struct *work)
21178c2ecf20Sopenharmony_ci{
21188c2ecf20Sopenharmony_ci	struct nvme_tcp_ctrl *tcp_ctrl = container_of(work,
21198c2ecf20Sopenharmony_ci				struct nvme_tcp_ctrl, err_work);
21208c2ecf20Sopenharmony_ci	struct nvme_ctrl *ctrl = &tcp_ctrl->ctrl;
21218c2ecf20Sopenharmony_ci
21228c2ecf20Sopenharmony_ci	nvme_stop_keep_alive(ctrl);
21238c2ecf20Sopenharmony_ci	flush_work(&ctrl->async_event_work);
21248c2ecf20Sopenharmony_ci	nvme_tcp_teardown_io_queues(ctrl, false);
21258c2ecf20Sopenharmony_ci	/* unquiesce to fail fast pending requests */
21268c2ecf20Sopenharmony_ci	nvme_start_queues(ctrl);
21278c2ecf20Sopenharmony_ci	nvme_tcp_teardown_admin_queue(ctrl, false);
21288c2ecf20Sopenharmony_ci	nvme_start_admin_queue(ctrl);
21298c2ecf20Sopenharmony_ci
21308c2ecf20Sopenharmony_ci	if (!nvme_change_ctrl_state(ctrl, NVME_CTRL_CONNECTING)) {
21318c2ecf20Sopenharmony_ci		/* state change failure is ok if we started ctrl delete */
21328c2ecf20Sopenharmony_ci		WARN_ON_ONCE(ctrl->state != NVME_CTRL_DELETING &&
21338c2ecf20Sopenharmony_ci			     ctrl->state != NVME_CTRL_DELETING_NOIO);
21348c2ecf20Sopenharmony_ci		return;
21358c2ecf20Sopenharmony_ci	}
21368c2ecf20Sopenharmony_ci
21378c2ecf20Sopenharmony_ci	nvme_tcp_reconnect_or_remove(ctrl);
21388c2ecf20Sopenharmony_ci}
21398c2ecf20Sopenharmony_ci
21408c2ecf20Sopenharmony_cistatic void nvme_tcp_teardown_ctrl(struct nvme_ctrl *ctrl, bool shutdown)
21418c2ecf20Sopenharmony_ci{
21428c2ecf20Sopenharmony_ci	nvme_tcp_teardown_io_queues(ctrl, shutdown);
21438c2ecf20Sopenharmony_ci	nvme_stop_admin_queue(ctrl);
21448c2ecf20Sopenharmony_ci	if (shutdown)
21458c2ecf20Sopenharmony_ci		nvme_shutdown_ctrl(ctrl);
21468c2ecf20Sopenharmony_ci	else
21478c2ecf20Sopenharmony_ci		nvme_disable_ctrl(ctrl);
21488c2ecf20Sopenharmony_ci	nvme_tcp_teardown_admin_queue(ctrl, shutdown);
21498c2ecf20Sopenharmony_ci}
21508c2ecf20Sopenharmony_ci
21518c2ecf20Sopenharmony_cistatic void nvme_tcp_delete_ctrl(struct nvme_ctrl *ctrl)
21528c2ecf20Sopenharmony_ci{
21538c2ecf20Sopenharmony_ci	nvme_tcp_teardown_ctrl(ctrl, true);
21548c2ecf20Sopenharmony_ci}
21558c2ecf20Sopenharmony_ci
21568c2ecf20Sopenharmony_cistatic void nvme_reset_ctrl_work(struct work_struct *work)
21578c2ecf20Sopenharmony_ci{
21588c2ecf20Sopenharmony_ci	struct nvme_ctrl *ctrl =
21598c2ecf20Sopenharmony_ci		container_of(work, struct nvme_ctrl, reset_work);
21608c2ecf20Sopenharmony_ci
21618c2ecf20Sopenharmony_ci	nvme_stop_ctrl(ctrl);
21628c2ecf20Sopenharmony_ci	nvme_tcp_teardown_ctrl(ctrl, false);
21638c2ecf20Sopenharmony_ci
21648c2ecf20Sopenharmony_ci	if (!nvme_change_ctrl_state(ctrl, NVME_CTRL_CONNECTING)) {
21658c2ecf20Sopenharmony_ci		/* state change failure is ok if we started ctrl delete */
21668c2ecf20Sopenharmony_ci		WARN_ON_ONCE(ctrl->state != NVME_CTRL_DELETING &&
21678c2ecf20Sopenharmony_ci			     ctrl->state != NVME_CTRL_DELETING_NOIO);
21688c2ecf20Sopenharmony_ci		return;
21698c2ecf20Sopenharmony_ci	}
21708c2ecf20Sopenharmony_ci
21718c2ecf20Sopenharmony_ci	if (nvme_tcp_setup_ctrl(ctrl, false))
21728c2ecf20Sopenharmony_ci		goto out_fail;
21738c2ecf20Sopenharmony_ci
21748c2ecf20Sopenharmony_ci	return;
21758c2ecf20Sopenharmony_ci
21768c2ecf20Sopenharmony_ciout_fail:
21778c2ecf20Sopenharmony_ci	++ctrl->nr_reconnects;
21788c2ecf20Sopenharmony_ci	nvme_tcp_reconnect_or_remove(ctrl);
21798c2ecf20Sopenharmony_ci}
21808c2ecf20Sopenharmony_ci
21818c2ecf20Sopenharmony_cistatic void nvme_tcp_stop_ctrl(struct nvme_ctrl *ctrl)
21828c2ecf20Sopenharmony_ci{
21838c2ecf20Sopenharmony_ci	cancel_work_sync(&to_tcp_ctrl(ctrl)->err_work);
21848c2ecf20Sopenharmony_ci	cancel_delayed_work_sync(&to_tcp_ctrl(ctrl)->connect_work);
21858c2ecf20Sopenharmony_ci}
21868c2ecf20Sopenharmony_ci
21878c2ecf20Sopenharmony_cistatic void nvme_tcp_free_ctrl(struct nvme_ctrl *nctrl)
21888c2ecf20Sopenharmony_ci{
21898c2ecf20Sopenharmony_ci	struct nvme_tcp_ctrl *ctrl = to_tcp_ctrl(nctrl);
21908c2ecf20Sopenharmony_ci
21918c2ecf20Sopenharmony_ci	if (list_empty(&ctrl->list))
21928c2ecf20Sopenharmony_ci		goto free_ctrl;
21938c2ecf20Sopenharmony_ci
21948c2ecf20Sopenharmony_ci	mutex_lock(&nvme_tcp_ctrl_mutex);
21958c2ecf20Sopenharmony_ci	list_del(&ctrl->list);
21968c2ecf20Sopenharmony_ci	mutex_unlock(&nvme_tcp_ctrl_mutex);
21978c2ecf20Sopenharmony_ci
21988c2ecf20Sopenharmony_ci	nvmf_free_options(nctrl->opts);
21998c2ecf20Sopenharmony_cifree_ctrl:
22008c2ecf20Sopenharmony_ci	kfree(ctrl->queues);
22018c2ecf20Sopenharmony_ci	kfree(ctrl);
22028c2ecf20Sopenharmony_ci}
22038c2ecf20Sopenharmony_ci
22048c2ecf20Sopenharmony_cistatic void nvme_tcp_set_sg_null(struct nvme_command *c)
22058c2ecf20Sopenharmony_ci{
22068c2ecf20Sopenharmony_ci	struct nvme_sgl_desc *sg = &c->common.dptr.sgl;
22078c2ecf20Sopenharmony_ci
22088c2ecf20Sopenharmony_ci	sg->addr = 0;
22098c2ecf20Sopenharmony_ci	sg->length = 0;
22108c2ecf20Sopenharmony_ci	sg->type = (NVME_TRANSPORT_SGL_DATA_DESC << 4) |
22118c2ecf20Sopenharmony_ci			NVME_SGL_FMT_TRANSPORT_A;
22128c2ecf20Sopenharmony_ci}
22138c2ecf20Sopenharmony_ci
22148c2ecf20Sopenharmony_cistatic void nvme_tcp_set_sg_inline(struct nvme_tcp_queue *queue,
22158c2ecf20Sopenharmony_ci		struct nvme_command *c, u32 data_len)
22168c2ecf20Sopenharmony_ci{
22178c2ecf20Sopenharmony_ci	struct nvme_sgl_desc *sg = &c->common.dptr.sgl;
22188c2ecf20Sopenharmony_ci
22198c2ecf20Sopenharmony_ci	sg->addr = cpu_to_le64(queue->ctrl->ctrl.icdoff);
22208c2ecf20Sopenharmony_ci	sg->length = cpu_to_le32(data_len);
22218c2ecf20Sopenharmony_ci	sg->type = (NVME_SGL_FMT_DATA_DESC << 4) | NVME_SGL_FMT_OFFSET;
22228c2ecf20Sopenharmony_ci}
22238c2ecf20Sopenharmony_ci
22248c2ecf20Sopenharmony_cistatic void nvme_tcp_set_sg_host_data(struct nvme_command *c,
22258c2ecf20Sopenharmony_ci		u32 data_len)
22268c2ecf20Sopenharmony_ci{
22278c2ecf20Sopenharmony_ci	struct nvme_sgl_desc *sg = &c->common.dptr.sgl;
22288c2ecf20Sopenharmony_ci
22298c2ecf20Sopenharmony_ci	sg->addr = 0;
22308c2ecf20Sopenharmony_ci	sg->length = cpu_to_le32(data_len);
22318c2ecf20Sopenharmony_ci	sg->type = (NVME_TRANSPORT_SGL_DATA_DESC << 4) |
22328c2ecf20Sopenharmony_ci			NVME_SGL_FMT_TRANSPORT_A;
22338c2ecf20Sopenharmony_ci}
22348c2ecf20Sopenharmony_ci
22358c2ecf20Sopenharmony_cistatic void nvme_tcp_submit_async_event(struct nvme_ctrl *arg)
22368c2ecf20Sopenharmony_ci{
22378c2ecf20Sopenharmony_ci	struct nvme_tcp_ctrl *ctrl = to_tcp_ctrl(arg);
22388c2ecf20Sopenharmony_ci	struct nvme_tcp_queue *queue = &ctrl->queues[0];
22398c2ecf20Sopenharmony_ci	struct nvme_tcp_cmd_pdu *pdu = ctrl->async_req.pdu;
22408c2ecf20Sopenharmony_ci	struct nvme_command *cmd = &pdu->cmd;
22418c2ecf20Sopenharmony_ci	u8 hdgst = nvme_tcp_hdgst_len(queue);
22428c2ecf20Sopenharmony_ci
22438c2ecf20Sopenharmony_ci	memset(pdu, 0, sizeof(*pdu));
22448c2ecf20Sopenharmony_ci	pdu->hdr.type = nvme_tcp_cmd;
22458c2ecf20Sopenharmony_ci	if (queue->hdr_digest)
22468c2ecf20Sopenharmony_ci		pdu->hdr.flags |= NVME_TCP_F_HDGST;
22478c2ecf20Sopenharmony_ci	pdu->hdr.hlen = sizeof(*pdu);
22488c2ecf20Sopenharmony_ci	pdu->hdr.plen = cpu_to_le32(pdu->hdr.hlen + hdgst);
22498c2ecf20Sopenharmony_ci
22508c2ecf20Sopenharmony_ci	cmd->common.opcode = nvme_admin_async_event;
22518c2ecf20Sopenharmony_ci	cmd->common.command_id = NVME_AQ_BLK_MQ_DEPTH;
22528c2ecf20Sopenharmony_ci	cmd->common.flags |= NVME_CMD_SGL_METABUF;
22538c2ecf20Sopenharmony_ci	nvme_tcp_set_sg_null(cmd);
22548c2ecf20Sopenharmony_ci
22558c2ecf20Sopenharmony_ci	ctrl->async_req.state = NVME_TCP_SEND_CMD_PDU;
22568c2ecf20Sopenharmony_ci	ctrl->async_req.offset = 0;
22578c2ecf20Sopenharmony_ci	ctrl->async_req.curr_bio = NULL;
22588c2ecf20Sopenharmony_ci	ctrl->async_req.data_len = 0;
22598c2ecf20Sopenharmony_ci
22608c2ecf20Sopenharmony_ci	nvme_tcp_queue_request(&ctrl->async_req, true, true);
22618c2ecf20Sopenharmony_ci}
22628c2ecf20Sopenharmony_ci
22638c2ecf20Sopenharmony_cistatic void nvme_tcp_complete_timed_out(struct request *rq)
22648c2ecf20Sopenharmony_ci{
22658c2ecf20Sopenharmony_ci	struct nvme_tcp_request *req = blk_mq_rq_to_pdu(rq);
22668c2ecf20Sopenharmony_ci	struct nvme_ctrl *ctrl = &req->queue->ctrl->ctrl;
22678c2ecf20Sopenharmony_ci
22688c2ecf20Sopenharmony_ci	nvme_tcp_stop_queue(ctrl, nvme_tcp_queue_id(req->queue));
22698c2ecf20Sopenharmony_ci	if (blk_mq_request_started(rq) && !blk_mq_request_completed(rq)) {
22708c2ecf20Sopenharmony_ci		nvme_req(rq)->status = NVME_SC_HOST_ABORTED_CMD;
22718c2ecf20Sopenharmony_ci		blk_mq_complete_request(rq);
22728c2ecf20Sopenharmony_ci	}
22738c2ecf20Sopenharmony_ci}
22748c2ecf20Sopenharmony_ci
22758c2ecf20Sopenharmony_cistatic enum blk_eh_timer_return
22768c2ecf20Sopenharmony_cinvme_tcp_timeout(struct request *rq, bool reserved)
22778c2ecf20Sopenharmony_ci{
22788c2ecf20Sopenharmony_ci	struct nvme_tcp_request *req = blk_mq_rq_to_pdu(rq);
22798c2ecf20Sopenharmony_ci	struct nvme_ctrl *ctrl = &req->queue->ctrl->ctrl;
22808c2ecf20Sopenharmony_ci	struct nvme_tcp_cmd_pdu *pdu = req->pdu;
22818c2ecf20Sopenharmony_ci
22828c2ecf20Sopenharmony_ci	dev_warn(ctrl->device,
22838c2ecf20Sopenharmony_ci		"queue %d: timeout request %#x type %d\n",
22848c2ecf20Sopenharmony_ci		nvme_tcp_queue_id(req->queue), rq->tag, pdu->hdr.type);
22858c2ecf20Sopenharmony_ci
22868c2ecf20Sopenharmony_ci	if (ctrl->state != NVME_CTRL_LIVE) {
22878c2ecf20Sopenharmony_ci		/*
22888c2ecf20Sopenharmony_ci		 * If we are resetting, connecting or deleting we should
22898c2ecf20Sopenharmony_ci		 * complete immediately because we may block controller
22908c2ecf20Sopenharmony_ci		 * teardown or setup sequence
22918c2ecf20Sopenharmony_ci		 * - ctrl disable/shutdown fabrics requests
22928c2ecf20Sopenharmony_ci		 * - connect requests
22938c2ecf20Sopenharmony_ci		 * - initialization admin requests
22948c2ecf20Sopenharmony_ci		 * - I/O requests that entered after unquiescing and
22958c2ecf20Sopenharmony_ci		 *   the controller stopped responding
22968c2ecf20Sopenharmony_ci		 *
22978c2ecf20Sopenharmony_ci		 * All other requests should be cancelled by the error
22988c2ecf20Sopenharmony_ci		 * recovery work, so it's fine that we fail it here.
22998c2ecf20Sopenharmony_ci		 */
23008c2ecf20Sopenharmony_ci		nvme_tcp_complete_timed_out(rq);
23018c2ecf20Sopenharmony_ci		return BLK_EH_DONE;
23028c2ecf20Sopenharmony_ci	}
23038c2ecf20Sopenharmony_ci
23048c2ecf20Sopenharmony_ci	/*
23058c2ecf20Sopenharmony_ci	 * LIVE state should trigger the normal error recovery which will
23068c2ecf20Sopenharmony_ci	 * handle completing this request.
23078c2ecf20Sopenharmony_ci	 */
23088c2ecf20Sopenharmony_ci	nvme_tcp_error_recovery(ctrl);
23098c2ecf20Sopenharmony_ci	return BLK_EH_RESET_TIMER;
23108c2ecf20Sopenharmony_ci}
23118c2ecf20Sopenharmony_ci
23128c2ecf20Sopenharmony_cistatic blk_status_t nvme_tcp_map_data(struct nvme_tcp_queue *queue,
23138c2ecf20Sopenharmony_ci			struct request *rq)
23148c2ecf20Sopenharmony_ci{
23158c2ecf20Sopenharmony_ci	struct nvme_tcp_request *req = blk_mq_rq_to_pdu(rq);
23168c2ecf20Sopenharmony_ci	struct nvme_tcp_cmd_pdu *pdu = req->pdu;
23178c2ecf20Sopenharmony_ci	struct nvme_command *c = &pdu->cmd;
23188c2ecf20Sopenharmony_ci
23198c2ecf20Sopenharmony_ci	c->common.flags |= NVME_CMD_SGL_METABUF;
23208c2ecf20Sopenharmony_ci
23218c2ecf20Sopenharmony_ci	if (!blk_rq_nr_phys_segments(rq))
23228c2ecf20Sopenharmony_ci		nvme_tcp_set_sg_null(c);
23238c2ecf20Sopenharmony_ci	else if (rq_data_dir(rq) == WRITE &&
23248c2ecf20Sopenharmony_ci	    req->data_len <= nvme_tcp_inline_data_size(queue))
23258c2ecf20Sopenharmony_ci		nvme_tcp_set_sg_inline(queue, c, req->data_len);
23268c2ecf20Sopenharmony_ci	else
23278c2ecf20Sopenharmony_ci		nvme_tcp_set_sg_host_data(c, req->data_len);
23288c2ecf20Sopenharmony_ci
23298c2ecf20Sopenharmony_ci	return 0;
23308c2ecf20Sopenharmony_ci}
23318c2ecf20Sopenharmony_ci
23328c2ecf20Sopenharmony_cistatic blk_status_t nvme_tcp_setup_cmd_pdu(struct nvme_ns *ns,
23338c2ecf20Sopenharmony_ci		struct request *rq)
23348c2ecf20Sopenharmony_ci{
23358c2ecf20Sopenharmony_ci	struct nvme_tcp_request *req = blk_mq_rq_to_pdu(rq);
23368c2ecf20Sopenharmony_ci	struct nvme_tcp_cmd_pdu *pdu = req->pdu;
23378c2ecf20Sopenharmony_ci	struct nvme_tcp_queue *queue = req->queue;
23388c2ecf20Sopenharmony_ci	u8 hdgst = nvme_tcp_hdgst_len(queue), ddgst = 0;
23398c2ecf20Sopenharmony_ci	blk_status_t ret;
23408c2ecf20Sopenharmony_ci
23418c2ecf20Sopenharmony_ci	ret = nvme_setup_cmd(ns, rq, &pdu->cmd);
23428c2ecf20Sopenharmony_ci	if (ret)
23438c2ecf20Sopenharmony_ci		return ret;
23448c2ecf20Sopenharmony_ci
23458c2ecf20Sopenharmony_ci	req->state = NVME_TCP_SEND_CMD_PDU;
23468c2ecf20Sopenharmony_ci	req->offset = 0;
23478c2ecf20Sopenharmony_ci	req->data_sent = 0;
23488c2ecf20Sopenharmony_ci	req->pdu_len = 0;
23498c2ecf20Sopenharmony_ci	req->pdu_sent = 0;
23508c2ecf20Sopenharmony_ci	req->data_len = blk_rq_nr_phys_segments(rq) ?
23518c2ecf20Sopenharmony_ci				blk_rq_payload_bytes(rq) : 0;
23528c2ecf20Sopenharmony_ci	req->curr_bio = rq->bio;
23538c2ecf20Sopenharmony_ci
23548c2ecf20Sopenharmony_ci	if (rq_data_dir(rq) == WRITE &&
23558c2ecf20Sopenharmony_ci	    req->data_len <= nvme_tcp_inline_data_size(queue))
23568c2ecf20Sopenharmony_ci		req->pdu_len = req->data_len;
23578c2ecf20Sopenharmony_ci	else if (req->curr_bio)
23588c2ecf20Sopenharmony_ci		nvme_tcp_init_iter(req, READ);
23598c2ecf20Sopenharmony_ci
23608c2ecf20Sopenharmony_ci	pdu->hdr.type = nvme_tcp_cmd;
23618c2ecf20Sopenharmony_ci	pdu->hdr.flags = 0;
23628c2ecf20Sopenharmony_ci	if (queue->hdr_digest)
23638c2ecf20Sopenharmony_ci		pdu->hdr.flags |= NVME_TCP_F_HDGST;
23648c2ecf20Sopenharmony_ci	if (queue->data_digest && req->pdu_len) {
23658c2ecf20Sopenharmony_ci		pdu->hdr.flags |= NVME_TCP_F_DDGST;
23668c2ecf20Sopenharmony_ci		ddgst = nvme_tcp_ddgst_len(queue);
23678c2ecf20Sopenharmony_ci	}
23688c2ecf20Sopenharmony_ci	pdu->hdr.hlen = sizeof(*pdu);
23698c2ecf20Sopenharmony_ci	pdu->hdr.pdo = req->pdu_len ? pdu->hdr.hlen + hdgst : 0;
23708c2ecf20Sopenharmony_ci	pdu->hdr.plen =
23718c2ecf20Sopenharmony_ci		cpu_to_le32(pdu->hdr.hlen + hdgst + req->pdu_len + ddgst);
23728c2ecf20Sopenharmony_ci
23738c2ecf20Sopenharmony_ci	ret = nvme_tcp_map_data(queue, rq);
23748c2ecf20Sopenharmony_ci	if (unlikely(ret)) {
23758c2ecf20Sopenharmony_ci		nvme_cleanup_cmd(rq);
23768c2ecf20Sopenharmony_ci		dev_err(queue->ctrl->ctrl.device,
23778c2ecf20Sopenharmony_ci			"Failed to map data (%d)\n", ret);
23788c2ecf20Sopenharmony_ci		return ret;
23798c2ecf20Sopenharmony_ci	}
23808c2ecf20Sopenharmony_ci
23818c2ecf20Sopenharmony_ci	return 0;
23828c2ecf20Sopenharmony_ci}
23838c2ecf20Sopenharmony_ci
23848c2ecf20Sopenharmony_cistatic void nvme_tcp_commit_rqs(struct blk_mq_hw_ctx *hctx)
23858c2ecf20Sopenharmony_ci{
23868c2ecf20Sopenharmony_ci	struct nvme_tcp_queue *queue = hctx->driver_data;
23878c2ecf20Sopenharmony_ci
23888c2ecf20Sopenharmony_ci	if (!llist_empty(&queue->req_list))
23898c2ecf20Sopenharmony_ci		queue_work_on(queue->io_cpu, nvme_tcp_wq, &queue->io_work);
23908c2ecf20Sopenharmony_ci}
23918c2ecf20Sopenharmony_ci
23928c2ecf20Sopenharmony_cistatic blk_status_t nvme_tcp_queue_rq(struct blk_mq_hw_ctx *hctx,
23938c2ecf20Sopenharmony_ci		const struct blk_mq_queue_data *bd)
23948c2ecf20Sopenharmony_ci{
23958c2ecf20Sopenharmony_ci	struct nvme_ns *ns = hctx->queue->queuedata;
23968c2ecf20Sopenharmony_ci	struct nvme_tcp_queue *queue = hctx->driver_data;
23978c2ecf20Sopenharmony_ci	struct request *rq = bd->rq;
23988c2ecf20Sopenharmony_ci	struct nvme_tcp_request *req = blk_mq_rq_to_pdu(rq);
23998c2ecf20Sopenharmony_ci	bool queue_ready = test_bit(NVME_TCP_Q_LIVE, &queue->flags);
24008c2ecf20Sopenharmony_ci	blk_status_t ret;
24018c2ecf20Sopenharmony_ci
24028c2ecf20Sopenharmony_ci	if (!nvmf_check_ready(&queue->ctrl->ctrl, rq, queue_ready))
24038c2ecf20Sopenharmony_ci		return nvmf_fail_nonready_command(&queue->ctrl->ctrl, rq);
24048c2ecf20Sopenharmony_ci
24058c2ecf20Sopenharmony_ci	ret = nvme_tcp_setup_cmd_pdu(ns, rq);
24068c2ecf20Sopenharmony_ci	if (unlikely(ret))
24078c2ecf20Sopenharmony_ci		return ret;
24088c2ecf20Sopenharmony_ci
24098c2ecf20Sopenharmony_ci	blk_mq_start_request(rq);
24108c2ecf20Sopenharmony_ci
24118c2ecf20Sopenharmony_ci	nvme_tcp_queue_request(req, true, bd->last);
24128c2ecf20Sopenharmony_ci
24138c2ecf20Sopenharmony_ci	return BLK_STS_OK;
24148c2ecf20Sopenharmony_ci}
24158c2ecf20Sopenharmony_ci
24168c2ecf20Sopenharmony_cistatic int nvme_tcp_map_queues(struct blk_mq_tag_set *set)
24178c2ecf20Sopenharmony_ci{
24188c2ecf20Sopenharmony_ci	struct nvme_tcp_ctrl *ctrl = set->driver_data;
24198c2ecf20Sopenharmony_ci	struct nvmf_ctrl_options *opts = ctrl->ctrl.opts;
24208c2ecf20Sopenharmony_ci
24218c2ecf20Sopenharmony_ci	if (opts->nr_write_queues && ctrl->io_queues[HCTX_TYPE_READ]) {
24228c2ecf20Sopenharmony_ci		/* separate read/write queues */
24238c2ecf20Sopenharmony_ci		set->map[HCTX_TYPE_DEFAULT].nr_queues =
24248c2ecf20Sopenharmony_ci			ctrl->io_queues[HCTX_TYPE_DEFAULT];
24258c2ecf20Sopenharmony_ci		set->map[HCTX_TYPE_DEFAULT].queue_offset = 0;
24268c2ecf20Sopenharmony_ci		set->map[HCTX_TYPE_READ].nr_queues =
24278c2ecf20Sopenharmony_ci			ctrl->io_queues[HCTX_TYPE_READ];
24288c2ecf20Sopenharmony_ci		set->map[HCTX_TYPE_READ].queue_offset =
24298c2ecf20Sopenharmony_ci			ctrl->io_queues[HCTX_TYPE_DEFAULT];
24308c2ecf20Sopenharmony_ci	} else {
24318c2ecf20Sopenharmony_ci		/* shared read/write queues */
24328c2ecf20Sopenharmony_ci		set->map[HCTX_TYPE_DEFAULT].nr_queues =
24338c2ecf20Sopenharmony_ci			ctrl->io_queues[HCTX_TYPE_DEFAULT];
24348c2ecf20Sopenharmony_ci		set->map[HCTX_TYPE_DEFAULT].queue_offset = 0;
24358c2ecf20Sopenharmony_ci		set->map[HCTX_TYPE_READ].nr_queues =
24368c2ecf20Sopenharmony_ci			ctrl->io_queues[HCTX_TYPE_DEFAULT];
24378c2ecf20Sopenharmony_ci		set->map[HCTX_TYPE_READ].queue_offset = 0;
24388c2ecf20Sopenharmony_ci	}
24398c2ecf20Sopenharmony_ci	blk_mq_map_queues(&set->map[HCTX_TYPE_DEFAULT]);
24408c2ecf20Sopenharmony_ci	blk_mq_map_queues(&set->map[HCTX_TYPE_READ]);
24418c2ecf20Sopenharmony_ci
24428c2ecf20Sopenharmony_ci	if (opts->nr_poll_queues && ctrl->io_queues[HCTX_TYPE_POLL]) {
24438c2ecf20Sopenharmony_ci		/* map dedicated poll queues only if we have queues left */
24448c2ecf20Sopenharmony_ci		set->map[HCTX_TYPE_POLL].nr_queues =
24458c2ecf20Sopenharmony_ci				ctrl->io_queues[HCTX_TYPE_POLL];
24468c2ecf20Sopenharmony_ci		set->map[HCTX_TYPE_POLL].queue_offset =
24478c2ecf20Sopenharmony_ci			ctrl->io_queues[HCTX_TYPE_DEFAULT] +
24488c2ecf20Sopenharmony_ci			ctrl->io_queues[HCTX_TYPE_READ];
24498c2ecf20Sopenharmony_ci		blk_mq_map_queues(&set->map[HCTX_TYPE_POLL]);
24508c2ecf20Sopenharmony_ci	}
24518c2ecf20Sopenharmony_ci
24528c2ecf20Sopenharmony_ci	dev_info(ctrl->ctrl.device,
24538c2ecf20Sopenharmony_ci		"mapped %d/%d/%d default/read/poll queues.\n",
24548c2ecf20Sopenharmony_ci		ctrl->io_queues[HCTX_TYPE_DEFAULT],
24558c2ecf20Sopenharmony_ci		ctrl->io_queues[HCTX_TYPE_READ],
24568c2ecf20Sopenharmony_ci		ctrl->io_queues[HCTX_TYPE_POLL]);
24578c2ecf20Sopenharmony_ci
24588c2ecf20Sopenharmony_ci	return 0;
24598c2ecf20Sopenharmony_ci}
24608c2ecf20Sopenharmony_ci
24618c2ecf20Sopenharmony_cistatic int nvme_tcp_poll(struct blk_mq_hw_ctx *hctx)
24628c2ecf20Sopenharmony_ci{
24638c2ecf20Sopenharmony_ci	struct nvme_tcp_queue *queue = hctx->driver_data;
24648c2ecf20Sopenharmony_ci	struct sock *sk = queue->sock->sk;
24658c2ecf20Sopenharmony_ci
24668c2ecf20Sopenharmony_ci	if (!test_bit(NVME_TCP_Q_LIVE, &queue->flags))
24678c2ecf20Sopenharmony_ci		return 0;
24688c2ecf20Sopenharmony_ci
24698c2ecf20Sopenharmony_ci	set_bit(NVME_TCP_Q_POLLING, &queue->flags);
24708c2ecf20Sopenharmony_ci	if (sk_can_busy_loop(sk) && skb_queue_empty_lockless(&sk->sk_receive_queue))
24718c2ecf20Sopenharmony_ci		sk_busy_loop(sk, true);
24728c2ecf20Sopenharmony_ci	nvme_tcp_try_recv(queue);
24738c2ecf20Sopenharmony_ci	clear_bit(NVME_TCP_Q_POLLING, &queue->flags);
24748c2ecf20Sopenharmony_ci	return queue->nr_cqe;
24758c2ecf20Sopenharmony_ci}
24768c2ecf20Sopenharmony_ci
24778c2ecf20Sopenharmony_cistatic const struct blk_mq_ops nvme_tcp_mq_ops = {
24788c2ecf20Sopenharmony_ci	.queue_rq	= nvme_tcp_queue_rq,
24798c2ecf20Sopenharmony_ci	.commit_rqs	= nvme_tcp_commit_rqs,
24808c2ecf20Sopenharmony_ci	.complete	= nvme_complete_rq,
24818c2ecf20Sopenharmony_ci	.init_request	= nvme_tcp_init_request,
24828c2ecf20Sopenharmony_ci	.exit_request	= nvme_tcp_exit_request,
24838c2ecf20Sopenharmony_ci	.init_hctx	= nvme_tcp_init_hctx,
24848c2ecf20Sopenharmony_ci	.timeout	= nvme_tcp_timeout,
24858c2ecf20Sopenharmony_ci	.map_queues	= nvme_tcp_map_queues,
24868c2ecf20Sopenharmony_ci	.poll		= nvme_tcp_poll,
24878c2ecf20Sopenharmony_ci};
24888c2ecf20Sopenharmony_ci
24898c2ecf20Sopenharmony_cistatic const struct blk_mq_ops nvme_tcp_admin_mq_ops = {
24908c2ecf20Sopenharmony_ci	.queue_rq	= nvme_tcp_queue_rq,
24918c2ecf20Sopenharmony_ci	.complete	= nvme_complete_rq,
24928c2ecf20Sopenharmony_ci	.init_request	= nvme_tcp_init_request,
24938c2ecf20Sopenharmony_ci	.exit_request	= nvme_tcp_exit_request,
24948c2ecf20Sopenharmony_ci	.init_hctx	= nvme_tcp_init_admin_hctx,
24958c2ecf20Sopenharmony_ci	.timeout	= nvme_tcp_timeout,
24968c2ecf20Sopenharmony_ci};
24978c2ecf20Sopenharmony_ci
24988c2ecf20Sopenharmony_cistatic const struct nvme_ctrl_ops nvme_tcp_ctrl_ops = {
24998c2ecf20Sopenharmony_ci	.name			= "tcp",
25008c2ecf20Sopenharmony_ci	.module			= THIS_MODULE,
25018c2ecf20Sopenharmony_ci	.flags			= NVME_F_FABRICS,
25028c2ecf20Sopenharmony_ci	.reg_read32		= nvmf_reg_read32,
25038c2ecf20Sopenharmony_ci	.reg_read64		= nvmf_reg_read64,
25048c2ecf20Sopenharmony_ci	.reg_write32		= nvmf_reg_write32,
25058c2ecf20Sopenharmony_ci	.free_ctrl		= nvme_tcp_free_ctrl,
25068c2ecf20Sopenharmony_ci	.submit_async_event	= nvme_tcp_submit_async_event,
25078c2ecf20Sopenharmony_ci	.delete_ctrl		= nvme_tcp_delete_ctrl,
25088c2ecf20Sopenharmony_ci	.get_address		= nvmf_get_address,
25098c2ecf20Sopenharmony_ci	.stop_ctrl		= nvme_tcp_stop_ctrl,
25108c2ecf20Sopenharmony_ci};
25118c2ecf20Sopenharmony_ci
25128c2ecf20Sopenharmony_cistatic bool
25138c2ecf20Sopenharmony_cinvme_tcp_existing_controller(struct nvmf_ctrl_options *opts)
25148c2ecf20Sopenharmony_ci{
25158c2ecf20Sopenharmony_ci	struct nvme_tcp_ctrl *ctrl;
25168c2ecf20Sopenharmony_ci	bool found = false;
25178c2ecf20Sopenharmony_ci
25188c2ecf20Sopenharmony_ci	mutex_lock(&nvme_tcp_ctrl_mutex);
25198c2ecf20Sopenharmony_ci	list_for_each_entry(ctrl, &nvme_tcp_ctrl_list, list) {
25208c2ecf20Sopenharmony_ci		found = nvmf_ip_options_match(&ctrl->ctrl, opts);
25218c2ecf20Sopenharmony_ci		if (found)
25228c2ecf20Sopenharmony_ci			break;
25238c2ecf20Sopenharmony_ci	}
25248c2ecf20Sopenharmony_ci	mutex_unlock(&nvme_tcp_ctrl_mutex);
25258c2ecf20Sopenharmony_ci
25268c2ecf20Sopenharmony_ci	return found;
25278c2ecf20Sopenharmony_ci}
25288c2ecf20Sopenharmony_ci
25298c2ecf20Sopenharmony_cistatic struct nvme_ctrl *nvme_tcp_create_ctrl(struct device *dev,
25308c2ecf20Sopenharmony_ci		struct nvmf_ctrl_options *opts)
25318c2ecf20Sopenharmony_ci{
25328c2ecf20Sopenharmony_ci	struct nvme_tcp_ctrl *ctrl;
25338c2ecf20Sopenharmony_ci	int ret;
25348c2ecf20Sopenharmony_ci
25358c2ecf20Sopenharmony_ci	ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
25368c2ecf20Sopenharmony_ci	if (!ctrl)
25378c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
25388c2ecf20Sopenharmony_ci
25398c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&ctrl->list);
25408c2ecf20Sopenharmony_ci	ctrl->ctrl.opts = opts;
25418c2ecf20Sopenharmony_ci	ctrl->ctrl.queue_count = opts->nr_io_queues + opts->nr_write_queues +
25428c2ecf20Sopenharmony_ci				opts->nr_poll_queues + 1;
25438c2ecf20Sopenharmony_ci	ctrl->ctrl.sqsize = opts->queue_size - 1;
25448c2ecf20Sopenharmony_ci	ctrl->ctrl.kato = opts->kato;
25458c2ecf20Sopenharmony_ci
25468c2ecf20Sopenharmony_ci	INIT_DELAYED_WORK(&ctrl->connect_work,
25478c2ecf20Sopenharmony_ci			nvme_tcp_reconnect_ctrl_work);
25488c2ecf20Sopenharmony_ci	INIT_WORK(&ctrl->err_work, nvme_tcp_error_recovery_work);
25498c2ecf20Sopenharmony_ci	INIT_WORK(&ctrl->ctrl.reset_work, nvme_reset_ctrl_work);
25508c2ecf20Sopenharmony_ci
25518c2ecf20Sopenharmony_ci	if (!(opts->mask & NVMF_OPT_TRSVCID)) {
25528c2ecf20Sopenharmony_ci		opts->trsvcid =
25538c2ecf20Sopenharmony_ci			kstrdup(__stringify(NVME_TCP_DISC_PORT), GFP_KERNEL);
25548c2ecf20Sopenharmony_ci		if (!opts->trsvcid) {
25558c2ecf20Sopenharmony_ci			ret = -ENOMEM;
25568c2ecf20Sopenharmony_ci			goto out_free_ctrl;
25578c2ecf20Sopenharmony_ci		}
25588c2ecf20Sopenharmony_ci		opts->mask |= NVMF_OPT_TRSVCID;
25598c2ecf20Sopenharmony_ci	}
25608c2ecf20Sopenharmony_ci
25618c2ecf20Sopenharmony_ci	ret = inet_pton_with_scope(&init_net, AF_UNSPEC,
25628c2ecf20Sopenharmony_ci			opts->traddr, opts->trsvcid, &ctrl->addr);
25638c2ecf20Sopenharmony_ci	if (ret) {
25648c2ecf20Sopenharmony_ci		pr_err("malformed address passed: %s:%s\n",
25658c2ecf20Sopenharmony_ci			opts->traddr, opts->trsvcid);
25668c2ecf20Sopenharmony_ci		goto out_free_ctrl;
25678c2ecf20Sopenharmony_ci	}
25688c2ecf20Sopenharmony_ci
25698c2ecf20Sopenharmony_ci	if (opts->mask & NVMF_OPT_HOST_TRADDR) {
25708c2ecf20Sopenharmony_ci		ret = inet_pton_with_scope(&init_net, AF_UNSPEC,
25718c2ecf20Sopenharmony_ci			opts->host_traddr, NULL, &ctrl->src_addr);
25728c2ecf20Sopenharmony_ci		if (ret) {
25738c2ecf20Sopenharmony_ci			pr_err("malformed src address passed: %s\n",
25748c2ecf20Sopenharmony_ci			       opts->host_traddr);
25758c2ecf20Sopenharmony_ci			goto out_free_ctrl;
25768c2ecf20Sopenharmony_ci		}
25778c2ecf20Sopenharmony_ci	}
25788c2ecf20Sopenharmony_ci
25798c2ecf20Sopenharmony_ci	if (!opts->duplicate_connect && nvme_tcp_existing_controller(opts)) {
25808c2ecf20Sopenharmony_ci		ret = -EALREADY;
25818c2ecf20Sopenharmony_ci		goto out_free_ctrl;
25828c2ecf20Sopenharmony_ci	}
25838c2ecf20Sopenharmony_ci
25848c2ecf20Sopenharmony_ci	ctrl->queues = kcalloc(ctrl->ctrl.queue_count, sizeof(*ctrl->queues),
25858c2ecf20Sopenharmony_ci				GFP_KERNEL);
25868c2ecf20Sopenharmony_ci	if (!ctrl->queues) {
25878c2ecf20Sopenharmony_ci		ret = -ENOMEM;
25888c2ecf20Sopenharmony_ci		goto out_free_ctrl;
25898c2ecf20Sopenharmony_ci	}
25908c2ecf20Sopenharmony_ci
25918c2ecf20Sopenharmony_ci	ret = nvme_init_ctrl(&ctrl->ctrl, dev, &nvme_tcp_ctrl_ops, 0);
25928c2ecf20Sopenharmony_ci	if (ret)
25938c2ecf20Sopenharmony_ci		goto out_kfree_queues;
25948c2ecf20Sopenharmony_ci
25958c2ecf20Sopenharmony_ci	if (!nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_CONNECTING)) {
25968c2ecf20Sopenharmony_ci		WARN_ON_ONCE(1);
25978c2ecf20Sopenharmony_ci		ret = -EINTR;
25988c2ecf20Sopenharmony_ci		goto out_uninit_ctrl;
25998c2ecf20Sopenharmony_ci	}
26008c2ecf20Sopenharmony_ci
26018c2ecf20Sopenharmony_ci	ret = nvme_tcp_setup_ctrl(&ctrl->ctrl, true);
26028c2ecf20Sopenharmony_ci	if (ret)
26038c2ecf20Sopenharmony_ci		goto out_uninit_ctrl;
26048c2ecf20Sopenharmony_ci
26058c2ecf20Sopenharmony_ci	dev_info(ctrl->ctrl.device, "new ctrl: NQN \"%s\", addr %pISp\n",
26068c2ecf20Sopenharmony_ci		ctrl->ctrl.opts->subsysnqn, &ctrl->addr);
26078c2ecf20Sopenharmony_ci
26088c2ecf20Sopenharmony_ci	mutex_lock(&nvme_tcp_ctrl_mutex);
26098c2ecf20Sopenharmony_ci	list_add_tail(&ctrl->list, &nvme_tcp_ctrl_list);
26108c2ecf20Sopenharmony_ci	mutex_unlock(&nvme_tcp_ctrl_mutex);
26118c2ecf20Sopenharmony_ci
26128c2ecf20Sopenharmony_ci	return &ctrl->ctrl;
26138c2ecf20Sopenharmony_ci
26148c2ecf20Sopenharmony_ciout_uninit_ctrl:
26158c2ecf20Sopenharmony_ci	nvme_uninit_ctrl(&ctrl->ctrl);
26168c2ecf20Sopenharmony_ci	nvme_put_ctrl(&ctrl->ctrl);
26178c2ecf20Sopenharmony_ci	if (ret > 0)
26188c2ecf20Sopenharmony_ci		ret = -EIO;
26198c2ecf20Sopenharmony_ci	return ERR_PTR(ret);
26208c2ecf20Sopenharmony_ciout_kfree_queues:
26218c2ecf20Sopenharmony_ci	kfree(ctrl->queues);
26228c2ecf20Sopenharmony_ciout_free_ctrl:
26238c2ecf20Sopenharmony_ci	kfree(ctrl);
26248c2ecf20Sopenharmony_ci	return ERR_PTR(ret);
26258c2ecf20Sopenharmony_ci}
26268c2ecf20Sopenharmony_ci
26278c2ecf20Sopenharmony_cistatic struct nvmf_transport_ops nvme_tcp_transport = {
26288c2ecf20Sopenharmony_ci	.name		= "tcp",
26298c2ecf20Sopenharmony_ci	.module		= THIS_MODULE,
26308c2ecf20Sopenharmony_ci	.required_opts	= NVMF_OPT_TRADDR,
26318c2ecf20Sopenharmony_ci	.allowed_opts	= NVMF_OPT_TRSVCID | NVMF_OPT_RECONNECT_DELAY |
26328c2ecf20Sopenharmony_ci			  NVMF_OPT_HOST_TRADDR | NVMF_OPT_CTRL_LOSS_TMO |
26338c2ecf20Sopenharmony_ci			  NVMF_OPT_HDR_DIGEST | NVMF_OPT_DATA_DIGEST |
26348c2ecf20Sopenharmony_ci			  NVMF_OPT_NR_WRITE_QUEUES | NVMF_OPT_NR_POLL_QUEUES |
26358c2ecf20Sopenharmony_ci			  NVMF_OPT_TOS,
26368c2ecf20Sopenharmony_ci	.create_ctrl	= nvme_tcp_create_ctrl,
26378c2ecf20Sopenharmony_ci};
26388c2ecf20Sopenharmony_ci
26398c2ecf20Sopenharmony_cistatic int __init nvme_tcp_init_module(void)
26408c2ecf20Sopenharmony_ci{
26418c2ecf20Sopenharmony_ci	nvme_tcp_wq = alloc_workqueue("nvme_tcp_wq",
26428c2ecf20Sopenharmony_ci			WQ_MEM_RECLAIM | WQ_HIGHPRI, 0);
26438c2ecf20Sopenharmony_ci	if (!nvme_tcp_wq)
26448c2ecf20Sopenharmony_ci		return -ENOMEM;
26458c2ecf20Sopenharmony_ci
26468c2ecf20Sopenharmony_ci	nvmf_register_transport(&nvme_tcp_transport);
26478c2ecf20Sopenharmony_ci	return 0;
26488c2ecf20Sopenharmony_ci}
26498c2ecf20Sopenharmony_ci
26508c2ecf20Sopenharmony_cistatic void __exit nvme_tcp_cleanup_module(void)
26518c2ecf20Sopenharmony_ci{
26528c2ecf20Sopenharmony_ci	struct nvme_tcp_ctrl *ctrl;
26538c2ecf20Sopenharmony_ci
26548c2ecf20Sopenharmony_ci	nvmf_unregister_transport(&nvme_tcp_transport);
26558c2ecf20Sopenharmony_ci
26568c2ecf20Sopenharmony_ci	mutex_lock(&nvme_tcp_ctrl_mutex);
26578c2ecf20Sopenharmony_ci	list_for_each_entry(ctrl, &nvme_tcp_ctrl_list, list)
26588c2ecf20Sopenharmony_ci		nvme_delete_ctrl(&ctrl->ctrl);
26598c2ecf20Sopenharmony_ci	mutex_unlock(&nvme_tcp_ctrl_mutex);
26608c2ecf20Sopenharmony_ci	flush_workqueue(nvme_delete_wq);
26618c2ecf20Sopenharmony_ci
26628c2ecf20Sopenharmony_ci	destroy_workqueue(nvme_tcp_wq);
26638c2ecf20Sopenharmony_ci}
26648c2ecf20Sopenharmony_ci
26658c2ecf20Sopenharmony_cimodule_init(nvme_tcp_init_module);
26668c2ecf20Sopenharmony_cimodule_exit(nvme_tcp_cleanup_module);
26678c2ecf20Sopenharmony_ci
26688c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
2669