1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 /*
26  * Copyright (c) 2005 SilverStorm Technologies, Inc. All rights reserved.
27  *
28  * This software is available to you under a choice of one of two
29  * licenses.  You may choose to be licensed under the terms of the GNU
30  * General Public License (GPL) Version 2, available from the file
31  * COPYING in the main directory of this source tree, or the
32  * OpenIB.org BSD license below:
33  *
34  *     Redistribution and use in source and binary forms, with or
35  *     without modification, are permitted provided that the following
36  *     conditions are met:
37  *
38  *	- Redistributions of source code must retain the above
39  *	  copyright notice, this list of conditions and the following
40  *	  disclaimer.
41  *
42  *	- Redistributions in binary form must reproduce the above
43  *	  copyright notice, this list of conditions and the following
44  *	  disclaimer in the documentation and/or other materials
45  *	  provided with the distribution.
46  *
47  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
48  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
49  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
50  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
51  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
52  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
53  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
54  * SOFTWARE.
55  *
56  */
57 /*
58  * Sun elects to include this software in Sun product
59  * under the OpenIB BSD license.
60  *
61  *
62  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
63  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
64  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
65  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
66  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
67  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
68  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
69  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
70  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
71  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
72  * POSSIBILITY OF SUCH DAMAGE.
73  */
74 
75 #pragma ident	"%Z%%M%	%I%	%E% SMI"
76 
77 #include <sys/ib/clients/rds/rdsib_cm.h>
78 #include <sys/ib/clients/rds/rdsib_ib.h>
79 #include <sys/ib/clients/rds/rdsib_buf.h>
80 #include <sys/ib/clients/rds/rdsib_ep.h>
81 
82 /*
83  * This file contains CM related work:
84  *
85  * Service registration/deregistration
86  * Path lookup
87  * CM connection callbacks
88  * CM active and passive connection establishment
89  * Connection failover
90  */
91 
92 /*
93  * Handle an incoming CM REQ
94  */
95 /* ARGSUSED */
96 static ibt_cm_status_t
97 rds_handle_cm_req(rds_state_t *statep, ibt_cm_event_t *evp,
98     ibt_cm_return_args_t *rargsp, void *rcmp, ibt_priv_data_len_t rcmp_len)
99 {
100 	ibt_cm_req_rcv_t	*reqp;
101 	ib_gid_t		lgid, rgid;
102 	rds_cm_private_data_t	cmp;
103 	rds_session_t		*sp;
104 	rds_ep_t		*ep;
105 	ibt_channel_hdl_t	chanhdl;
106 	int			ret;
107 
108 	RDS_DPRINTF2("rds_handle_cm_req", "Enter");
109 
110 	reqp = &evp->cm_event.req;
111 	rgid = reqp->req_prim_addr.av_dgid; /* requester gid */
112 	lgid = reqp->req_prim_addr.av_sgid; /* receiver gid */
113 
114 	RDS_DPRINTF2(LABEL, "REQ Received: From: %llx:%llx To: %llx:%llx",
115 	    rgid.gid_prefix, rgid.gid_guid, lgid.gid_prefix, lgid.gid_guid);
116 
117 	/*
118 	 * CM private data brings IP information
119 	 * Private data received is a stream of bytes and may not be properly
120 	 * aligned. So, bcopy the data onto the stack before accessing it.
121 	 */
122 	bcopy((uint8_t *)evp->cm_priv_data, &cmp,
123 	    sizeof (rds_cm_private_data_t));
124 
125 	RDS_DPRINTF2(LABEL, "REQ Received: From IP: 0x%x To IP: 0x%x type: %d",
126 	    cmp.cmp_localip, cmp.cmp_remip, cmp.cmp_eptype);
127 
128 	if (cmp.cmp_version != RDS_VERSION) {
129 		RDS_DPRINTF2(LABEL, "Version Mismatch: Local version: %d "
130 		    "Remote version: %d", RDS_VERSION, cmp.cmp_version);
131 		return (IBT_CM_REJECT);
132 	}
133 
134 	if (cmp.cmp_arch != RDS_THIS_ARCH) {
135 		RDS_DPRINTF2(LABEL, "ARCH does not match (%d != %d)",
136 		    cmp.cmp_arch, RDS_THIS_ARCH);
137 		return (IBT_CM_REJECT);
138 	}
139 
140 	if ((cmp.cmp_eptype != RDS_EP_TYPE_CTRL) &&
141 	    (cmp.cmp_eptype != RDS_EP_TYPE_DATA)) {
142 		RDS_DPRINTF2(LABEL, "Unknown Channel type: %d", cmp.cmp_eptype);
143 		return (IBT_CM_REJECT);
144 	}
145 
146 	/* user_buffer_size should be same on all nodes */
147 	if (cmp.cmp_user_buffer_size != UserBufferSize) {
148 		RDS_DPRINTF2(LABEL,
149 		    "UserBufferSize Mismatch, this node: %d remote node: %d",
150 		    UserBufferSize, cmp.cmp_user_buffer_size);
151 		return (IBT_CM_REJECT);
152 	}
153 
154 	/*
155 	 * RDS needs more time to process a failover REQ so send an MRA.
156 	 * Otherwise, the remote may retry the REQ and fail the connection.
157 	 */
158 	if ((cmp.cmp_failover) && (cmp.cmp_eptype == RDS_EP_TYPE_DATA)) {
159 		RDS_DPRINTF2("rds_handle_cm_req", "Session Failover, send MRA");
160 		(void) ibt_cm_delay(IBT_CM_DELAY_REQ, evp->cm_session_id,
161 		    10000000 /* 10 sec */, NULL, 0);
162 	}
163 
164 	/* Is there a session to the destination node? */
165 	rw_enter(&statep->rds_sessionlock, RW_READER);
166 	sp = rds_session_lkup(statep, cmp.cmp_localip, rgid.gid_guid);
167 	rw_exit(&statep->rds_sessionlock);
168 
169 	if (sp == NULL) {
170 		/*
171 		 * currently there is no session to the destination
172 		 * remote ip in the private data is the local ip and vice
173 		 * versa
174 		 */
175 		sp = rds_session_create(statep, cmp.cmp_remip, cmp.cmp_localip,
176 		    reqp, RDS_SESSION_PASSIVE);
177 		if (sp == NULL) {
178 			/* Check the list anyway. */
179 			rw_enter(&statep->rds_sessionlock, RW_READER);
180 			sp = rds_session_lkup(statep, cmp.cmp_localip,
181 			    rgid.gid_guid);
182 			rw_exit(&statep->rds_sessionlock);
183 			if (sp == NULL) {
184 				/*
185 				 * The only way this can fail is due to lack
186 				 * of kernel resources
187 				 */
188 				return (IBT_CM_REJECT);
189 			}
190 		}
191 	}
192 
193 	rw_enter(&sp->session_lock, RW_WRITER);
194 
195 	/* catch peer-to-peer case as soon as possible */
196 	if (sp->session_state == RDS_SESSION_STATE_CREATED) {
197 		/* Check possible peer-to-peer case here */
198 		if (sp->session_type != RDS_SESSION_PASSIVE) {
199 			RDS_DPRINTF2(LABEL, "SP(%p) Peer-peer connection "
200 			    "handling", sp);
201 			if (lgid.gid_guid > rgid.gid_guid) {
202 				/* this node is active so reject this request */
203 				rw_exit(&sp->session_lock);
204 				return (IBT_CM_REJECT);
205 			} else {
206 				/* this node is passive, change the session */
207 				sp->session_type = RDS_SESSION_PASSIVE;
208 				sp->session_myip = cmp.cmp_remip;
209 				sp->session_lgid = lgid;
210 				sp->session_rgid = rgid;
211 			}
212 		}
213 	}
214 
215 	RDS_DPRINTF2(LABEL, "SP(%p) state: %d", sp, sp->session_state);
216 
217 	switch (sp->session_state) {
218 	case RDS_SESSION_STATE_CONNECTED:
219 		RDS_DPRINTF2(LABEL, "STALE Session Detected SP(%p)", sp);
220 		sp->session_state = RDS_SESSION_STATE_ERROR;
221 		RDS_DPRINTF3("rds_handle_cm_req", "SP(%p) State "
222 		    "RDS_SESSION_STATE_ERROR", sp);
223 
224 		/* FALLTHRU */
225 	case RDS_SESSION_STATE_ERROR:
226 	case RDS_SESSION_STATE_PASSIVE_CLOSING:
227 		sp->session_type = RDS_SESSION_PASSIVE;
228 		rw_exit(&sp->session_lock);
229 
230 		rds_session_close(sp, IBT_NOCALLBACKS, 1);
231 
232 		/* move the session to init state */
233 		rw_enter(&sp->session_lock, RW_WRITER);
234 		ret = rds_session_reinit(sp, lgid);
235 		sp->session_myip = cmp.cmp_remip;
236 		sp->session_lgid = lgid;
237 		sp->session_rgid = rgid;
238 		if (ret != 0) {
239 			rds_session_fini(sp);
240 			sp->session_state = RDS_SESSION_STATE_FAILED;
241 			RDS_DPRINTF3("rds_handle_cm_req", "SP(%p) State "
242 			    "RDS_SESSION_STATE_FAILED", sp);
243 			rw_exit(&sp->session_lock);
244 			return (IBT_CM_REJECT);
245 		} else {
246 			sp->session_state = RDS_SESSION_STATE_INIT;
247 			RDS_DPRINTF3("rds_handle_cm_req", "SP(%p) State "
248 			    "RDS_SESSION_STATE_INIT", sp);
249 		}
250 
251 		if (cmp.cmp_eptype == RDS_EP_TYPE_CTRL) {
252 			ep = &sp->session_ctrlep;
253 		} else {
254 			ep = &sp->session_dataep;
255 		}
256 		break;
257 	case RDS_SESSION_STATE_CREATED:
258 	case RDS_SESSION_STATE_FAILED:
259 	case RDS_SESSION_STATE_FINI:
260 		/*
261 		 * Initialize both channels, we accept this connection
262 		 * only if both channels are initialized
263 		 */
264 		sp->session_state = RDS_SESSION_STATE_CREATED;
265 		RDS_DPRINTF3("rds_handle_cm_req", "SP(%p) State "
266 		    "RDS_SESSION_STATE_CREATED", sp);
267 		ret = rds_session_init(sp);
268 		if (ret != 0) {
269 			/* Seems like there are not enough resources */
270 			sp->session_state = RDS_SESSION_STATE_FAILED;
271 			RDS_DPRINTF3("rds_handle_cm_req", "SP(%p) State "
272 			    "RDS_SESSION_STATE_FAILED", sp);
273 			rw_exit(&sp->session_lock);
274 			return (IBT_CM_REJECT);
275 		}
276 		sp->session_state = RDS_SESSION_STATE_INIT;
277 		RDS_DPRINTF3("rds_handle_cm_req", "SP(%p) State "
278 		    "RDS_SESSION_STATE_INIT", sp);
279 
280 		/* FALLTHRU */
281 	case RDS_SESSION_STATE_INIT:
282 		if (cmp.cmp_eptype == RDS_EP_TYPE_CTRL) {
283 			ep = &sp->session_ctrlep;
284 		} else {
285 			ep = &sp->session_dataep;
286 		}
287 
288 		break;
289 	default:
290 		RDS_DPRINTF2(LABEL, "ERROR: SP(%p) is in an unexpected "
291 		    "state: %d", sp, sp->session_state);
292 		rw_exit(&sp->session_lock);
293 		return (IBT_CM_REJECT);
294 	}
295 
296 	if (cmp.cmp_failover) {
297 		RDS_DPRINTF2("rds_handle_cm_req",
298 		    "SP(%p) Failover Session (BP %p)", sp, cmp.cmp_last_bufid);
299 		sp->session_failover = cmp.cmp_failover;
300 	}
301 
302 	mutex_enter(&ep->ep_lock);
303 	if (ep->ep_state == RDS_EP_STATE_UNCONNECTED) {
304 		ep->ep_state = RDS_EP_STATE_PASSIVE_PENDING;
305 		sp->session_type = RDS_SESSION_PASSIVE;
306 		rw_exit(&sp->session_lock);
307 	} else if (ep->ep_state == RDS_EP_STATE_ACTIVE_PENDING) {
308 		rw_exit(&sp->session_lock);
309 		/*
310 		 * Peer to peer connection. There is an active
311 		 * connection pending on this ep. The one with
312 		 * greater port guid becomes active and the
313 		 * other becomes passive.
314 		 */
315 		RDS_DPRINTF2(LABEL, "EP(%p) Peer-peer connection handling", ep);
316 		if (lgid.gid_guid > rgid.gid_guid) {
317 			/* this node is active so reject this request */
318 			mutex_exit(&ep->ep_lock);
319 			RDS_DPRINTF2(LABEL, "SP(%p) EP(%p): "
320 			    "Rejecting passive in favor of active", sp, ep);
321 			return (IBT_CM_REJECT);
322 		} else {
323 			/*
324 			 * This session is not the active end, change it
325 			 * to passive end.
326 			 */
327 			ASSERT(sp->session_type == RDS_SESSION_ACTIVE);
328 			ep->ep_state = RDS_EP_STATE_PASSIVE_PENDING;
329 
330 			rw_enter(&sp->session_lock, RW_WRITER);
331 			sp->session_type = RDS_SESSION_PASSIVE;
332 			sp->session_lgid = lgid;
333 			sp->session_rgid = rgid;
334 			rw_exit(&sp->session_lock);
335 		}
336 	} else {
337 		rw_exit(&sp->session_lock);
338 	}
339 
340 	ep->ep_lbufid = cmp.cmp_last_bufid;
341 	ep->ep_ackwr.wr.rc.rcwr.rdma.rdma_raddr = (ib_vaddr_t)cmp.cmp_ack_addr;
342 	ep->ep_ackwr.wr.rc.rcwr.rdma.rdma_rkey = cmp.cmp_ack_rkey;
343 	cmp.cmp_last_bufid = ep->ep_rbufid;
344 	cmp.cmp_ack_addr = ep->ep_ack_addr;
345 	cmp.cmp_ack_rkey = ep->ep_ack_rkey;
346 	mutex_exit(&ep->ep_lock);
347 
348 	/* continue with accepting the connection request for this channel */
349 	chanhdl = rds_ep_alloc_rc_channel(ep, reqp->req_prim_hca_port);
350 	if (chanhdl == NULL) {
351 		mutex_enter(&ep->ep_lock);
352 		ep->ep_state = RDS_EP_STATE_UNCONNECTED;
353 		mutex_exit(&ep->ep_lock);
354 		return (IBT_CM_REJECT);
355 	}
356 
357 	/* pre-post recv buffers in the RQ */
358 	rds_post_recv_buf((void *)chanhdl);
359 
360 	rargsp->cm_ret_len = sizeof (rds_cm_private_data_t);
361 	bcopy((uint8_t *)&cmp, rcmp, sizeof (rds_cm_private_data_t));
362 	rargsp->cm_ret.rep.cm_channel = chanhdl;
363 	rargsp->cm_ret.rep.cm_rdma_ra_out = 4;
364 	rargsp->cm_ret.rep.cm_rdma_ra_in = 4;
365 	rargsp->cm_ret.rep.cm_rnr_retry_cnt = MinRnrRetry;
366 
367 	RDS_DPRINTF2("rds_handle_cm_req", "Return: SP(%p) EP(%p) Chan (%p)",
368 	    sp, ep, chanhdl);
369 
370 	return (IBT_CM_ACCEPT);
371 }
372 
373 /*
374  * Handle an incoming CM REP
375  * Pre-post recv buffers for the QP
376  */
377 /* ARGSUSED */
378 static ibt_cm_status_t
379 rds_handle_cm_rep(ibt_cm_event_t *evp, ibt_cm_return_args_t *rargsp,
380     void *rcmp, ibt_priv_data_len_t rcmp_len)
381 {
382 	rds_ep_t	*ep;
383 	rds_cm_private_data_t	cmp;
384 
385 	RDS_DPRINTF2("rds_handle_cm_rep", "Enter");
386 
387 	/* pre-post recv buffers in the RQ */
388 	rds_post_recv_buf((void *)evp->cm_channel);
389 
390 	ep = (rds_ep_t *)ibt_get_chan_private(evp->cm_channel);
391 	bcopy((uint8_t *)evp->cm_priv_data, &cmp,
392 	    sizeof (rds_cm_private_data_t));
393 	ep->ep_lbufid = cmp.cmp_last_bufid;
394 	ep->ep_ackwr.wr.rc.rcwr.rdma.rdma_raddr = (ib_vaddr_t)cmp.cmp_ack_addr;
395 	ep->ep_ackwr.wr.rc.rcwr.rdma.rdma_rkey = cmp.cmp_ack_rkey;
396 
397 	rargsp->cm_ret_len = 0;
398 
399 	RDS_DPRINTF2("rds_handle_cm_rep", "Return: lbufid: %p", ep->ep_lbufid);
400 
401 	return (IBT_CM_ACCEPT);
402 }
403 
404 /*
405  * Handle CONN EST
406  */
407 static ibt_cm_status_t
408 rds_handle_cm_conn_est(ibt_cm_event_t *evp)
409 {
410 	rds_session_t	*sp;
411 	rds_ep_t	*ep;
412 
413 	ep = (rds_ep_t *)ibt_get_chan_private(evp->cm_channel);
414 
415 	RDS_DPRINTF2("rds_handle_cm_conn_est", "EP(%p) State: %d", ep,
416 	    ep->ep_state);
417 
418 	mutex_enter(&ep->ep_lock);
419 	ASSERT((ep->ep_state == RDS_EP_STATE_ACTIVE_PENDING) ||
420 	    (ep->ep_state == RDS_EP_STATE_PASSIVE_PENDING));
421 	ep->ep_state = RDS_EP_STATE_CONNECTED;
422 	ep->ep_chanhdl = evp->cm_channel;
423 	sp = ep->ep_sp;
424 	mutex_exit(&ep->ep_lock);
425 
426 	(void) rds_session_active(sp);
427 
428 	RDS_DPRINTF2("rds_handle_cm_conn_est", "Return");
429 	return (IBT_CM_ACCEPT);
430 }
431 
432 /*
433  * Handle CONN CLOSED
434  */
435 static ibt_cm_status_t
436 rds_handle_cm_conn_closed(ibt_cm_event_t *evp)
437 {
438 	rds_ep_t	*ep;
439 	rds_session_t	*sp;
440 
441 	/* Catch DREQs but ignore DREPs */
442 	if (evp->cm_event.closed != IBT_CM_CLOSED_DREQ_RCVD) {
443 		RDS_DPRINTF2("rds_handle_cm_conn_closed",
444 		    "Ignoring Event: %d received", evp->cm_event.closed);
445 		return (IBT_CM_ACCEPT);
446 	}
447 
448 	ep = (rds_ep_t *)ibt_get_chan_private(evp->cm_channel);
449 	sp = ep->ep_sp;
450 	RDS_DPRINTF2("rds_handle_cm_conn_closed", "EP(%p) Enter", ep);
451 
452 	mutex_enter(&ep->ep_lock);
453 	if (ep->ep_state != RDS_EP_STATE_CONNECTED) {
454 		/* Ignore this DREQ */
455 		RDS_DPRINTF2("rds_handle_cm_conn_closed",
456 		    "EP(%p) not connected, state: %d", ep, ep->ep_state);
457 		mutex_exit(&ep->ep_lock);
458 		return (IBT_CM_ACCEPT);
459 	}
460 	ep->ep_state = RDS_EP_STATE_CLOSING;
461 	mutex_exit(&ep->ep_lock);
462 
463 	rw_enter(&sp->session_lock, RW_WRITER);
464 	RDS_DPRINTF2("rds_handle_cm_conn_closed", "SP(%p) - state: %d", sp,
465 	    sp->session_state);
466 
467 	switch (sp->session_state) {
468 	case RDS_SESSION_STATE_CONNECTED:
469 		sp->session_state = RDS_SESSION_STATE_PASSIVE_CLOSING;
470 		RDS_DPRINTF3("rds_handle_cm_conn_closed", "SP(%p) State "
471 		    "RDS_SESSION_STATE_PASSIVE_CLOSING", sp);
472 		break;
473 
474 	case RDS_SESSION_STATE_PASSIVE_CLOSING:
475 		sp->session_state = RDS_SESSION_STATE_CLOSED;
476 		RDS_DPRINTF3("rds_handle_cm_conn_closed", "SP(%p) State "
477 		    "RDS_SESSION_STATE_CLOSED", sp);
478 		rds_passive_session_fini(sp);
479 		sp->session_state = RDS_SESSION_STATE_FINI;
480 		RDS_DPRINTF3("rds_handle_cm_conn_closed",
481 		    "SP(%p) State RDS_SESSION_STATE_FINI", sp);
482 		break;
483 
484 	case RDS_SESSION_STATE_ACTIVE_CLOSING:
485 	case RDS_SESSION_STATE_ERROR:
486 	case RDS_SESSION_STATE_CLOSED:
487 		break;
488 
489 	case RDS_SESSION_STATE_INIT:
490 		sp->session_state = RDS_SESSION_STATE_ERROR;
491 		RDS_DPRINTF3("rds_handle_cm_conn_closed", "SP(%p) State "
492 		    "RDS_SESSION_STATE_ERROR", sp);
493 		rds_passive_session_fini(sp);
494 		sp->session_state = RDS_SESSION_STATE_FAILED;
495 		RDS_DPRINTF3("rds_handle_cm_conn_closed",
496 		    "SP(%p) State RDS_SESSION_STATE_FAILED", sp);
497 		break;
498 
499 	default:
500 		RDS_DPRINTF2("rds_handle_cm_conn_closed",
501 		    "SP(%p) - Unexpected state: %d", sp, sp->session_state);
502 		rds_passive_session_fini(sp);
503 		sp->session_state = RDS_SESSION_STATE_FAILED;
504 		RDS_DPRINTF3("rds_handle_cm_conn_closed", "SP(%p) State "
505 		    "RDS_SESSION_STATE_FAILED", sp);
506 	}
507 	rw_exit(&sp->session_lock);
508 
509 	mutex_enter(&ep->ep_lock);
510 	ep->ep_state = RDS_EP_STATE_CLOSED;
511 	mutex_exit(&ep->ep_lock);
512 
513 	RDS_DPRINTF2("rds_handle_cm_conn_closed", "SP(%p) Return", sp);
514 	return (IBT_CM_ACCEPT);
515 }
516 
517 /*
518  * Handle EVENT FAILURE
519  */
520 static ibt_cm_status_t
521 rds_handle_cm_event_failure(ibt_cm_event_t *evp)
522 {
523 	rds_ep_t	*ep;
524 	rds_session_t	*sp;
525 	int		ret;
526 
527 	RDS_DPRINTF2("rds_handle_cm_event_failure", "Enter: Chan hdl: 0x%p "
528 	    "Code: %d msg: %d reason: %d", evp->cm_channel,
529 	    evp->cm_event.failed.cf_code, evp->cm_event.failed.cf_msg,
530 	    evp->cm_event.failed.cf_reason);
531 
532 	if (evp->cm_channel == NULL) {
533 		return (IBT_CM_ACCEPT);
534 	}
535 
536 	ep = (rds_ep_t *)ibt_get_chan_private(evp->cm_channel);
537 	sp = ep->ep_sp;
538 
539 	mutex_enter(&ep->ep_lock);
540 	ep->ep_state = RDS_EP_STATE_ERROR;
541 	mutex_exit(&ep->ep_lock);
542 
543 	rw_enter(&sp->session_lock, RW_WRITER);
544 	if (sp->session_type == RDS_SESSION_PASSIVE) {
545 		RDS_DPRINTF2("rds_handle_cm_event_failure",
546 		    "SP(%p) - state: %d", sp, sp->session_state);
547 		if ((sp->session_state == RDS_SESSION_STATE_INIT) ||
548 		    (sp->session_state == RDS_SESSION_STATE_CONNECTED)) {
549 			sp->session_state = RDS_SESSION_STATE_ERROR;
550 			RDS_DPRINTF3("rds_handle_cm_event_failure",
551 			    "SP(%p) State RDS_SESSION_STATE_ERROR", sp);
552 
553 			/*
554 			 * Store the cm_channel for freeing later
555 			 * Active side frees it on ibt_open_rc_channel
556 			 * failure
557 			 */
558 			if (ep->ep_chanhdl == NULL) {
559 				ep->ep_chanhdl = evp->cm_channel;
560 			}
561 			rw_exit(&sp->session_lock);
562 
563 			/*
564 			 * rds_passive_session_fini should not be called
565 			 * directly in the CM handler. It will cause a deadlock.
566 			 */
567 			ret = ddi_taskq_dispatch(rds_taskq,
568 			    rds_cleanup_passive_session, (void *)sp,
569 			    DDI_NOSLEEP);
570 			if (ret != DDI_SUCCESS) {
571 				RDS_DPRINTF1("rds_handle_cm_event_failure",
572 				    "SP(%p) TaskQ dispatch FAILED:%d", sp, ret);
573 			}
574 			return (IBT_CM_ACCEPT);
575 		}
576 	}
577 	rw_exit(&sp->session_lock);
578 
579 	RDS_DPRINTF2("rds_handle_cm_event_failure", "SP(%p) Return", sp);
580 	return (IBT_CM_ACCEPT);
581 }
582 
583 /*
584  * CM Handler
585  *
586  * Called by IBCM
587  * The cm_private type differs for active and passive events.
588  */
589 ibt_cm_status_t
590 rds_cm_handler(void *cm_private, ibt_cm_event_t *eventp,
591     ibt_cm_return_args_t *ret_args, void *ret_priv_data,
592     ibt_priv_data_len_t ret_len_max)
593 {
594 	ibt_cm_status_t		ret = IBT_CM_ACCEPT;
595 
596 	RDS_DPRINTF2("rds_cm_handler", "Enter: event: %d", eventp->cm_type);
597 
598 	switch (eventp->cm_type) {
599 	case IBT_CM_EVENT_REQ_RCV:
600 		ret = rds_handle_cm_req((rds_state_t *)cm_private, eventp,
601 		    ret_args, ret_priv_data, ret_len_max);
602 		break;
603 	case IBT_CM_EVENT_REP_RCV:
604 		ret = rds_handle_cm_rep(eventp, ret_args, ret_priv_data,
605 		    ret_len_max);
606 		break;
607 	case IBT_CM_EVENT_MRA_RCV:
608 		/* Not supported */
609 		break;
610 	case IBT_CM_EVENT_CONN_EST:
611 		ret = rds_handle_cm_conn_est(eventp);
612 		break;
613 	case IBT_CM_EVENT_CONN_CLOSED:
614 		ret = rds_handle_cm_conn_closed(eventp);
615 		break;
616 	case IBT_CM_EVENT_FAILURE:
617 		ret = rds_handle_cm_event_failure(eventp);
618 		break;
619 	case IBT_CM_EVENT_LAP_RCV:
620 		/* Not supported */
621 		RDS_DPRINTF2(LABEL, "LAP message received");
622 		break;
623 	case IBT_CM_EVENT_APR_RCV:
624 		/* Not supported */
625 		RDS_DPRINTF2(LABEL, "APR message received");
626 		break;
627 	default:
628 		break;
629 	}
630 
631 	RDS_DPRINTF2("rds_cm_handler", "Return");
632 
633 	return (ret);
634 }
635 
636 /*
637  * Register the wellknown service with service id: RDS_SERVICE_ID
638  * Incoming connection requests should arrive on this service id.
639  */
640 ibt_srv_hdl_t
641 rds_register_service(ibt_clnt_hdl_t rds_ibhdl)
642 {
643 	ibt_srv_hdl_t	srvhdl;
644 	ibt_srv_desc_t	srvdesc;
645 	int		ret;
646 
647 	RDS_DPRINTF2("rds_register_service", "Enter: 0x%p", rds_ibhdl);
648 
649 	bzero(&srvdesc, sizeof (ibt_srv_desc_t));
650 	srvdesc.sd_handler = rds_cm_handler;
651 	srvdesc.sd_flags = IBT_SRV_NO_FLAGS;
652 
653 	ret = ibt_register_service(rds_ibhdl, &srvdesc, RDS_SERVICE_ID,
654 	    1, &srvhdl, NULL);
655 	if (ret != IBT_SUCCESS) {
656 		RDS_DPRINTF2(LABEL, "RDS Service Registration Failed: %d",
657 		    ret);
658 		return (NULL);
659 	}
660 
661 	RDS_DPRINTF2("rds_register_service", "Return: 0x%p", srvhdl);
662 	return (srvhdl);
663 }
664 
665 /* Bind the RDS service on all ports */
666 int
667 rds_bind_service(rds_state_t *statep)
668 {
669 	rds_hca_t	*hcap;
670 	ib_gid_t	gid;
671 	uint_t		jx, nbinds = 0, nports = 0;
672 	int		ret;
673 
674 	RDS_DPRINTF2("rds_bind_service", "Enter: 0x%p", statep);
675 
676 	hcap = statep->rds_hcalistp;
677 	while (hcap != NULL) {
678 		for (jx = 0; jx < hcap->hca_nports; jx++) {
679 			nports++;
680 			if (hcap->hca_pinfop[jx].p_linkstate !=
681 			    IBT_PORT_ACTIVE) {
682 				/*
683 				 * service bind will be called in the async
684 				 * handler when the port comes up
685 				 */
686 				continue;
687 			}
688 
689 			gid = hcap->hca_pinfop[jx].p_sgid_tbl[0];
690 			RDS_DPRINTF5(LABEL, "HCA: 0x%llx Port: %d "
691 			    "gid: %llx:%llx", hcap->hca_guid,
692 			    hcap->hca_pinfop[jx].p_port_num, gid.gid_prefix,
693 			    gid.gid_guid);
694 
695 			/* pass statep as cm_private */
696 			ret = ibt_bind_service(statep->rds_srvhdl, gid,
697 			    NULL, statep, NULL);
698 			if (ret != IBT_SUCCESS) {
699 				RDS_DPRINTF2(LABEL, "Bind service for "
700 				    "HCA: 0x%llx Port: %d gid %llx:%llx "
701 				    "failed: %d", hcap->hca_guid,
702 				    hcap->hca_pinfop[jx].p_port_num,
703 				    gid.gid_prefix, gid.gid_guid, ret);
704 				continue;
705 			}
706 
707 			nbinds++;
708 		}
709 		hcap = hcap->hca_nextp;
710 	}
711 
712 	RDS_DPRINTF2(LABEL, "RDS Service available on %d/%d ports",
713 	    nbinds, nports);
714 
715 #if 0
716 	if (nbinds == 0) {
717 		return (-1);
718 	}
719 #endif
720 
721 	RDS_DPRINTF2("rds_bind_service", "Return");
722 
723 	return (0);
724 }
725 
726 /* Open an RC connection */
727 int
728 rds_open_rc_channel(rds_ep_t *ep, ibt_path_info_t *pinfo,
729     ibt_execution_mode_t mode, ibt_channel_hdl_t *chanhdl)
730 {
731 	rds_session_t		*sp;
732 	ibt_chan_open_args_t	ocargs;
733 	ibt_rc_returns_t	ocrets;
734 	rds_cm_private_data_t	cmp;
735 	uint8_t			hca_port;
736 	ibt_channel_hdl_t	hdl;
737 	int			ret = 0;
738 
739 	RDS_DPRINTF2("rds_open_rc_channel", "Enter: EP(%p) mode: %d", ep, mode);
740 
741 	sp = ep->ep_sp;
742 
743 	hca_port = pinfo->pi_prim_cep_path.cep_hca_port_num;
744 
745 	hdl = rds_ep_alloc_rc_channel(ep, hca_port);
746 	if (hdl == NULL) {
747 		return (-1);
748 	}
749 
750 	cmp.cmp_version = RDS_VERSION;
751 	cmp.cmp_arch = RDS_THIS_ARCH;
752 	cmp.cmp_remip = sp->session_remip;
753 	cmp.cmp_localip = sp->session_myip;
754 	cmp.cmp_eptype = ep->ep_type;
755 	cmp.cmp_failover = sp->session_failover;
756 	cmp.cmp_last_bufid = ep->ep_rbufid;
757 	cmp.cmp_user_buffer_size = UserBufferSize;
758 	cmp.cmp_ack_addr = ep->ep_ack_addr;
759 	cmp.cmp_ack_rkey = ep->ep_ack_rkey;
760 
761 	bzero(&ocargs, sizeof (ibt_chan_open_args_t));
762 	bzero(&ocrets, sizeof (ibt_rc_returns_t));
763 	ocargs.oc_path = pinfo;
764 	ocargs.oc_cm_handler = rds_cm_handler;
765 	ocargs.oc_cm_clnt_private = NULL;
766 	ocargs.oc_rdma_ra_out = 4;
767 	ocargs.oc_rdma_ra_in = 4;
768 	ocargs.oc_priv_data_len = sizeof (rds_cm_private_data_t);
769 	ocargs.oc_priv_data = &cmp;
770 	ocargs.oc_path_retry_cnt = IBPathRetryCount;
771 	ocargs.oc_path_rnr_retry_cnt = MinRnrRetry;
772 	ret = ibt_open_rc_channel(hdl, IBT_OCHAN_NO_FLAGS,
773 	    mode, &ocargs, &ocrets);
774 	if (ret != IBT_SUCCESS) {
775 		RDS_DPRINTF2(LABEL, "SP(%p) EP(%p) ibt_open_rc_channel "
776 		    "failed: %d", sp, ep, ret);
777 		(void) ibt_flush_channel(hdl);
778 		(void) ibt_free_channel(hdl);
779 		/* cleanup stuff allocated in rds_ep_alloc_rc_channel */
780 		(void) ibt_free_cq(ep->ep_recvcq);
781 		ep->ep_recvcq = NULL;
782 		(void) ibt_free_cq(ep->ep_sendcq);
783 		ep->ep_sendcq = NULL;
784 		return (-1);
785 	}
786 
787 	*chanhdl = hdl;
788 
789 	RDS_DPRINTF2("rds_open_rc_channel", "Return: EP(%p) Chan: %p", ep,
790 	    *chanhdl);
791 
792 	return (0);
793 }
794 
795 int
796 rds_close_rc_channel(ibt_channel_hdl_t chanhdl, ibt_execution_mode_t mode)
797 {
798 	int	ret;
799 
800 	RDS_DPRINTF2("rds_close_rc_channel", "Enter: Chan(%p) Mode(%d)",
801 	    chanhdl, mode);
802 
803 	ret = ibt_close_rc_channel(chanhdl, mode, NULL, 0, NULL, NULL, 0);
804 
805 	RDS_DPRINTF2("rds_close_rc_channel", "Return Chan(%p)", chanhdl);
806 
807 	return (ret);
808 }
809