xref: /linux/fs/smb/smbdirect/socket.c (revision 0fc8f6200d2313278fbf4539bbab74677c685531)
1*1249c01aSStefan Metzmacher // SPDX-License-Identifier: GPL-2.0-or-later
2*1249c01aSStefan Metzmacher /*
3*1249c01aSStefan Metzmacher  *   Copyright (C) 2017, Microsoft Corporation.
4*1249c01aSStefan Metzmacher  *   Copyright (c) 2025, Stefan Metzmacher
5*1249c01aSStefan Metzmacher  */
6*1249c01aSStefan Metzmacher 
7*1249c01aSStefan Metzmacher #include "internal.h"
8*1249c01aSStefan Metzmacher 
9*1249c01aSStefan Metzmacher bool smbdirect_frwr_is_supported(const struct ib_device_attr *attrs)
10*1249c01aSStefan Metzmacher {
11*1249c01aSStefan Metzmacher 	/*
12*1249c01aSStefan Metzmacher 	 * Test if FRWR (Fast Registration Work Requests) is supported on the
13*1249c01aSStefan Metzmacher 	 * device This implementation requires FRWR on RDMA read/write return
14*1249c01aSStefan Metzmacher 	 * value: true if it is supported
15*1249c01aSStefan Metzmacher 	 */
16*1249c01aSStefan Metzmacher 
17*1249c01aSStefan Metzmacher 	if (!(attrs->device_cap_flags & IB_DEVICE_MEM_MGT_EXTENSIONS))
18*1249c01aSStefan Metzmacher 		return false;
19*1249c01aSStefan Metzmacher 	if (attrs->max_fast_reg_page_list_len == 0)
20*1249c01aSStefan Metzmacher 		return false;
21*1249c01aSStefan Metzmacher 	return true;
22*1249c01aSStefan Metzmacher }
23*1249c01aSStefan Metzmacher __SMBDIRECT_EXPORT_SYMBOL__(smbdirect_frwr_is_supported);
24*1249c01aSStefan Metzmacher 
25*1249c01aSStefan Metzmacher static void smbdirect_socket_cleanup_work(struct work_struct *work);
26*1249c01aSStefan Metzmacher 
27*1249c01aSStefan Metzmacher static int smbdirect_socket_rdma_event_handler(struct rdma_cm_id *id,
28*1249c01aSStefan Metzmacher 					       struct rdma_cm_event *event)
29*1249c01aSStefan Metzmacher {
30*1249c01aSStefan Metzmacher 	struct smbdirect_socket *sc = id->context;
31*1249c01aSStefan Metzmacher 	int ret = -ESTALE;
32*1249c01aSStefan Metzmacher 
33*1249c01aSStefan Metzmacher 	/*
34*1249c01aSStefan Metzmacher 	 * This should be replaced before any real work
35*1249c01aSStefan Metzmacher 	 * starts! So it should never be called!
36*1249c01aSStefan Metzmacher 	 */
37*1249c01aSStefan Metzmacher 
38*1249c01aSStefan Metzmacher 	if (event->event == RDMA_CM_EVENT_DEVICE_REMOVAL)
39*1249c01aSStefan Metzmacher 		ret = -ENETDOWN;
40*1249c01aSStefan Metzmacher 	if (IS_ERR(SMBDIRECT_DEBUG_ERR_PTR(event->status)))
41*1249c01aSStefan Metzmacher 		ret = event->status;
42*1249c01aSStefan Metzmacher 	pr_err("%s (first_error=%1pe, expected=%s) => event=%s status=%d => ret=%1pe\n",
43*1249c01aSStefan Metzmacher 		smbdirect_socket_status_string(sc->status),
44*1249c01aSStefan Metzmacher 		SMBDIRECT_DEBUG_ERR_PTR(sc->first_error),
45*1249c01aSStefan Metzmacher 		rdma_event_msg(sc->rdma.expected_event),
46*1249c01aSStefan Metzmacher 		rdma_event_msg(event->event),
47*1249c01aSStefan Metzmacher 		event->status,
48*1249c01aSStefan Metzmacher 		SMBDIRECT_DEBUG_ERR_PTR(ret));
49*1249c01aSStefan Metzmacher 	WARN_ONCE(1, "%s should not be called!\n", __func__);
50*1249c01aSStefan Metzmacher 	sc->rdma.cm_id = NULL;
51*1249c01aSStefan Metzmacher 	return -ESTALE;
52*1249c01aSStefan Metzmacher }
53*1249c01aSStefan Metzmacher 
54*1249c01aSStefan Metzmacher int smbdirect_socket_init_new(struct net *net, struct smbdirect_socket *sc)
55*1249c01aSStefan Metzmacher {
56*1249c01aSStefan Metzmacher 	struct rdma_cm_id *id;
57*1249c01aSStefan Metzmacher 	int ret;
58*1249c01aSStefan Metzmacher 
59*1249c01aSStefan Metzmacher 	smbdirect_socket_init(sc);
60*1249c01aSStefan Metzmacher 
61*1249c01aSStefan Metzmacher 	id = rdma_create_id(net,
62*1249c01aSStefan Metzmacher 			    smbdirect_socket_rdma_event_handler,
63*1249c01aSStefan Metzmacher 			    sc,
64*1249c01aSStefan Metzmacher 			    RDMA_PS_TCP,
65*1249c01aSStefan Metzmacher 			    IB_QPT_RC);
66*1249c01aSStefan Metzmacher 	if (IS_ERR(id)) {
67*1249c01aSStefan Metzmacher 		pr_err("%s: rdma_create_id() failed %1pe\n", __func__, id);
68*1249c01aSStefan Metzmacher 		return PTR_ERR(id);
69*1249c01aSStefan Metzmacher 	}
70*1249c01aSStefan Metzmacher 
71*1249c01aSStefan Metzmacher 	ret = rdma_set_afonly(id, 1);
72*1249c01aSStefan Metzmacher 	if (ret) {
73*1249c01aSStefan Metzmacher 		rdma_destroy_id(id);
74*1249c01aSStefan Metzmacher 		pr_err("%s: rdma_set_afonly() failed %1pe\n",
75*1249c01aSStefan Metzmacher 		       __func__, SMBDIRECT_DEBUG_ERR_PTR(ret));
76*1249c01aSStefan Metzmacher 		return ret;
77*1249c01aSStefan Metzmacher 	}
78*1249c01aSStefan Metzmacher 
79*1249c01aSStefan Metzmacher 	sc->rdma.cm_id = id;
80*1249c01aSStefan Metzmacher 
81*1249c01aSStefan Metzmacher 	INIT_WORK(&sc->disconnect_work, smbdirect_socket_cleanup_work);
82*1249c01aSStefan Metzmacher 
83*1249c01aSStefan Metzmacher 	return 0;
84*1249c01aSStefan Metzmacher }
85*1249c01aSStefan Metzmacher 
86*1249c01aSStefan Metzmacher int smbdirect_socket_create_kern(struct net *net, struct smbdirect_socket **_sc)
87*1249c01aSStefan Metzmacher {
88*1249c01aSStefan Metzmacher 	struct smbdirect_socket *sc;
89*1249c01aSStefan Metzmacher 	int ret;
90*1249c01aSStefan Metzmacher 
91*1249c01aSStefan Metzmacher 	ret = -ENOMEM;
92*1249c01aSStefan Metzmacher 	sc = kzalloc_obj(*sc);
93*1249c01aSStefan Metzmacher 	if (!sc)
94*1249c01aSStefan Metzmacher 		goto alloc_failed;
95*1249c01aSStefan Metzmacher 
96*1249c01aSStefan Metzmacher 	ret = smbdirect_socket_init_new(net, sc);
97*1249c01aSStefan Metzmacher 	if (ret)
98*1249c01aSStefan Metzmacher 		goto init_failed;
99*1249c01aSStefan Metzmacher 
100*1249c01aSStefan Metzmacher 	kref_init(&sc->refs.destroy);
101*1249c01aSStefan Metzmacher 
102*1249c01aSStefan Metzmacher 	*_sc = sc;
103*1249c01aSStefan Metzmacher 	return 0;
104*1249c01aSStefan Metzmacher 
105*1249c01aSStefan Metzmacher init_failed:
106*1249c01aSStefan Metzmacher 	kfree(sc);
107*1249c01aSStefan Metzmacher alloc_failed:
108*1249c01aSStefan Metzmacher 	return ret;
109*1249c01aSStefan Metzmacher }
110*1249c01aSStefan Metzmacher __SMBDIRECT_EXPORT_SYMBOL__(smbdirect_socket_create_kern);
111*1249c01aSStefan Metzmacher 
112*1249c01aSStefan Metzmacher int smbdirect_socket_init_accepting(struct rdma_cm_id *id, struct smbdirect_socket *sc)
113*1249c01aSStefan Metzmacher {
114*1249c01aSStefan Metzmacher 	smbdirect_socket_init(sc);
115*1249c01aSStefan Metzmacher 
116*1249c01aSStefan Metzmacher 	sc->rdma.cm_id = id;
117*1249c01aSStefan Metzmacher 	sc->rdma.cm_id->context = sc;
118*1249c01aSStefan Metzmacher 	sc->rdma.cm_id->event_handler = smbdirect_socket_rdma_event_handler;
119*1249c01aSStefan Metzmacher 
120*1249c01aSStefan Metzmacher 	sc->ib.dev = sc->rdma.cm_id->device;
121*1249c01aSStefan Metzmacher 
122*1249c01aSStefan Metzmacher 	INIT_WORK(&sc->disconnect_work, smbdirect_socket_cleanup_work);
123*1249c01aSStefan Metzmacher 
124*1249c01aSStefan Metzmacher 	return 0;
125*1249c01aSStefan Metzmacher }
126*1249c01aSStefan Metzmacher 
127*1249c01aSStefan Metzmacher int smbdirect_socket_create_accepting(struct rdma_cm_id *id, struct smbdirect_socket **_sc)
128*1249c01aSStefan Metzmacher {
129*1249c01aSStefan Metzmacher 	struct smbdirect_socket *sc;
130*1249c01aSStefan Metzmacher 	int ret;
131*1249c01aSStefan Metzmacher 
132*1249c01aSStefan Metzmacher 	ret = -ENOMEM;
133*1249c01aSStefan Metzmacher 	sc = kzalloc_obj(*sc);
134*1249c01aSStefan Metzmacher 	if (!sc)
135*1249c01aSStefan Metzmacher 		goto alloc_failed;
136*1249c01aSStefan Metzmacher 
137*1249c01aSStefan Metzmacher 	ret = smbdirect_socket_init_accepting(id, sc);
138*1249c01aSStefan Metzmacher 	if (ret)
139*1249c01aSStefan Metzmacher 		goto init_failed;
140*1249c01aSStefan Metzmacher 
141*1249c01aSStefan Metzmacher 	kref_init(&sc->refs.destroy);
142*1249c01aSStefan Metzmacher 
143*1249c01aSStefan Metzmacher 	*_sc = sc;
144*1249c01aSStefan Metzmacher 	return 0;
145*1249c01aSStefan Metzmacher 
146*1249c01aSStefan Metzmacher init_failed:
147*1249c01aSStefan Metzmacher 	kfree(sc);
148*1249c01aSStefan Metzmacher alloc_failed:
149*1249c01aSStefan Metzmacher 	return ret;
150*1249c01aSStefan Metzmacher }
151*1249c01aSStefan Metzmacher __SMBDIRECT_EXPORT_SYMBOL__(smbdirect_socket_create_accepting);
152*1249c01aSStefan Metzmacher 
153*1249c01aSStefan Metzmacher int smbdirect_socket_set_initial_parameters(struct smbdirect_socket *sc,
154*1249c01aSStefan Metzmacher 					    const struct smbdirect_socket_parameters *sp)
155*1249c01aSStefan Metzmacher {
156*1249c01aSStefan Metzmacher 	/*
157*1249c01aSStefan Metzmacher 	 * This is only allowed before connect or accept
158*1249c01aSStefan Metzmacher 	 */
159*1249c01aSStefan Metzmacher 	WARN_ONCE(sc->status != SMBDIRECT_SOCKET_CREATED,
160*1249c01aSStefan Metzmacher 		  "status=%s first_error=%1pe",
161*1249c01aSStefan Metzmacher 		  smbdirect_socket_status_string(sc->status),
162*1249c01aSStefan Metzmacher 		  SMBDIRECT_DEBUG_ERR_PTR(sc->first_error));
163*1249c01aSStefan Metzmacher 	if (sc->status != SMBDIRECT_SOCKET_CREATED)
164*1249c01aSStefan Metzmacher 		return -EINVAL;
165*1249c01aSStefan Metzmacher 
166*1249c01aSStefan Metzmacher 	if (sp->flags & ~SMBDIRECT_FLAG_PORT_RANGE_MASK)
167*1249c01aSStefan Metzmacher 		return -EINVAL;
168*1249c01aSStefan Metzmacher 
169*1249c01aSStefan Metzmacher 	if (sp->initiator_depth > U8_MAX)
170*1249c01aSStefan Metzmacher 		return -EINVAL;
171*1249c01aSStefan Metzmacher 	if (sp->responder_resources > U8_MAX)
172*1249c01aSStefan Metzmacher 		return -EINVAL;
173*1249c01aSStefan Metzmacher 
174*1249c01aSStefan Metzmacher 	if (sp->flags & SMBDIRECT_FLAG_PORT_RANGE_ONLY_IB &&
175*1249c01aSStefan Metzmacher 	    sp->flags & SMBDIRECT_FLAG_PORT_RANGE_ONLY_IW)
176*1249c01aSStefan Metzmacher 		return -EINVAL;
177*1249c01aSStefan Metzmacher 	else if (sp->flags & SMBDIRECT_FLAG_PORT_RANGE_ONLY_IB)
178*1249c01aSStefan Metzmacher 		rdma_restrict_node_type(sc->rdma.cm_id, RDMA_NODE_IB_CA);
179*1249c01aSStefan Metzmacher 	else if (sp->flags & SMBDIRECT_FLAG_PORT_RANGE_ONLY_IW)
180*1249c01aSStefan Metzmacher 		rdma_restrict_node_type(sc->rdma.cm_id, RDMA_NODE_RNIC);
181*1249c01aSStefan Metzmacher 
182*1249c01aSStefan Metzmacher 	/*
183*1249c01aSStefan Metzmacher 	 * Make a copy of the callers parameters
184*1249c01aSStefan Metzmacher 	 * from here we only work on the copy
185*1249c01aSStefan Metzmacher 	 *
186*1249c01aSStefan Metzmacher 	 * TODO: do we want consistency checking?
187*1249c01aSStefan Metzmacher 	 */
188*1249c01aSStefan Metzmacher 	sc->parameters = *sp;
189*1249c01aSStefan Metzmacher 
190*1249c01aSStefan Metzmacher 	return 0;
191*1249c01aSStefan Metzmacher }
192*1249c01aSStefan Metzmacher __SMBDIRECT_EXPORT_SYMBOL__(smbdirect_socket_set_initial_parameters);
193*1249c01aSStefan Metzmacher 
194*1249c01aSStefan Metzmacher const struct smbdirect_socket_parameters *
195*1249c01aSStefan Metzmacher smbdirect_socket_get_current_parameters(struct smbdirect_socket *sc)
196*1249c01aSStefan Metzmacher {
197*1249c01aSStefan Metzmacher 	return &sc->parameters;
198*1249c01aSStefan Metzmacher }
199*1249c01aSStefan Metzmacher __SMBDIRECT_EXPORT_SYMBOL__(smbdirect_socket_get_current_parameters);
200*1249c01aSStefan Metzmacher 
201*1249c01aSStefan Metzmacher int smbdirect_socket_set_kernel_settings(struct smbdirect_socket *sc,
202*1249c01aSStefan Metzmacher 					 enum ib_poll_context poll_ctx,
203*1249c01aSStefan Metzmacher 					 gfp_t gfp_mask)
204*1249c01aSStefan Metzmacher {
205*1249c01aSStefan Metzmacher 	/*
206*1249c01aSStefan Metzmacher 	 * This is only allowed before connect or accept
207*1249c01aSStefan Metzmacher 	 */
208*1249c01aSStefan Metzmacher 	WARN_ONCE(sc->status != SMBDIRECT_SOCKET_CREATED,
209*1249c01aSStefan Metzmacher 		  "status=%s first_error=%1pe",
210*1249c01aSStefan Metzmacher 		  smbdirect_socket_status_string(sc->status),
211*1249c01aSStefan Metzmacher 		  SMBDIRECT_DEBUG_ERR_PTR(sc->first_error));
212*1249c01aSStefan Metzmacher 	if (sc->status != SMBDIRECT_SOCKET_CREATED)
213*1249c01aSStefan Metzmacher 		return -EINVAL;
214*1249c01aSStefan Metzmacher 
215*1249c01aSStefan Metzmacher 	sc->ib.poll_ctx = poll_ctx;
216*1249c01aSStefan Metzmacher 
217*1249c01aSStefan Metzmacher 	sc->send_io.mem.gfp_mask = gfp_mask;
218*1249c01aSStefan Metzmacher 	sc->recv_io.mem.gfp_mask = gfp_mask;
219*1249c01aSStefan Metzmacher 	sc->rw_io.mem.gfp_mask = gfp_mask;
220*1249c01aSStefan Metzmacher 
221*1249c01aSStefan Metzmacher 	return 0;
222*1249c01aSStefan Metzmacher }
223*1249c01aSStefan Metzmacher __SMBDIRECT_EXPORT_SYMBOL__(smbdirect_socket_set_kernel_settings);
224*1249c01aSStefan Metzmacher 
225*1249c01aSStefan Metzmacher void smbdirect_socket_set_logging(struct smbdirect_socket *sc,
226*1249c01aSStefan Metzmacher 				  void *private_ptr,
227*1249c01aSStefan Metzmacher 				  bool (*needed)(struct smbdirect_socket *sc,
228*1249c01aSStefan Metzmacher 						 void *private_ptr,
229*1249c01aSStefan Metzmacher 						 unsigned int lvl,
230*1249c01aSStefan Metzmacher 						 unsigned int cls),
231*1249c01aSStefan Metzmacher 				  void (*vaprintf)(struct smbdirect_socket *sc,
232*1249c01aSStefan Metzmacher 						   const char *func,
233*1249c01aSStefan Metzmacher 						   unsigned int line,
234*1249c01aSStefan Metzmacher 						   void *private_ptr,
235*1249c01aSStefan Metzmacher 						   unsigned int lvl,
236*1249c01aSStefan Metzmacher 						   unsigned int cls,
237*1249c01aSStefan Metzmacher 						   struct va_format *vaf))
238*1249c01aSStefan Metzmacher {
239*1249c01aSStefan Metzmacher 	sc->logging.private_ptr = private_ptr;
240*1249c01aSStefan Metzmacher 	sc->logging.needed = needed;
241*1249c01aSStefan Metzmacher 	sc->logging.vaprintf = vaprintf;
242*1249c01aSStefan Metzmacher }
243*1249c01aSStefan Metzmacher __SMBDIRECT_EXPORT_SYMBOL__(smbdirect_socket_set_logging);
244*1249c01aSStefan Metzmacher 
245*1249c01aSStefan Metzmacher static void smbdirect_socket_wake_up_all(struct smbdirect_socket *sc)
246*1249c01aSStefan Metzmacher {
247*1249c01aSStefan Metzmacher 	/*
248*1249c01aSStefan Metzmacher 	 * Wake up all waiters in all wait queues
249*1249c01aSStefan Metzmacher 	 * in order to notice the broken connection.
250*1249c01aSStefan Metzmacher 	 */
251*1249c01aSStefan Metzmacher 	wake_up_all(&sc->status_wait);
252*1249c01aSStefan Metzmacher 	wake_up_all(&sc->listen.wait_queue);
253*1249c01aSStefan Metzmacher 	wake_up_all(&sc->send_io.bcredits.wait_queue);
254*1249c01aSStefan Metzmacher 	wake_up_all(&sc->send_io.lcredits.wait_queue);
255*1249c01aSStefan Metzmacher 	wake_up_all(&sc->send_io.credits.wait_queue);
256*1249c01aSStefan Metzmacher 	wake_up_all(&sc->send_io.pending.zero_wait_queue);
257*1249c01aSStefan Metzmacher 	wake_up_all(&sc->recv_io.reassembly.wait_queue);
258*1249c01aSStefan Metzmacher 	wake_up_all(&sc->rw_io.credits.wait_queue);
259*1249c01aSStefan Metzmacher 	wake_up_all(&sc->mr_io.ready.wait_queue);
260*1249c01aSStefan Metzmacher }
261*1249c01aSStefan Metzmacher 
262*1249c01aSStefan Metzmacher void __smbdirect_socket_schedule_cleanup(struct smbdirect_socket *sc,
263*1249c01aSStefan Metzmacher 					 const char *macro_name,
264*1249c01aSStefan Metzmacher 					 unsigned int lvl,
265*1249c01aSStefan Metzmacher 					 const char *func,
266*1249c01aSStefan Metzmacher 					 unsigned int line,
267*1249c01aSStefan Metzmacher 					 int error,
268*1249c01aSStefan Metzmacher 					 enum smbdirect_socket_status *force_status)
269*1249c01aSStefan Metzmacher {
270*1249c01aSStefan Metzmacher 	struct smbdirect_socket *psc, *tsc;
271*1249c01aSStefan Metzmacher 	unsigned long flags;
272*1249c01aSStefan Metzmacher 	bool was_first = false;
273*1249c01aSStefan Metzmacher 
274*1249c01aSStefan Metzmacher 	if (!sc->first_error) {
275*1249c01aSStefan Metzmacher 		___smbdirect_log_generic(sc, func, line,
276*1249c01aSStefan Metzmacher 			lvl,
277*1249c01aSStefan Metzmacher 			SMBDIRECT_LOG_RDMA_EVENT,
278*1249c01aSStefan Metzmacher 			"%s(%1pe%s%s) called from %s in line=%u status=%s\n",
279*1249c01aSStefan Metzmacher 			macro_name,
280*1249c01aSStefan Metzmacher 			SMBDIRECT_DEBUG_ERR_PTR(error),
281*1249c01aSStefan Metzmacher 			force_status ? ", " : "",
282*1249c01aSStefan Metzmacher 			force_status ? smbdirect_socket_status_string(*force_status) : "",
283*1249c01aSStefan Metzmacher 			func, line,
284*1249c01aSStefan Metzmacher 			smbdirect_socket_status_string(sc->status));
285*1249c01aSStefan Metzmacher 		if (error)
286*1249c01aSStefan Metzmacher 			sc->first_error = error;
287*1249c01aSStefan Metzmacher 		else
288*1249c01aSStefan Metzmacher 			sc->first_error = -ECONNABORTED;
289*1249c01aSStefan Metzmacher 		was_first = true;
290*1249c01aSStefan Metzmacher 	}
291*1249c01aSStefan Metzmacher 
292*1249c01aSStefan Metzmacher 	/*
293*1249c01aSStefan Metzmacher 	 * make sure other work (than disconnect_work)
294*1249c01aSStefan Metzmacher 	 * is not queued again but here we don't block and avoid
295*1249c01aSStefan Metzmacher 	 * disable[_delayed]_work_sync()
296*1249c01aSStefan Metzmacher 	 */
297*1249c01aSStefan Metzmacher 	disable_work(&sc->connect.work);
298*1249c01aSStefan Metzmacher 	disable_work(&sc->recv_io.posted.refill_work);
299*1249c01aSStefan Metzmacher 	disable_work(&sc->idle.immediate_work);
300*1249c01aSStefan Metzmacher 	sc->idle.keepalive = SMBDIRECT_KEEPALIVE_NONE;
301*1249c01aSStefan Metzmacher 	disable_delayed_work(&sc->idle.timer_work);
302*1249c01aSStefan Metzmacher 
303*1249c01aSStefan Metzmacher 	/*
304*1249c01aSStefan Metzmacher 	 * In case we were a listener we need to
305*1249c01aSStefan Metzmacher 	 * disconnect all pending and ready sockets
306*1249c01aSStefan Metzmacher 	 *
307*1249c01aSStefan Metzmacher 	 * First we move ready sockets to pending again.
308*1249c01aSStefan Metzmacher 	 */
309*1249c01aSStefan Metzmacher 	spin_lock_irqsave(&sc->listen.lock, flags);
310*1249c01aSStefan Metzmacher 	list_splice_init(&sc->listen.ready, &sc->listen.pending);
311*1249c01aSStefan Metzmacher 	list_for_each_entry_safe(psc, tsc, &sc->listen.pending, accept.list)
312*1249c01aSStefan Metzmacher 		smbdirect_socket_schedule_cleanup(psc, sc->first_error);
313*1249c01aSStefan Metzmacher 	spin_unlock_irqrestore(&sc->listen.lock, flags);
314*1249c01aSStefan Metzmacher 
315*1249c01aSStefan Metzmacher 	switch (sc->status) {
316*1249c01aSStefan Metzmacher 	case SMBDIRECT_SOCKET_RESOLVE_ADDR_FAILED:
317*1249c01aSStefan Metzmacher 	case SMBDIRECT_SOCKET_RESOLVE_ROUTE_FAILED:
318*1249c01aSStefan Metzmacher 	case SMBDIRECT_SOCKET_RDMA_CONNECT_FAILED:
319*1249c01aSStefan Metzmacher 	case SMBDIRECT_SOCKET_NEGOTIATE_FAILED:
320*1249c01aSStefan Metzmacher 	case SMBDIRECT_SOCKET_ERROR:
321*1249c01aSStefan Metzmacher 	case SMBDIRECT_SOCKET_DISCONNECTING:
322*1249c01aSStefan Metzmacher 	case SMBDIRECT_SOCKET_DISCONNECTED:
323*1249c01aSStefan Metzmacher 	case SMBDIRECT_SOCKET_DESTROYED:
324*1249c01aSStefan Metzmacher 		/*
325*1249c01aSStefan Metzmacher 		 * Keep the current error status
326*1249c01aSStefan Metzmacher 		 */
327*1249c01aSStefan Metzmacher 		break;
328*1249c01aSStefan Metzmacher 
329*1249c01aSStefan Metzmacher 	case SMBDIRECT_SOCKET_RESOLVE_ADDR_NEEDED:
330*1249c01aSStefan Metzmacher 	case SMBDIRECT_SOCKET_RESOLVE_ADDR_RUNNING:
331*1249c01aSStefan Metzmacher 		sc->status = SMBDIRECT_SOCKET_RESOLVE_ADDR_FAILED;
332*1249c01aSStefan Metzmacher 		break;
333*1249c01aSStefan Metzmacher 
334*1249c01aSStefan Metzmacher 	case SMBDIRECT_SOCKET_RESOLVE_ROUTE_NEEDED:
335*1249c01aSStefan Metzmacher 	case SMBDIRECT_SOCKET_RESOLVE_ROUTE_RUNNING:
336*1249c01aSStefan Metzmacher 		sc->status = SMBDIRECT_SOCKET_RESOLVE_ROUTE_FAILED;
337*1249c01aSStefan Metzmacher 		break;
338*1249c01aSStefan Metzmacher 
339*1249c01aSStefan Metzmacher 	case SMBDIRECT_SOCKET_RDMA_CONNECT_NEEDED:
340*1249c01aSStefan Metzmacher 	case SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING:
341*1249c01aSStefan Metzmacher 		sc->status = SMBDIRECT_SOCKET_RDMA_CONNECT_FAILED;
342*1249c01aSStefan Metzmacher 		break;
343*1249c01aSStefan Metzmacher 
344*1249c01aSStefan Metzmacher 	case SMBDIRECT_SOCKET_NEGOTIATE_NEEDED:
345*1249c01aSStefan Metzmacher 	case SMBDIRECT_SOCKET_NEGOTIATE_RUNNING:
346*1249c01aSStefan Metzmacher 		sc->status = SMBDIRECT_SOCKET_NEGOTIATE_FAILED;
347*1249c01aSStefan Metzmacher 		break;
348*1249c01aSStefan Metzmacher 
349*1249c01aSStefan Metzmacher 	case SMBDIRECT_SOCKET_CREATED:
350*1249c01aSStefan Metzmacher 	case SMBDIRECT_SOCKET_LISTENING:
351*1249c01aSStefan Metzmacher 		sc->status = SMBDIRECT_SOCKET_DISCONNECTED;
352*1249c01aSStefan Metzmacher 		break;
353*1249c01aSStefan Metzmacher 
354*1249c01aSStefan Metzmacher 	case SMBDIRECT_SOCKET_CONNECTED:
355*1249c01aSStefan Metzmacher 		sc->status = SMBDIRECT_SOCKET_ERROR;
356*1249c01aSStefan Metzmacher 		break;
357*1249c01aSStefan Metzmacher 	}
358*1249c01aSStefan Metzmacher 
359*1249c01aSStefan Metzmacher 	if (force_status && (was_first || *force_status > sc->status))
360*1249c01aSStefan Metzmacher 		sc->status = *force_status;
361*1249c01aSStefan Metzmacher 
362*1249c01aSStefan Metzmacher 	/*
363*1249c01aSStefan Metzmacher 	 * Wake up all waiters in all wait queues
364*1249c01aSStefan Metzmacher 	 * in order to notice the broken connection.
365*1249c01aSStefan Metzmacher 	 */
366*1249c01aSStefan Metzmacher 	smbdirect_socket_wake_up_all(sc);
367*1249c01aSStefan Metzmacher 
368*1249c01aSStefan Metzmacher 	queue_work(sc->workqueues.cleanup, &sc->disconnect_work);
369*1249c01aSStefan Metzmacher }
370*1249c01aSStefan Metzmacher 
371*1249c01aSStefan Metzmacher static void smbdirect_socket_cleanup_work(struct work_struct *work)
372*1249c01aSStefan Metzmacher {
373*1249c01aSStefan Metzmacher 	struct smbdirect_socket *sc =
374*1249c01aSStefan Metzmacher 		container_of(work, struct smbdirect_socket, disconnect_work);
375*1249c01aSStefan Metzmacher 	struct smbdirect_socket *psc, *tsc;
376*1249c01aSStefan Metzmacher 	unsigned long flags;
377*1249c01aSStefan Metzmacher 
378*1249c01aSStefan Metzmacher 	/*
379*1249c01aSStefan Metzmacher 	 * This should not never be called in an interrupt!
380*1249c01aSStefan Metzmacher 	 */
381*1249c01aSStefan Metzmacher 	WARN_ON_ONCE(in_interrupt());
382*1249c01aSStefan Metzmacher 
383*1249c01aSStefan Metzmacher 	if (!sc->first_error) {
384*1249c01aSStefan Metzmacher 		smbdirect_log_rdma_event(sc, SMBDIRECT_LOG_ERR,
385*1249c01aSStefan Metzmacher 			"%s called with first_error==0\n",
386*1249c01aSStefan Metzmacher 			smbdirect_socket_status_string(sc->status));
387*1249c01aSStefan Metzmacher 
388*1249c01aSStefan Metzmacher 		sc->first_error = -ECONNABORTED;
389*1249c01aSStefan Metzmacher 	}
390*1249c01aSStefan Metzmacher 
391*1249c01aSStefan Metzmacher 	/*
392*1249c01aSStefan Metzmacher 	 * make sure this and other work is not queued again
393*1249c01aSStefan Metzmacher 	 * but here we don't block and avoid
394*1249c01aSStefan Metzmacher 	 * disable[_delayed]_work_sync()
395*1249c01aSStefan Metzmacher 	 */
396*1249c01aSStefan Metzmacher 	disable_work(&sc->disconnect_work);
397*1249c01aSStefan Metzmacher 	disable_work(&sc->connect.work);
398*1249c01aSStefan Metzmacher 	disable_work(&sc->recv_io.posted.refill_work);
399*1249c01aSStefan Metzmacher 	disable_work(&sc->idle.immediate_work);
400*1249c01aSStefan Metzmacher 	sc->idle.keepalive = SMBDIRECT_KEEPALIVE_NONE;
401*1249c01aSStefan Metzmacher 	disable_delayed_work(&sc->idle.timer_work);
402*1249c01aSStefan Metzmacher 
403*1249c01aSStefan Metzmacher 	/*
404*1249c01aSStefan Metzmacher 	 * In case we were a listener we need to
405*1249c01aSStefan Metzmacher 	 * disconnect all pending and ready sockets
406*1249c01aSStefan Metzmacher 	 *
407*1249c01aSStefan Metzmacher 	 * First we move ready sockets to pending again.
408*1249c01aSStefan Metzmacher 	 */
409*1249c01aSStefan Metzmacher 	spin_lock_irqsave(&sc->listen.lock, flags);
410*1249c01aSStefan Metzmacher 	list_splice_init(&sc->listen.ready, &sc->listen.pending);
411*1249c01aSStefan Metzmacher 	list_for_each_entry_safe(psc, tsc, &sc->listen.pending, accept.list)
412*1249c01aSStefan Metzmacher 		smbdirect_socket_schedule_cleanup(psc, sc->first_error);
413*1249c01aSStefan Metzmacher 	spin_unlock_irqrestore(&sc->listen.lock, flags);
414*1249c01aSStefan Metzmacher 
415*1249c01aSStefan Metzmacher 	switch (sc->status) {
416*1249c01aSStefan Metzmacher 	case SMBDIRECT_SOCKET_NEGOTIATE_NEEDED:
417*1249c01aSStefan Metzmacher 	case SMBDIRECT_SOCKET_NEGOTIATE_RUNNING:
418*1249c01aSStefan Metzmacher 	case SMBDIRECT_SOCKET_NEGOTIATE_FAILED:
419*1249c01aSStefan Metzmacher 	case SMBDIRECT_SOCKET_CONNECTED:
420*1249c01aSStefan Metzmacher 	case SMBDIRECT_SOCKET_ERROR:
421*1249c01aSStefan Metzmacher 		sc->status = SMBDIRECT_SOCKET_DISCONNECTING;
422*1249c01aSStefan Metzmacher 		/*
423*1249c01aSStefan Metzmacher 		 * Make sure we hold the callback lock
424*1249c01aSStefan Metzmacher 		 * im order to coordinate with the
425*1249c01aSStefan Metzmacher 		 * rdma_event handlers, typically
426*1249c01aSStefan Metzmacher 		 * smbdirect_connection_rdma_event_handler(),
427*1249c01aSStefan Metzmacher 		 * and smbdirect_socket_destroy().
428*1249c01aSStefan Metzmacher 		 *
429*1249c01aSStefan Metzmacher 		 * So that the order of ib_drain_qp()
430*1249c01aSStefan Metzmacher 		 * and rdma_disconnect() is controlled
431*1249c01aSStefan Metzmacher 		 * by the mutex.
432*1249c01aSStefan Metzmacher 		 */
433*1249c01aSStefan Metzmacher 		rdma_lock_handler(sc->rdma.cm_id);
434*1249c01aSStefan Metzmacher 		rdma_disconnect(sc->rdma.cm_id);
435*1249c01aSStefan Metzmacher 		rdma_unlock_handler(sc->rdma.cm_id);
436*1249c01aSStefan Metzmacher 		break;
437*1249c01aSStefan Metzmacher 
438*1249c01aSStefan Metzmacher 	case SMBDIRECT_SOCKET_CREATED:
439*1249c01aSStefan Metzmacher 	case SMBDIRECT_SOCKET_LISTENING:
440*1249c01aSStefan Metzmacher 	case SMBDIRECT_SOCKET_RESOLVE_ADDR_NEEDED:
441*1249c01aSStefan Metzmacher 	case SMBDIRECT_SOCKET_RESOLVE_ADDR_RUNNING:
442*1249c01aSStefan Metzmacher 	case SMBDIRECT_SOCKET_RESOLVE_ADDR_FAILED:
443*1249c01aSStefan Metzmacher 	case SMBDIRECT_SOCKET_RESOLVE_ROUTE_NEEDED:
444*1249c01aSStefan Metzmacher 	case SMBDIRECT_SOCKET_RESOLVE_ROUTE_RUNNING:
445*1249c01aSStefan Metzmacher 	case SMBDIRECT_SOCKET_RESOLVE_ROUTE_FAILED:
446*1249c01aSStefan Metzmacher 	case SMBDIRECT_SOCKET_RDMA_CONNECT_NEEDED:
447*1249c01aSStefan Metzmacher 	case SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING:
448*1249c01aSStefan Metzmacher 	case SMBDIRECT_SOCKET_RDMA_CONNECT_FAILED:
449*1249c01aSStefan Metzmacher 		/*
450*1249c01aSStefan Metzmacher 		 * rdma_{accept,connect}() never reached
451*1249c01aSStefan Metzmacher 		 * RDMA_CM_EVENT_ESTABLISHED
452*1249c01aSStefan Metzmacher 		 */
453*1249c01aSStefan Metzmacher 		sc->status = SMBDIRECT_SOCKET_DISCONNECTED;
454*1249c01aSStefan Metzmacher 		break;
455*1249c01aSStefan Metzmacher 
456*1249c01aSStefan Metzmacher 	case SMBDIRECT_SOCKET_DISCONNECTING:
457*1249c01aSStefan Metzmacher 	case SMBDIRECT_SOCKET_DISCONNECTED:
458*1249c01aSStefan Metzmacher 	case SMBDIRECT_SOCKET_DESTROYED:
459*1249c01aSStefan Metzmacher 		break;
460*1249c01aSStefan Metzmacher 	}
461*1249c01aSStefan Metzmacher 
462*1249c01aSStefan Metzmacher 	/*
463*1249c01aSStefan Metzmacher 	 * Wake up all waiters in all wait queues
464*1249c01aSStefan Metzmacher 	 * in order to notice the broken connection.
465*1249c01aSStefan Metzmacher 	 */
466*1249c01aSStefan Metzmacher 	smbdirect_socket_wake_up_all(sc);
467*1249c01aSStefan Metzmacher }
468*1249c01aSStefan Metzmacher 
469*1249c01aSStefan Metzmacher static void smbdirect_socket_destroy(struct smbdirect_socket *sc)
470*1249c01aSStefan Metzmacher {
471*1249c01aSStefan Metzmacher 	struct smbdirect_socket *psc, *tsc;
472*1249c01aSStefan Metzmacher 	size_t psockets;
473*1249c01aSStefan Metzmacher 	struct smbdirect_recv_io *recv_io;
474*1249c01aSStefan Metzmacher 	struct smbdirect_recv_io *recv_tmp;
475*1249c01aSStefan Metzmacher 	LIST_HEAD(all_list);
476*1249c01aSStefan Metzmacher 	unsigned long flags;
477*1249c01aSStefan Metzmacher 
478*1249c01aSStefan Metzmacher 	smbdirect_log_rdma_event(sc, SMBDIRECT_LOG_INFO,
479*1249c01aSStefan Metzmacher 		"status=%s first_error=%1pe",
480*1249c01aSStefan Metzmacher 		smbdirect_socket_status_string(sc->status),
481*1249c01aSStefan Metzmacher 		SMBDIRECT_DEBUG_ERR_PTR(sc->first_error));
482*1249c01aSStefan Metzmacher 
483*1249c01aSStefan Metzmacher 	/*
484*1249c01aSStefan Metzmacher 	 * This should not never be called in an interrupt!
485*1249c01aSStefan Metzmacher 	 */
486*1249c01aSStefan Metzmacher 	WARN_ON_ONCE(in_interrupt());
487*1249c01aSStefan Metzmacher 
488*1249c01aSStefan Metzmacher 	if (sc->status == SMBDIRECT_SOCKET_DESTROYED)
489*1249c01aSStefan Metzmacher 		return;
490*1249c01aSStefan Metzmacher 
491*1249c01aSStefan Metzmacher 	WARN_ONCE(sc->status != SMBDIRECT_SOCKET_DISCONNECTED,
492*1249c01aSStefan Metzmacher 		  "status=%s first_error=%1pe",
493*1249c01aSStefan Metzmacher 		  smbdirect_socket_status_string(sc->status),
494*1249c01aSStefan Metzmacher 		  SMBDIRECT_DEBUG_ERR_PTR(sc->first_error));
495*1249c01aSStefan Metzmacher 
496*1249c01aSStefan Metzmacher 	/*
497*1249c01aSStefan Metzmacher 	 * The listener should clear this before we reach this
498*1249c01aSStefan Metzmacher 	 */
499*1249c01aSStefan Metzmacher 	WARN_ONCE(sc->accept.listener,
500*1249c01aSStefan Metzmacher 		  "status=%s first_error=%1pe",
501*1249c01aSStefan Metzmacher 		  smbdirect_socket_status_string(sc->status),
502*1249c01aSStefan Metzmacher 		  SMBDIRECT_DEBUG_ERR_PTR(sc->first_error));
503*1249c01aSStefan Metzmacher 
504*1249c01aSStefan Metzmacher 	/*
505*1249c01aSStefan Metzmacher 	 * Wake up all waiters in all wait queues
506*1249c01aSStefan Metzmacher 	 * in order to notice the broken connection.
507*1249c01aSStefan Metzmacher 	 *
508*1249c01aSStefan Metzmacher 	 * Most likely this was already called via
509*1249c01aSStefan Metzmacher 	 * smbdirect_socket_cleanup_work(), but call it again...
510*1249c01aSStefan Metzmacher 	 */
511*1249c01aSStefan Metzmacher 	smbdirect_socket_wake_up_all(sc);
512*1249c01aSStefan Metzmacher 
513*1249c01aSStefan Metzmacher 	disable_work_sync(&sc->disconnect_work);
514*1249c01aSStefan Metzmacher 	disable_work_sync(&sc->connect.work);
515*1249c01aSStefan Metzmacher 	disable_work_sync(&sc->recv_io.posted.refill_work);
516*1249c01aSStefan Metzmacher 	disable_work_sync(&sc->idle.immediate_work);
517*1249c01aSStefan Metzmacher 	disable_delayed_work_sync(&sc->idle.timer_work);
518*1249c01aSStefan Metzmacher 
519*1249c01aSStefan Metzmacher 	if (sc->rdma.cm_id)
520*1249c01aSStefan Metzmacher 		rdma_lock_handler(sc->rdma.cm_id);
521*1249c01aSStefan Metzmacher 
522*1249c01aSStefan Metzmacher 	if (sc->ib.qp) {
523*1249c01aSStefan Metzmacher 		smbdirect_log_rdma_event(sc, SMBDIRECT_LOG_INFO,
524*1249c01aSStefan Metzmacher 			"drain qp\n");
525*1249c01aSStefan Metzmacher 		ib_drain_qp(sc->ib.qp);
526*1249c01aSStefan Metzmacher 	}
527*1249c01aSStefan Metzmacher 
528*1249c01aSStefan Metzmacher 	/*
529*1249c01aSStefan Metzmacher 	 * In case we were a listener we need to
530*1249c01aSStefan Metzmacher 	 * disconnect all pending and ready sockets
531*1249c01aSStefan Metzmacher 	 *
532*1249c01aSStefan Metzmacher 	 * We move ready sockets to pending again.
533*1249c01aSStefan Metzmacher 	 */
534*1249c01aSStefan Metzmacher 	spin_lock_irqsave(&sc->listen.lock, flags);
535*1249c01aSStefan Metzmacher 	list_splice_tail_init(&sc->listen.ready, &all_list);
536*1249c01aSStefan Metzmacher 	list_splice_tail_init(&sc->listen.pending, &all_list);
537*1249c01aSStefan Metzmacher 	spin_unlock_irqrestore(&sc->listen.lock, flags);
538*1249c01aSStefan Metzmacher 	psockets = list_count_nodes(&all_list);
539*1249c01aSStefan Metzmacher 	if (sc->listen.backlog != -1) /* was a listener */
540*1249c01aSStefan Metzmacher 		smbdirect_log_rdma_event(sc, SMBDIRECT_LOG_INFO,
541*1249c01aSStefan Metzmacher 			"release %zu pending sockets\n", psockets);
542*1249c01aSStefan Metzmacher 	list_for_each_entry_safe(psc, tsc, &all_list, accept.list) {
543*1249c01aSStefan Metzmacher 		list_del_init(&psc->accept.list);
544*1249c01aSStefan Metzmacher 		psc->accept.listener = NULL;
545*1249c01aSStefan Metzmacher 		smbdirect_socket_release(psc);
546*1249c01aSStefan Metzmacher 	}
547*1249c01aSStefan Metzmacher 	if (sc->listen.backlog != -1) /* was a listener */
548*1249c01aSStefan Metzmacher 		smbdirect_log_rdma_event(sc, SMBDIRECT_LOG_INFO,
549*1249c01aSStefan Metzmacher 			"released %zu pending sockets\n", psockets);
550*1249c01aSStefan Metzmacher 	INIT_LIST_HEAD(&all_list);
551*1249c01aSStefan Metzmacher 
552*1249c01aSStefan Metzmacher 	/* It's not possible for upper layer to get to reassembly */
553*1249c01aSStefan Metzmacher 	if (sc->listen.backlog == -1) /* was not a listener */
554*1249c01aSStefan Metzmacher 		smbdirect_log_rdma_event(sc, SMBDIRECT_LOG_INFO,
555*1249c01aSStefan Metzmacher 			"drain the reassembly queue\n");
556*1249c01aSStefan Metzmacher 	spin_lock_irqsave(&sc->recv_io.reassembly.lock, flags);
557*1249c01aSStefan Metzmacher 	list_splice_tail_init(&sc->recv_io.reassembly.list, &all_list);
558*1249c01aSStefan Metzmacher 	spin_unlock_irqrestore(&sc->recv_io.reassembly.lock, flags);
559*1249c01aSStefan Metzmacher 	list_for_each_entry_safe(recv_io, recv_tmp, &all_list, list)
560*1249c01aSStefan Metzmacher 		smbdirect_connection_put_recv_io(recv_io);
561*1249c01aSStefan Metzmacher 	sc->recv_io.reassembly.data_length = 0;
562*1249c01aSStefan Metzmacher 
563*1249c01aSStefan Metzmacher 	if (sc->listen.backlog == -1) /* was not a listener */
564*1249c01aSStefan Metzmacher 		smbdirect_log_rdma_event(sc, SMBDIRECT_LOG_INFO,
565*1249c01aSStefan Metzmacher 			"freeing mr list\n");
566*1249c01aSStefan Metzmacher 	smbdirect_connection_destroy_mr_list(sc);
567*1249c01aSStefan Metzmacher 
568*1249c01aSStefan Metzmacher 	if (sc->listen.backlog == -1) /* was not a listener */
569*1249c01aSStefan Metzmacher 		smbdirect_log_rdma_event(sc, SMBDIRECT_LOG_INFO,
570*1249c01aSStefan Metzmacher 			"destroying qp\n");
571*1249c01aSStefan Metzmacher 	smbdirect_connection_destroy_qp(sc);
572*1249c01aSStefan Metzmacher 	if (sc->rdma.cm_id) {
573*1249c01aSStefan Metzmacher 		rdma_unlock_handler(sc->rdma.cm_id);
574*1249c01aSStefan Metzmacher 		smbdirect_log_rdma_event(sc, SMBDIRECT_LOG_INFO,
575*1249c01aSStefan Metzmacher 			"destroying cm_id\n");
576*1249c01aSStefan Metzmacher 		rdma_destroy_id(sc->rdma.cm_id);
577*1249c01aSStefan Metzmacher 		sc->rdma.cm_id = NULL;
578*1249c01aSStefan Metzmacher 	}
579*1249c01aSStefan Metzmacher 
580*1249c01aSStefan Metzmacher 	if (sc->listen.backlog == -1) /* was not a listener */
581*1249c01aSStefan Metzmacher 		smbdirect_log_rdma_event(sc, SMBDIRECT_LOG_INFO,
582*1249c01aSStefan Metzmacher 			"destroying mem pools\n");
583*1249c01aSStefan Metzmacher 	smbdirect_connection_destroy_mem_pools(sc);
584*1249c01aSStefan Metzmacher 
585*1249c01aSStefan Metzmacher 	sc->status = SMBDIRECT_SOCKET_DESTROYED;
586*1249c01aSStefan Metzmacher 
587*1249c01aSStefan Metzmacher 	smbdirect_log_rdma_event(sc, SMBDIRECT_LOG_INFO,
588*1249c01aSStefan Metzmacher 		"rdma session destroyed\n");
589*1249c01aSStefan Metzmacher }
590*1249c01aSStefan Metzmacher 
591*1249c01aSStefan Metzmacher void smbdirect_socket_destroy_sync(struct smbdirect_socket *sc)
592*1249c01aSStefan Metzmacher {
593*1249c01aSStefan Metzmacher 	smbdirect_log_rdma_event(sc, SMBDIRECT_LOG_INFO,
594*1249c01aSStefan Metzmacher 		"status=%s first_error=%1pe",
595*1249c01aSStefan Metzmacher 		smbdirect_socket_status_string(sc->status),
596*1249c01aSStefan Metzmacher 		SMBDIRECT_DEBUG_ERR_PTR(sc->first_error));
597*1249c01aSStefan Metzmacher 
598*1249c01aSStefan Metzmacher 	/*
599*1249c01aSStefan Metzmacher 	 * This should not never be called in an interrupt!
600*1249c01aSStefan Metzmacher 	 */
601*1249c01aSStefan Metzmacher 	WARN_ON_ONCE(in_interrupt());
602*1249c01aSStefan Metzmacher 
603*1249c01aSStefan Metzmacher 	/*
604*1249c01aSStefan Metzmacher 	 * First we try to disable the work
605*1249c01aSStefan Metzmacher 	 * without disable_work_sync() in a
606*1249c01aSStefan Metzmacher 	 * non blocking way, if it's already
607*1249c01aSStefan Metzmacher 	 * running it will be handles by
608*1249c01aSStefan Metzmacher 	 * disable_work_sync() below.
609*1249c01aSStefan Metzmacher 	 *
610*1249c01aSStefan Metzmacher 	 * Here we just want to make sure queue_work() in
611*1249c01aSStefan Metzmacher 	 * smbdirect_socket_schedule_cleanup_lvl()
612*1249c01aSStefan Metzmacher 	 * is a no-op.
613*1249c01aSStefan Metzmacher 	 */
614*1249c01aSStefan Metzmacher 	disable_work(&sc->disconnect_work);
615*1249c01aSStefan Metzmacher 
616*1249c01aSStefan Metzmacher 	if (!sc->first_error)
617*1249c01aSStefan Metzmacher 		/*
618*1249c01aSStefan Metzmacher 		 * SMBDIRECT_LOG_INFO is enough here
619*1249c01aSStefan Metzmacher 		 * as this is the typical case where
620*1249c01aSStefan Metzmacher 		 * we terminate the connection ourself.
621*1249c01aSStefan Metzmacher 		 */
622*1249c01aSStefan Metzmacher 		smbdirect_socket_schedule_cleanup_lvl(sc,
623*1249c01aSStefan Metzmacher 						      SMBDIRECT_LOG_INFO,
624*1249c01aSStefan Metzmacher 						      -ESHUTDOWN);
625*1249c01aSStefan Metzmacher 
626*1249c01aSStefan Metzmacher 	smbdirect_log_rdma_event(sc, SMBDIRECT_LOG_INFO,
627*1249c01aSStefan Metzmacher 		"cancelling and disable disconnect_work\n");
628*1249c01aSStefan Metzmacher 	disable_work_sync(&sc->disconnect_work);
629*1249c01aSStefan Metzmacher 
630*1249c01aSStefan Metzmacher 	smbdirect_log_rdma_event(sc, SMBDIRECT_LOG_INFO,
631*1249c01aSStefan Metzmacher 		"destroying rdma session\n");
632*1249c01aSStefan Metzmacher 	if (sc->status < SMBDIRECT_SOCKET_DISCONNECTING)
633*1249c01aSStefan Metzmacher 		smbdirect_socket_cleanup_work(&sc->disconnect_work);
634*1249c01aSStefan Metzmacher 	if (sc->status < SMBDIRECT_SOCKET_DISCONNECTED) {
635*1249c01aSStefan Metzmacher 		smbdirect_log_rdma_event(sc, SMBDIRECT_LOG_INFO,
636*1249c01aSStefan Metzmacher 			"wait for transport being disconnected\n");
637*1249c01aSStefan Metzmacher 		wait_event(sc->status_wait, sc->status == SMBDIRECT_SOCKET_DISCONNECTED);
638*1249c01aSStefan Metzmacher 		smbdirect_log_rdma_event(sc, SMBDIRECT_LOG_INFO,
639*1249c01aSStefan Metzmacher 			"waited for transport being disconnected\n");
640*1249c01aSStefan Metzmacher 	}
641*1249c01aSStefan Metzmacher 
642*1249c01aSStefan Metzmacher 	/*
643*1249c01aSStefan Metzmacher 	 * Once we reached SMBDIRECT_SOCKET_DISCONNECTED,
644*1249c01aSStefan Metzmacher 	 * we should call smbdirect_socket_destroy()
645*1249c01aSStefan Metzmacher 	 */
646*1249c01aSStefan Metzmacher 	smbdirect_socket_destroy(sc);
647*1249c01aSStefan Metzmacher 	smbdirect_log_rdma_event(sc, SMBDIRECT_LOG_INFO,
648*1249c01aSStefan Metzmacher 		"status=%s first_error=%1pe",
649*1249c01aSStefan Metzmacher 		smbdirect_socket_status_string(sc->status),
650*1249c01aSStefan Metzmacher 		SMBDIRECT_DEBUG_ERR_PTR(sc->first_error));
651*1249c01aSStefan Metzmacher }
652*1249c01aSStefan Metzmacher 
653*1249c01aSStefan Metzmacher int smbdirect_socket_bind(struct smbdirect_socket *sc, struct sockaddr *addr)
654*1249c01aSStefan Metzmacher {
655*1249c01aSStefan Metzmacher 	int ret;
656*1249c01aSStefan Metzmacher 
657*1249c01aSStefan Metzmacher 	if (sc->status != SMBDIRECT_SOCKET_CREATED)
658*1249c01aSStefan Metzmacher 		return -EINVAL;
659*1249c01aSStefan Metzmacher 
660*1249c01aSStefan Metzmacher 	ret = rdma_bind_addr(sc->rdma.cm_id, addr);
661*1249c01aSStefan Metzmacher 	if (ret)
662*1249c01aSStefan Metzmacher 		return ret;
663*1249c01aSStefan Metzmacher 
664*1249c01aSStefan Metzmacher 	return 0;
665*1249c01aSStefan Metzmacher }
666*1249c01aSStefan Metzmacher __SMBDIRECT_EXPORT_SYMBOL__(smbdirect_socket_bind);
667*1249c01aSStefan Metzmacher 
668*1249c01aSStefan Metzmacher void smbdirect_socket_shutdown(struct smbdirect_socket *sc)
669*1249c01aSStefan Metzmacher {
670*1249c01aSStefan Metzmacher 	smbdirect_socket_schedule_cleanup_lvl(sc, SMBDIRECT_LOG_INFO, -ESHUTDOWN);
671*1249c01aSStefan Metzmacher }
672*1249c01aSStefan Metzmacher __SMBDIRECT_EXPORT_SYMBOL__(smbdirect_socket_shutdown);
673*1249c01aSStefan Metzmacher 
674*1249c01aSStefan Metzmacher static void smbdirect_socket_release_disconnect(struct kref *kref)
675*1249c01aSStefan Metzmacher {
676*1249c01aSStefan Metzmacher 	struct smbdirect_socket *sc =
677*1249c01aSStefan Metzmacher 		container_of(kref, struct smbdirect_socket, refs.disconnect);
678*1249c01aSStefan Metzmacher 
679*1249c01aSStefan Metzmacher 	/*
680*1249c01aSStefan Metzmacher 	 * For now do a sync disconnect/destroy
681*1249c01aSStefan Metzmacher 	 */
682*1249c01aSStefan Metzmacher 	smbdirect_socket_destroy_sync(sc);
683*1249c01aSStefan Metzmacher }
684*1249c01aSStefan Metzmacher 
685*1249c01aSStefan Metzmacher static void smbdirect_socket_release_destroy(struct kref *kref)
686*1249c01aSStefan Metzmacher {
687*1249c01aSStefan Metzmacher 	struct smbdirect_socket *sc =
688*1249c01aSStefan Metzmacher 		container_of(kref, struct smbdirect_socket, refs.destroy);
689*1249c01aSStefan Metzmacher 
690*1249c01aSStefan Metzmacher 	/*
691*1249c01aSStefan Metzmacher 	 * Do a sync disconnect/destroy...
692*1249c01aSStefan Metzmacher 	 * hopefully a no-op, as it should be already
693*1249c01aSStefan Metzmacher 	 * in DESTROYED state, before we free the memory.
694*1249c01aSStefan Metzmacher 	 */
695*1249c01aSStefan Metzmacher 	smbdirect_socket_destroy_sync(sc);
696*1249c01aSStefan Metzmacher 	kfree(sc);
697*1249c01aSStefan Metzmacher }
698*1249c01aSStefan Metzmacher 
699*1249c01aSStefan Metzmacher void smbdirect_socket_release(struct smbdirect_socket *sc)
700*1249c01aSStefan Metzmacher {
701*1249c01aSStefan Metzmacher 	/*
702*1249c01aSStefan Metzmacher 	 * We expect only 1 disconnect reference
703*1249c01aSStefan Metzmacher 	 * and if it is already 0, it's a use after free!
704*1249c01aSStefan Metzmacher 	 */
705*1249c01aSStefan Metzmacher 	WARN_ON_ONCE(kref_read(&sc->refs.disconnect) != 1);
706*1249c01aSStefan Metzmacher 	WARN_ON(!kref_put(&sc->refs.disconnect, smbdirect_socket_release_disconnect));
707*1249c01aSStefan Metzmacher 
708*1249c01aSStefan Metzmacher 	/*
709*1249c01aSStefan Metzmacher 	 * This may not trigger smbdirect_socket_release_destroy(),
710*1249c01aSStefan Metzmacher 	 * if struct smbdirect_socket is embedded in another structure
711*1249c01aSStefan Metzmacher 	 * indicated by REFCOUNT_MAX.
712*1249c01aSStefan Metzmacher 	 */
713*1249c01aSStefan Metzmacher 	kref_put(&sc->refs.destroy, smbdirect_socket_release_destroy);
714*1249c01aSStefan Metzmacher }
715*1249c01aSStefan Metzmacher __SMBDIRECT_EXPORT_SYMBOL__(smbdirect_socket_release);
716*1249c01aSStefan Metzmacher 
717*1249c01aSStefan Metzmacher int smbdirect_socket_wait_for_credits(struct smbdirect_socket *sc,
718*1249c01aSStefan Metzmacher 				      enum smbdirect_socket_status expected_status,
719*1249c01aSStefan Metzmacher 				      int unexpected_errno,
720*1249c01aSStefan Metzmacher 				      wait_queue_head_t *waitq,
721*1249c01aSStefan Metzmacher 				      atomic_t *total_credits,
722*1249c01aSStefan Metzmacher 				      int needed)
723*1249c01aSStefan Metzmacher {
724*1249c01aSStefan Metzmacher 	int ret;
725*1249c01aSStefan Metzmacher 
726*1249c01aSStefan Metzmacher 	if (WARN_ON_ONCE(needed < 0))
727*1249c01aSStefan Metzmacher 		return -EINVAL;
728*1249c01aSStefan Metzmacher 
729*1249c01aSStefan Metzmacher 	do {
730*1249c01aSStefan Metzmacher 		if (atomic_sub_return(needed, total_credits) >= 0)
731*1249c01aSStefan Metzmacher 			return 0;
732*1249c01aSStefan Metzmacher 
733*1249c01aSStefan Metzmacher 		atomic_add(needed, total_credits);
734*1249c01aSStefan Metzmacher 		ret = wait_event_interruptible(*waitq,
735*1249c01aSStefan Metzmacher 					       atomic_read(total_credits) >= needed ||
736*1249c01aSStefan Metzmacher 					       sc->status != expected_status);
737*1249c01aSStefan Metzmacher 
738*1249c01aSStefan Metzmacher 		if (sc->status != expected_status)
739*1249c01aSStefan Metzmacher 			return unexpected_errno;
740*1249c01aSStefan Metzmacher 		else if (ret < 0)
741*1249c01aSStefan Metzmacher 			return ret;
742*1249c01aSStefan Metzmacher 	} while (true);
743*1249c01aSStefan Metzmacher }
744