109c434b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2ac713874SUrsula Braun /* 3ac713874SUrsula Braun * Shared Memory Communications over RDMA (SMC-R) and RoCE 4ac713874SUrsula Braun * 5ac713874SUrsula Braun * AF_SMC protocol family socket handler keeping the AF_INET sock address type 6ac713874SUrsula Braun * applies to SOCK_STREAM sockets only 7ac713874SUrsula Braun * offers an alternative communication option for TCP-protocol sockets 8ac713874SUrsula Braun * applicable with RoCE-cards only 9ac713874SUrsula Braun * 10a046d57dSUrsula Braun * Initial restrictions: 11a046d57dSUrsula Braun * - support for alternate links postponed 12a046d57dSUrsula Braun * 13aaa4d33fSKarsten Graul * Copyright IBM Corp. 2016, 2018 14ac713874SUrsula Braun * 15ac713874SUrsula Braun * Author(s): Ursula Braun <ubraun@linux.vnet.ibm.com> 16ac713874SUrsula Braun * based on prototype from Frank Blaschka 17ac713874SUrsula Braun */ 18ac713874SUrsula Braun 19ac713874SUrsula Braun #define KMSG_COMPONENT "smc" 20ac713874SUrsula Braun #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 21ac713874SUrsula Braun 22ac713874SUrsula Braun #include <linux/module.h> 23ac713874SUrsula Braun #include <linux/socket.h> 24a046d57dSUrsula Braun #include <linux/workqueue.h> 255f08318fSUrsula Braun #include <linux/in.h> 26c3edc401SIngo Molnar #include <linux/sched/signal.h> 2741349844SHans Wippel #include <linux/if_vlan.h> 284ead9c96SUrsula Braun #include <linux/rcupdate_wait.h> 29c3edc401SIngo Molnar 30ac713874SUrsula Braun #include <net/sock.h> 31a046d57dSUrsula Braun #include <net/tcp.h> 32f16a7dd5SUrsula Braun #include <net/smc.h> 339b67e26fSUrsula Braun #include <asm/ioctls.h> 34ac713874SUrsula Braun 3564e28b52SHans Wippel #include <net/net_namespace.h> 3664e28b52SHans Wippel #include <net/netns/generic.h> 3764e28b52SHans Wippel #include "smc_netns.h" 3864e28b52SHans Wippel 39ac713874SUrsula Braun #include "smc.h" 40a046d57dSUrsula Braun #include "smc_clc.h" 419bf9abeaSUrsula Braun #include "smc_llc.h" 425f08318fSUrsula Braun #include "smc_cdc.h" 430cfdd8f9SUrsula Braun #include "smc_core.h" 44a4cf0443SUrsula Braun #include "smc_ib.h" 4541349844SHans Wippel #include "smc_ism.h" 466812baabSThomas Richter #include "smc_pnet.h" 47e6727f39SUrsula Braun #include "smc_tx.h" 48952310ccSUrsula Braun #include "smc_rx.h" 49b38d7324SUrsula Braun #include "smc_close.h" 50ac713874SUrsula Braun 5172a36a8aSHans Wippel static DEFINE_MUTEX(smc_server_lgr_pending); /* serialize link group 5272a36a8aSHans Wippel * creation on server 5372a36a8aSHans Wippel */ 5472a36a8aSHans Wippel static DEFINE_MUTEX(smc_client_lgr_pending); /* serialize link group 5572a36a8aSHans Wippel * creation on client 560cfdd8f9SUrsula Braun */ 570cfdd8f9SUrsula Braun 58a046d57dSUrsula Braun static void smc_tcp_listen_work(struct work_struct *); 5924ac3a08SUrsula Braun static void smc_connect_work(struct work_struct *); 60a046d57dSUrsula Braun 61ac713874SUrsula Braun static void smc_set_keepalive(struct sock *sk, int val) 62ac713874SUrsula Braun { 63ac713874SUrsula Braun struct smc_sock *smc = smc_sk(sk); 64ac713874SUrsula Braun 65ac713874SUrsula Braun smc->clcsock->sk->sk_prot->keepalive(smc->clcsock->sk, val); 66ac713874SUrsula Braun } 67ac713874SUrsula Braun 68f16a7dd5SUrsula Braun static struct smc_hashinfo smc_v4_hashinfo = { 69f16a7dd5SUrsula Braun .lock = __RW_LOCK_UNLOCKED(smc_v4_hashinfo.lock), 70f16a7dd5SUrsula Braun }; 71f16a7dd5SUrsula Braun 72aaa4d33fSKarsten Graul static struct smc_hashinfo smc_v6_hashinfo = { 73aaa4d33fSKarsten Graul .lock = __RW_LOCK_UNLOCKED(smc_v6_hashinfo.lock), 74aaa4d33fSKarsten Graul }; 75aaa4d33fSKarsten Graul 76f16a7dd5SUrsula Braun int smc_hash_sk(struct sock *sk) 77f16a7dd5SUrsula Braun { 78f16a7dd5SUrsula Braun struct smc_hashinfo *h = sk->sk_prot->h.smc_hash; 79f16a7dd5SUrsula Braun struct hlist_head *head; 80f16a7dd5SUrsula Braun 81f16a7dd5SUrsula Braun head = &h->ht; 82f16a7dd5SUrsula Braun 83f16a7dd5SUrsula Braun write_lock_bh(&h->lock); 84f16a7dd5SUrsula Braun sk_add_node(sk, head); 85f16a7dd5SUrsula Braun sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); 86f16a7dd5SUrsula Braun write_unlock_bh(&h->lock); 87f16a7dd5SUrsula Braun 88f16a7dd5SUrsula Braun return 0; 89f16a7dd5SUrsula Braun } 90f16a7dd5SUrsula Braun EXPORT_SYMBOL_GPL(smc_hash_sk); 91f16a7dd5SUrsula Braun 92f16a7dd5SUrsula Braun void smc_unhash_sk(struct sock *sk) 93f16a7dd5SUrsula Braun { 94f16a7dd5SUrsula Braun struct smc_hashinfo *h = sk->sk_prot->h.smc_hash; 95f16a7dd5SUrsula Braun 96f16a7dd5SUrsula Braun write_lock_bh(&h->lock); 97f16a7dd5SUrsula Braun if (sk_del_node_init(sk)) 98f16a7dd5SUrsula Braun sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); 99f16a7dd5SUrsula Braun write_unlock_bh(&h->lock); 100f16a7dd5SUrsula Braun } 101f16a7dd5SUrsula Braun EXPORT_SYMBOL_GPL(smc_unhash_sk); 102f16a7dd5SUrsula Braun 103f16a7dd5SUrsula Braun struct proto smc_proto = { 104ac713874SUrsula Braun .name = "SMC", 105ac713874SUrsula Braun .owner = THIS_MODULE, 106ac713874SUrsula Braun .keepalive = smc_set_keepalive, 107f16a7dd5SUrsula Braun .hash = smc_hash_sk, 108f16a7dd5SUrsula Braun .unhash = smc_unhash_sk, 109ac713874SUrsula Braun .obj_size = sizeof(struct smc_sock), 110f16a7dd5SUrsula Braun .h.smc_hash = &smc_v4_hashinfo, 1115f0d5a3aSPaul E. McKenney .slab_flags = SLAB_TYPESAFE_BY_RCU, 112ac713874SUrsula Braun }; 113f16a7dd5SUrsula Braun EXPORT_SYMBOL_GPL(smc_proto); 114ac713874SUrsula Braun 115aaa4d33fSKarsten Graul struct proto smc_proto6 = { 116aaa4d33fSKarsten Graul .name = "SMC6", 117aaa4d33fSKarsten Graul .owner = THIS_MODULE, 118aaa4d33fSKarsten Graul .keepalive = smc_set_keepalive, 119aaa4d33fSKarsten Graul .hash = smc_hash_sk, 120aaa4d33fSKarsten Graul .unhash = smc_unhash_sk, 121aaa4d33fSKarsten Graul .obj_size = sizeof(struct smc_sock), 122aaa4d33fSKarsten Graul .h.smc_hash = &smc_v6_hashinfo, 123aaa4d33fSKarsten Graul .slab_flags = SLAB_TYPESAFE_BY_RCU, 124aaa4d33fSKarsten Graul }; 125aaa4d33fSKarsten Graul EXPORT_SYMBOL_GPL(smc_proto6); 126aaa4d33fSKarsten Graul 127f536dffcSUrsula Braun static void smc_restore_fallback_changes(struct smc_sock *smc) 128f536dffcSUrsula Braun { 1291ad24058SKarsten Graul if (smc->clcsock->file) { /* non-accepted sockets have no file yet */ 130f536dffcSUrsula Braun smc->clcsock->file->private_data = smc->sk.sk_socket; 131f536dffcSUrsula Braun smc->clcsock->file = NULL; 132f536dffcSUrsula Braun } 1331ad24058SKarsten Graul } 134f536dffcSUrsula Braun 13539f41f36SUrsula Braun static int __smc_release(struct smc_sock *smc) 136ac713874SUrsula Braun { 13739f41f36SUrsula Braun struct sock *sk = &smc->sk; 138b38d7324SUrsula Braun int rc = 0; 139ac713874SUrsula Braun 14051f1de79SUrsula Braun if (!smc->use_fallback) { 141b38d7324SUrsula Braun rc = smc_close_active(smc); 142b38d7324SUrsula Braun sock_set_flag(sk, SOCK_DEAD); 143b38d7324SUrsula Braun sk->sk_shutdown |= SHUTDOWN_MASK; 144b03faa1fSUrsula Braun } else { 145b03faa1fSUrsula Braun if (sk->sk_state != SMC_LISTEN && sk->sk_state != SMC_INIT) 146b03faa1fSUrsula Braun sock_put(sk); /* passive closing */ 147b03faa1fSUrsula Braun if (sk->sk_state == SMC_LISTEN) { 148b03faa1fSUrsula Braun /* wake up clcsock accept */ 149b03faa1fSUrsula Braun rc = kernel_sock_shutdown(smc->clcsock, SHUT_RDWR); 150b03faa1fSUrsula Braun } 151b03faa1fSUrsula Braun sk->sk_state = SMC_CLOSED; 152b03faa1fSUrsula Braun sk->sk_state_change(sk); 153f536dffcSUrsula Braun smc_restore_fallback_changes(smc); 154b38d7324SUrsula Braun } 15526d92e95SCong Wang 15626d92e95SCong Wang sk->sk_prot->unhash(sk); 15726d92e95SCong Wang 158b03faa1fSUrsula Braun if (sk->sk_state == SMC_CLOSED) { 159ac713874SUrsula Braun if (smc->clcsock) { 160fd57770dSKarsten Graul release_sock(sk); 161fd57770dSKarsten Graul smc_clcsock_release(smc); 162fd57770dSKarsten Graul lock_sock(sk); 163ac713874SUrsula Braun } 164b03faa1fSUrsula Braun if (!smc->use_fallback) 165b03faa1fSUrsula Braun smc_conn_free(&smc->conn); 16651f1de79SUrsula Braun } 167ac713874SUrsula Braun 16839f41f36SUrsula Braun return rc; 16939f41f36SUrsula Braun } 17039f41f36SUrsula Braun 17139f41f36SUrsula Braun static int smc_release(struct socket *sock) 17239f41f36SUrsula Braun { 17339f41f36SUrsula Braun struct sock *sk = sock->sk; 17439f41f36SUrsula Braun struct smc_sock *smc; 17539f41f36SUrsula Braun int rc = 0; 17639f41f36SUrsula Braun 17739f41f36SUrsula Braun if (!sk) 17839f41f36SUrsula Braun goto out; 17939f41f36SUrsula Braun 18081cf4f47SUrsula Braun sock_hold(sk); /* sock_put below */ 18139f41f36SUrsula Braun smc = smc_sk(sk); 18239f41f36SUrsula Braun 18339f41f36SUrsula Braun /* cleanup for a dangling non-blocking connect */ 18439f41f36SUrsula Braun if (smc->connect_nonblock && sk->sk_state == SMC_INIT) 18539f41f36SUrsula Braun tcp_abort(smc->clcsock->sk, ECONNABORTED); 18639f41f36SUrsula Braun flush_work(&smc->connect_work); 18739f41f36SUrsula Braun 18839f41f36SUrsula Braun if (sk->sk_state == SMC_LISTEN) 18939f41f36SUrsula Braun /* smc_close_non_accepted() is called and acquires 19039f41f36SUrsula Braun * sock lock for child sockets again 19139f41f36SUrsula Braun */ 19239f41f36SUrsula Braun lock_sock_nested(sk, SINGLE_DEPTH_NESTING); 19339f41f36SUrsula Braun else 19439f41f36SUrsula Braun lock_sock(sk); 19539f41f36SUrsula Braun 19639f41f36SUrsula Braun rc = __smc_release(smc); 19739f41f36SUrsula Braun 198ac713874SUrsula Braun /* detach socket */ 199ac713874SUrsula Braun sock_orphan(sk); 200ac713874SUrsula Braun sock->sk = NULL; 201ac713874SUrsula Braun release_sock(sk); 202ac713874SUrsula Braun 20381cf4f47SUrsula Braun sock_put(sk); /* sock_hold above */ 20451f1de79SUrsula Braun sock_put(sk); /* final sock_put */ 205ac713874SUrsula Braun out: 206b38d7324SUrsula Braun return rc; 207ac713874SUrsula Braun } 208ac713874SUrsula Braun 209ac713874SUrsula Braun static void smc_destruct(struct sock *sk) 210ac713874SUrsula Braun { 211ac713874SUrsula Braun if (sk->sk_state != SMC_CLOSED) 212ac713874SUrsula Braun return; 213ac713874SUrsula Braun if (!sock_flag(sk, SOCK_DEAD)) 214ac713874SUrsula Braun return; 215ac713874SUrsula Braun 216ac713874SUrsula Braun sk_refcnt_debug_dec(sk); 217ac713874SUrsula Braun } 218ac713874SUrsula Braun 219aaa4d33fSKarsten Graul static struct sock *smc_sock_alloc(struct net *net, struct socket *sock, 220aaa4d33fSKarsten Graul int protocol) 221ac713874SUrsula Braun { 222ac713874SUrsula Braun struct smc_sock *smc; 223aaa4d33fSKarsten Graul struct proto *prot; 224ac713874SUrsula Braun struct sock *sk; 225ac713874SUrsula Braun 226aaa4d33fSKarsten Graul prot = (protocol == SMCPROTO_SMC6) ? &smc_proto6 : &smc_proto; 227aaa4d33fSKarsten Graul sk = sk_alloc(net, PF_SMC, GFP_KERNEL, prot, 0); 228ac713874SUrsula Braun if (!sk) 229ac713874SUrsula Braun return NULL; 230ac713874SUrsula Braun 231ac713874SUrsula Braun sock_init_data(sock, sk); /* sets sk_refcnt to 1 */ 232ac713874SUrsula Braun sk->sk_state = SMC_INIT; 233ac713874SUrsula Braun sk->sk_destruct = smc_destruct; 234aaa4d33fSKarsten Graul sk->sk_protocol = protocol; 235ac713874SUrsula Braun smc = smc_sk(sk); 236a046d57dSUrsula Braun INIT_WORK(&smc->tcp_listen_work, smc_tcp_listen_work); 23724ac3a08SUrsula Braun INIT_WORK(&smc->connect_work, smc_connect_work); 238be7f3e59SEric Dumazet INIT_DELAYED_WORK(&smc->conn.tx_work, smc_tx_work); 239a046d57dSUrsula Braun INIT_LIST_HEAD(&smc->accept_q); 240a046d57dSUrsula Braun spin_lock_init(&smc->accept_q_lock); 241be7f3e59SEric Dumazet spin_lock_init(&smc->conn.send_lock); 242f16a7dd5SUrsula Braun sk->sk_prot->hash(sk); 243a046d57dSUrsula Braun sk_refcnt_debug_inc(sk); 24478abe3d0SMyungho Jung mutex_init(&smc->clcsock_release_lock); 245ac713874SUrsula Braun 246ac713874SUrsula Braun return sk; 247ac713874SUrsula Braun } 248ac713874SUrsula Braun 249ac713874SUrsula Braun static int smc_bind(struct socket *sock, struct sockaddr *uaddr, 250ac713874SUrsula Braun int addr_len) 251ac713874SUrsula Braun { 252ac713874SUrsula Braun struct sockaddr_in *addr = (struct sockaddr_in *)uaddr; 253ac713874SUrsula Braun struct sock *sk = sock->sk; 254ac713874SUrsula Braun struct smc_sock *smc; 255ac713874SUrsula Braun int rc; 256ac713874SUrsula Braun 257ac713874SUrsula Braun smc = smc_sk(sk); 258ac713874SUrsula Braun 259ac713874SUrsula Braun /* replicate tests from inet_bind(), to be safe wrt. future changes */ 260ac713874SUrsula Braun rc = -EINVAL; 261ac713874SUrsula Braun if (addr_len < sizeof(struct sockaddr_in)) 262ac713874SUrsula Braun goto out; 263ac713874SUrsula Braun 264ac713874SUrsula Braun rc = -EAFNOSUPPORT; 265aaa4d33fSKarsten Graul if (addr->sin_family != AF_INET && 266aaa4d33fSKarsten Graul addr->sin_family != AF_INET6 && 267aaa4d33fSKarsten Graul addr->sin_family != AF_UNSPEC) 268aaa4d33fSKarsten Graul goto out; 269ac713874SUrsula Braun /* accept AF_UNSPEC (mapped to AF_INET) only if s_addr is INADDR_ANY */ 270aaa4d33fSKarsten Graul if (addr->sin_family == AF_UNSPEC && 271aaa4d33fSKarsten Graul addr->sin_addr.s_addr != htonl(INADDR_ANY)) 272ac713874SUrsula Braun goto out; 273ac713874SUrsula Braun 274ac713874SUrsula Braun lock_sock(sk); 275ac713874SUrsula Braun 276ac713874SUrsula Braun /* Check if socket is already active */ 277ac713874SUrsula Braun rc = -EINVAL; 278cd206360SUrsula Braun if (sk->sk_state != SMC_INIT || smc->connect_nonblock) 279ac713874SUrsula Braun goto out_rel; 280ac713874SUrsula Braun 281ac713874SUrsula Braun smc->clcsock->sk->sk_reuse = sk->sk_reuse; 282ac713874SUrsula Braun rc = kernel_bind(smc->clcsock, uaddr, addr_len); 283ac713874SUrsula Braun 284ac713874SUrsula Braun out_rel: 285ac713874SUrsula Braun release_sock(sk); 286ac713874SUrsula Braun out: 287ac713874SUrsula Braun return rc; 288ac713874SUrsula Braun } 289ac713874SUrsula Braun 290ac713874SUrsula Braun static void smc_copy_sock_settings(struct sock *nsk, struct sock *osk, 291ac713874SUrsula Braun unsigned long mask) 292ac713874SUrsula Braun { 293ac713874SUrsula Braun /* options we don't get control via setsockopt for */ 294ac713874SUrsula Braun nsk->sk_type = osk->sk_type; 295ac713874SUrsula Braun nsk->sk_sndbuf = osk->sk_sndbuf; 296ac713874SUrsula Braun nsk->sk_rcvbuf = osk->sk_rcvbuf; 297ac713874SUrsula Braun nsk->sk_sndtimeo = osk->sk_sndtimeo; 298ac713874SUrsula Braun nsk->sk_rcvtimeo = osk->sk_rcvtimeo; 299ac713874SUrsula Braun nsk->sk_mark = osk->sk_mark; 300ac713874SUrsula Braun nsk->sk_priority = osk->sk_priority; 301ac713874SUrsula Braun nsk->sk_rcvlowat = osk->sk_rcvlowat; 302ac713874SUrsula Braun nsk->sk_bound_dev_if = osk->sk_bound_dev_if; 303ac713874SUrsula Braun nsk->sk_err = osk->sk_err; 304ac713874SUrsula Braun 305ac713874SUrsula Braun nsk->sk_flags &= ~mask; 306ac713874SUrsula Braun nsk->sk_flags |= osk->sk_flags & mask; 307ac713874SUrsula Braun } 308ac713874SUrsula Braun 309ac713874SUrsula Braun #define SK_FLAGS_SMC_TO_CLC ((1UL << SOCK_URGINLINE) | \ 310ac713874SUrsula Braun (1UL << SOCK_KEEPOPEN) | \ 311ac713874SUrsula Braun (1UL << SOCK_LINGER) | \ 312ac713874SUrsula Braun (1UL << SOCK_BROADCAST) | \ 313ac713874SUrsula Braun (1UL << SOCK_TIMESTAMP) | \ 314ac713874SUrsula Braun (1UL << SOCK_DBG) | \ 315ac713874SUrsula Braun (1UL << SOCK_RCVTSTAMP) | \ 316ac713874SUrsula Braun (1UL << SOCK_RCVTSTAMPNS) | \ 317ac713874SUrsula Braun (1UL << SOCK_LOCALROUTE) | \ 318ac713874SUrsula Braun (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE) | \ 319ac713874SUrsula Braun (1UL << SOCK_RXQ_OVFL) | \ 320ac713874SUrsula Braun (1UL << SOCK_WIFI_STATUS) | \ 321ac713874SUrsula Braun (1UL << SOCK_NOFCS) | \ 3229718475eSDeepa Dinamani (1UL << SOCK_FILTER_LOCKED) | \ 3239718475eSDeepa Dinamani (1UL << SOCK_TSTAMP_NEW)) 324ac713874SUrsula Braun /* copy only relevant settings and flags of SOL_SOCKET level from smc to 325ac713874SUrsula Braun * clc socket (since smc is not called for these options from net/core) 326ac713874SUrsula Braun */ 327ac713874SUrsula Braun static void smc_copy_sock_settings_to_clc(struct smc_sock *smc) 328ac713874SUrsula Braun { 329ac713874SUrsula Braun smc_copy_sock_settings(smc->clcsock->sk, &smc->sk, SK_FLAGS_SMC_TO_CLC); 330ac713874SUrsula Braun } 331ac713874SUrsula Braun 332ac713874SUrsula Braun #define SK_FLAGS_CLC_TO_SMC ((1UL << SOCK_URGINLINE) | \ 333ac713874SUrsula Braun (1UL << SOCK_KEEPOPEN) | \ 334ac713874SUrsula Braun (1UL << SOCK_LINGER) | \ 335ac713874SUrsula Braun (1UL << SOCK_DBG)) 336ac713874SUrsula Braun /* copy only settings and flags relevant for smc from clc to smc socket */ 337ac713874SUrsula Braun static void smc_copy_sock_settings_to_smc(struct smc_sock *smc) 338ac713874SUrsula Braun { 339ac713874SUrsula Braun smc_copy_sock_settings(&smc->sk, smc->clcsock->sk, SK_FLAGS_CLC_TO_SMC); 340ac713874SUrsula Braun } 341ac713874SUrsula Braun 342b9247544SKarsten Graul /* register the new rmb on all links */ 3437562a13dSKarsten Graul static int smcr_lgr_reg_rmbs(struct smc_link *link, 344b9247544SKarsten Graul struct smc_buf_desc *rmb_desc) 345b9247544SKarsten Graul { 3467562a13dSKarsten Graul struct smc_link_group *lgr = link->lgr; 3477562a13dSKarsten Graul int i, rc = 0; 348b9247544SKarsten Graul 349d5500667SKarsten Graul rc = smc_llc_flow_initiate(lgr, SMC_LLC_FLOW_RKEY); 350d5500667SKarsten Graul if (rc) 351d5500667SKarsten Graul return rc; 352d5500667SKarsten Graul /* protect against parallel smc_llc_cli_rkey_exchange() and 353d5500667SKarsten Graul * parallel smcr_link_reg_rmb() 354d5500667SKarsten Graul */ 355d5500667SKarsten Graul mutex_lock(&lgr->llc_conf_mutex); 356b9247544SKarsten Graul for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) { 357741a49a4SKarsten Graul if (!smc_link_active(&lgr->lnk[i])) 358b9247544SKarsten Graul continue; 3597562a13dSKarsten Graul rc = smcr_link_reg_rmb(&lgr->lnk[i], rmb_desc); 360b9247544SKarsten Graul if (rc) 3617562a13dSKarsten Graul goto out; 362b9247544SKarsten Graul } 3637562a13dSKarsten Graul 3647562a13dSKarsten Graul /* exchange confirm_rkey msg with peer */ 3657562a13dSKarsten Graul rc = smc_llc_do_confirm_rkey(link, rmb_desc); 3667562a13dSKarsten Graul if (rc) { 3677562a13dSKarsten Graul rc = -EFAULT; 3687562a13dSKarsten Graul goto out; 3697562a13dSKarsten Graul } 3707562a13dSKarsten Graul rmb_desc->is_conf_rkey = true; 3717562a13dSKarsten Graul out: 372d5500667SKarsten Graul mutex_unlock(&lgr->llc_conf_mutex); 373d5500667SKarsten Graul smc_llc_flow_stop(lgr, &lgr->llc_flow_lcl); 3747562a13dSKarsten Graul return rc; 375b9247544SKarsten Graul } 376b9247544SKarsten Graul 377b9247544SKarsten Graul static int smcr_clnt_conf_first_link(struct smc_sock *smc) 3789bf9abeaSUrsula Braun { 379387707fdSKarsten Graul struct smc_link *link = smc->conn.lnk; 3800fb0b02bSKarsten Graul struct smc_llc_qentry *qentry; 3819bf9abeaSUrsula Braun int rc; 3829bf9abeaSUrsula Braun 3839bf9abeaSUrsula Braun /* receive CONFIRM LINK request from server over RoCE fabric */ 3840fb0b02bSKarsten Graul qentry = smc_llc_wait(link->lgr, NULL, SMC_LLC_WAIT_TIME, 3850fb0b02bSKarsten Graul SMC_LLC_CONFIRM_LINK); 3860fb0b02bSKarsten Graul if (!qentry) { 3879bf9abeaSUrsula Braun struct smc_clc_msg_decline dclc; 3889bf9abeaSUrsula Braun 3899bf9abeaSUrsula Braun rc = smc_clc_wait_msg(smc, &dclc, sizeof(dclc), 3902b59f58eSUrsula Braun SMC_CLC_DECLINE, CLC_WAIT_TIME_SHORT); 3919ed28556SUrsula Braun return rc == -EAGAIN ? SMC_CLC_DECL_TIMEOUT_CL : rc; 3929bf9abeaSUrsula Braun } 393649758ffSKarsten Graul smc_llc_save_peer_uid(qentry); 3940fb0b02bSKarsten Graul rc = smc_llc_eval_conf_link(qentry, SMC_LLC_REQ); 3950fb0b02bSKarsten Graul smc_llc_flow_qentry_del(&link->lgr->llc_flow_lcl); 3960fb0b02bSKarsten Graul if (rc) 39775d320d6SKarsten Graul return SMC_CLC_DECL_RMBE_EC; 39875d320d6SKarsten Graul 3999bf9abeaSUrsula Braun rc = smc_ib_modify_qp_rts(link); 4009bf9abeaSUrsula Braun if (rc) 401603cc149SKarsten Graul return SMC_CLC_DECL_ERR_RDYLNK; 4029bf9abeaSUrsula Braun 4039bf9abeaSUrsula Braun smc_wr_remember_qp_attr(link); 404652a1e41SUrsula Braun 4057562a13dSKarsten Graul if (smcr_link_reg_rmb(link, smc->conn.rmb_desc)) 406603cc149SKarsten Graul return SMC_CLC_DECL_ERR_REGRMB; 407652a1e41SUrsula Braun 4080fb0b02bSKarsten Graul /* confirm_rkey is implicit on 1st contact */ 4090fb0b02bSKarsten Graul smc->conn.rmb_desc->is_conf_rkey = true; 4100fb0b02bSKarsten Graul 4119bf9abeaSUrsula Braun /* send CONFIRM LINK response over RoCE fabric */ 412947541f3SUrsula Braun rc = smc_llc_send_confirm_link(link, SMC_LLC_RESP); 4139bf9abeaSUrsula Braun if (rc < 0) 414603cc149SKarsten Graul return SMC_CLC_DECL_TIMEOUT_CL; 4159bf9abeaSUrsula Braun 4160fb0b02bSKarsten Graul smc_llc_link_active(link); 4170a99be43SKarsten Graul smcr_lgr_set_type(link->lgr, SMC_LGR_SINGLE); 4180fb0b02bSKarsten Graul 4190fb0b02bSKarsten Graul /* optional 2nd link, receive ADD LINK request from server */ 4200fb0b02bSKarsten Graul qentry = smc_llc_wait(link->lgr, NULL, SMC_LLC_WAIT_TIME, 4210fb0b02bSKarsten Graul SMC_LLC_ADD_LINK); 4220fb0b02bSKarsten Graul if (!qentry) { 42352bedf37SKarsten Graul struct smc_clc_msg_decline dclc; 42452bedf37SKarsten Graul 42552bedf37SKarsten Graul rc = smc_clc_wait_msg(smc, &dclc, sizeof(dclc), 4262b59f58eSUrsula Braun SMC_CLC_DECLINE, CLC_WAIT_TIME_SHORT); 4270fb0b02bSKarsten Graul if (rc == -EAGAIN) 4280fb0b02bSKarsten Graul rc = 0; /* no DECLINE received, go with one link */ 4290fb0b02bSKarsten Graul return rc; 43052bedf37SKarsten Graul } 4310fb0b02bSKarsten Graul smc_llc_flow_qentry_clr(&link->lgr->llc_flow_lcl); 432b1570a87SKarsten Graul smc_llc_cli_add_link(link, qentry); 43375d320d6SKarsten Graul return 0; 4349bf9abeaSUrsula Braun } 4359bf9abeaSUrsula Braun 43641349844SHans Wippel static void smcr_conn_save_peer_info(struct smc_sock *smc, 4370cfdd8f9SUrsula Braun struct smc_clc_msg_accept_confirm *clc) 4380cfdd8f9SUrsula Braun { 439*3d9725a6SUrsula Braun int bufsize = smc_uncompress_bufsize(clc->r0.rmbe_size); 44095d8d263SHans Wippel 441*3d9725a6SUrsula Braun smc->conn.peer_rmbe_idx = clc->r0.rmbe_idx; 442*3d9725a6SUrsula Braun smc->conn.local_tx_ctrl.token = ntohl(clc->r0.rmbe_alert_token); 44395d8d263SHans Wippel smc->conn.peer_rmbe_size = bufsize; 444cd6851f3SUrsula Braun atomic_set(&smc->conn.peer_rmbe_space, smc->conn.peer_rmbe_size); 44595d8d263SHans Wippel smc->conn.tx_off = bufsize * (smc->conn.peer_rmbe_idx - 1); 4460cfdd8f9SUrsula Braun } 4470cfdd8f9SUrsula Braun 44841349844SHans Wippel static void smcd_conn_save_peer_info(struct smc_sock *smc, 44941349844SHans Wippel struct smc_clc_msg_accept_confirm *clc) 45041349844SHans Wippel { 451*3d9725a6SUrsula Braun int bufsize = smc_uncompress_bufsize(clc->d0.dmbe_size); 45241349844SHans Wippel 453*3d9725a6SUrsula Braun smc->conn.peer_rmbe_idx = clc->d0.dmbe_idx; 454*3d9725a6SUrsula Braun smc->conn.peer_token = clc->d0.token; 45541349844SHans Wippel /* msg header takes up space in the buffer */ 45641349844SHans Wippel smc->conn.peer_rmbe_size = bufsize - sizeof(struct smcd_cdc_msg); 45741349844SHans Wippel atomic_set(&smc->conn.peer_rmbe_space, smc->conn.peer_rmbe_size); 45841349844SHans Wippel smc->conn.tx_off = bufsize * smc->conn.peer_rmbe_idx; 45941349844SHans Wippel } 46041349844SHans Wippel 46141349844SHans Wippel static void smc_conn_save_peer_info(struct smc_sock *smc, 46241349844SHans Wippel struct smc_clc_msg_accept_confirm *clc) 46341349844SHans Wippel { 46441349844SHans Wippel if (smc->conn.lgr->is_smcd) 46541349844SHans Wippel smcd_conn_save_peer_info(smc, clc); 46641349844SHans Wippel else 46741349844SHans Wippel smcr_conn_save_peer_info(smc, clc); 46841349844SHans Wippel } 46941349844SHans Wippel 4700cfdd8f9SUrsula Braun static void smc_link_save_peer_info(struct smc_link *link, 4710cfdd8f9SUrsula Braun struct smc_clc_msg_accept_confirm *clc) 4720cfdd8f9SUrsula Braun { 473*3d9725a6SUrsula Braun link->peer_qpn = ntoh24(clc->r0.qpn); 474*3d9725a6SUrsula Braun memcpy(link->peer_gid, clc->r0.lcl.gid, SMC_GID_SIZE); 475*3d9725a6SUrsula Braun memcpy(link->peer_mac, clc->r0.lcl.mac, sizeof(link->peer_mac)); 476*3d9725a6SUrsula Braun link->peer_psn = ntoh24(clc->r0.psn); 477*3d9725a6SUrsula Braun link->peer_mtu = clc->r0.qp_mtu; 4780cfdd8f9SUrsula Braun } 4790cfdd8f9SUrsula Braun 48007603b23SUrsula Braun static void smc_switch_to_fallback(struct smc_sock *smc) 48107603b23SUrsula Braun { 48207603b23SUrsula Braun smc->use_fallback = true; 48307603b23SUrsula Braun if (smc->sk.sk_socket && smc->sk.sk_socket->file) { 48407603b23SUrsula Braun smc->clcsock->file = smc->sk.sk_socket->file; 48507603b23SUrsula Braun smc->clcsock->file->private_data = smc->clcsock; 48667f562e3SUrsula Braun smc->clcsock->wq.fasync_list = 48767f562e3SUrsula Braun smc->sk.sk_socket->wq.fasync_list; 48807603b23SUrsula Braun } 48907603b23SUrsula Braun } 49007603b23SUrsula Braun 4913b2dec26SHans Wippel /* fall back during connect */ 492603cc149SKarsten Graul static int smc_connect_fallback(struct smc_sock *smc, int reason_code) 4933b2dec26SHans Wippel { 49407603b23SUrsula Braun smc_switch_to_fallback(smc); 495603cc149SKarsten Graul smc->fallback_rsn = reason_code; 4963b2dec26SHans Wippel smc_copy_sock_settings_to_clc(smc); 49750717a37SUrsula Braun smc->connect_nonblock = 0; 4983b2dec26SHans Wippel if (smc->sk.sk_state == SMC_INIT) 4993b2dec26SHans Wippel smc->sk.sk_state = SMC_ACTIVE; 5003b2dec26SHans Wippel return 0; 5013b2dec26SHans Wippel } 5023b2dec26SHans Wippel 5033b2dec26SHans Wippel /* decline and fall back during connect */ 5043b2dec26SHans Wippel static int smc_connect_decline_fallback(struct smc_sock *smc, int reason_code) 5053b2dec26SHans Wippel { 5063b2dec26SHans Wippel int rc; 5073b2dec26SHans Wippel 508e1bbdd57SUrsula Braun if (reason_code < 0) { /* error, fallback is not possible */ 509e1bbdd57SUrsula Braun if (smc->sk.sk_state == SMC_INIT) 510e1bbdd57SUrsula Braun sock_put(&smc->sk); /* passive closing */ 5113b2dec26SHans Wippel return reason_code; 512e1bbdd57SUrsula Braun } 513603cc149SKarsten Graul if (reason_code != SMC_CLC_DECL_PEERDECL) { 5143b2dec26SHans Wippel rc = smc_clc_send_decline(smc, reason_code); 515e1bbdd57SUrsula Braun if (rc < 0) { 516e1bbdd57SUrsula Braun if (smc->sk.sk_state == SMC_INIT) 517e1bbdd57SUrsula Braun sock_put(&smc->sk); /* passive closing */ 5183b2dec26SHans Wippel return rc; 5193b2dec26SHans Wippel } 520e1bbdd57SUrsula Braun } 521603cc149SKarsten Graul return smc_connect_fallback(smc, reason_code); 5223b2dec26SHans Wippel } 5233b2dec26SHans Wippel 5243b2dec26SHans Wippel /* abort connecting */ 5253b2dec26SHans Wippel static int smc_connect_abort(struct smc_sock *smc, int reason_code, 5265ac54d87SUrsula Braun int local_first) 5273b2dec26SHans Wippel { 52851e3dfa8SUrsula Braun bool is_smcd = smc->conn.lgr->is_smcd; 52951e3dfa8SUrsula Braun 5305ac54d87SUrsula Braun if (local_first) 53151e3dfa8SUrsula Braun smc_lgr_cleanup_early(&smc->conn); 53251e3dfa8SUrsula Braun else 53351e3dfa8SUrsula Braun smc_conn_free(&smc->conn); 53451e3dfa8SUrsula Braun if (is_smcd) 53572a36a8aSHans Wippel /* there is only one lgr role for SMC-D; use server lock */ 53672a36a8aSHans Wippel mutex_unlock(&smc_server_lgr_pending); 53772a36a8aSHans Wippel else 53872a36a8aSHans Wippel mutex_unlock(&smc_client_lgr_pending); 53972a36a8aSHans Wippel 54050717a37SUrsula Braun smc->connect_nonblock = 0; 5413b2dec26SHans Wippel return reason_code; 5423b2dec26SHans Wippel } 5433b2dec26SHans Wippel 5443b2dec26SHans Wippel /* check if there is a rdma device available for this connection. */ 5453b2dec26SHans Wippel /* called for connect and listen */ 546228bae05SKarsten Graul static int smc_find_rdma_device(struct smc_sock *smc, struct smc_init_info *ini) 5473b2dec26SHans Wippel { 5483b2dec26SHans Wippel /* PNET table look up: search active ib_device and port 5493b2dec26SHans Wippel * within same PNETID that also contains the ethernet device 5503b2dec26SHans Wippel * used for the internal TCP socket 5513b2dec26SHans Wippel */ 552bc36d2fcSKarsten Graul smc_pnet_find_roce_resource(smc->clcsock->sk, ini); 5539aa68d29SKarsten Graul if (!ini->ib_dev) 5549aa68d29SKarsten Graul return SMC_CLC_DECL_NOSMCRDEV; 555bc36d2fcSKarsten Graul return 0; 5563b2dec26SHans Wippel } 5573b2dec26SHans Wippel 55841349844SHans Wippel /* check if there is an ISM device available for this connection. */ 55941349844SHans Wippel /* called for connect and listen */ 560228bae05SKarsten Graul static int smc_find_ism_device(struct smc_sock *smc, struct smc_init_info *ini) 56141349844SHans Wippel { 56241349844SHans Wippel /* Find ISM device with same PNETID as connecting interface */ 563bc36d2fcSKarsten Graul smc_pnet_find_ism_resource(smc->clcsock->sk, ini); 564bc36d2fcSKarsten Graul if (!ini->ism_dev) 5659aa68d29SKarsten Graul return SMC_CLC_DECL_NOSMCDDEV; 56641349844SHans Wippel return 0; 56741349844SHans Wippel } 56841349844SHans Wippel 56941349844SHans Wippel /* Check for VLAN ID and register it on ISM device just for CLC handshake */ 57041349844SHans Wippel static int smc_connect_ism_vlan_setup(struct smc_sock *smc, 571bc36d2fcSKarsten Graul struct smc_init_info *ini) 57241349844SHans Wippel { 573bc36d2fcSKarsten Graul if (ini->vlan_id && smc_ism_get_vlan(ini->ism_dev, ini->vlan_id)) 5747a62725aSKarsten Graul return SMC_CLC_DECL_ISMVLANERR; 57541349844SHans Wippel return 0; 57641349844SHans Wippel } 57741349844SHans Wippel 57841349844SHans Wippel /* cleanup temporary VLAN ID registration used for CLC handshake. If ISM is 57941349844SHans Wippel * used, the VLAN ID will be registered again during the connection setup. 58041349844SHans Wippel */ 58141349844SHans Wippel static int smc_connect_ism_vlan_cleanup(struct smc_sock *smc, bool is_smcd, 582bc36d2fcSKarsten Graul struct smc_init_info *ini) 58341349844SHans Wippel { 58441349844SHans Wippel if (!is_smcd) 58541349844SHans Wippel return 0; 586bc36d2fcSKarsten Graul if (ini->vlan_id && smc_ism_put_vlan(ini->ism_dev, ini->vlan_id)) 58741349844SHans Wippel return SMC_CLC_DECL_CNFERR; 58841349844SHans Wippel return 0; 58941349844SHans Wippel } 59041349844SHans Wippel 5913b2dec26SHans Wippel /* CLC handshake during connect */ 592c758dfddSHans Wippel static int smc_connect_clc(struct smc_sock *smc, int smc_type, 5933b2dec26SHans Wippel struct smc_clc_msg_accept_confirm *aclc, 594bc36d2fcSKarsten Graul struct smc_init_info *ini) 5953b2dec26SHans Wippel { 5963b2dec26SHans Wippel int rc = 0; 5973b2dec26SHans Wippel 5983b2dec26SHans Wippel /* do inband token exchange */ 599bc36d2fcSKarsten Graul rc = smc_clc_send_proposal(smc, smc_type, ini); 6003b2dec26SHans Wippel if (rc) 6013b2dec26SHans Wippel return rc; 6023b2dec26SHans Wippel /* receive SMC Accept CLC message */ 6032b59f58eSUrsula Braun return smc_clc_wait_msg(smc, aclc, sizeof(*aclc), SMC_CLC_ACCEPT, 6042b59f58eSUrsula Braun CLC_WAIT_TIME); 6053b2dec26SHans Wippel } 6063b2dec26SHans Wippel 607a046d57dSUrsula Braun /* setup for RDMA connection of client */ 6083b2dec26SHans Wippel static int smc_connect_rdma(struct smc_sock *smc, 6093b2dec26SHans Wippel struct smc_clc_msg_accept_confirm *aclc, 610bc36d2fcSKarsten Graul struct smc_init_info *ini) 6113b2dec26SHans Wippel { 6120fb0b02bSKarsten Graul int i, reason_code = 0; 6133b2dec26SHans Wippel struct smc_link *link; 6143b2dec26SHans Wippel 615bc36d2fcSKarsten Graul ini->is_smcd = false; 616*3d9725a6SUrsula Braun ini->ib_lcl = &aclc->r0.lcl; 617*3d9725a6SUrsula Braun ini->ib_clcqpn = ntoh24(aclc->r0.qpn); 6185ac54d87SUrsula Braun ini->first_contact_peer = aclc->hdr.flag; 619bc36d2fcSKarsten Graul 62072a36a8aSHans Wippel mutex_lock(&smc_client_lgr_pending); 6217a62725aSKarsten Graul reason_code = smc_conn_create(smc, ini); 6227a62725aSKarsten Graul if (reason_code) { 62372a36a8aSHans Wippel mutex_unlock(&smc_client_lgr_pending); 62472a36a8aSHans Wippel return reason_code; 6253b2dec26SHans Wippel } 6263b2dec26SHans Wippel 6273b2dec26SHans Wippel smc_conn_save_peer_info(smc, aclc); 6283b2dec26SHans Wippel 6295ac54d87SUrsula Braun if (ini->first_contact_local) { 6300fb0b02bSKarsten Graul link = smc->conn.lnk; 6310fb0b02bSKarsten Graul } else { 6320fb0b02bSKarsten Graul /* set link that was assigned by server */ 6330fb0b02bSKarsten Graul link = NULL; 6340fb0b02bSKarsten Graul for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) { 6350fb0b02bSKarsten Graul struct smc_link *l = &smc->conn.lgr->lnk[i]; 6360fb0b02bSKarsten Graul 637*3d9725a6SUrsula Braun if (l->peer_qpn == ntoh24(aclc->r0.qpn) && 638*3d9725a6SUrsula Braun !memcmp(l->peer_gid, &aclc->r0.lcl.gid, 639*3d9725a6SUrsula Braun SMC_GID_SIZE) && 640*3d9725a6SUrsula Braun !memcmp(l->peer_mac, &aclc->r0.lcl.mac, 641*3d9725a6SUrsula Braun sizeof(l->peer_mac))) { 6420fb0b02bSKarsten Graul link = l; 6430fb0b02bSKarsten Graul break; 6440fb0b02bSKarsten Graul } 6450fb0b02bSKarsten Graul } 6460fb0b02bSKarsten Graul if (!link) 6470fb0b02bSKarsten Graul return smc_connect_abort(smc, SMC_CLC_DECL_NOSRVLINK, 6485ac54d87SUrsula Braun ini->first_contact_local); 6490fb0b02bSKarsten Graul smc->conn.lnk = link; 6500fb0b02bSKarsten Graul } 6510fb0b02bSKarsten Graul 6523b2dec26SHans Wippel /* create send buffer and rmb */ 653c6ba7c9bSHans Wippel if (smc_buf_create(smc, false)) 6547a62725aSKarsten Graul return smc_connect_abort(smc, SMC_CLC_DECL_MEM, 6555ac54d87SUrsula Braun ini->first_contact_local); 6563b2dec26SHans Wippel 6575ac54d87SUrsula Braun if (ini->first_contact_local) 6583b2dec26SHans Wippel smc_link_save_peer_info(link, aclc); 6593b2dec26SHans Wippel 660e07d31dcSKarsten Graul if (smc_rmb_rtoken_handling(&smc->conn, link, aclc)) 661603cc149SKarsten Graul return smc_connect_abort(smc, SMC_CLC_DECL_ERR_RTOK, 6625ac54d87SUrsula Braun ini->first_contact_local); 6633b2dec26SHans Wippel 6643b2dec26SHans Wippel smc_close_init(smc); 6653b2dec26SHans Wippel smc_rx_init(smc); 6663b2dec26SHans Wippel 6675ac54d87SUrsula Braun if (ini->first_contact_local) { 6683b2dec26SHans Wippel if (smc_ib_ready_link(link)) 669603cc149SKarsten Graul return smc_connect_abort(smc, SMC_CLC_DECL_ERR_RDYLNK, 6705ac54d87SUrsula Braun ini->first_contact_local); 6713b2dec26SHans Wippel } else { 6727562a13dSKarsten Graul if (smcr_lgr_reg_rmbs(link, smc->conn.rmb_desc)) 673603cc149SKarsten Graul return smc_connect_abort(smc, SMC_CLC_DECL_ERR_REGRMB, 6745ac54d87SUrsula Braun ini->first_contact_local); 6753b2dec26SHans Wippel } 6763b2dec26SHans Wippel smc_rmb_sync_sg_for_device(&smc->conn); 6773b2dec26SHans Wippel 6783b2dec26SHans Wippel reason_code = smc_clc_send_confirm(smc); 6793b2dec26SHans Wippel if (reason_code) 6807a62725aSKarsten Graul return smc_connect_abort(smc, reason_code, 6815ac54d87SUrsula Braun ini->first_contact_local); 6823b2dec26SHans Wippel 6833b2dec26SHans Wippel smc_tx_init(smc); 6843b2dec26SHans Wippel 6855ac54d87SUrsula Braun if (ini->first_contact_local) { 6863b2dec26SHans Wippel /* QP confirmation over RoCE fabric */ 6870fb0b02bSKarsten Graul smc_llc_flow_initiate(link->lgr, SMC_LLC_FLOW_ADD_LINK); 688b9247544SKarsten Graul reason_code = smcr_clnt_conf_first_link(smc); 6890fb0b02bSKarsten Graul smc_llc_flow_stop(link->lgr, &link->lgr->llc_flow_lcl); 6903b2dec26SHans Wippel if (reason_code) 6913b2dec26SHans Wippel return smc_connect_abort(smc, reason_code, 6925ac54d87SUrsula Braun ini->first_contact_local); 6933b2dec26SHans Wippel } 69472a36a8aSHans Wippel mutex_unlock(&smc_client_lgr_pending); 6953b2dec26SHans Wippel 6963b2dec26SHans Wippel smc_copy_sock_settings_to_clc(smc); 69750717a37SUrsula Braun smc->connect_nonblock = 0; 6983b2dec26SHans Wippel if (smc->sk.sk_state == SMC_INIT) 6993b2dec26SHans Wippel smc->sk.sk_state = SMC_ACTIVE; 7003b2dec26SHans Wippel 7013b2dec26SHans Wippel return 0; 7023b2dec26SHans Wippel } 7033b2dec26SHans Wippel 70441349844SHans Wippel /* setup for ISM connection of client */ 70541349844SHans Wippel static int smc_connect_ism(struct smc_sock *smc, 70641349844SHans Wippel struct smc_clc_msg_accept_confirm *aclc, 707bc36d2fcSKarsten Graul struct smc_init_info *ini) 70841349844SHans Wippel { 70941349844SHans Wippel int rc = 0; 71041349844SHans Wippel 711bc36d2fcSKarsten Graul ini->is_smcd = true; 712*3d9725a6SUrsula Braun ini->ism_peer_gid = aclc->d0.gid; 7135ac54d87SUrsula Braun ini->first_contact_peer = aclc->hdr.flag; 714bc36d2fcSKarsten Graul 71572a36a8aSHans Wippel /* there is only one lgr role for SMC-D; use server lock */ 71672a36a8aSHans Wippel mutex_lock(&smc_server_lgr_pending); 7177a62725aSKarsten Graul rc = smc_conn_create(smc, ini); 7187a62725aSKarsten Graul if (rc) { 71972a36a8aSHans Wippel mutex_unlock(&smc_server_lgr_pending); 7207a62725aSKarsten Graul return rc; 72172a36a8aSHans Wippel } 72241349844SHans Wippel 72341349844SHans Wippel /* Create send and receive buffers */ 72472b7f6c4SKarsten Graul rc = smc_buf_create(smc, true); 72572b7f6c4SKarsten Graul if (rc) 72672b7f6c4SKarsten Graul return smc_connect_abort(smc, (rc == -ENOSPC) ? 72772b7f6c4SKarsten Graul SMC_CLC_DECL_MAX_DMB : 72872b7f6c4SKarsten Graul SMC_CLC_DECL_MEM, 7295ac54d87SUrsula Braun ini->first_contact_local); 73041349844SHans Wippel 73141349844SHans Wippel smc_conn_save_peer_info(smc, aclc); 73241349844SHans Wippel smc_close_init(smc); 73341349844SHans Wippel smc_rx_init(smc); 73441349844SHans Wippel smc_tx_init(smc); 73541349844SHans Wippel 73641349844SHans Wippel rc = smc_clc_send_confirm(smc); 73741349844SHans Wippel if (rc) 7385ac54d87SUrsula Braun return smc_connect_abort(smc, rc, ini->first_contact_local); 73972a36a8aSHans Wippel mutex_unlock(&smc_server_lgr_pending); 74041349844SHans Wippel 74141349844SHans Wippel smc_copy_sock_settings_to_clc(smc); 74250717a37SUrsula Braun smc->connect_nonblock = 0; 74341349844SHans Wippel if (smc->sk.sk_state == SMC_INIT) 74441349844SHans Wippel smc->sk.sk_state = SMC_ACTIVE; 74541349844SHans Wippel 74641349844SHans Wippel return 0; 74741349844SHans Wippel } 74841349844SHans Wippel 7493b2dec26SHans Wippel /* perform steps before actually connecting */ 7503b2dec26SHans Wippel static int __smc_connect(struct smc_sock *smc) 751a046d57dSUrsula Braun { 75241349844SHans Wippel bool ism_supported = false, rdma_supported = false; 753a046d57dSUrsula Braun struct smc_clc_msg_accept_confirm aclc; 754bc36d2fcSKarsten Graul struct smc_init_info ini = {0}; 75541349844SHans Wippel int smc_type; 756a046d57dSUrsula Braun int rc = 0; 757a046d57dSUrsula Braun 758ee9dfbefSUrsula Braun if (smc->use_fallback) 759603cc149SKarsten Graul return smc_connect_fallback(smc, smc->fallback_rsn); 760ee9dfbefSUrsula Braun 7613b2dec26SHans Wippel /* if peer has not signalled SMC-capability, fall back */ 7623b2dec26SHans Wippel if (!tcp_sk(smc->clcsock->sk)->syn_smc) 763603cc149SKarsten Graul return smc_connect_fallback(smc, SMC_CLC_DECL_PEERNOSMC); 764c5c1cc9cSUrsula Braun 765a046d57dSUrsula Braun /* IPSec connections opt out of SMC-R optimizations */ 7663b2dec26SHans Wippel if (using_ipsec(smc)) 7673b2dec26SHans Wippel return smc_connect_decline_fallback(smc, SMC_CLC_DECL_IPSEC); 768a046d57dSUrsula Braun 769fba7e8efSKarsten Graul /* get vlan id from IP device */ 770bc36d2fcSKarsten Graul if (smc_vlan_by_tcpsk(smc->clcsock, &ini)) 771fba7e8efSKarsten Graul return smc_connect_decline_fallback(smc, 772fba7e8efSKarsten Graul SMC_CLC_DECL_GETVLANERR); 77341349844SHans Wippel 77441349844SHans Wippel /* check if there is an ism device available */ 775228bae05SKarsten Graul if (!smc_find_ism_device(smc, &ini) && 776bc36d2fcSKarsten Graul !smc_connect_ism_vlan_setup(smc, &ini)) { 77741349844SHans Wippel /* ISM is supported for this connection */ 77841349844SHans Wippel ism_supported = true; 77941349844SHans Wippel smc_type = SMC_TYPE_D; 78041349844SHans Wippel } 78141349844SHans Wippel 78241349844SHans Wippel /* check if there is a rdma device available */ 783228bae05SKarsten Graul if (!smc_find_rdma_device(smc, &ini)) { 78441349844SHans Wippel /* RDMA is supported for this connection */ 78541349844SHans Wippel rdma_supported = true; 78641349844SHans Wippel if (ism_supported) 78741349844SHans Wippel smc_type = SMC_TYPE_B; /* both */ 78841349844SHans Wippel else 78941349844SHans Wippel smc_type = SMC_TYPE_R; /* only RDMA */ 79041349844SHans Wippel } 79141349844SHans Wippel 79241349844SHans Wippel /* if neither ISM nor RDMA are supported, fallback */ 79341349844SHans Wippel if (!rdma_supported && !ism_supported) 794603cc149SKarsten Graul return smc_connect_decline_fallback(smc, SMC_CLC_DECL_NOSMCDEV); 795a046d57dSUrsula Braun 7963b2dec26SHans Wippel /* perform CLC handshake */ 797bc36d2fcSKarsten Graul rc = smc_connect_clc(smc, smc_type, &aclc, &ini); 79841349844SHans Wippel if (rc) { 799bc36d2fcSKarsten Graul smc_connect_ism_vlan_cleanup(smc, ism_supported, &ini); 8003b2dec26SHans Wippel return smc_connect_decline_fallback(smc, rc); 80141349844SHans Wippel } 802a046d57dSUrsula Braun 80341349844SHans Wippel /* depending on previous steps, connect using rdma or ism */ 80441349844SHans Wippel if (rdma_supported && aclc.hdr.path == SMC_TYPE_R) 805bc36d2fcSKarsten Graul rc = smc_connect_rdma(smc, &aclc, &ini); 80641349844SHans Wippel else if (ism_supported && aclc.hdr.path == SMC_TYPE_D) 807bc36d2fcSKarsten Graul rc = smc_connect_ism(smc, &aclc, &ini); 80841349844SHans Wippel else 809603cc149SKarsten Graul rc = SMC_CLC_DECL_MODEUNSUPP; 81041349844SHans Wippel if (rc) { 811bc36d2fcSKarsten Graul smc_connect_ism_vlan_cleanup(smc, ism_supported, &ini); 8123b2dec26SHans Wippel return smc_connect_decline_fallback(smc, rc); 81341349844SHans Wippel } 814a046d57dSUrsula Braun 815bc36d2fcSKarsten Graul smc_connect_ism_vlan_cleanup(smc, ism_supported, &ini); 8163b2dec26SHans Wippel return 0; 817a046d57dSUrsula Braun } 818a046d57dSUrsula Braun 81924ac3a08SUrsula Braun static void smc_connect_work(struct work_struct *work) 82024ac3a08SUrsula Braun { 82124ac3a08SUrsula Braun struct smc_sock *smc = container_of(work, struct smc_sock, 82224ac3a08SUrsula Braun connect_work); 82350717a37SUrsula Braun long timeo = smc->sk.sk_sndtimeo; 82450717a37SUrsula Braun int rc = 0; 82524ac3a08SUrsula Braun 82650717a37SUrsula Braun if (!timeo) 82750717a37SUrsula Braun timeo = MAX_SCHEDULE_TIMEOUT; 82850717a37SUrsula Braun lock_sock(smc->clcsock->sk); 82924ac3a08SUrsula Braun if (smc->clcsock->sk->sk_err) { 83024ac3a08SUrsula Braun smc->sk.sk_err = smc->clcsock->sk->sk_err; 83150717a37SUrsula Braun } else if ((1 << smc->clcsock->sk->sk_state) & 83250717a37SUrsula Braun (TCPF_SYN_SENT | TCP_SYN_RECV)) { 83350717a37SUrsula Braun rc = sk_stream_wait_connect(smc->clcsock->sk, &timeo); 83450717a37SUrsula Braun if ((rc == -EPIPE) && 83550717a37SUrsula Braun ((1 << smc->clcsock->sk->sk_state) & 83650717a37SUrsula Braun (TCPF_ESTABLISHED | TCPF_CLOSE_WAIT))) 83750717a37SUrsula Braun rc = 0; 83824ac3a08SUrsula Braun } 83950717a37SUrsula Braun release_sock(smc->clcsock->sk); 84050717a37SUrsula Braun lock_sock(&smc->sk); 84150717a37SUrsula Braun if (rc != 0 || smc->sk.sk_err) { 84250717a37SUrsula Braun smc->sk.sk_state = SMC_CLOSED; 84350717a37SUrsula Braun if (rc == -EPIPE || rc == -EAGAIN) 84450717a37SUrsula Braun smc->sk.sk_err = EPIPE; 84550717a37SUrsula Braun else if (signal_pending(current)) 84650717a37SUrsula Braun smc->sk.sk_err = -sock_intr_errno(timeo); 8476d6dd528SUrsula Braun sock_put(&smc->sk); /* passive closing */ 84824ac3a08SUrsula Braun goto out; 84924ac3a08SUrsula Braun } 85024ac3a08SUrsula Braun 85124ac3a08SUrsula Braun rc = __smc_connect(smc); 85224ac3a08SUrsula Braun if (rc < 0) 85324ac3a08SUrsula Braun smc->sk.sk_err = -rc; 85424ac3a08SUrsula Braun 85524ac3a08SUrsula Braun out: 85607603b23SUrsula Braun if (!sock_flag(&smc->sk, SOCK_DEAD)) { 85707603b23SUrsula Braun if (smc->sk.sk_err) { 85824ac3a08SUrsula Braun smc->sk.sk_state_change(&smc->sk); 85907603b23SUrsula Braun } else { /* allow polling before and after fallback decision */ 86007603b23SUrsula Braun smc->clcsock->sk->sk_write_space(smc->clcsock->sk); 861648a5a7aSUrsula Braun smc->sk.sk_write_space(&smc->sk); 86207603b23SUrsula Braun } 86307603b23SUrsula Braun } 86424ac3a08SUrsula Braun release_sock(&smc->sk); 86524ac3a08SUrsula Braun } 86624ac3a08SUrsula Braun 867ac713874SUrsula Braun static int smc_connect(struct socket *sock, struct sockaddr *addr, 868ac713874SUrsula Braun int alen, int flags) 869ac713874SUrsula Braun { 870ac713874SUrsula Braun struct sock *sk = sock->sk; 871ac713874SUrsula Braun struct smc_sock *smc; 872ac713874SUrsula Braun int rc = -EINVAL; 873ac713874SUrsula Braun 874ac713874SUrsula Braun smc = smc_sk(sk); 875ac713874SUrsula Braun 876ac713874SUrsula Braun /* separate smc parameter checking to be safe */ 877ac713874SUrsula Braun if (alen < sizeof(addr->sa_family)) 878ac713874SUrsula Braun goto out_err; 879aaa4d33fSKarsten Graul if (addr->sa_family != AF_INET && addr->sa_family != AF_INET6) 880ac713874SUrsula Braun goto out_err; 881ac713874SUrsula Braun 882ac713874SUrsula Braun lock_sock(sk); 883ac713874SUrsula Braun switch (sk->sk_state) { 884ac713874SUrsula Braun default: 885ac713874SUrsula Braun goto out; 886ac713874SUrsula Braun case SMC_ACTIVE: 887ac713874SUrsula Braun rc = -EISCONN; 888ac713874SUrsula Braun goto out; 889ac713874SUrsula Braun case SMC_INIT: 890ac713874SUrsula Braun rc = 0; 891ac713874SUrsula Braun break; 892ac713874SUrsula Braun } 893ac713874SUrsula Braun 894ac713874SUrsula Braun smc_copy_sock_settings_to_clc(smc); 895c5c1cc9cSUrsula Braun tcp_sk(smc->clcsock->sk)->syn_smc = 1; 89650717a37SUrsula Braun if (smc->connect_nonblock) { 89724ac3a08SUrsula Braun rc = -EALREADY; 89824ac3a08SUrsula Braun goto out; 89924ac3a08SUrsula Braun } 90050717a37SUrsula Braun rc = kernel_connect(smc->clcsock, addr, alen, flags); 90150717a37SUrsula Braun if (rc && rc != -EINPROGRESS) 90224ac3a08SUrsula Braun goto out; 903301428eaSUrsula Braun 904301428eaSUrsula Braun sock_hold(&smc->sk); /* sock put in passive closing */ 90586434744SUrsula Braun if (smc->use_fallback) 90686434744SUrsula Braun goto out; 90750717a37SUrsula Braun if (flags & O_NONBLOCK) { 90850717a37SUrsula Braun if (schedule_work(&smc->connect_work)) 90950717a37SUrsula Braun smc->connect_nonblock = 1; 91024ac3a08SUrsula Braun rc = -EINPROGRESS; 91124ac3a08SUrsula Braun } else { 9123b2dec26SHans Wippel rc = __smc_connect(smc); 913a046d57dSUrsula Braun if (rc < 0) 914a046d57dSUrsula Braun goto out; 915a046d57dSUrsula Braun else 916a046d57dSUrsula Braun rc = 0; /* success cases including fallback */ 91724ac3a08SUrsula Braun } 918ac713874SUrsula Braun 919ac713874SUrsula Braun out: 920ac713874SUrsula Braun release_sock(sk); 921ac713874SUrsula Braun out_err: 922ac713874SUrsula Braun return rc; 923ac713874SUrsula Braun } 924ac713874SUrsula Braun 925ac713874SUrsula Braun static int smc_clcsock_accept(struct smc_sock *lsmc, struct smc_sock **new_smc) 926ac713874SUrsula Braun { 9273163c507SUrsula Braun struct socket *new_clcsock = NULL; 9283163c507SUrsula Braun struct sock *lsk = &lsmc->sk; 929ac713874SUrsula Braun struct sock *new_sk; 93078abe3d0SMyungho Jung int rc = -EINVAL; 931ac713874SUrsula Braun 9323163c507SUrsula Braun release_sock(lsk); 933aaa4d33fSKarsten Graul new_sk = smc_sock_alloc(sock_net(lsk), NULL, lsk->sk_protocol); 934ac713874SUrsula Braun if (!new_sk) { 935ac713874SUrsula Braun rc = -ENOMEM; 9363163c507SUrsula Braun lsk->sk_err = ENOMEM; 937ac713874SUrsula Braun *new_smc = NULL; 9383163c507SUrsula Braun lock_sock(lsk); 939ac713874SUrsula Braun goto out; 940ac713874SUrsula Braun } 941ac713874SUrsula Braun *new_smc = smc_sk(new_sk); 942ac713874SUrsula Braun 94378abe3d0SMyungho Jung mutex_lock(&lsmc->clcsock_release_lock); 94478abe3d0SMyungho Jung if (lsmc->clcsock) 945a60a2b1eSUrsula Braun rc = kernel_accept(lsmc->clcsock, &new_clcsock, SOCK_NONBLOCK); 94678abe3d0SMyungho Jung mutex_unlock(&lsmc->clcsock_release_lock); 9473163c507SUrsula Braun lock_sock(lsk); 948a60a2b1eSUrsula Braun if (rc < 0 && rc != -EAGAIN) 9493163c507SUrsula Braun lsk->sk_err = -rc; 95035a6b178SUrsula Braun if (rc < 0 || lsk->sk_state == SMC_CLOSED) { 951f61bca58SUrsula Braun new_sk->sk_prot->unhash(new_sk); 952a046d57dSUrsula Braun if (new_clcsock) 953a046d57dSUrsula Braun sock_release(new_clcsock); 954a046d57dSUrsula Braun new_sk->sk_state = SMC_CLOSED; 955a046d57dSUrsula Braun sock_set_flag(new_sk, SOCK_DEAD); 95651f1de79SUrsula Braun sock_put(new_sk); /* final */ 957ac713874SUrsula Braun *new_smc = NULL; 958ac713874SUrsula Braun goto out; 959ac713874SUrsula Braun } 960ac713874SUrsula Braun 961a60a2b1eSUrsula Braun /* new clcsock has inherited the smc listen-specific sk_data_ready 962a60a2b1eSUrsula Braun * function; switch it back to the original sk_data_ready function 963a60a2b1eSUrsula Braun */ 964a60a2b1eSUrsula Braun new_clcsock->sk->sk_data_ready = lsmc->clcsk_data_ready; 965ac713874SUrsula Braun (*new_smc)->clcsock = new_clcsock; 966ac713874SUrsula Braun out: 967ac713874SUrsula Braun return rc; 968ac713874SUrsula Braun } 969ac713874SUrsula Braun 970a046d57dSUrsula Braun /* add a just created sock to the accept queue of the listen sock as 971a046d57dSUrsula Braun * candidate for a following socket accept call from user space 972a046d57dSUrsula Braun */ 973a046d57dSUrsula Braun static void smc_accept_enqueue(struct sock *parent, struct sock *sk) 974a046d57dSUrsula Braun { 975a046d57dSUrsula Braun struct smc_sock *par = smc_sk(parent); 976a046d57dSUrsula Braun 97751f1de79SUrsula Braun sock_hold(sk); /* sock_put in smc_accept_unlink () */ 978a046d57dSUrsula Braun spin_lock(&par->accept_q_lock); 979a046d57dSUrsula Braun list_add_tail(&smc_sk(sk)->accept_q, &par->accept_q); 980a046d57dSUrsula Braun spin_unlock(&par->accept_q_lock); 981a046d57dSUrsula Braun sk_acceptq_added(parent); 982a046d57dSUrsula Braun } 983a046d57dSUrsula Braun 984a046d57dSUrsula Braun /* remove a socket from the accept queue of its parental listening socket */ 985a046d57dSUrsula Braun static void smc_accept_unlink(struct sock *sk) 986a046d57dSUrsula Braun { 987a046d57dSUrsula Braun struct smc_sock *par = smc_sk(sk)->listen_smc; 988a046d57dSUrsula Braun 989a046d57dSUrsula Braun spin_lock(&par->accept_q_lock); 990a046d57dSUrsula Braun list_del_init(&smc_sk(sk)->accept_q); 991a046d57dSUrsula Braun spin_unlock(&par->accept_q_lock); 992a046d57dSUrsula Braun sk_acceptq_removed(&smc_sk(sk)->listen_smc->sk); 99351f1de79SUrsula Braun sock_put(sk); /* sock_hold in smc_accept_enqueue */ 994a046d57dSUrsula Braun } 995a046d57dSUrsula Braun 996a046d57dSUrsula Braun /* remove a sock from the accept queue to bind it to a new socket created 997a046d57dSUrsula Braun * for a socket accept call from user space 998a046d57dSUrsula Braun */ 999b38d7324SUrsula Braun struct sock *smc_accept_dequeue(struct sock *parent, 1000a046d57dSUrsula Braun struct socket *new_sock) 1001a046d57dSUrsula Braun { 1002a046d57dSUrsula Braun struct smc_sock *isk, *n; 1003a046d57dSUrsula Braun struct sock *new_sk; 1004a046d57dSUrsula Braun 1005a046d57dSUrsula Braun list_for_each_entry_safe(isk, n, &smc_sk(parent)->accept_q, accept_q) { 1006a046d57dSUrsula Braun new_sk = (struct sock *)isk; 1007a046d57dSUrsula Braun 1008a046d57dSUrsula Braun smc_accept_unlink(new_sk); 1009a046d57dSUrsula Braun if (new_sk->sk_state == SMC_CLOSED) { 1010f61bca58SUrsula Braun new_sk->sk_prot->unhash(new_sk); 1011127f4970SUrsula Braun if (isk->clcsock) { 1012127f4970SUrsula Braun sock_release(isk->clcsock); 1013127f4970SUrsula Braun isk->clcsock = NULL; 1014127f4970SUrsula Braun } 101551f1de79SUrsula Braun sock_put(new_sk); /* final */ 1016a046d57dSUrsula Braun continue; 1017a046d57dSUrsula Braun } 101807603b23SUrsula Braun if (new_sock) { 1019a046d57dSUrsula Braun sock_graft(new_sk, new_sock); 102007603b23SUrsula Braun if (isk->use_fallback) { 102107603b23SUrsula Braun smc_sk(new_sk)->clcsock->file = new_sock->file; 102207603b23SUrsula Braun isk->clcsock->file->private_data = isk->clcsock; 102307603b23SUrsula Braun } 102407603b23SUrsula Braun } 1025a046d57dSUrsula Braun return new_sk; 1026a046d57dSUrsula Braun } 1027a046d57dSUrsula Braun return NULL; 1028a046d57dSUrsula Braun } 1029a046d57dSUrsula Braun 1030a046d57dSUrsula Braun /* clean up for a created but never accepted sock */ 1031b38d7324SUrsula Braun void smc_close_non_accepted(struct sock *sk) 1032a046d57dSUrsula Braun { 1033a046d57dSUrsula Braun struct smc_sock *smc = smc_sk(sk); 1034a046d57dSUrsula Braun 103581cf4f47SUrsula Braun sock_hold(sk); /* sock_put below */ 1036b38d7324SUrsula Braun lock_sock(sk); 1037b38d7324SUrsula Braun if (!sk->sk_lingertime) 1038b38d7324SUrsula Braun /* wait for peer closing */ 1039b38d7324SUrsula Braun sk->sk_lingertime = SMC_MAX_STREAM_WAIT_TIMEOUT; 104039f41f36SUrsula Braun __smc_release(smc); 1041b38d7324SUrsula Braun release_sock(sk); 104281cf4f47SUrsula Braun sock_put(sk); /* sock_hold above */ 104351f1de79SUrsula Braun sock_put(sk); /* final sock_put */ 1044a046d57dSUrsula Braun } 1045a046d57dSUrsula Braun 1046b9247544SKarsten Graul static int smcr_serv_conf_first_link(struct smc_sock *smc) 10479bf9abeaSUrsula Braun { 1048387707fdSKarsten Graul struct smc_link *link = smc->conn.lnk; 10494667bb4aSKarsten Graul struct smc_llc_qentry *qentry; 10509bf9abeaSUrsula Braun int rc; 10519bf9abeaSUrsula Braun 10527562a13dSKarsten Graul if (smcr_link_reg_rmb(link, smc->conn.rmb_desc)) 1053603cc149SKarsten Graul return SMC_CLC_DECL_ERR_REGRMB; 1054652a1e41SUrsula Braun 10559bf9abeaSUrsula Braun /* send CONFIRM LINK request to client over the RoCE fabric */ 1056947541f3SUrsula Braun rc = smc_llc_send_confirm_link(link, SMC_LLC_REQ); 10579bf9abeaSUrsula Braun if (rc < 0) 1058603cc149SKarsten Graul return SMC_CLC_DECL_TIMEOUT_CL; 10599bf9abeaSUrsula Braun 10609bf9abeaSUrsula Braun /* receive CONFIRM LINK response from client over the RoCE fabric */ 10614667bb4aSKarsten Graul qentry = smc_llc_wait(link->lgr, link, SMC_LLC_WAIT_TIME, 10624667bb4aSKarsten Graul SMC_LLC_CONFIRM_LINK); 10634667bb4aSKarsten Graul if (!qentry) { 10649bf9abeaSUrsula Braun struct smc_clc_msg_decline dclc; 10659bf9abeaSUrsula Braun 10669bf9abeaSUrsula Braun rc = smc_clc_wait_msg(smc, &dclc, sizeof(dclc), 10672b59f58eSUrsula Braun SMC_CLC_DECLINE, CLC_WAIT_TIME_SHORT); 10689ed28556SUrsula Braun return rc == -EAGAIN ? SMC_CLC_DECL_TIMEOUT_CL : rc; 10699bf9abeaSUrsula Braun } 1070649758ffSKarsten Graul smc_llc_save_peer_uid(qentry); 10714667bb4aSKarsten Graul rc = smc_llc_eval_conf_link(qentry, SMC_LLC_RESP); 10724667bb4aSKarsten Graul smc_llc_flow_qentry_del(&link->lgr->llc_flow_lcl); 10734667bb4aSKarsten Graul if (rc) 107475d320d6SKarsten Graul return SMC_CLC_DECL_RMBE_EC; 107575d320d6SKarsten Graul 10764667bb4aSKarsten Graul /* confirm_rkey is implicit on 1st contact */ 10774667bb4aSKarsten Graul smc->conn.rmb_desc->is_conf_rkey = true; 107852bedf37SKarsten Graul 107900a049cfSKarsten Graul smc_llc_link_active(link); 10800a99be43SKarsten Graul smcr_lgr_set_type(link->lgr, SMC_LGR_SINGLE); 108152bedf37SKarsten Graul 10824667bb4aSKarsten Graul /* initial contact - try to establish second link */ 10832d2209f2SKarsten Graul smc_llc_srv_add_link(link); 108475d320d6SKarsten Graul return 0; 10859bf9abeaSUrsula Braun } 10869bf9abeaSUrsula Braun 10873b2dec26SHans Wippel /* listen worker: finish */ 10883b2dec26SHans Wippel static void smc_listen_out(struct smc_sock *new_smc) 1089a046d57dSUrsula Braun { 1090a046d57dSUrsula Braun struct smc_sock *lsmc = new_smc->listen_smc; 1091a046d57dSUrsula Braun struct sock *newsmcsk = &new_smc->sk; 1092a046d57dSUrsula Braun 1093a046d57dSUrsula Braun if (lsmc->sk.sk_state == SMC_LISTEN) { 1094fd57770dSKarsten Graul lock_sock_nested(&lsmc->sk, SINGLE_DEPTH_NESTING); 1095a046d57dSUrsula Braun smc_accept_enqueue(&lsmc->sk, newsmcsk); 1096fd57770dSKarsten Graul release_sock(&lsmc->sk); 1097a046d57dSUrsula Braun } else { /* no longer listening */ 1098a046d57dSUrsula Braun smc_close_non_accepted(newsmcsk); 1099a046d57dSUrsula Braun } 1100a046d57dSUrsula Braun 1101a046d57dSUrsula Braun /* Wake up accept */ 1102a046d57dSUrsula Braun lsmc->sk.sk_data_ready(&lsmc->sk); 1103a046d57dSUrsula Braun sock_put(&lsmc->sk); /* sock_hold in smc_tcp_listen_work */ 1104a046d57dSUrsula Braun } 1105a046d57dSUrsula Braun 11063b2dec26SHans Wippel /* listen worker: finish in state connected */ 11073b2dec26SHans Wippel static void smc_listen_out_connected(struct smc_sock *new_smc) 11083b2dec26SHans Wippel { 11093b2dec26SHans Wippel struct sock *newsmcsk = &new_smc->sk; 11103b2dec26SHans Wippel 11113b2dec26SHans Wippel sk_refcnt_debug_inc(newsmcsk); 11123b2dec26SHans Wippel if (newsmcsk->sk_state == SMC_INIT) 11133b2dec26SHans Wippel newsmcsk->sk_state = SMC_ACTIVE; 11143b2dec26SHans Wippel 11153b2dec26SHans Wippel smc_listen_out(new_smc); 11163b2dec26SHans Wippel } 11173b2dec26SHans Wippel 11183b2dec26SHans Wippel /* listen worker: finish in error state */ 11193b2dec26SHans Wippel static void smc_listen_out_err(struct smc_sock *new_smc) 11203b2dec26SHans Wippel { 11213b2dec26SHans Wippel struct sock *newsmcsk = &new_smc->sk; 11223b2dec26SHans Wippel 112351f1de79SUrsula Braun if (newsmcsk->sk_state == SMC_INIT) 112451f1de79SUrsula Braun sock_put(&new_smc->sk); /* passive closing */ 1125a046d57dSUrsula Braun newsmcsk->sk_state = SMC_CLOSED; 11263b2dec26SHans Wippel 11273b2dec26SHans Wippel smc_listen_out(new_smc); 11283b2dec26SHans Wippel } 11293b2dec26SHans Wippel 11303b2dec26SHans Wippel /* listen worker: decline and fall back if possible */ 11313b2dec26SHans Wippel static void smc_listen_decline(struct smc_sock *new_smc, int reason_code, 11325ac54d87SUrsula Braun bool local_first) 11333b2dec26SHans Wippel { 11343b2dec26SHans Wippel /* RDMA setup failed, switch back to TCP */ 11355ac54d87SUrsula Braun if (local_first) 113651e3dfa8SUrsula Braun smc_lgr_cleanup_early(&new_smc->conn); 113751e3dfa8SUrsula Braun else 113851e3dfa8SUrsula Braun smc_conn_free(&new_smc->conn); 11393b2dec26SHans Wippel if (reason_code < 0) { /* error, no fallback possible */ 11403b2dec26SHans Wippel smc_listen_out_err(new_smc); 11413b2dec26SHans Wippel return; 11423b2dec26SHans Wippel } 114307603b23SUrsula Braun smc_switch_to_fallback(new_smc); 1144603cc149SKarsten Graul new_smc->fallback_rsn = reason_code; 1145603cc149SKarsten Graul if (reason_code && reason_code != SMC_CLC_DECL_PEERDECL) { 11463b2dec26SHans Wippel if (smc_clc_send_decline(new_smc, reason_code) < 0) { 11473b2dec26SHans Wippel smc_listen_out_err(new_smc); 11483b2dec26SHans Wippel return; 11493b2dec26SHans Wippel } 11503b2dec26SHans Wippel } 11513b2dec26SHans Wippel smc_listen_out_connected(new_smc); 11523b2dec26SHans Wippel } 11533b2dec26SHans Wippel 11543b2dec26SHans Wippel /* listen worker: check prefixes */ 115559886697SKarsten Graul static int smc_listen_prfx_check(struct smc_sock *new_smc, 11563b2dec26SHans Wippel struct smc_clc_msg_proposal *pclc) 11573b2dec26SHans Wippel { 11583b2dec26SHans Wippel struct smc_clc_msg_proposal_prefix *pclc_prfx; 11593b2dec26SHans Wippel struct socket *newclcsock = new_smc->clcsock; 11603b2dec26SHans Wippel 11613b2dec26SHans Wippel pclc_prfx = smc_clc_proposal_get_prefix(pclc); 11623b2dec26SHans Wippel if (smc_clc_prfx_match(newclcsock, pclc_prfx)) 116359886697SKarsten Graul return SMC_CLC_DECL_DIFFPREFIX; 11643b2dec26SHans Wippel 11653b2dec26SHans Wippel return 0; 11663b2dec26SHans Wippel } 11673b2dec26SHans Wippel 11683b2dec26SHans Wippel /* listen worker: initialize connection and buffers */ 11693b2dec26SHans Wippel static int smc_listen_rdma_init(struct smc_sock *new_smc, 11707a62725aSKarsten Graul struct smc_init_info *ini) 11713b2dec26SHans Wippel { 11727a62725aSKarsten Graul int rc; 11737a62725aSKarsten Graul 11743b2dec26SHans Wippel /* allocate connection / link group */ 11757a62725aSKarsten Graul rc = smc_conn_create(new_smc, ini); 11767a62725aSKarsten Graul if (rc) 11777a62725aSKarsten Graul return rc; 11783b2dec26SHans Wippel 11793b2dec26SHans Wippel /* create send buffer and rmb */ 1180c6ba7c9bSHans Wippel if (smc_buf_create(new_smc, false)) 11813b2dec26SHans Wippel return SMC_CLC_DECL_MEM; 11823b2dec26SHans Wippel 11833b2dec26SHans Wippel return 0; 11843b2dec26SHans Wippel } 11853b2dec26SHans Wippel 118641349844SHans Wippel /* listen worker: initialize connection and buffers for SMC-D */ 118741349844SHans Wippel static int smc_listen_ism_init(struct smc_sock *new_smc, 118841349844SHans Wippel struct smc_clc_msg_proposal *pclc, 11897a62725aSKarsten Graul struct smc_init_info *ini) 119041349844SHans Wippel { 119141349844SHans Wippel struct smc_clc_msg_smcd *pclc_smcd; 11927a62725aSKarsten Graul int rc; 119341349844SHans Wippel 119441349844SHans Wippel pclc_smcd = smc_get_clc_msg_smcd(pclc); 11955ac54d87SUrsula Braun ini->ism_peer_gid = pclc_smcd->gid; 11967a62725aSKarsten Graul rc = smc_conn_create(new_smc, ini); 11977a62725aSKarsten Graul if (rc) 11987a62725aSKarsten Graul return rc; 119941349844SHans Wippel 120041349844SHans Wippel /* Check if peer can be reached via ISM device */ 120141349844SHans Wippel if (smc_ism_cantalk(new_smc->conn.lgr->peer_gid, 120241349844SHans Wippel new_smc->conn.lgr->vlan_id, 120341349844SHans Wippel new_smc->conn.lgr->smcd)) { 12045ac54d87SUrsula Braun if (ini->first_contact_local) 120551e3dfa8SUrsula Braun smc_lgr_cleanup_early(&new_smc->conn); 120651e3dfa8SUrsula Braun else 120741349844SHans Wippel smc_conn_free(&new_smc->conn); 12089aa68d29SKarsten Graul return SMC_CLC_DECL_SMCDNOTALK; 120941349844SHans Wippel } 121041349844SHans Wippel 121141349844SHans Wippel /* Create send and receive buffers */ 121272b7f6c4SKarsten Graul rc = smc_buf_create(new_smc, true); 121372b7f6c4SKarsten Graul if (rc) { 12145ac54d87SUrsula Braun if (ini->first_contact_local) 121551e3dfa8SUrsula Braun smc_lgr_cleanup_early(&new_smc->conn); 121651e3dfa8SUrsula Braun else 121741349844SHans Wippel smc_conn_free(&new_smc->conn); 121872b7f6c4SKarsten Graul return (rc == -ENOSPC) ? SMC_CLC_DECL_MAX_DMB : 121972b7f6c4SKarsten Graul SMC_CLC_DECL_MEM; 122041349844SHans Wippel } 122141349844SHans Wippel 122241349844SHans Wippel return 0; 122341349844SHans Wippel } 122441349844SHans Wippel 12253b2dec26SHans Wippel /* listen worker: register buffers */ 12265ac54d87SUrsula Braun static int smc_listen_rdma_reg(struct smc_sock *new_smc, bool local_first) 12273b2dec26SHans Wippel { 1228b9247544SKarsten Graul struct smc_connection *conn = &new_smc->conn; 12293b2dec26SHans Wippel 12305ac54d87SUrsula Braun if (!local_first) { 12317562a13dSKarsten Graul if (smcr_lgr_reg_rmbs(conn->lnk, conn->rmb_desc)) 1232603cc149SKarsten Graul return SMC_CLC_DECL_ERR_REGRMB; 12333b2dec26SHans Wippel } 12343b2dec26SHans Wippel smc_rmb_sync_sg_for_device(&new_smc->conn); 12353b2dec26SHans Wippel 12363b2dec26SHans Wippel return 0; 12373b2dec26SHans Wippel } 12383b2dec26SHans Wippel 12393b2dec26SHans Wippel /* listen worker: finish RDMA setup */ 12401ca52fcfSUrsula Braun static int smc_listen_rdma_finish(struct smc_sock *new_smc, 12413b2dec26SHans Wippel struct smc_clc_msg_accept_confirm *cclc, 12425ac54d87SUrsula Braun bool local_first) 12433b2dec26SHans Wippel { 1244387707fdSKarsten Graul struct smc_link *link = new_smc->conn.lnk; 12453b2dec26SHans Wippel int reason_code = 0; 12463b2dec26SHans Wippel 12475ac54d87SUrsula Braun if (local_first) 12483b2dec26SHans Wippel smc_link_save_peer_info(link, cclc); 12493b2dec26SHans Wippel 1250e07d31dcSKarsten Graul if (smc_rmb_rtoken_handling(&new_smc->conn, link, cclc)) { 1251603cc149SKarsten Graul reason_code = SMC_CLC_DECL_ERR_RTOK; 12523b2dec26SHans Wippel goto decline; 12533b2dec26SHans Wippel } 12543b2dec26SHans Wippel 12555ac54d87SUrsula Braun if (local_first) { 12563b2dec26SHans Wippel if (smc_ib_ready_link(link)) { 1257603cc149SKarsten Graul reason_code = SMC_CLC_DECL_ERR_RDYLNK; 12583b2dec26SHans Wippel goto decline; 12593b2dec26SHans Wippel } 12603b2dec26SHans Wippel /* QP confirmation over RoCE fabric */ 12614667bb4aSKarsten Graul smc_llc_flow_initiate(link->lgr, SMC_LLC_FLOW_ADD_LINK); 1262b9247544SKarsten Graul reason_code = smcr_serv_conf_first_link(new_smc); 12634667bb4aSKarsten Graul smc_llc_flow_stop(link->lgr, &link->lgr->llc_flow_lcl); 12643b2dec26SHans Wippel if (reason_code) 12653b2dec26SHans Wippel goto decline; 12663b2dec26SHans Wippel } 12671ca52fcfSUrsula Braun return 0; 12683b2dec26SHans Wippel 12693b2dec26SHans Wippel decline: 12705ac54d87SUrsula Braun smc_listen_decline(new_smc, reason_code, local_first); 12711ca52fcfSUrsula Braun return reason_code; 12723b2dec26SHans Wippel } 12733b2dec26SHans Wippel 12743b2dec26SHans Wippel /* setup for RDMA connection of server */ 12753b2dec26SHans Wippel static void smc_listen_work(struct work_struct *work) 12763b2dec26SHans Wippel { 12773b2dec26SHans Wippel struct smc_sock *new_smc = container_of(work, struct smc_sock, 12783b2dec26SHans Wippel smc_listen_work); 12793b2dec26SHans Wippel struct socket *newclcsock = new_smc->clcsock; 12803b2dec26SHans Wippel struct smc_clc_msg_accept_confirm cclc; 12816bb14e48SUrsula Braun struct smc_clc_msg_proposal_area *buf; 12823b2dec26SHans Wippel struct smc_clc_msg_proposal *pclc; 1283bc36d2fcSKarsten Graul struct smc_init_info ini = {0}; 128441349844SHans Wippel bool ism_supported = false; 12853b2dec26SHans Wippel int rc = 0; 12863b2dec26SHans Wippel 1287fd57770dSKarsten Graul if (new_smc->listen_smc->sk.sk_state != SMC_LISTEN) 1288fd57770dSKarsten Graul return smc_listen_out_err(new_smc); 1289fd57770dSKarsten Graul 12903b2dec26SHans Wippel if (new_smc->use_fallback) { 12913b2dec26SHans Wippel smc_listen_out_connected(new_smc); 12923b2dec26SHans Wippel return; 12933b2dec26SHans Wippel } 12943b2dec26SHans Wippel 12953b2dec26SHans Wippel /* check if peer is smc capable */ 12963b2dec26SHans Wippel if (!tcp_sk(newclcsock->sk)->syn_smc) { 129707603b23SUrsula Braun smc_switch_to_fallback(new_smc); 1298603cc149SKarsten Graul new_smc->fallback_rsn = SMC_CLC_DECL_PEERNOSMC; 12993b2dec26SHans Wippel smc_listen_out_connected(new_smc); 13003b2dec26SHans Wippel return; 13013b2dec26SHans Wippel } 13023b2dec26SHans Wippel 13033b2dec26SHans Wippel /* do inband token exchange - 13043b2dec26SHans Wippel * wait for and receive SMC Proposal CLC message 13053b2dec26SHans Wippel */ 13066bb14e48SUrsula Braun buf = kzalloc(sizeof(*buf), GFP_KERNEL); 13076bb14e48SUrsula Braun if (!buf) { 13086bb14e48SUrsula Braun rc = SMC_CLC_DECL_MEM; 13096bb14e48SUrsula Braun goto out_decl; 13106bb14e48SUrsula Braun } 13116bb14e48SUrsula Braun pclc = (struct smc_clc_msg_proposal *)buf; 13126bb14e48SUrsula Braun rc = smc_clc_wait_msg(new_smc, pclc, sizeof(*buf), 13132b59f58eSUrsula Braun SMC_CLC_PROPOSAL, CLC_WAIT_TIME); 13149aa68d29SKarsten Graul if (rc) 13159aa68d29SKarsten Graul goto out_decl; 13163b2dec26SHans Wippel 13173b2dec26SHans Wippel /* IPSec connections opt out of SMC-R optimizations */ 13183b2dec26SHans Wippel if (using_ipsec(new_smc)) { 13199aa68d29SKarsten Graul rc = SMC_CLC_DECL_IPSEC; 13209aa68d29SKarsten Graul goto out_decl; 13213b2dec26SHans Wippel } 13223b2dec26SHans Wippel 132359886697SKarsten Graul /* check for matching IP prefix and subnet length */ 132459886697SKarsten Graul rc = smc_listen_prfx_check(new_smc, pclc); 13259aa68d29SKarsten Graul if (rc) 13269aa68d29SKarsten Graul goto out_decl; 132759886697SKarsten Graul 1328fba7e8efSKarsten Graul /* get vlan id from IP device */ 1329fba7e8efSKarsten Graul if (smc_vlan_by_tcpsk(new_smc->clcsock, &ini)) { 13309aa68d29SKarsten Graul rc = SMC_CLC_DECL_GETVLANERR; 13319aa68d29SKarsten Graul goto out_decl; 1332fba7e8efSKarsten Graul } 1333fba7e8efSKarsten Graul 133472a36a8aSHans Wippel mutex_lock(&smc_server_lgr_pending); 13353b2dec26SHans Wippel smc_close_init(new_smc); 13363b2dec26SHans Wippel smc_rx_init(new_smc); 13373b2dec26SHans Wippel smc_tx_init(new_smc); 13383b2dec26SHans Wippel 133941349844SHans Wippel /* check if ISM is available */ 13409aa68d29SKarsten Graul if (pclc->hdr.path == SMC_TYPE_D || pclc->hdr.path == SMC_TYPE_B) { 13419aa68d29SKarsten Graul ini.is_smcd = true; /* prepare ISM check */ 13429aa68d29SKarsten Graul rc = smc_find_ism_device(new_smc, &ini); 13439aa68d29SKarsten Graul if (!rc) 13447a62725aSKarsten Graul rc = smc_listen_ism_init(new_smc, pclc, &ini); 13459aa68d29SKarsten Graul if (!rc) 134641349844SHans Wippel ism_supported = true; 13479aa68d29SKarsten Graul else if (pclc->hdr.path == SMC_TYPE_D) 13489aa68d29SKarsten Graul goto out_unlock; /* skip RDMA and decline */ 13499aa68d29SKarsten Graul } 13509aa68d29SKarsten Graul 13519aa68d29SKarsten Graul /* check if RDMA is available */ 13529aa68d29SKarsten Graul if (!ism_supported) { /* SMC_TYPE_R or SMC_TYPE_B */ 1353bc36d2fcSKarsten Graul /* prepare RDMA check */ 1354bc36d2fcSKarsten Graul ini.is_smcd = false; 1355ca5f8d2dSUrsula Braun ini.ism_dev = NULL; 1356bc36d2fcSKarsten Graul ini.ib_lcl = &pclc->lcl; 13579aa68d29SKarsten Graul rc = smc_find_rdma_device(new_smc, &ini); 13589aa68d29SKarsten Graul if (rc) { 13599aa68d29SKarsten Graul /* no RDMA device found */ 13609aa68d29SKarsten Graul if (pclc->hdr.path == SMC_TYPE_B) 13619aa68d29SKarsten Graul /* neither ISM nor RDMA device found */ 13629aa68d29SKarsten Graul rc = SMC_CLC_DECL_NOSMCDEV; 13639aa68d29SKarsten Graul goto out_unlock; 136441349844SHans Wippel } 13657a62725aSKarsten Graul rc = smc_listen_rdma_init(new_smc, &ini); 13669aa68d29SKarsten Graul if (rc) 13679aa68d29SKarsten Graul goto out_unlock; 13685ac54d87SUrsula Braun rc = smc_listen_rdma_reg(new_smc, ini.first_contact_local); 13699aa68d29SKarsten Graul if (rc) 13709aa68d29SKarsten Graul goto out_unlock; 13713b2dec26SHans Wippel } 13723b2dec26SHans Wippel 13733b2dec26SHans Wippel /* send SMC Accept CLC message */ 13745ac54d87SUrsula Braun rc = smc_clc_send_accept(new_smc, ini.first_contact_local); 13759aa68d29SKarsten Graul if (rc) 13769aa68d29SKarsten Graul goto out_unlock; 13773b2dec26SHans Wippel 137862c7139fSHans Wippel /* SMC-D does not need this lock any more */ 137962c7139fSHans Wippel if (ism_supported) 138072a36a8aSHans Wippel mutex_unlock(&smc_server_lgr_pending); 138162c7139fSHans Wippel 13823b2dec26SHans Wippel /* receive SMC Confirm CLC message */ 1383228bae05SKarsten Graul rc = smc_clc_wait_msg(new_smc, &cclc, sizeof(cclc), 13842b59f58eSUrsula Braun SMC_CLC_CONFIRM, CLC_WAIT_TIME); 1385228bae05SKarsten Graul if (rc) { 138662c7139fSHans Wippel if (!ism_supported) 13879aa68d29SKarsten Graul goto out_unlock; 13889aa68d29SKarsten Graul goto out_decl; 13893b2dec26SHans Wippel } 13903b2dec26SHans Wippel 13913b2dec26SHans Wippel /* finish worker */ 13926bb14e48SUrsula Braun kfree(buf); 13931ca52fcfSUrsula Braun if (!ism_supported) { 13947a62725aSKarsten Graul rc = smc_listen_rdma_finish(new_smc, &cclc, 13955ac54d87SUrsula Braun ini.first_contact_local); 139672a36a8aSHans Wippel mutex_unlock(&smc_server_lgr_pending); 139762c7139fSHans Wippel if (rc) 13981ca52fcfSUrsula Braun return; 13991ca52fcfSUrsula Braun } 14003b2dec26SHans Wippel smc_conn_save_peer_info(new_smc, &cclc); 14013b2dec26SHans Wippel smc_listen_out_connected(new_smc); 14029aa68d29SKarsten Graul return; 14039aa68d29SKarsten Graul 14049aa68d29SKarsten Graul out_unlock: 14059aa68d29SKarsten Graul mutex_unlock(&smc_server_lgr_pending); 14069aa68d29SKarsten Graul out_decl: 14075ac54d87SUrsula Braun smc_listen_decline(new_smc, rc, ini.first_contact_local); 14086bb14e48SUrsula Braun kfree(buf); 1409a046d57dSUrsula Braun } 1410a046d57dSUrsula Braun 1411a046d57dSUrsula Braun static void smc_tcp_listen_work(struct work_struct *work) 1412a046d57dSUrsula Braun { 1413a046d57dSUrsula Braun struct smc_sock *lsmc = container_of(work, struct smc_sock, 1414a046d57dSUrsula Braun tcp_listen_work); 14153163c507SUrsula Braun struct sock *lsk = &lsmc->sk; 1416a046d57dSUrsula Braun struct smc_sock *new_smc; 1417a046d57dSUrsula Braun int rc = 0; 1418a046d57dSUrsula Braun 14193163c507SUrsula Braun lock_sock(lsk); 14203163c507SUrsula Braun while (lsk->sk_state == SMC_LISTEN) { 1421a046d57dSUrsula Braun rc = smc_clcsock_accept(lsmc, &new_smc); 1422a60a2b1eSUrsula Braun if (rc) /* clcsock accept queue empty or error */ 1423a046d57dSUrsula Braun goto out; 1424a046d57dSUrsula Braun if (!new_smc) 1425a046d57dSUrsula Braun continue; 1426a046d57dSUrsula Braun 1427a046d57dSUrsula Braun new_smc->listen_smc = lsmc; 1428ee9dfbefSUrsula Braun new_smc->use_fallback = lsmc->use_fallback; 1429603cc149SKarsten Graul new_smc->fallback_rsn = lsmc->fallback_rsn; 14303163c507SUrsula Braun sock_hold(lsk); /* sock_put in smc_listen_work */ 1431a046d57dSUrsula Braun INIT_WORK(&new_smc->smc_listen_work, smc_listen_work); 1432a046d57dSUrsula Braun smc_copy_sock_settings_to_smc(new_smc); 1433bd58c7e0SUrsula Braun new_smc->sk.sk_sndbuf = lsmc->sk.sk_sndbuf; 1434bd58c7e0SUrsula Braun new_smc->sk.sk_rcvbuf = lsmc->sk.sk_rcvbuf; 143551f1de79SUrsula Braun sock_hold(&new_smc->sk); /* sock_put in passive closing */ 143651f1de79SUrsula Braun if (!schedule_work(&new_smc->smc_listen_work)) 143751f1de79SUrsula Braun sock_put(&new_smc->sk); 1438a046d57dSUrsula Braun } 1439a046d57dSUrsula Braun 1440a046d57dSUrsula Braun out: 14413163c507SUrsula Braun release_sock(lsk); 1442a60a2b1eSUrsula Braun sock_put(&lsmc->sk); /* sock_hold in smc_clcsock_data_ready() */ 1443a60a2b1eSUrsula Braun } 1444a60a2b1eSUrsula Braun 1445a60a2b1eSUrsula Braun static void smc_clcsock_data_ready(struct sock *listen_clcsock) 1446a60a2b1eSUrsula Braun { 1447a60a2b1eSUrsula Braun struct smc_sock *lsmc; 1448a60a2b1eSUrsula Braun 1449a60a2b1eSUrsula Braun lsmc = (struct smc_sock *) 1450a60a2b1eSUrsula Braun ((uintptr_t)listen_clcsock->sk_user_data & ~SK_USER_DATA_NOCOPY); 1451a60a2b1eSUrsula Braun if (!lsmc) 1452a60a2b1eSUrsula Braun return; 1453a60a2b1eSUrsula Braun lsmc->clcsk_data_ready(listen_clcsock); 1454a60a2b1eSUrsula Braun if (lsmc->sk.sk_state == SMC_LISTEN) { 1455a60a2b1eSUrsula Braun sock_hold(&lsmc->sk); /* sock_put in smc_tcp_listen_work() */ 1456a60a2b1eSUrsula Braun if (!schedule_work(&lsmc->tcp_listen_work)) 1457a60a2b1eSUrsula Braun sock_put(&lsmc->sk); 1458a60a2b1eSUrsula Braun } 1459a046d57dSUrsula Braun } 1460a046d57dSUrsula Braun 1461ac713874SUrsula Braun static int smc_listen(struct socket *sock, int backlog) 1462ac713874SUrsula Braun { 1463ac713874SUrsula Braun struct sock *sk = sock->sk; 1464ac713874SUrsula Braun struct smc_sock *smc; 1465ac713874SUrsula Braun int rc; 1466ac713874SUrsula Braun 1467ac713874SUrsula Braun smc = smc_sk(sk); 1468ac713874SUrsula Braun lock_sock(sk); 1469ac713874SUrsula Braun 1470ac713874SUrsula Braun rc = -EINVAL; 1471cd206360SUrsula Braun if ((sk->sk_state != SMC_INIT && sk->sk_state != SMC_LISTEN) || 1472cd206360SUrsula Braun smc->connect_nonblock) 1473ac713874SUrsula Braun goto out; 1474ac713874SUrsula Braun 1475ac713874SUrsula Braun rc = 0; 1476ac713874SUrsula Braun if (sk->sk_state == SMC_LISTEN) { 1477ac713874SUrsula Braun sk->sk_max_ack_backlog = backlog; 1478ac713874SUrsula Braun goto out; 1479ac713874SUrsula Braun } 1480ac713874SUrsula Braun /* some socket options are handled in core, so we could not apply 1481ac713874SUrsula Braun * them to the clc socket -- copy smc socket options to clc socket 1482ac713874SUrsula Braun */ 1483ac713874SUrsula Braun smc_copy_sock_settings_to_clc(smc); 1484ee9dfbefSUrsula Braun if (!smc->use_fallback) 1485c5c1cc9cSUrsula Braun tcp_sk(smc->clcsock->sk)->syn_smc = 1; 1486ac713874SUrsula Braun 1487a60a2b1eSUrsula Braun /* save original sk_data_ready function and establish 1488a60a2b1eSUrsula Braun * smc-specific sk_data_ready function 1489a60a2b1eSUrsula Braun */ 1490a60a2b1eSUrsula Braun smc->clcsk_data_ready = smc->clcsock->sk->sk_data_ready; 1491a60a2b1eSUrsula Braun smc->clcsock->sk->sk_data_ready = smc_clcsock_data_ready; 1492a60a2b1eSUrsula Braun smc->clcsock->sk->sk_user_data = 1493a60a2b1eSUrsula Braun (void *)((uintptr_t)smc | SK_USER_DATA_NOCOPY); 1494ac713874SUrsula Braun rc = kernel_listen(smc->clcsock, backlog); 1495ac713874SUrsula Braun if (rc) 1496ac713874SUrsula Braun goto out; 1497ac713874SUrsula Braun sk->sk_max_ack_backlog = backlog; 1498ac713874SUrsula Braun sk->sk_ack_backlog = 0; 1499ac713874SUrsula Braun sk->sk_state = SMC_LISTEN; 1500ac713874SUrsula Braun 1501ac713874SUrsula Braun out: 1502ac713874SUrsula Braun release_sock(sk); 1503ac713874SUrsula Braun return rc; 1504ac713874SUrsula Braun } 1505ac713874SUrsula Braun 1506ac713874SUrsula Braun static int smc_accept(struct socket *sock, struct socket *new_sock, 1507cdfbabfbSDavid Howells int flags, bool kern) 1508ac713874SUrsula Braun { 1509a046d57dSUrsula Braun struct sock *sk = sock->sk, *nsk; 1510a046d57dSUrsula Braun DECLARE_WAITQUEUE(wait, current); 1511ac713874SUrsula Braun struct smc_sock *lsmc; 1512a046d57dSUrsula Braun long timeo; 1513a046d57dSUrsula Braun int rc = 0; 1514ac713874SUrsula Braun 1515ac713874SUrsula Braun lsmc = smc_sk(sk); 151651f1de79SUrsula Braun sock_hold(sk); /* sock_put below */ 1517ac713874SUrsula Braun lock_sock(sk); 1518ac713874SUrsula Braun 1519ac713874SUrsula Braun if (lsmc->sk.sk_state != SMC_LISTEN) { 1520ac713874SUrsula Braun rc = -EINVAL; 1521abb190f1SUrsula Braun release_sock(sk); 1522ac713874SUrsula Braun goto out; 1523ac713874SUrsula Braun } 1524ac713874SUrsula Braun 1525a046d57dSUrsula Braun /* Wait for an incoming connection */ 1526a046d57dSUrsula Braun timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK); 1527a046d57dSUrsula Braun add_wait_queue_exclusive(sk_sleep(sk), &wait); 1528a046d57dSUrsula Braun while (!(nsk = smc_accept_dequeue(sk, new_sock))) { 1529a046d57dSUrsula Braun set_current_state(TASK_INTERRUPTIBLE); 1530a046d57dSUrsula Braun if (!timeo) { 1531a046d57dSUrsula Braun rc = -EAGAIN; 1532a046d57dSUrsula Braun break; 1533a046d57dSUrsula Braun } 1534a046d57dSUrsula Braun release_sock(sk); 1535a046d57dSUrsula Braun timeo = schedule_timeout(timeo); 1536a046d57dSUrsula Braun /* wakeup by sk_data_ready in smc_listen_work() */ 1537a046d57dSUrsula Braun sched_annotate_sleep(); 1538a046d57dSUrsula Braun lock_sock(sk); 1539a046d57dSUrsula Braun if (signal_pending(current)) { 1540a046d57dSUrsula Braun rc = sock_intr_errno(timeo); 1541a046d57dSUrsula Braun break; 1542a046d57dSUrsula Braun } 1543a046d57dSUrsula Braun } 1544a046d57dSUrsula Braun set_current_state(TASK_RUNNING); 1545a046d57dSUrsula Braun remove_wait_queue(sk_sleep(sk), &wait); 1546ac713874SUrsula Braun 1547a046d57dSUrsula Braun if (!rc) 1548a046d57dSUrsula Braun rc = sock_error(nsk); 1549abb190f1SUrsula Braun release_sock(sk); 1550abb190f1SUrsula Braun if (rc) 1551abb190f1SUrsula Braun goto out; 1552abb190f1SUrsula Braun 1553abb190f1SUrsula Braun if (lsmc->sockopt_defer_accept && !(flags & O_NONBLOCK)) { 1554abb190f1SUrsula Braun /* wait till data arrives on the socket */ 1555abb190f1SUrsula Braun timeo = msecs_to_jiffies(lsmc->sockopt_defer_accept * 1556abb190f1SUrsula Braun MSEC_PER_SEC); 1557abb190f1SUrsula Braun if (smc_sk(nsk)->use_fallback) { 1558abb190f1SUrsula Braun struct sock *clcsk = smc_sk(nsk)->clcsock->sk; 1559abb190f1SUrsula Braun 1560abb190f1SUrsula Braun lock_sock(clcsk); 1561abb190f1SUrsula Braun if (skb_queue_empty(&clcsk->sk_receive_queue)) 1562abb190f1SUrsula Braun sk_wait_data(clcsk, &timeo, NULL); 1563abb190f1SUrsula Braun release_sock(clcsk); 1564abb190f1SUrsula Braun } else if (!atomic_read(&smc_sk(nsk)->conn.bytes_to_rcv)) { 1565abb190f1SUrsula Braun lock_sock(nsk); 1566b51fa1b1SStefan Raspl smc_rx_wait(smc_sk(nsk), &timeo, smc_rx_data_available); 1567abb190f1SUrsula Braun release_sock(nsk); 1568abb190f1SUrsula Braun } 1569abb190f1SUrsula Braun } 1570ac713874SUrsula Braun 1571ac713874SUrsula Braun out: 157251f1de79SUrsula Braun sock_put(sk); /* sock_hold above */ 1573ac713874SUrsula Braun return rc; 1574ac713874SUrsula Braun } 1575ac713874SUrsula Braun 1576ac713874SUrsula Braun static int smc_getname(struct socket *sock, struct sockaddr *addr, 15779b2c45d4SDenys Vlasenko int peer) 1578ac713874SUrsula Braun { 1579ac713874SUrsula Braun struct smc_sock *smc; 1580ac713874SUrsula Braun 1581b38d7324SUrsula Braun if (peer && (sock->sk->sk_state != SMC_ACTIVE) && 1582b38d7324SUrsula Braun (sock->sk->sk_state != SMC_APPCLOSEWAIT1)) 1583ac713874SUrsula Braun return -ENOTCONN; 1584ac713874SUrsula Braun 1585ac713874SUrsula Braun smc = smc_sk(sock->sk); 1586ac713874SUrsula Braun 15879b2c45d4SDenys Vlasenko return smc->clcsock->ops->getname(smc->clcsock, addr, peer); 1588ac713874SUrsula Braun } 1589ac713874SUrsula Braun 1590ac713874SUrsula Braun static int smc_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) 1591ac713874SUrsula Braun { 1592ac713874SUrsula Braun struct sock *sk = sock->sk; 1593ac713874SUrsula Braun struct smc_sock *smc; 1594ac713874SUrsula Braun int rc = -EPIPE; 1595ac713874SUrsula Braun 1596ac713874SUrsula Braun smc = smc_sk(sk); 1597ac713874SUrsula Braun lock_sock(sk); 1598b38d7324SUrsula Braun if ((sk->sk_state != SMC_ACTIVE) && 1599b38d7324SUrsula Braun (sk->sk_state != SMC_APPCLOSEWAIT1) && 1600b38d7324SUrsula Braun (sk->sk_state != SMC_INIT)) 1601ac713874SUrsula Braun goto out; 1602ee9dfbefSUrsula Braun 1603ee9dfbefSUrsula Braun if (msg->msg_flags & MSG_FASTOPEN) { 1604cd206360SUrsula Braun if (sk->sk_state == SMC_INIT && !smc->connect_nonblock) { 160507603b23SUrsula Braun smc_switch_to_fallback(smc); 1606603cc149SKarsten Graul smc->fallback_rsn = SMC_CLC_DECL_OPTUNSUPP; 1607ee9dfbefSUrsula Braun } else { 1608ee9dfbefSUrsula Braun rc = -EINVAL; 1609ee9dfbefSUrsula Braun goto out; 1610ee9dfbefSUrsula Braun } 1611ee9dfbefSUrsula Braun } 1612ee9dfbefSUrsula Braun 1613ac713874SUrsula Braun if (smc->use_fallback) 1614ac713874SUrsula Braun rc = smc->clcsock->ops->sendmsg(smc->clcsock, msg, len); 1615ac713874SUrsula Braun else 1616e6727f39SUrsula Braun rc = smc_tx_sendmsg(smc, msg, len); 1617ac713874SUrsula Braun out: 1618ac713874SUrsula Braun release_sock(sk); 1619ac713874SUrsula Braun return rc; 1620ac713874SUrsula Braun } 1621ac713874SUrsula Braun 1622ac713874SUrsula Braun static int smc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, 1623ac713874SUrsula Braun int flags) 1624ac713874SUrsula Braun { 1625ac713874SUrsula Braun struct sock *sk = sock->sk; 1626ac713874SUrsula Braun struct smc_sock *smc; 1627ac713874SUrsula Braun int rc = -ENOTCONN; 1628ac713874SUrsula Braun 1629ac713874SUrsula Braun smc = smc_sk(sk); 1630ac713874SUrsula Braun lock_sock(sk); 163151c5aba3SKarsten Graul if (sk->sk_state == SMC_CLOSED && (sk->sk_shutdown & RCV_SHUTDOWN)) { 163251c5aba3SKarsten Graul /* socket was connected before, no more data to read */ 163351c5aba3SKarsten Graul rc = 0; 163451c5aba3SKarsten Graul goto out; 163551c5aba3SKarsten Graul } 1636b38d7324SUrsula Braun if ((sk->sk_state == SMC_INIT) || 1637b38d7324SUrsula Braun (sk->sk_state == SMC_LISTEN) || 1638b38d7324SUrsula Braun (sk->sk_state == SMC_CLOSED)) 1639ac713874SUrsula Braun goto out; 1640ac713874SUrsula Braun 1641b38d7324SUrsula Braun if (sk->sk_state == SMC_PEERFINCLOSEWAIT) { 1642b38d7324SUrsula Braun rc = 0; 1643b38d7324SUrsula Braun goto out; 1644b38d7324SUrsula Braun } 1645b38d7324SUrsula Braun 16469014db20SStefan Raspl if (smc->use_fallback) { 1647ac713874SUrsula Braun rc = smc->clcsock->ops->recvmsg(smc->clcsock, msg, len, flags); 16489014db20SStefan Raspl } else { 16499014db20SStefan Raspl msg->msg_namelen = 0; 16509014db20SStefan Raspl rc = smc_rx_recvmsg(smc, msg, NULL, len, flags); 16519014db20SStefan Raspl } 1652b38d7324SUrsula Braun 1653ac713874SUrsula Braun out: 1654ac713874SUrsula Braun release_sock(sk); 1655ac713874SUrsula Braun return rc; 1656ac713874SUrsula Braun } 1657ac713874SUrsula Braun 1658ade994f4SAl Viro static __poll_t smc_accept_poll(struct sock *parent) 1659a046d57dSUrsula Braun { 16608dce2786SUrsula Braun struct smc_sock *isk = smc_sk(parent); 166163e2480cSAl Viro __poll_t mask = 0; 1662a046d57dSUrsula Braun 16638dce2786SUrsula Braun spin_lock(&isk->accept_q_lock); 16648dce2786SUrsula Braun if (!list_empty(&isk->accept_q)) 1665a9a08845SLinus Torvalds mask = EPOLLIN | EPOLLRDNORM; 16668dce2786SUrsula Braun spin_unlock(&isk->accept_q_lock); 1667a046d57dSUrsula Braun 16688dce2786SUrsula Braun return mask; 1669a046d57dSUrsula Braun } 1670a046d57dSUrsula Braun 1671a11e1d43SLinus Torvalds static __poll_t smc_poll(struct file *file, struct socket *sock, 1672a11e1d43SLinus Torvalds poll_table *wait) 1673ac713874SUrsula Braun { 1674ac713874SUrsula Braun struct sock *sk = sock->sk; 1675ac713874SUrsula Braun struct smc_sock *smc; 167650717a37SUrsula Braun __poll_t mask = 0; 1677ac713874SUrsula Braun 16788dce2786SUrsula Braun if (!sk) 1679a9a08845SLinus Torvalds return EPOLLNVAL; 16808dce2786SUrsula Braun 1681ac713874SUrsula Braun smc = smc_sk(sock->sk); 1682648a5a7aSUrsula Braun if (smc->use_fallback) { 1683a046d57dSUrsula Braun /* delegate to CLC child sock */ 1684a11e1d43SLinus Torvalds mask = smc->clcsock->ops->poll(file, smc->clcsock, wait); 1685a046d57dSUrsula Braun sk->sk_err = smc->clcsock->sk->sk_err; 1686a046d57dSUrsula Braun } else { 1687410da1e1SLinus Torvalds if (sk->sk_state != SMC_CLOSED) 168889ab066dSKarsten Graul sock_poll_wait(file, sock, wait); 1689a046d57dSUrsula Braun if (sk->sk_err) 1690a9a08845SLinus Torvalds mask |= EPOLLERR; 16918dce2786SUrsula Braun if ((sk->sk_shutdown == SHUTDOWN_MASK) || 16928dce2786SUrsula Braun (sk->sk_state == SMC_CLOSED)) 1693a9a08845SLinus Torvalds mask |= EPOLLHUP; 16948dce2786SUrsula Braun if (sk->sk_state == SMC_LISTEN) { 16958dce2786SUrsula Braun /* woken up by sk_data_ready in smc_listen_work() */ 169650717a37SUrsula Braun mask |= smc_accept_poll(sk); 169750717a37SUrsula Braun } else if (smc->use_fallback) { /* as result of connect_work()*/ 169850717a37SUrsula Braun mask |= smc->clcsock->ops->poll(file, smc->clcsock, 169950717a37SUrsula Braun wait); 170050717a37SUrsula Braun sk->sk_err = smc->clcsock->sk->sk_err; 17018dce2786SUrsula Braun } else { 170250717a37SUrsula Braun if ((sk->sk_state != SMC_INIT && 170350717a37SUrsula Braun atomic_read(&smc->conn.sndbuf_space)) || 17048dce2786SUrsula Braun sk->sk_shutdown & SEND_SHUTDOWN) { 1705a9a08845SLinus Torvalds mask |= EPOLLOUT | EPOLLWRNORM; 1706e6727f39SUrsula Braun } else { 1707e6727f39SUrsula Braun sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk); 1708e6727f39SUrsula Braun set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); 1709e6727f39SUrsula Braun } 1710952310ccSUrsula Braun if (atomic_read(&smc->conn.bytes_to_rcv)) 1711a9a08845SLinus Torvalds mask |= EPOLLIN | EPOLLRDNORM; 1712b38d7324SUrsula Braun if (sk->sk_shutdown & RCV_SHUTDOWN) 1713a9a08845SLinus Torvalds mask |= EPOLLIN | EPOLLRDNORM | EPOLLRDHUP; 1714b38d7324SUrsula Braun if (sk->sk_state == SMC_APPCLOSEWAIT1) 1715a9a08845SLinus Torvalds mask |= EPOLLIN; 1716de8474ebSStefan Raspl if (smc->conn.urg_state == SMC_URG_VALID) 1717de8474ebSStefan Raspl mask |= EPOLLPRI; 1718ac713874SUrsula Braun } 171971d117f5SKarsten Graul } 1720ac713874SUrsula Braun 1721ac713874SUrsula Braun return mask; 1722ac713874SUrsula Braun } 1723ac713874SUrsula Braun 1724ac713874SUrsula Braun static int smc_shutdown(struct socket *sock, int how) 1725ac713874SUrsula Braun { 1726ac713874SUrsula Braun struct sock *sk = sock->sk; 1727ac713874SUrsula Braun struct smc_sock *smc; 1728ac713874SUrsula Braun int rc = -EINVAL; 1729b38d7324SUrsula Braun int rc1 = 0; 1730ac713874SUrsula Braun 1731ac713874SUrsula Braun smc = smc_sk(sk); 1732ac713874SUrsula Braun 1733ac713874SUrsula Braun if ((how < SHUT_RD) || (how > SHUT_RDWR)) 1734b38d7324SUrsula Braun return rc; 1735ac713874SUrsula Braun 1736ac713874SUrsula Braun lock_sock(sk); 1737ac713874SUrsula Braun 1738ac713874SUrsula Braun rc = -ENOTCONN; 1739caa21e19SUrsula Braun if ((sk->sk_state != SMC_ACTIVE) && 1740b38d7324SUrsula Braun (sk->sk_state != SMC_PEERCLOSEWAIT1) && 1741b38d7324SUrsula Braun (sk->sk_state != SMC_PEERCLOSEWAIT2) && 1742b38d7324SUrsula Braun (sk->sk_state != SMC_APPCLOSEWAIT1) && 1743b38d7324SUrsula Braun (sk->sk_state != SMC_APPCLOSEWAIT2) && 1744b38d7324SUrsula Braun (sk->sk_state != SMC_APPFINCLOSEWAIT)) 1745ac713874SUrsula Braun goto out; 1746ac713874SUrsula Braun if (smc->use_fallback) { 1747ac713874SUrsula Braun rc = kernel_sock_shutdown(smc->clcsock, how); 1748ac713874SUrsula Braun sk->sk_shutdown = smc->clcsock->sk->sk_shutdown; 1749ac713874SUrsula Braun if (sk->sk_shutdown == SHUTDOWN_MASK) 1750ac713874SUrsula Braun sk->sk_state = SMC_CLOSED; 1751b38d7324SUrsula Braun goto out; 1752ac713874SUrsula Braun } 1753b38d7324SUrsula Braun switch (how) { 1754b38d7324SUrsula Braun case SHUT_RDWR: /* shutdown in both directions */ 1755b38d7324SUrsula Braun rc = smc_close_active(smc); 1756b38d7324SUrsula Braun break; 1757b38d7324SUrsula Braun case SHUT_WR: 1758b38d7324SUrsula Braun rc = smc_close_shutdown_write(smc); 1759b38d7324SUrsula Braun break; 1760b38d7324SUrsula Braun case SHUT_RD: 1761b38d7324SUrsula Braun rc = 0; 1762b38d7324SUrsula Braun /* nothing more to do because peer is not involved */ 1763b38d7324SUrsula Braun break; 1764b38d7324SUrsula Braun } 17651255fcb2SUrsula Braun if (smc->clcsock) 1766b38d7324SUrsula Braun rc1 = kernel_sock_shutdown(smc->clcsock, how); 1767b38d7324SUrsula Braun /* map sock_shutdown_cmd constants to sk_shutdown value range */ 1768b38d7324SUrsula Braun sk->sk_shutdown |= how + 1; 1769ac713874SUrsula Braun 1770ac713874SUrsula Braun out: 1771ac713874SUrsula Braun release_sock(sk); 1772b38d7324SUrsula Braun return rc ? rc : rc1; 1773ac713874SUrsula Braun } 1774ac713874SUrsula Braun 1775ac713874SUrsula Braun static int smc_setsockopt(struct socket *sock, int level, int optname, 1776a7b75c5aSChristoph Hellwig sockptr_t optval, unsigned int optlen) 1777ac713874SUrsula Braun { 1778ac713874SUrsula Braun struct sock *sk = sock->sk; 1779ac713874SUrsula Braun struct smc_sock *smc; 178001d2f7e2SUrsula Braun int val, rc; 1781ac713874SUrsula Braun 1782ac713874SUrsula Braun smc = smc_sk(sk); 1783ac713874SUrsula Braun 1784ac713874SUrsula Braun /* generic setsockopts reaching us here always apply to the 1785ac713874SUrsula Braun * CLC socket 1786ac713874SUrsula Braun */ 1787a44d9e72SChristoph Hellwig if (unlikely(!smc->clcsock->ops->setsockopt)) 1788a44d9e72SChristoph Hellwig rc = -EOPNOTSUPP; 1789a44d9e72SChristoph Hellwig else 1790ee9dfbefSUrsula Braun rc = smc->clcsock->ops->setsockopt(smc->clcsock, level, optname, 1791ac713874SUrsula Braun optval, optlen); 1792ee9dfbefSUrsula Braun if (smc->clcsock->sk->sk_err) { 1793ee9dfbefSUrsula Braun sk->sk_err = smc->clcsock->sk->sk_err; 1794ee9dfbefSUrsula Braun sk->sk_error_report(sk); 1795ee9dfbefSUrsula Braun } 1796ee9dfbefSUrsula Braun 179701d2f7e2SUrsula Braun if (optlen < sizeof(int)) 17983dc9f558SWei Yongjun return -EINVAL; 1799a7b75c5aSChristoph Hellwig if (copy_from_sockptr(&val, optval, sizeof(int))) 1800ac0107edSUrsula Braun return -EFAULT; 180101d2f7e2SUrsula Braun 1802ee9dfbefSUrsula Braun lock_sock(sk); 180386434744SUrsula Braun if (rc || smc->use_fallback) 180486434744SUrsula Braun goto out; 1805ee9dfbefSUrsula Braun switch (optname) { 1806ee9dfbefSUrsula Braun case TCP_ULP: 1807ee9dfbefSUrsula Braun case TCP_FASTOPEN: 1808ee9dfbefSUrsula Braun case TCP_FASTOPEN_CONNECT: 1809ee9dfbefSUrsula Braun case TCP_FASTOPEN_KEY: 1810ee9dfbefSUrsula Braun case TCP_FASTOPEN_NO_COOKIE: 1811ee9dfbefSUrsula Braun /* option not supported by SMC */ 18128204df72SUrsula Braun if (sk->sk_state == SMC_INIT && !smc->connect_nonblock) { 181307603b23SUrsula Braun smc_switch_to_fallback(smc); 1814603cc149SKarsten Graul smc->fallback_rsn = SMC_CLC_DECL_OPTUNSUPP; 1815ee9dfbefSUrsula Braun } else { 1816ee9dfbefSUrsula Braun rc = -EINVAL; 1817ee9dfbefSUrsula Braun } 1818ee9dfbefSUrsula Braun break; 181901d2f7e2SUrsula Braun case TCP_NODELAY: 1820f9cedf1aSUrsula Braun if (sk->sk_state != SMC_INIT && 1821f9cedf1aSUrsula Braun sk->sk_state != SMC_LISTEN && 1822f9cedf1aSUrsula Braun sk->sk_state != SMC_CLOSED) { 182386434744SUrsula Braun if (val) 182401d2f7e2SUrsula Braun mod_delayed_work(system_wq, &smc->conn.tx_work, 182501d2f7e2SUrsula Braun 0); 182601d2f7e2SUrsula Braun } 182701d2f7e2SUrsula Braun break; 182801d2f7e2SUrsula Braun case TCP_CORK: 1829f9cedf1aSUrsula Braun if (sk->sk_state != SMC_INIT && 1830f9cedf1aSUrsula Braun sk->sk_state != SMC_LISTEN && 1831f9cedf1aSUrsula Braun sk->sk_state != SMC_CLOSED) { 183286434744SUrsula Braun if (!val) 183301d2f7e2SUrsula Braun mod_delayed_work(system_wq, &smc->conn.tx_work, 183401d2f7e2SUrsula Braun 0); 183501d2f7e2SUrsula Braun } 183601d2f7e2SUrsula Braun break; 1837abb190f1SUrsula Braun case TCP_DEFER_ACCEPT: 1838abb190f1SUrsula Braun smc->sockopt_defer_accept = val; 1839abb190f1SUrsula Braun break; 1840ee9dfbefSUrsula Braun default: 1841ee9dfbefSUrsula Braun break; 1842ee9dfbefSUrsula Braun } 184386434744SUrsula Braun out: 1844ee9dfbefSUrsula Braun release_sock(sk); 1845ee9dfbefSUrsula Braun 1846ee9dfbefSUrsula Braun return rc; 1847ac713874SUrsula Braun } 1848ac713874SUrsula Braun 1849ac713874SUrsula Braun static int smc_getsockopt(struct socket *sock, int level, int optname, 1850ac713874SUrsula Braun char __user *optval, int __user *optlen) 1851ac713874SUrsula Braun { 1852ac713874SUrsula Braun struct smc_sock *smc; 1853ac713874SUrsula Braun 1854ac713874SUrsula Braun smc = smc_sk(sock->sk); 1855ac713874SUrsula Braun /* socket options apply to the CLC socket */ 1856a44d9e72SChristoph Hellwig if (unlikely(!smc->clcsock->ops->getsockopt)) 1857a44d9e72SChristoph Hellwig return -EOPNOTSUPP; 1858ac713874SUrsula Braun return smc->clcsock->ops->getsockopt(smc->clcsock, level, optname, 1859ac713874SUrsula Braun optval, optlen); 1860ac713874SUrsula Braun } 1861ac713874SUrsula Braun 1862ac713874SUrsula Braun static int smc_ioctl(struct socket *sock, unsigned int cmd, 1863ac713874SUrsula Braun unsigned long arg) 1864ac713874SUrsula Braun { 1865de8474ebSStefan Raspl union smc_host_cursor cons, urg; 1866de8474ebSStefan Raspl struct smc_connection *conn; 1867ac713874SUrsula Braun struct smc_sock *smc; 18689b67e26fSUrsula Braun int answ; 1869ac713874SUrsula Braun 1870ac713874SUrsula Braun smc = smc_sk(sock->sk); 1871de8474ebSStefan Raspl conn = &smc->conn; 18721992d998SUrsula Braun lock_sock(&smc->sk); 18737311d665SUrsula Braun if (smc->use_fallback) { 18747311d665SUrsula Braun if (!smc->clcsock) { 18757311d665SUrsula Braun release_sock(&smc->sk); 18767311d665SUrsula Braun return -EBADF; 18777311d665SUrsula Braun } 18787311d665SUrsula Braun answ = smc->clcsock->ops->ioctl(smc->clcsock, cmd, arg); 18797311d665SUrsula Braun release_sock(&smc->sk); 18807311d665SUrsula Braun return answ; 18817311d665SUrsula Braun } 18829b67e26fSUrsula Braun switch (cmd) { 18839b67e26fSUrsula Braun case SIOCINQ: /* same as FIONREAD */ 18841992d998SUrsula Braun if (smc->sk.sk_state == SMC_LISTEN) { 18851992d998SUrsula Braun release_sock(&smc->sk); 18869b67e26fSUrsula Braun return -EINVAL; 18871992d998SUrsula Braun } 18882351abe6SUrsula Braun if (smc->sk.sk_state == SMC_INIT || 18892351abe6SUrsula Braun smc->sk.sk_state == SMC_CLOSED) 18902351abe6SUrsula Braun answ = 0; 18912351abe6SUrsula Braun else 18929b67e26fSUrsula Braun answ = atomic_read(&smc->conn.bytes_to_rcv); 18939b67e26fSUrsula Braun break; 18949b67e26fSUrsula Braun case SIOCOUTQ: 18959b67e26fSUrsula Braun /* output queue size (not send + not acked) */ 18961992d998SUrsula Braun if (smc->sk.sk_state == SMC_LISTEN) { 18971992d998SUrsula Braun release_sock(&smc->sk); 18989b67e26fSUrsula Braun return -EINVAL; 18991992d998SUrsula Braun } 19002351abe6SUrsula Braun if (smc->sk.sk_state == SMC_INIT || 19012351abe6SUrsula Braun smc->sk.sk_state == SMC_CLOSED) 19022351abe6SUrsula Braun answ = 0; 19032351abe6SUrsula Braun else 190469cb7dc0SHans Wippel answ = smc->conn.sndbuf_desc->len - 19059b67e26fSUrsula Braun atomic_read(&smc->conn.sndbuf_space); 19069b67e26fSUrsula Braun break; 19079b67e26fSUrsula Braun case SIOCOUTQNSD: 19089b67e26fSUrsula Braun /* output queue size (not send only) */ 19091992d998SUrsula Braun if (smc->sk.sk_state == SMC_LISTEN) { 19101992d998SUrsula Braun release_sock(&smc->sk); 19119b67e26fSUrsula Braun return -EINVAL; 19121992d998SUrsula Braun } 19132351abe6SUrsula Braun if (smc->sk.sk_state == SMC_INIT || 19142351abe6SUrsula Braun smc->sk.sk_state == SMC_CLOSED) 19152351abe6SUrsula Braun answ = 0; 19162351abe6SUrsula Braun else 19179b67e26fSUrsula Braun answ = smc_tx_prepared_sends(&smc->conn); 19189b67e26fSUrsula Braun break; 1919de8474ebSStefan Raspl case SIOCATMARK: 19201992d998SUrsula Braun if (smc->sk.sk_state == SMC_LISTEN) { 19211992d998SUrsula Braun release_sock(&smc->sk); 1922de8474ebSStefan Raspl return -EINVAL; 19231992d998SUrsula Braun } 1924de8474ebSStefan Raspl if (smc->sk.sk_state == SMC_INIT || 1925de8474ebSStefan Raspl smc->sk.sk_state == SMC_CLOSED) { 1926de8474ebSStefan Raspl answ = 0; 1927de8474ebSStefan Raspl } else { 1928bac6de7bSStefan Raspl smc_curs_copy(&cons, &conn->local_tx_ctrl.cons, conn); 1929bac6de7bSStefan Raspl smc_curs_copy(&urg, &conn->urg_curs, conn); 1930de8474ebSStefan Raspl answ = smc_curs_diff(conn->rmb_desc->len, 1931de8474ebSStefan Raspl &cons, &urg) == 1; 1932de8474ebSStefan Raspl } 1933de8474ebSStefan Raspl break; 19349b67e26fSUrsula Braun default: 19351992d998SUrsula Braun release_sock(&smc->sk); 19369b67e26fSUrsula Braun return -ENOIOCTLCMD; 19379b67e26fSUrsula Braun } 19381992d998SUrsula Braun release_sock(&smc->sk); 19399b67e26fSUrsula Braun 19409b67e26fSUrsula Braun return put_user(answ, (int __user *)arg); 1941ac713874SUrsula Braun } 1942ac713874SUrsula Braun 1943ac713874SUrsula Braun static ssize_t smc_sendpage(struct socket *sock, struct page *page, 1944ac713874SUrsula Braun int offset, size_t size, int flags) 1945ac713874SUrsula Braun { 1946ac713874SUrsula Braun struct sock *sk = sock->sk; 1947ac713874SUrsula Braun struct smc_sock *smc; 1948ac713874SUrsula Braun int rc = -EPIPE; 1949ac713874SUrsula Braun 1950ac713874SUrsula Braun smc = smc_sk(sk); 1951ac713874SUrsula Braun lock_sock(sk); 1952bda27ff5SStefan Raspl if (sk->sk_state != SMC_ACTIVE) { 1953bda27ff5SStefan Raspl release_sock(sk); 1954ac713874SUrsula Braun goto out; 1955bda27ff5SStefan Raspl } 1956bda27ff5SStefan Raspl release_sock(sk); 1957ac713874SUrsula Braun if (smc->use_fallback) 1958ac713874SUrsula Braun rc = kernel_sendpage(smc->clcsock, page, offset, 1959ac713874SUrsula Braun size, flags); 1960ac713874SUrsula Braun else 1961ac713874SUrsula Braun rc = sock_no_sendpage(sock, page, offset, size, flags); 1962ac713874SUrsula Braun 1963ac713874SUrsula Braun out: 1964ac713874SUrsula Braun return rc; 1965ac713874SUrsula Braun } 1966ac713874SUrsula Braun 19679014db20SStefan Raspl /* Map the affected portions of the rmbe into an spd, note the number of bytes 19689014db20SStefan Raspl * to splice in conn->splice_pending, and press 'go'. Delays consumer cursor 19699014db20SStefan Raspl * updates till whenever a respective page has been fully processed. 19709014db20SStefan Raspl * Note that subsequent recv() calls have to wait till all splice() processing 19719014db20SStefan Raspl * completed. 19729014db20SStefan Raspl */ 1973ac713874SUrsula Braun static ssize_t smc_splice_read(struct socket *sock, loff_t *ppos, 1974ac713874SUrsula Braun struct pipe_inode_info *pipe, size_t len, 1975ac713874SUrsula Braun unsigned int flags) 1976ac713874SUrsula Braun { 1977ac713874SUrsula Braun struct sock *sk = sock->sk; 1978ac713874SUrsula Braun struct smc_sock *smc; 1979ac713874SUrsula Braun int rc = -ENOTCONN; 1980ac713874SUrsula Braun 1981ac713874SUrsula Braun smc = smc_sk(sk); 1982ac713874SUrsula Braun lock_sock(sk); 198351c5aba3SKarsten Graul if (sk->sk_state == SMC_CLOSED && (sk->sk_shutdown & RCV_SHUTDOWN)) { 198451c5aba3SKarsten Graul /* socket was connected before, no more data to read */ 198551c5aba3SKarsten Graul rc = 0; 198651c5aba3SKarsten Graul goto out; 198751c5aba3SKarsten Graul } 19889014db20SStefan Raspl if (sk->sk_state == SMC_INIT || 19899014db20SStefan Raspl sk->sk_state == SMC_LISTEN || 19909014db20SStefan Raspl sk->sk_state == SMC_CLOSED) 1991ac713874SUrsula Braun goto out; 19929014db20SStefan Raspl 19939014db20SStefan Raspl if (sk->sk_state == SMC_PEERFINCLOSEWAIT) { 19949014db20SStefan Raspl rc = 0; 19959014db20SStefan Raspl goto out; 19969014db20SStefan Raspl } 19979014db20SStefan Raspl 1998ac713874SUrsula Braun if (smc->use_fallback) { 1999ac713874SUrsula Braun rc = smc->clcsock->ops->splice_read(smc->clcsock, ppos, 2000ac713874SUrsula Braun pipe, len, flags); 2001ac713874SUrsula Braun } else { 20029014db20SStefan Raspl if (*ppos) { 20039014db20SStefan Raspl rc = -ESPIPE; 20049014db20SStefan Raspl goto out; 20059014db20SStefan Raspl } 20069014db20SStefan Raspl if (flags & SPLICE_F_NONBLOCK) 20079014db20SStefan Raspl flags = MSG_DONTWAIT; 20089014db20SStefan Raspl else 20099014db20SStefan Raspl flags = 0; 20109014db20SStefan Raspl rc = smc_rx_recvmsg(smc, NULL, pipe, len, flags); 2011ac713874SUrsula Braun } 2012ac713874SUrsula Braun out: 2013ac713874SUrsula Braun release_sock(sk); 20149014db20SStefan Raspl 2015ac713874SUrsula Braun return rc; 2016ac713874SUrsula Braun } 2017ac713874SUrsula Braun 2018ac713874SUrsula Braun /* must look like tcp */ 2019ac713874SUrsula Braun static const struct proto_ops smc_sock_ops = { 2020ac713874SUrsula Braun .family = PF_SMC, 2021ac713874SUrsula Braun .owner = THIS_MODULE, 2022ac713874SUrsula Braun .release = smc_release, 2023ac713874SUrsula Braun .bind = smc_bind, 2024ac713874SUrsula Braun .connect = smc_connect, 2025ac713874SUrsula Braun .socketpair = sock_no_socketpair, 2026ac713874SUrsula Braun .accept = smc_accept, 2027ac713874SUrsula Braun .getname = smc_getname, 2028a11e1d43SLinus Torvalds .poll = smc_poll, 2029ac713874SUrsula Braun .ioctl = smc_ioctl, 2030ac713874SUrsula Braun .listen = smc_listen, 2031ac713874SUrsula Braun .shutdown = smc_shutdown, 2032ac713874SUrsula Braun .setsockopt = smc_setsockopt, 2033ac713874SUrsula Braun .getsockopt = smc_getsockopt, 2034ac713874SUrsula Braun .sendmsg = smc_sendmsg, 2035ac713874SUrsula Braun .recvmsg = smc_recvmsg, 2036ac713874SUrsula Braun .mmap = sock_no_mmap, 2037ac713874SUrsula Braun .sendpage = smc_sendpage, 2038ac713874SUrsula Braun .splice_read = smc_splice_read, 2039ac713874SUrsula Braun }; 2040ac713874SUrsula Braun 2041ac713874SUrsula Braun static int smc_create(struct net *net, struct socket *sock, int protocol, 2042ac713874SUrsula Braun int kern) 2043ac713874SUrsula Braun { 2044aaa4d33fSKarsten Graul int family = (protocol == SMCPROTO_SMC6) ? PF_INET6 : PF_INET; 2045ac713874SUrsula Braun struct smc_sock *smc; 2046ac713874SUrsula Braun struct sock *sk; 2047ac713874SUrsula Braun int rc; 2048ac713874SUrsula Braun 2049ac713874SUrsula Braun rc = -ESOCKTNOSUPPORT; 2050ac713874SUrsula Braun if (sock->type != SOCK_STREAM) 2051ac713874SUrsula Braun goto out; 2052ac713874SUrsula Braun 2053ac713874SUrsula Braun rc = -EPROTONOSUPPORT; 2054aaa4d33fSKarsten Graul if (protocol != SMCPROTO_SMC && protocol != SMCPROTO_SMC6) 2055ac713874SUrsula Braun goto out; 2056ac713874SUrsula Braun 2057ac713874SUrsula Braun rc = -ENOBUFS; 2058ac713874SUrsula Braun sock->ops = &smc_sock_ops; 2059aaa4d33fSKarsten Graul sk = smc_sock_alloc(net, sock, protocol); 2060ac713874SUrsula Braun if (!sk) 2061ac713874SUrsula Braun goto out; 2062ac713874SUrsula Braun 2063ac713874SUrsula Braun /* create internal TCP socket for CLC handshake and fallback */ 2064ac713874SUrsula Braun smc = smc_sk(sk); 2065a046d57dSUrsula Braun smc->use_fallback = false; /* assume rdma capability first */ 2066603cc149SKarsten Graul smc->fallback_rsn = 0; 2067aaa4d33fSKarsten Graul rc = sock_create_kern(net, family, SOCK_STREAM, IPPROTO_TCP, 2068aaa4d33fSKarsten Graul &smc->clcsock); 2069a5dcb73bSDavide Caratti if (rc) { 2070ac713874SUrsula Braun sk_common_release(sk); 2071a5dcb73bSDavide Caratti goto out; 2072a5dcb73bSDavide Caratti } 2073cd6851f3SUrsula Braun smc->sk.sk_sndbuf = max(smc->clcsock->sk->sk_sndbuf, SMC_BUF_MIN_SIZE); 2074cd6851f3SUrsula Braun smc->sk.sk_rcvbuf = max(smc->clcsock->sk->sk_rcvbuf, SMC_BUF_MIN_SIZE); 2075ac713874SUrsula Braun 2076ac713874SUrsula Braun out: 2077ac713874SUrsula Braun return rc; 2078ac713874SUrsula Braun } 2079ac713874SUrsula Braun 2080ac713874SUrsula Braun static const struct net_proto_family smc_sock_family_ops = { 2081ac713874SUrsula Braun .family = PF_SMC, 2082ac713874SUrsula Braun .owner = THIS_MODULE, 2083ac713874SUrsula Braun .create = smc_create, 2084ac713874SUrsula Braun }; 2085ac713874SUrsula Braun 208664e28b52SHans Wippel unsigned int smc_net_id; 208764e28b52SHans Wippel 208864e28b52SHans Wippel static __net_init int smc_net_init(struct net *net) 208964e28b52SHans Wippel { 209064e28b52SHans Wippel return smc_pnet_net_init(net); 209164e28b52SHans Wippel } 209264e28b52SHans Wippel 209364e28b52SHans Wippel static void __net_exit smc_net_exit(struct net *net) 209464e28b52SHans Wippel { 209564e28b52SHans Wippel smc_pnet_net_exit(net); 209664e28b52SHans Wippel } 209764e28b52SHans Wippel 209864e28b52SHans Wippel static struct pernet_operations smc_net_ops = { 209964e28b52SHans Wippel .init = smc_net_init, 210064e28b52SHans Wippel .exit = smc_net_exit, 210164e28b52SHans Wippel .id = &smc_net_id, 210264e28b52SHans Wippel .size = sizeof(struct smc_net), 210364e28b52SHans Wippel }; 210464e28b52SHans Wippel 2105ac713874SUrsula Braun static int __init smc_init(void) 2106ac713874SUrsula Braun { 2107ac713874SUrsula Braun int rc; 2108ac713874SUrsula Braun 210964e28b52SHans Wippel rc = register_pernet_subsys(&smc_net_ops); 211064e28b52SHans Wippel if (rc) 211164e28b52SHans Wippel return rc; 211264e28b52SHans Wippel 21136812baabSThomas Richter rc = smc_pnet_init(); 21146812baabSThomas Richter if (rc) 21158c33bf1bSYueHaibing goto out_pernet_subsys; 21166812baabSThomas Richter 21176dabd405SUrsula Braun rc = smc_core_init(); 21186dabd405SUrsula Braun if (rc) { 21196dabd405SUrsula Braun pr_err("%s: smc_core_init fails with %d\n", __func__, rc); 21206dabd405SUrsula Braun goto out_pnet; 21216dabd405SUrsula Braun } 21226dabd405SUrsula Braun 21239bf9abeaSUrsula Braun rc = smc_llc_init(); 21249bf9abeaSUrsula Braun if (rc) { 21259bf9abeaSUrsula Braun pr_err("%s: smc_llc_init fails with %d\n", __func__, rc); 21266dabd405SUrsula Braun goto out_core; 21279bf9abeaSUrsula Braun } 21289bf9abeaSUrsula Braun 21295f08318fSUrsula Braun rc = smc_cdc_init(); 21305f08318fSUrsula Braun if (rc) { 21315f08318fSUrsula Braun pr_err("%s: smc_cdc_init fails with %d\n", __func__, rc); 21326dabd405SUrsula Braun goto out_core; 21335f08318fSUrsula Braun } 21345f08318fSUrsula Braun 2135ac713874SUrsula Braun rc = proto_register(&smc_proto, 1); 2136ac713874SUrsula Braun if (rc) { 2137aaa4d33fSKarsten Graul pr_err("%s: proto_register(v4) fails with %d\n", __func__, rc); 21386dabd405SUrsula Braun goto out_core; 2139ac713874SUrsula Braun } 2140ac713874SUrsula Braun 2141aaa4d33fSKarsten Graul rc = proto_register(&smc_proto6, 1); 2142aaa4d33fSKarsten Graul if (rc) { 2143aaa4d33fSKarsten Graul pr_err("%s: proto_register(v6) fails with %d\n", __func__, rc); 2144aaa4d33fSKarsten Graul goto out_proto; 2145aaa4d33fSKarsten Graul } 2146aaa4d33fSKarsten Graul 2147ac713874SUrsula Braun rc = sock_register(&smc_sock_family_ops); 2148ac713874SUrsula Braun if (rc) { 2149ac713874SUrsula Braun pr_err("%s: sock_register fails with %d\n", __func__, rc); 2150aaa4d33fSKarsten Graul goto out_proto6; 2151ac713874SUrsula Braun } 2152f16a7dd5SUrsula Braun INIT_HLIST_HEAD(&smc_v4_hashinfo.ht); 2153aaa4d33fSKarsten Graul INIT_HLIST_HEAD(&smc_v6_hashinfo.ht); 2154ac713874SUrsula Braun 2155a4cf0443SUrsula Braun rc = smc_ib_register_client(); 2156a4cf0443SUrsula Braun if (rc) { 2157a4cf0443SUrsula Braun pr_err("%s: ib_register fails with %d\n", __func__, rc); 2158a4cf0443SUrsula Braun goto out_sock; 2159a4cf0443SUrsula Braun } 2160a4cf0443SUrsula Braun 2161c5c1cc9cSUrsula Braun static_branch_enable(&tcp_have_smc); 2162ac713874SUrsula Braun return 0; 2163ac713874SUrsula Braun 2164a4cf0443SUrsula Braun out_sock: 2165a4cf0443SUrsula Braun sock_unregister(PF_SMC); 2166aaa4d33fSKarsten Graul out_proto6: 2167aaa4d33fSKarsten Graul proto_unregister(&smc_proto6); 2168ac713874SUrsula Braun out_proto: 2169ac713874SUrsula Braun proto_unregister(&smc_proto); 21706dabd405SUrsula Braun out_core: 21716dabd405SUrsula Braun smc_core_exit(); 21726812baabSThomas Richter out_pnet: 21736812baabSThomas Richter smc_pnet_exit(); 21748c33bf1bSYueHaibing out_pernet_subsys: 21758c33bf1bSYueHaibing unregister_pernet_subsys(&smc_net_ops); 21768c33bf1bSYueHaibing 2177ac713874SUrsula Braun return rc; 2178ac713874SUrsula Braun } 2179ac713874SUrsula Braun 2180ac713874SUrsula Braun static void __exit smc_exit(void) 2181ac713874SUrsula Braun { 2182c5c1cc9cSUrsula Braun static_branch_disable(&tcp_have_smc); 2183ac713874SUrsula Braun sock_unregister(PF_SMC); 21846dabd405SUrsula Braun smc_core_exit(); 21856dabd405SUrsula Braun smc_ib_unregister_client(); 2186aaa4d33fSKarsten Graul proto_unregister(&smc_proto6); 2187ac713874SUrsula Braun proto_unregister(&smc_proto); 21886812baabSThomas Richter smc_pnet_exit(); 218964e28b52SHans Wippel unregister_pernet_subsys(&smc_net_ops); 21904ead9c96SUrsula Braun rcu_barrier(); 2191ac713874SUrsula Braun } 2192ac713874SUrsula Braun 2193ac713874SUrsula Braun module_init(smc_init); 2194ac713874SUrsula Braun module_exit(smc_exit); 2195ac713874SUrsula Braun 2196ac713874SUrsula Braun MODULE_AUTHOR("Ursula Braun <ubraun@linux.vnet.ibm.com>"); 2197ac713874SUrsula Braun MODULE_DESCRIPTION("smc socket address family"); 2198ac713874SUrsula Braun MODULE_LICENSE("GPL"); 2199ac713874SUrsula Braun MODULE_ALIAS_NETPROTO(PF_SMC); 2200