1219820Sjeff/*
2219820Sjeff * Copyright (c) 2006 Mellanox Technologies Ltd.  All rights reserved.
3219820Sjeff *
4219820Sjeff * This software is available to you under a choice of one of two
5219820Sjeff * licenses.  You may choose to be licensed under the terms of the GNU
6219820Sjeff * General Public License (GPL) Version 2, available from the file
7219820Sjeff * COPYING in the main directory of this source tree, or the
8219820Sjeff * OpenIB.org BSD license below:
9219820Sjeff *
10219820Sjeff *     Redistribution and use in source and binary forms, with or
11219820Sjeff *     without modification, are permitted provided that the following
12219820Sjeff *     conditions are met:
13219820Sjeff *
14219820Sjeff *      - Redistributions of source code must retain the above
15219820Sjeff *        copyright notice, this list of conditions and the following
16219820Sjeff *        disclaimer.
17219820Sjeff *
18219820Sjeff *      - Redistributions in binary form must reproduce the above
19219820Sjeff *        copyright notice, this list of conditions and the following
20219820Sjeff *        disclaimer in the documentation and/or other materials
21219820Sjeff *        provided with the distribution.
22219820Sjeff *
23219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30219820Sjeff * SOFTWARE.
31219820Sjeff *
32219820Sjeff * $Id$
33219820Sjeff */
34219820Sjeff#include "sdp.h"
35219820Sjeff
36219820Sjeff#define SDP_MAJV_MINV 0x22
37219820Sjeff
38219820SjeffSDP_MODPARAM_SINT(sdp_link_layer_ib_only, 1, "Support only link layer of "
39219820Sjeff		"type Infiniband");
40219820Sjeff
41219820Sjeffenum {
42219820Sjeff	SDP_HH_SIZE = 76,
43219820Sjeff	SDP_HAH_SIZE = 180,
44219820Sjeff};
45219820Sjeff
46219820Sjeffstatic void
47219820Sjeffsdp_qp_event_handler(struct ib_event *event, void *data)
48219820Sjeff{
49219820Sjeff}
50219820Sjeff
51219820Sjeffstatic int
52219820Sjeffsdp_get_max_dev_sge(struct ib_device *dev)
53219820Sjeff{
54331769Shselasky	struct ib_device_attr *device_attr;
55219820Sjeff	static int max_sges = -1;
56219820Sjeff
57219820Sjeff	if (max_sges > 0)
58219820Sjeff		goto out;
59219820Sjeff
60331769Shselasky	device_attr = &dev->attrs;
61331769Shselasky	max_sges = device_attr->max_sge;
62219820Sjeff
63219820Sjeffout:
64219820Sjeff	return max_sges;
65219820Sjeff}
66219820Sjeff
67219820Sjeffstatic int
68219820Sjeffsdp_init_qp(struct socket *sk, struct rdma_cm_id *id)
69219820Sjeff{
70219820Sjeff	struct ib_qp_init_attr qp_init_attr = {
71219820Sjeff		.event_handler = sdp_qp_event_handler,
72219820Sjeff		.cap.max_send_wr = SDP_TX_SIZE,
73219820Sjeff		.cap.max_recv_wr = SDP_RX_SIZE,
74219820Sjeff        	.sq_sig_type = IB_SIGNAL_REQ_WR,
75219820Sjeff        	.qp_type = IB_QPT_RC,
76219820Sjeff	};
77219820Sjeff	struct ib_device *device = id->device;
78219820Sjeff	struct sdp_sock *ssk;
79219820Sjeff	int rc;
80219820Sjeff
81219820Sjeff	sdp_dbg(sk, "%s\n", __func__);
82219820Sjeff
83219820Sjeff	ssk = sdp_sk(sk);
84219820Sjeff	ssk->max_sge = sdp_get_max_dev_sge(device);
85219820Sjeff	sdp_dbg(sk, "Max sges: %d\n", ssk->max_sge);
86219820Sjeff
87219820Sjeff	qp_init_attr.cap.max_send_sge = MIN(ssk->max_sge, SDP_MAX_SEND_SGES);
88219820Sjeff	sdp_dbg(sk, "Setting max send sge to: %d\n",
89219820Sjeff	    qp_init_attr.cap.max_send_sge);
90219820Sjeff
91219820Sjeff	qp_init_attr.cap.max_recv_sge = MIN(ssk->max_sge, SDP_MAX_RECV_SGES);
92219820Sjeff	sdp_dbg(sk, "Setting max recv sge to: %d\n",
93219820Sjeff	    qp_init_attr.cap.max_recv_sge);
94219820Sjeff
95219820Sjeff	ssk->sdp_dev = ib_get_client_data(device, &sdp_client);
96219820Sjeff	if (!ssk->sdp_dev) {
97219820Sjeff		sdp_warn(sk, "SDP not available on device %s\n", device->name);
98219820Sjeff		rc = -ENODEV;
99219820Sjeff		goto err_rx;
100219820Sjeff	}
101219820Sjeff
102219820Sjeff	rc = sdp_rx_ring_create(ssk, device);
103219820Sjeff	if (rc)
104219820Sjeff		goto err_rx;
105219820Sjeff
106219820Sjeff	rc = sdp_tx_ring_create(ssk, device);
107219820Sjeff	if (rc)
108219820Sjeff		goto err_tx;
109219820Sjeff
110219820Sjeff	qp_init_attr.recv_cq = ssk->rx_ring.cq;
111219820Sjeff	qp_init_attr.send_cq = ssk->tx_ring.cq;
112219820Sjeff
113219820Sjeff	rc = rdma_create_qp(id, ssk->sdp_dev->pd, &qp_init_attr);
114219820Sjeff	if (rc) {
115219820Sjeff		sdp_warn(sk, "Unable to create QP: %d.\n", rc);
116219820Sjeff		goto err_qp;
117219820Sjeff	}
118219820Sjeff	ssk->qp = id->qp;
119219820Sjeff	ssk->ib_device = device;
120219820Sjeff	ssk->qp_active = 1;
121219820Sjeff	ssk->context.device = device;
122219820Sjeff
123219820Sjeff	sdp_dbg(sk, "%s done\n", __func__);
124219820Sjeff	return 0;
125219820Sjeff
126219820Sjefferr_qp:
127219820Sjeff	sdp_tx_ring_destroy(ssk);
128219820Sjefferr_tx:
129219820Sjeff	sdp_rx_ring_destroy(ssk);
130219820Sjefferr_rx:
131219820Sjeff	return rc;
132219820Sjeff}
133219820Sjeff
134219820Sjeffstatic int
135219820Sjeffsdp_connect_handler(struct socket *sk, struct rdma_cm_id *id,
136219820Sjeff    struct rdma_cm_event *event)
137219820Sjeff{
138219820Sjeff	struct sockaddr_in *src_addr;
139219820Sjeff	struct sockaddr_in *dst_addr;
140219820Sjeff	struct socket *child;
141219820Sjeff	const struct sdp_hh *h;
142219820Sjeff	struct sdp_sock *ssk;
143219820Sjeff	int rc;
144219820Sjeff
145219820Sjeff	sdp_dbg(sk, "%s %p -> %p\n", __func__, sdp_sk(sk)->id, id);
146219820Sjeff
147219820Sjeff	h = event->param.conn.private_data;
148219820Sjeff	SDP_DUMP_PACKET(sk, "RX", NULL, &h->bsdh);
149219820Sjeff
150219820Sjeff	if (!h->max_adverts)
151219820Sjeff		return -EINVAL;
152219820Sjeff
153219820Sjeff	child = sonewconn(sk, SS_ISCONNECTED);
154219820Sjeff	if (!child)
155219820Sjeff		return -ENOMEM;
156219820Sjeff
157219820Sjeff	ssk = sdp_sk(child);
158219820Sjeff	rc = sdp_init_qp(child, id);
159219820Sjeff	if (rc)
160219820Sjeff		return rc;
161219820Sjeff	SDP_WLOCK(ssk);
162219820Sjeff	id->context = ssk;
163219820Sjeff	ssk->id = id;
164219820Sjeff	ssk->socket = child;
165219820Sjeff	ssk->cred = crhold(child->so_cred);
166219820Sjeff	dst_addr = (struct sockaddr_in *)&id->route.addr.dst_addr;
167219820Sjeff	src_addr = (struct sockaddr_in *)&id->route.addr.src_addr;
168219820Sjeff	ssk->fport = dst_addr->sin_port;
169219820Sjeff	ssk->faddr = dst_addr->sin_addr.s_addr;
170219820Sjeff	ssk->lport = src_addr->sin_port;
171219820Sjeff	ssk->max_bufs = ntohs(h->bsdh.bufs);
172219820Sjeff	atomic_set(&ssk->tx_ring.credits, ssk->max_bufs);
173219820Sjeff	ssk->min_bufs = tx_credits(ssk) / 4;
174219820Sjeff	ssk->xmit_size_goal = ntohl(h->localrcvsz) - sizeof(struct sdp_bsdh);
175219820Sjeff	sdp_init_buffers(ssk, rcvbuf_initial_size);
176219820Sjeff	ssk->state = TCPS_SYN_RECEIVED;
177219820Sjeff	SDP_WUNLOCK(ssk);
178219820Sjeff
179219820Sjeff	return 0;
180219820Sjeff}
181219820Sjeff
182219820Sjeffstatic int
183219820Sjeffsdp_response_handler(struct socket *sk, struct rdma_cm_id *id,
184219820Sjeff    struct rdma_cm_event *event)
185219820Sjeff{
186219820Sjeff	const struct sdp_hah *h;
187219820Sjeff	struct sockaddr_in *dst_addr;
188219820Sjeff	struct sdp_sock *ssk;
189219820Sjeff	sdp_dbg(sk, "%s\n", __func__);
190219820Sjeff
191219820Sjeff	ssk = sdp_sk(sk);
192219820Sjeff	SDP_WLOCK(ssk);
193219820Sjeff	ssk->state = TCPS_ESTABLISHED;
194219820Sjeff	sdp_set_default_moderation(ssk);
195219820Sjeff	if (ssk->flags & SDP_DROPPED) {
196219820Sjeff		SDP_WUNLOCK(ssk);
197219820Sjeff		return 0;
198219820Sjeff	}
199219820Sjeff	if (sk->so_options & SO_KEEPALIVE)
200219820Sjeff		sdp_start_keepalive_timer(sk);
201219820Sjeff	h = event->param.conn.private_data;
202219820Sjeff	SDP_DUMP_PACKET(sk, "RX", NULL, &h->bsdh);
203219820Sjeff	ssk->max_bufs = ntohs(h->bsdh.bufs);
204219820Sjeff	atomic_set(&ssk->tx_ring.credits, ssk->max_bufs);
205219820Sjeff	ssk->min_bufs = tx_credits(ssk) / 4;
206219820Sjeff	ssk->xmit_size_goal =
207219820Sjeff		ntohl(h->actrcvsz) - sizeof(struct sdp_bsdh);
208219820Sjeff	ssk->poll_cq = 1;
209219820Sjeff
210219820Sjeff	dst_addr = (struct sockaddr_in *)&id->route.addr.dst_addr;
211219820Sjeff	ssk->fport = dst_addr->sin_port;
212219820Sjeff	ssk->faddr = dst_addr->sin_addr.s_addr;
213219820Sjeff	soisconnected(sk);
214219820Sjeff	SDP_WUNLOCK(ssk);
215219820Sjeff
216219820Sjeff	return 0;
217219820Sjeff}
218219820Sjeff
219219820Sjeffstatic int
220219820Sjeffsdp_connected_handler(struct socket *sk, struct rdma_cm_event *event)
221219820Sjeff{
222219820Sjeff	struct sdp_sock *ssk;
223219820Sjeff
224219820Sjeff	sdp_dbg(sk, "%s\n", __func__);
225219820Sjeff
226219820Sjeff	ssk = sdp_sk(sk);
227219820Sjeff	SDP_WLOCK(ssk);
228219820Sjeff	ssk->state = TCPS_ESTABLISHED;
229219820Sjeff
230219820Sjeff	sdp_set_default_moderation(ssk);
231219820Sjeff
232219820Sjeff	if (sk->so_options & SO_KEEPALIVE)
233219820Sjeff		sdp_start_keepalive_timer(sk);
234219820Sjeff
235219820Sjeff	if ((ssk->flags & SDP_DROPPED) == 0)
236219820Sjeff		soisconnected(sk);
237219820Sjeff	SDP_WUNLOCK(ssk);
238219820Sjeff	return 0;
239219820Sjeff}
240219820Sjeff
241219820Sjeffstatic int
242219820Sjeffsdp_disconnected_handler(struct socket *sk)
243219820Sjeff{
244219820Sjeff	struct sdp_sock *ssk;
245219820Sjeff
246219820Sjeff	ssk = sdp_sk(sk);
247219820Sjeff	sdp_dbg(sk, "%s\n", __func__);
248219820Sjeff
249219820Sjeff	SDP_WLOCK_ASSERT(ssk);
250219820Sjeff	if (sdp_sk(sk)->state == TCPS_SYN_RECEIVED) {
251219820Sjeff		sdp_connected_handler(sk, NULL);
252219820Sjeff
253219820Sjeff		if (rcv_nxt(ssk))
254219820Sjeff			return 0;
255219820Sjeff	}
256219820Sjeff
257219820Sjeff	return -ECONNRESET;
258219820Sjeff}
259219820Sjeff
260219820Sjeffint
261219820Sjeffsdp_cma_handler(struct rdma_cm_id *id, struct rdma_cm_event *event)
262219820Sjeff{
263219820Sjeff	struct rdma_conn_param conn_param;
264219820Sjeff	struct socket *sk;
265219820Sjeff	struct sdp_sock *ssk;
266219820Sjeff	struct sdp_hah hah;
267219820Sjeff	struct sdp_hh hh;
268219820Sjeff
269219820Sjeff	int rc = 0;
270219820Sjeff
271219820Sjeff	ssk = id->context;
272219820Sjeff	sk = NULL;
273219820Sjeff	if (ssk)
274219820Sjeff		sk = ssk->socket;
275219820Sjeff	if (!ssk || !sk || !ssk->id) {
276219820Sjeff		sdp_dbg(sk,
277219820Sjeff		    "cm_id is being torn down, event %d, ssk %p, sk %p, id %p\n",
278219820Sjeff		       	event->event, ssk, sk, id);
279219820Sjeff		return event->event == RDMA_CM_EVENT_CONNECT_REQUEST ?
280219820Sjeff			-EINVAL : 0;
281219820Sjeff	}
282219820Sjeff
283219820Sjeff	sdp_dbg(sk, "%s event %d id %p\n", __func__, event->event, id);
284219820Sjeff	switch (event->event) {
285219820Sjeff	case RDMA_CM_EVENT_ADDR_RESOLVED:
286219820Sjeff		sdp_dbg(sk, "RDMA_CM_EVENT_ADDR_RESOLVED\n");
287219820Sjeff
288219820Sjeff		if (sdp_link_layer_ib_only &&
289219820Sjeff			rdma_node_get_transport(id->device->node_type) ==
290219820Sjeff				RDMA_TRANSPORT_IB &&
291219820Sjeff			rdma_port_get_link_layer(id->device, id->port_num) !=
292219820Sjeff				IB_LINK_LAYER_INFINIBAND) {
293219820Sjeff			sdp_dbg(sk, "Link layer is: %d. Only IB link layer "
294219820Sjeff				"is allowed\n",
295219820Sjeff				rdma_port_get_link_layer(id->device, id->port_num));
296219820Sjeff			rc = -ENETUNREACH;
297219820Sjeff			break;
298219820Sjeff		}
299219820Sjeff
300219820Sjeff		rc = rdma_resolve_route(id, SDP_ROUTE_TIMEOUT);
301219820Sjeff		break;
302219820Sjeff	case RDMA_CM_EVENT_ADDR_ERROR:
303219820Sjeff		sdp_dbg(sk, "RDMA_CM_EVENT_ADDR_ERROR\n");
304219820Sjeff		rc = -ENETUNREACH;
305219820Sjeff		break;
306219820Sjeff	case RDMA_CM_EVENT_ROUTE_RESOLVED:
307219820Sjeff		sdp_dbg(sk, "RDMA_CM_EVENT_ROUTE_RESOLVED : %p\n", id);
308219820Sjeff		rc = sdp_init_qp(sk, id);
309219820Sjeff		if (rc)
310219820Sjeff			break;
311219820Sjeff		atomic_set(&sdp_sk(sk)->remote_credits,
312219820Sjeff				rx_ring_posted(sdp_sk(sk)));
313219820Sjeff		memset(&hh, 0, sizeof hh);
314219820Sjeff		hh.bsdh.mid = SDP_MID_HELLO;
315219820Sjeff		hh.bsdh.len = htonl(sizeof(struct sdp_hh));
316219820Sjeff		hh.max_adverts = 1;
317219820Sjeff		hh.ipv_cap = 0x40;
318219820Sjeff		hh.majv_minv = SDP_MAJV_MINV;
319219820Sjeff		sdp_init_buffers(sdp_sk(sk), rcvbuf_initial_size);
320219820Sjeff		hh.bsdh.bufs = htons(rx_ring_posted(sdp_sk(sk)));
321219820Sjeff		hh.localrcvsz = hh.desremrcvsz = htonl(sdp_sk(sk)->recv_bytes);
322219820Sjeff		hh.max_adverts = 0x1;
323219820Sjeff		sdp_sk(sk)->laddr =
324219820Sjeff			((struct sockaddr_in *)&id->route.addr.src_addr)->sin_addr.s_addr;
325219820Sjeff		memset(&conn_param, 0, sizeof conn_param);
326219820Sjeff		conn_param.private_data_len = sizeof hh;
327219820Sjeff		conn_param.private_data = &hh;
328219820Sjeff		conn_param.responder_resources = 4 /* TODO */;
329219820Sjeff		conn_param.initiator_depth = 4 /* TODO */;
330219820Sjeff		conn_param.retry_count = SDP_RETRY_COUNT;
331219820Sjeff		SDP_DUMP_PACKET(NULL, "TX", NULL, &hh.bsdh);
332219820Sjeff		rc = rdma_connect(id, &conn_param);
333219820Sjeff		break;
334219820Sjeff	case RDMA_CM_EVENT_ROUTE_ERROR:
335219820Sjeff		sdp_dbg(sk, "RDMA_CM_EVENT_ROUTE_ERROR : %p\n", id);
336219820Sjeff		rc = -ETIMEDOUT;
337219820Sjeff		break;
338219820Sjeff	case RDMA_CM_EVENT_CONNECT_REQUEST:
339219820Sjeff		sdp_dbg(sk, "RDMA_CM_EVENT_CONNECT_REQUEST\n");
340219820Sjeff		rc = sdp_connect_handler(sk, id, event);
341219820Sjeff		if (rc) {
342219820Sjeff			sdp_dbg(sk, "Destroying qp\n");
343219820Sjeff			rdma_reject(id, NULL, 0);
344219820Sjeff			break;
345219820Sjeff		}
346219820Sjeff		ssk = id->context;
347219820Sjeff		atomic_set(&ssk->remote_credits, rx_ring_posted(ssk));
348219820Sjeff		memset(&hah, 0, sizeof hah);
349219820Sjeff		hah.bsdh.mid = SDP_MID_HELLO_ACK;
350219820Sjeff		hah.bsdh.bufs = htons(rx_ring_posted(ssk));
351219820Sjeff		hah.bsdh.len = htonl(sizeof(struct sdp_hah));
352219820Sjeff		hah.majv_minv = SDP_MAJV_MINV;
353219820Sjeff		hah.ext_max_adverts = 1; /* Doesn't seem to be mandated by spec,
354219820Sjeff					    but just in case */
355219820Sjeff		hah.actrcvsz = htonl(ssk->recv_bytes);
356219820Sjeff		memset(&conn_param, 0, sizeof conn_param);
357219820Sjeff		conn_param.private_data_len = sizeof hah;
358219820Sjeff		conn_param.private_data = &hah;
359219820Sjeff		conn_param.responder_resources = 4 /* TODO */;
360219820Sjeff		conn_param.initiator_depth = 4 /* TODO */;
361219820Sjeff		conn_param.retry_count = SDP_RETRY_COUNT;
362219820Sjeff		SDP_DUMP_PACKET(sk, "TX", NULL, &hah.bsdh);
363219820Sjeff		rc = rdma_accept(id, &conn_param);
364219820Sjeff		if (rc) {
365219820Sjeff			ssk->id = NULL;
366219820Sjeff			id->qp = NULL;
367219820Sjeff			id->context = NULL;
368219820Sjeff		}
369219820Sjeff		break;
370219820Sjeff	case RDMA_CM_EVENT_CONNECT_RESPONSE:
371219820Sjeff		sdp_dbg(sk, "RDMA_CM_EVENT_CONNECT_RESPONSE\n");
372219820Sjeff		rc = sdp_response_handler(sk, id, event);
373219820Sjeff		if (rc) {
374219820Sjeff			sdp_dbg(sk, "Destroying qp\n");
375219820Sjeff			rdma_reject(id, NULL, 0);
376219820Sjeff		} else
377219820Sjeff			rc = rdma_accept(id, NULL);
378219820Sjeff		break;
379219820Sjeff	case RDMA_CM_EVENT_CONNECT_ERROR:
380219820Sjeff		sdp_dbg(sk, "RDMA_CM_EVENT_CONNECT_ERROR\n");
381219820Sjeff		rc = -ETIMEDOUT;
382219820Sjeff		break;
383219820Sjeff	case RDMA_CM_EVENT_UNREACHABLE:
384219820Sjeff		sdp_dbg(sk, "RDMA_CM_EVENT_UNREACHABLE\n");
385219820Sjeff		rc = -ENETUNREACH;
386219820Sjeff		break;
387219820Sjeff	case RDMA_CM_EVENT_REJECTED:
388219820Sjeff		sdp_dbg(sk, "RDMA_CM_EVENT_REJECTED\n");
389219820Sjeff		rc = -ECONNREFUSED;
390219820Sjeff		break;
391219820Sjeff	case RDMA_CM_EVENT_ESTABLISHED:
392219820Sjeff		sdp_dbg(sk, "RDMA_CM_EVENT_ESTABLISHED\n");
393219820Sjeff		sdp_sk(sk)->laddr =
394219820Sjeff			((struct sockaddr_in *)&id->route.addr.src_addr)->sin_addr.s_addr;
395219820Sjeff		rc = sdp_connected_handler(sk, event);
396219820Sjeff		break;
397219820Sjeff	case RDMA_CM_EVENT_DISCONNECTED: /* This means DREQ/DREP received */
398219820Sjeff		sdp_dbg(sk, "RDMA_CM_EVENT_DISCONNECTED\n");
399219820Sjeff
400219820Sjeff		SDP_WLOCK(ssk);
401219820Sjeff		if (ssk->state == TCPS_LAST_ACK) {
402219820Sjeff			sdp_cancel_dreq_wait_timeout(ssk);
403219820Sjeff
404219820Sjeff			sdp_dbg(sk, "%s: waiting for Infiniband tear down\n",
405219820Sjeff				__func__);
406219820Sjeff		}
407219820Sjeff		ssk->qp_active = 0;
408219820Sjeff		SDP_WUNLOCK(ssk);
409219820Sjeff		rdma_disconnect(id);
410219820Sjeff		SDP_WLOCK(ssk);
411219820Sjeff		if (ssk->state != TCPS_TIME_WAIT) {
412219820Sjeff			if (ssk->state == TCPS_CLOSE_WAIT) {
413219820Sjeff				sdp_dbg(sk, "IB teardown while in "
414219820Sjeff					"TCPS_CLOSE_WAIT taking reference to "
415219820Sjeff					"let close() finish the work\n");
416219820Sjeff			}
417219820Sjeff			rc = sdp_disconnected_handler(sk);
418219820Sjeff			if (rc)
419219820Sjeff				rc = -EPIPE;
420219820Sjeff		}
421219820Sjeff		SDP_WUNLOCK(ssk);
422219820Sjeff		break;
423219820Sjeff	case RDMA_CM_EVENT_TIMEWAIT_EXIT:
424219820Sjeff		sdp_dbg(sk, "RDMA_CM_EVENT_TIMEWAIT_EXIT\n");
425219820Sjeff		SDP_WLOCK(ssk);
426219820Sjeff		rc = sdp_disconnected_handler(sk);
427219820Sjeff		SDP_WUNLOCK(ssk);
428219820Sjeff		break;
429219820Sjeff	case RDMA_CM_EVENT_DEVICE_REMOVAL:
430219820Sjeff		sdp_dbg(sk, "RDMA_CM_EVENT_DEVICE_REMOVAL\n");
431219820Sjeff		rc = -ENETRESET;
432219820Sjeff		break;
433219820Sjeff	default:
434219820Sjeff		printk(KERN_ERR "SDP: Unexpected CMA event: %d\n",
435219820Sjeff		       event->event);
436219820Sjeff		rc = -ECONNABORTED;
437219820Sjeff		break;
438219820Sjeff	}
439219820Sjeff
440219820Sjeff	sdp_dbg(sk, "event %d done. status %d\n", event->event, rc);
441219820Sjeff
442219820Sjeff	if (rc) {
443219820Sjeff		SDP_WLOCK(ssk);
444219820Sjeff		if (ssk->id == id) {
445219820Sjeff			ssk->id = NULL;
446219820Sjeff			id->qp = NULL;
447219820Sjeff			id->context = NULL;
448219820Sjeff			if (sdp_notify(ssk, -rc))
449219820Sjeff				SDP_WUNLOCK(ssk);
450219820Sjeff		} else
451219820Sjeff			SDP_WUNLOCK(ssk);
452219820Sjeff	}
453219820Sjeff
454219820Sjeff	return rc;
455219820Sjeff}
456