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