xref: /openbmc/linux/net/smc/af_smc.c (revision 3d9725a6a1330bed78f452ba3b171b24d9b83ac7)
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