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{
54219820Sjeff	struct ib_device_attr attr;
55219820Sjeff	static int max_sges = -1;
56219820Sjeff
57219820Sjeff	if (max_sges > 0)
58219820Sjeff		goto out;
59219820Sjeff
60219820Sjeff	ib_query_device(dev, &attr);
61219820Sjeff
62219820Sjeff	max_sges = attr.max_sge;
63219820Sjeff
64219820Sjeffout:
65219820Sjeff	return max_sges;
66219820Sjeff}
67219820Sjeff
68219820Sjeffstatic int
69219820Sjeffsdp_init_qp(struct socket *sk, struct rdma_cm_id *id)
70219820Sjeff{
71219820Sjeff	struct ib_qp_init_attr qp_init_attr = {
72219820Sjeff		.event_handler = sdp_qp_event_handler,
73219820Sjeff		.cap.max_send_wr = SDP_TX_SIZE,
74219820Sjeff		.cap.max_recv_wr = SDP_RX_SIZE,
75219820Sjeff        	.sq_sig_type = IB_SIGNAL_REQ_WR,
76219820Sjeff        	.qp_type = IB_QPT_RC,
77219820Sjeff	};
78219820Sjeff	struct ib_device *device = id->device;
79219820Sjeff	struct sdp_sock *ssk;
80219820Sjeff	int rc;
81219820Sjeff
82219820Sjeff	sdp_dbg(sk, "%s\n", __func__);
83219820Sjeff
84219820Sjeff	ssk = sdp_sk(sk);
85219820Sjeff	ssk->max_sge = sdp_get_max_dev_sge(device);
86219820Sjeff	sdp_dbg(sk, "Max sges: %d\n", ssk->max_sge);
87219820Sjeff
88219820Sjeff	qp_init_attr.cap.max_send_sge = MIN(ssk->max_sge, SDP_MAX_SEND_SGES);
89219820Sjeff	sdp_dbg(sk, "Setting max send sge to: %d\n",
90219820Sjeff	    qp_init_attr.cap.max_send_sge);
91219820Sjeff
92219820Sjeff	qp_init_attr.cap.max_recv_sge = MIN(ssk->max_sge, SDP_MAX_RECV_SGES);
93219820Sjeff	sdp_dbg(sk, "Setting max recv sge to: %d\n",
94219820Sjeff	    qp_init_attr.cap.max_recv_sge);
95219820Sjeff
96219820Sjeff	ssk->sdp_dev = ib_get_client_data(device, &sdp_client);
97219820Sjeff	if (!ssk->sdp_dev) {
98219820Sjeff		sdp_warn(sk, "SDP not available on device %s\n", device->name);
99219820Sjeff		rc = -ENODEV;
100219820Sjeff		goto err_rx;
101219820Sjeff	}
102219820Sjeff
103219820Sjeff	rc = sdp_rx_ring_create(ssk, device);
104219820Sjeff	if (rc)
105219820Sjeff		goto err_rx;
106219820Sjeff
107219820Sjeff	rc = sdp_tx_ring_create(ssk, device);
108219820Sjeff	if (rc)
109219820Sjeff		goto err_tx;
110219820Sjeff
111219820Sjeff	qp_init_attr.recv_cq = ssk->rx_ring.cq;
112219820Sjeff	qp_init_attr.send_cq = ssk->tx_ring.cq;
113219820Sjeff
114219820Sjeff	rc = rdma_create_qp(id, ssk->sdp_dev->pd, &qp_init_attr);
115219820Sjeff	if (rc) {
116219820Sjeff		sdp_warn(sk, "Unable to create QP: %d.\n", rc);
117219820Sjeff		goto err_qp;
118219820Sjeff	}
119219820Sjeff	ssk->qp = id->qp;
120219820Sjeff	ssk->ib_device = device;
121219820Sjeff	ssk->qp_active = 1;
122219820Sjeff	ssk->context.device = device;
123219820Sjeff
124219820Sjeff	sdp_dbg(sk, "%s done\n", __func__);
125219820Sjeff	return 0;
126219820Sjeff
127219820Sjefferr_qp:
128219820Sjeff	sdp_tx_ring_destroy(ssk);
129219820Sjefferr_tx:
130219820Sjeff	sdp_rx_ring_destroy(ssk);
131219820Sjefferr_rx:
132219820Sjeff	return rc;
133219820Sjeff}
134219820Sjeff
135219820Sjeffstatic int
136219820Sjeffsdp_connect_handler(struct socket *sk, struct rdma_cm_id *id,
137219820Sjeff    struct rdma_cm_event *event)
138219820Sjeff{
139219820Sjeff	struct sockaddr_in *src_addr;
140219820Sjeff	struct sockaddr_in *dst_addr;
141219820Sjeff	struct socket *child;
142219820Sjeff	const struct sdp_hh *h;
143219820Sjeff	struct sdp_sock *ssk;
144219820Sjeff	int rc;
145219820Sjeff
146219820Sjeff	sdp_dbg(sk, "%s %p -> %p\n", __func__, sdp_sk(sk)->id, id);
147219820Sjeff
148219820Sjeff	h = event->param.conn.private_data;
149219820Sjeff	SDP_DUMP_PACKET(sk, "RX", NULL, &h->bsdh);
150219820Sjeff
151219820Sjeff	if (!h->max_adverts)
152219820Sjeff		return -EINVAL;
153219820Sjeff
154219820Sjeff	child = sonewconn(sk, SS_ISCONNECTED);
155219820Sjeff	if (!child)
156219820Sjeff		return -ENOMEM;
157219820Sjeff
158219820Sjeff	ssk = sdp_sk(child);
159219820Sjeff	rc = sdp_init_qp(child, id);
160219820Sjeff	if (rc)
161219820Sjeff		return rc;
162219820Sjeff	SDP_WLOCK(ssk);
163219820Sjeff	id->context = ssk;
164219820Sjeff	ssk->id = id;
165219820Sjeff	ssk->socket = child;
166219820Sjeff	ssk->cred = crhold(child->so_cred);
167219820Sjeff	dst_addr = (struct sockaddr_in *)&id->route.addr.dst_addr;
168219820Sjeff	src_addr = (struct sockaddr_in *)&id->route.addr.src_addr;
169219820Sjeff	ssk->fport = dst_addr->sin_port;
170219820Sjeff	ssk->faddr = dst_addr->sin_addr.s_addr;
171219820Sjeff	ssk->lport = src_addr->sin_port;
172219820Sjeff	ssk->max_bufs = ntohs(h->bsdh.bufs);
173219820Sjeff	atomic_set(&ssk->tx_ring.credits, ssk->max_bufs);
174219820Sjeff	ssk->min_bufs = tx_credits(ssk) / 4;
175219820Sjeff	ssk->xmit_size_goal = ntohl(h->localrcvsz) - sizeof(struct sdp_bsdh);
176219820Sjeff	sdp_init_buffers(ssk, rcvbuf_initial_size);
177219820Sjeff	ssk->state = TCPS_SYN_RECEIVED;
178219820Sjeff	SDP_WUNLOCK(ssk);
179219820Sjeff
180219820Sjeff	return 0;
181219820Sjeff}
182219820Sjeff
183219820Sjeffstatic int
184219820Sjeffsdp_response_handler(struct socket *sk, struct rdma_cm_id *id,
185219820Sjeff    struct rdma_cm_event *event)
186219820Sjeff{
187219820Sjeff	const struct sdp_hah *h;
188219820Sjeff	struct sockaddr_in *dst_addr;
189219820Sjeff	struct sdp_sock *ssk;
190219820Sjeff	sdp_dbg(sk, "%s\n", __func__);
191219820Sjeff
192219820Sjeff	ssk = sdp_sk(sk);
193219820Sjeff	SDP_WLOCK(ssk);
194219820Sjeff	ssk->state = TCPS_ESTABLISHED;
195219820Sjeff	sdp_set_default_moderation(ssk);
196219820Sjeff	if (ssk->flags & SDP_DROPPED) {
197219820Sjeff		SDP_WUNLOCK(ssk);
198219820Sjeff		return 0;
199219820Sjeff	}
200219820Sjeff	if (sk->so_options & SO_KEEPALIVE)
201219820Sjeff		sdp_start_keepalive_timer(sk);
202219820Sjeff	h = event->param.conn.private_data;
203219820Sjeff	SDP_DUMP_PACKET(sk, "RX", NULL, &h->bsdh);
204219820Sjeff	ssk->max_bufs = ntohs(h->bsdh.bufs);
205219820Sjeff	atomic_set(&ssk->tx_ring.credits, ssk->max_bufs);
206219820Sjeff	ssk->min_bufs = tx_credits(ssk) / 4;
207219820Sjeff	ssk->xmit_size_goal =
208219820Sjeff		ntohl(h->actrcvsz) - sizeof(struct sdp_bsdh);
209219820Sjeff	ssk->poll_cq = 1;
210219820Sjeff
211219820Sjeff	dst_addr = (struct sockaddr_in *)&id->route.addr.dst_addr;
212219820Sjeff	ssk->fport = dst_addr->sin_port;
213219820Sjeff	ssk->faddr = dst_addr->sin_addr.s_addr;
214219820Sjeff	soisconnected(sk);
215219820Sjeff	SDP_WUNLOCK(ssk);
216219820Sjeff
217219820Sjeff	return 0;
218219820Sjeff}
219219820Sjeff
220219820Sjeffstatic int
221219820Sjeffsdp_connected_handler(struct socket *sk, struct rdma_cm_event *event)
222219820Sjeff{
223219820Sjeff	struct sdp_sock *ssk;
224219820Sjeff
225219820Sjeff	sdp_dbg(sk, "%s\n", __func__);
226219820Sjeff
227219820Sjeff	ssk = sdp_sk(sk);
228219820Sjeff	SDP_WLOCK(ssk);
229219820Sjeff	ssk->state = TCPS_ESTABLISHED;
230219820Sjeff
231219820Sjeff	sdp_set_default_moderation(ssk);
232219820Sjeff
233219820Sjeff	if (sk->so_options & SO_KEEPALIVE)
234219820Sjeff		sdp_start_keepalive_timer(sk);
235219820Sjeff
236219820Sjeff	if ((ssk->flags & SDP_DROPPED) == 0)
237219820Sjeff		soisconnected(sk);
238219820Sjeff	SDP_WUNLOCK(ssk);
239219820Sjeff	return 0;
240219820Sjeff}
241219820Sjeff
242219820Sjeffstatic int
243219820Sjeffsdp_disconnected_handler(struct socket *sk)
244219820Sjeff{
245219820Sjeff	struct sdp_sock *ssk;
246219820Sjeff
247219820Sjeff	ssk = sdp_sk(sk);
248219820Sjeff	sdp_dbg(sk, "%s\n", __func__);
249219820Sjeff
250219820Sjeff	SDP_WLOCK_ASSERT(ssk);
251219820Sjeff	if (sdp_sk(sk)->state == TCPS_SYN_RECEIVED) {
252219820Sjeff		sdp_connected_handler(sk, NULL);
253219820Sjeff
254219820Sjeff		if (rcv_nxt(ssk))
255219820Sjeff			return 0;
256219820Sjeff	}
257219820Sjeff
258219820Sjeff	return -ECONNRESET;
259219820Sjeff}
260219820Sjeff
261219820Sjeffint
262219820Sjeffsdp_cma_handler(struct rdma_cm_id *id, struct rdma_cm_event *event)
263219820Sjeff{
264219820Sjeff	struct rdma_conn_param conn_param;
265219820Sjeff	struct socket *sk;
266219820Sjeff	struct sdp_sock *ssk;
267219820Sjeff	struct sdp_hah hah;
268219820Sjeff	struct sdp_hh hh;
269219820Sjeff
270219820Sjeff	int rc = 0;
271219820Sjeff
272219820Sjeff	ssk = id->context;
273219820Sjeff	sk = NULL;
274219820Sjeff	if (ssk)
275219820Sjeff		sk = ssk->socket;
276219820Sjeff	if (!ssk || !sk || !ssk->id) {
277219820Sjeff		sdp_dbg(sk,
278219820Sjeff		    "cm_id is being torn down, event %d, ssk %p, sk %p, id %p\n",
279219820Sjeff		       	event->event, ssk, sk, id);
280219820Sjeff		return event->event == RDMA_CM_EVENT_CONNECT_REQUEST ?
281219820Sjeff			-EINVAL : 0;
282219820Sjeff	}
283219820Sjeff
284219820Sjeff	sdp_dbg(sk, "%s event %d id %p\n", __func__, event->event, id);
285219820Sjeff	switch (event->event) {
286219820Sjeff	case RDMA_CM_EVENT_ADDR_RESOLVED:
287219820Sjeff		sdp_dbg(sk, "RDMA_CM_EVENT_ADDR_RESOLVED\n");
288219820Sjeff
289219820Sjeff		if (sdp_link_layer_ib_only &&
290219820Sjeff			rdma_node_get_transport(id->device->node_type) ==
291219820Sjeff				RDMA_TRANSPORT_IB &&
292219820Sjeff			rdma_port_get_link_layer(id->device, id->port_num) !=
293219820Sjeff				IB_LINK_LAYER_INFINIBAND) {
294219820Sjeff			sdp_dbg(sk, "Link layer is: %d. Only IB link layer "
295219820Sjeff				"is allowed\n",
296219820Sjeff				rdma_port_get_link_layer(id->device, id->port_num));
297219820Sjeff			rc = -ENETUNREACH;
298219820Sjeff			break;
299219820Sjeff		}
300219820Sjeff
301219820Sjeff		rc = rdma_resolve_route(id, SDP_ROUTE_TIMEOUT);
302219820Sjeff		break;
303219820Sjeff	case RDMA_CM_EVENT_ADDR_ERROR:
304219820Sjeff		sdp_dbg(sk, "RDMA_CM_EVENT_ADDR_ERROR\n");
305219820Sjeff		rc = -ENETUNREACH;
306219820Sjeff		break;
307219820Sjeff	case RDMA_CM_EVENT_ROUTE_RESOLVED:
308219820Sjeff		sdp_dbg(sk, "RDMA_CM_EVENT_ROUTE_RESOLVED : %p\n", id);
309219820Sjeff		rc = sdp_init_qp(sk, id);
310219820Sjeff		if (rc)
311219820Sjeff			break;
312219820Sjeff		atomic_set(&sdp_sk(sk)->remote_credits,
313219820Sjeff				rx_ring_posted(sdp_sk(sk)));
314219820Sjeff		memset(&hh, 0, sizeof hh);
315219820Sjeff		hh.bsdh.mid = SDP_MID_HELLO;
316219820Sjeff		hh.bsdh.len = htonl(sizeof(struct sdp_hh));
317219820Sjeff		hh.max_adverts = 1;
318219820Sjeff		hh.ipv_cap = 0x40;
319219820Sjeff		hh.majv_minv = SDP_MAJV_MINV;
320219820Sjeff		sdp_init_buffers(sdp_sk(sk), rcvbuf_initial_size);
321219820Sjeff		hh.bsdh.bufs = htons(rx_ring_posted(sdp_sk(sk)));
322219820Sjeff		hh.localrcvsz = hh.desremrcvsz = htonl(sdp_sk(sk)->recv_bytes);
323219820Sjeff		hh.max_adverts = 0x1;
324219820Sjeff		sdp_sk(sk)->laddr =
325219820Sjeff			((struct sockaddr_in *)&id->route.addr.src_addr)->sin_addr.s_addr;
326219820Sjeff		memset(&conn_param, 0, sizeof conn_param);
327219820Sjeff		conn_param.private_data_len = sizeof hh;
328219820Sjeff		conn_param.private_data = &hh;
329219820Sjeff		conn_param.responder_resources = 4 /* TODO */;
330219820Sjeff		conn_param.initiator_depth = 4 /* TODO */;
331219820Sjeff		conn_param.retry_count = SDP_RETRY_COUNT;
332219820Sjeff		SDP_DUMP_PACKET(NULL, "TX", NULL, &hh.bsdh);
333219820Sjeff		rc = rdma_connect(id, &conn_param);
334219820Sjeff		break;
335219820Sjeff	case RDMA_CM_EVENT_ROUTE_ERROR:
336219820Sjeff		sdp_dbg(sk, "RDMA_CM_EVENT_ROUTE_ERROR : %p\n", id);
337219820Sjeff		rc = -ETIMEDOUT;
338219820Sjeff		break;
339219820Sjeff	case RDMA_CM_EVENT_CONNECT_REQUEST:
340219820Sjeff		sdp_dbg(sk, "RDMA_CM_EVENT_CONNECT_REQUEST\n");
341219820Sjeff		rc = sdp_connect_handler(sk, id, event);
342219820Sjeff		if (rc) {
343219820Sjeff			sdp_dbg(sk, "Destroying qp\n");
344219820Sjeff			rdma_reject(id, NULL, 0);
345219820Sjeff			break;
346219820Sjeff		}
347219820Sjeff		ssk = id->context;
348219820Sjeff		atomic_set(&ssk->remote_credits, rx_ring_posted(ssk));
349219820Sjeff		memset(&hah, 0, sizeof hah);
350219820Sjeff		hah.bsdh.mid = SDP_MID_HELLO_ACK;
351219820Sjeff		hah.bsdh.bufs = htons(rx_ring_posted(ssk));
352219820Sjeff		hah.bsdh.len = htonl(sizeof(struct sdp_hah));
353219820Sjeff		hah.majv_minv = SDP_MAJV_MINV;
354219820Sjeff		hah.ext_max_adverts = 1; /* Doesn't seem to be mandated by spec,
355219820Sjeff					    but just in case */
356219820Sjeff		hah.actrcvsz = htonl(ssk->recv_bytes);
357219820Sjeff		memset(&conn_param, 0, sizeof conn_param);
358219820Sjeff		conn_param.private_data_len = sizeof hah;
359219820Sjeff		conn_param.private_data = &hah;
360219820Sjeff		conn_param.responder_resources = 4 /* TODO */;
361219820Sjeff		conn_param.initiator_depth = 4 /* TODO */;
362219820Sjeff		conn_param.retry_count = SDP_RETRY_COUNT;
363219820Sjeff		SDP_DUMP_PACKET(sk, "TX", NULL, &hah.bsdh);
364219820Sjeff		rc = rdma_accept(id, &conn_param);
365219820Sjeff		if (rc) {
366219820Sjeff			ssk->id = NULL;
367219820Sjeff			id->qp = NULL;
368219820Sjeff			id->context = NULL;
369219820Sjeff		}
370219820Sjeff		break;
371219820Sjeff	case RDMA_CM_EVENT_CONNECT_RESPONSE:
372219820Sjeff		sdp_dbg(sk, "RDMA_CM_EVENT_CONNECT_RESPONSE\n");
373219820Sjeff		rc = sdp_response_handler(sk, id, event);
374219820Sjeff		if (rc) {
375219820Sjeff			sdp_dbg(sk, "Destroying qp\n");
376219820Sjeff			rdma_reject(id, NULL, 0);
377219820Sjeff		} else
378219820Sjeff			rc = rdma_accept(id, NULL);
379219820Sjeff		break;
380219820Sjeff	case RDMA_CM_EVENT_CONNECT_ERROR:
381219820Sjeff		sdp_dbg(sk, "RDMA_CM_EVENT_CONNECT_ERROR\n");
382219820Sjeff		rc = -ETIMEDOUT;
383219820Sjeff		break;
384219820Sjeff	case RDMA_CM_EVENT_UNREACHABLE:
385219820Sjeff		sdp_dbg(sk, "RDMA_CM_EVENT_UNREACHABLE\n");
386219820Sjeff		rc = -ENETUNREACH;
387219820Sjeff		break;
388219820Sjeff	case RDMA_CM_EVENT_REJECTED:
389219820Sjeff		sdp_dbg(sk, "RDMA_CM_EVENT_REJECTED\n");
390219820Sjeff		rc = -ECONNREFUSED;
391219820Sjeff		break;
392219820Sjeff	case RDMA_CM_EVENT_ESTABLISHED:
393219820Sjeff		sdp_dbg(sk, "RDMA_CM_EVENT_ESTABLISHED\n");
394219820Sjeff		sdp_sk(sk)->laddr =
395219820Sjeff			((struct sockaddr_in *)&id->route.addr.src_addr)->sin_addr.s_addr;
396219820Sjeff		rc = sdp_connected_handler(sk, event);
397219820Sjeff		break;
398219820Sjeff	case RDMA_CM_EVENT_DISCONNECTED: /* This means DREQ/DREP received */
399219820Sjeff		sdp_dbg(sk, "RDMA_CM_EVENT_DISCONNECTED\n");
400219820Sjeff
401219820Sjeff		SDP_WLOCK(ssk);
402219820Sjeff		if (ssk->state == TCPS_LAST_ACK) {
403219820Sjeff			sdp_cancel_dreq_wait_timeout(ssk);
404219820Sjeff
405219820Sjeff			sdp_dbg(sk, "%s: waiting for Infiniband tear down\n",
406219820Sjeff				__func__);
407219820Sjeff		}
408219820Sjeff		ssk->qp_active = 0;
409219820Sjeff		SDP_WUNLOCK(ssk);
410219820Sjeff		rdma_disconnect(id);
411219820Sjeff		SDP_WLOCK(ssk);
412219820Sjeff		if (ssk->state != TCPS_TIME_WAIT) {
413219820Sjeff			if (ssk->state == TCPS_CLOSE_WAIT) {
414219820Sjeff				sdp_dbg(sk, "IB teardown while in "
415219820Sjeff					"TCPS_CLOSE_WAIT taking reference to "
416219820Sjeff					"let close() finish the work\n");
417219820Sjeff			}
418219820Sjeff			rc = sdp_disconnected_handler(sk);
419219820Sjeff			if (rc)
420219820Sjeff				rc = -EPIPE;
421219820Sjeff		}
422219820Sjeff		SDP_WUNLOCK(ssk);
423219820Sjeff		break;
424219820Sjeff	case RDMA_CM_EVENT_TIMEWAIT_EXIT:
425219820Sjeff		sdp_dbg(sk, "RDMA_CM_EVENT_TIMEWAIT_EXIT\n");
426219820Sjeff		SDP_WLOCK(ssk);
427219820Sjeff		rc = sdp_disconnected_handler(sk);
428219820Sjeff		SDP_WUNLOCK(ssk);
429219820Sjeff		break;
430219820Sjeff	case RDMA_CM_EVENT_DEVICE_REMOVAL:
431219820Sjeff		sdp_dbg(sk, "RDMA_CM_EVENT_DEVICE_REMOVAL\n");
432219820Sjeff		rc = -ENETRESET;
433219820Sjeff		break;
434219820Sjeff	default:
435219820Sjeff		printk(KERN_ERR "SDP: Unexpected CMA event: %d\n",
436219820Sjeff		       event->event);
437219820Sjeff		rc = -ECONNABORTED;
438219820Sjeff		break;
439219820Sjeff	}
440219820Sjeff
441219820Sjeff	sdp_dbg(sk, "event %d done. status %d\n", event->event, rc);
442219820Sjeff
443219820Sjeff	if (rc) {
444219820Sjeff		SDP_WLOCK(ssk);
445219820Sjeff		if (ssk->id == id) {
446219820Sjeff			ssk->id = NULL;
447219820Sjeff			id->qp = NULL;
448219820Sjeff			id->context = NULL;
449219820Sjeff			if (sdp_notify(ssk, -rc))
450219820Sjeff				SDP_WUNLOCK(ssk);
451219820Sjeff		} else
452219820Sjeff			SDP_WUNLOCK(ssk);
453219820Sjeff	}
454219820Sjeff
455219820Sjeff	return rc;
456219820Sjeff}
457