2 * Copyright (c) 2005 SilverStorm Technologies. All rights reserved.
\r
4 * This software is available to you under the OpenIB.org BSD license
\r
7 * Redistribution and use in source and binary forms, with or
\r
8 * without modification, are permitted provided that the following
\r
9 * conditions are met:
\r
11 * - Redistributions of source code must retain the above
\r
12 * copyright notice, this list of conditions and the following
\r
15 * - Redistributions in binary form must reproduce the above
\r
16 * copyright notice, this list of conditions and the following
\r
17 * disclaimer in the documentation and/or other materials
\r
18 * provided with the distribution.
\r
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
\r
21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
\r
22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
\r
23 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
\r
24 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
\r
25 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
\r
26 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
\r
32 #include "ibspdll.h"
\r
34 static void AL_API cm_req_callback(IN ib_cm_req_rec_t * p_cm_req_rec);
\r
35 static void AL_API cm_rep_callback(IN ib_cm_rep_rec_t * p_cm_rep_rec);
\r
36 static void AL_API cm_rtu_callback(IN ib_cm_rtu_rec_t * p_cm_rtu_rec);
\r
37 static void AL_API cm_rej_callback(IN ib_cm_rej_rec_t * p_cm_rej_rec);
\r
38 static void AL_API cm_mra_callback(IN ib_cm_mra_rec_t * p_cm_mra_rec);
\r
39 static void AL_API cm_dreq_callback(IN ib_cm_dreq_rec_t * p_cm_dreq_rec);
\r
40 static void AL_API listen_err_callback(IN ib_listen_err_rec_t * p_listen_err_rec);
\r
41 static void AL_API cm_apr_callback(IN ib_cm_apr_rec_t * p_cm_apr_rec);
\r
44 /* Computes a service ID for a port. */
\r
45 static inline ib_net64_t
\r
46 get_service_id_for_port(
\r
49 return BASE_LISTEN_ID | ip_port;
\r
53 /* Signals a select event to the switch. */
\r
55 ibsp_post_select_event(
\r
56 struct ibsp_socket_info *socket_info,
\r
62 IBSP_ENTER( IBSP_DBG_NEV );
\r
64 CL_ASSERT( socket_info );
\r
70 IBSP_TRACE1( IBSP_DBG_NEV,
\r
71 ("socket %p FD_CONNECT\n", socket_info) );
\r
72 socket_info->errno_connect = error;
\r
76 IBSP_TRACE1( IBSP_DBG_NEV,
\r
77 ("socket %p FD_ACCEPT\n", socket_info) );
\r
85 _InterlockedOr( &socket_info->network_events, event );
\r
87 h_event = InterlockedCompareExchangePointer(
\r
88 &socket_info->event_select, NULL, NULL );
\r
89 /* Check for event notification request and signal as needed. */
\r
90 if( (socket_info->event_mask & event) && h_event )
\r
92 IBSP_TRACE2( IBSP_DBG_NEV,
\r
93 ("Signaling eventHandle %p at time %I64d.\n",
\r
94 h_event, cl_get_time_stamp() ) );
\r
95 SetEvent( h_event );
\r
98 IBSP_EXIT( IBSP_DBG_NEV );
\r
103 * A user-specified callback that is invoked after receiving a connection
\r
104 * request message (REQ).
\r
108 IN ib_cm_req_rec_t *p_cm_req_rec )
\r
110 struct ibsp_socket_info *socket_info =
\r
111 (struct ibsp_socket_info * __ptr64)p_cm_req_rec->context;
\r
112 struct listen_incoming *incoming;
\r
115 IBSP_ENTER( IBSP_DBG_CM );
\r
117 CL_ASSERT( socket_info );
\r
118 CL_ASSERT( p_cm_req_rec->p_req_pdata );
\r
120 incoming = HeapAlloc( g_ibsp.heap, 0, sizeof(struct listen_incoming) );
\r
123 /* Low on memory. */
\r
124 IBSP_ERROR( ("HeapAlloc failed, rejecting\n") );
\r
125 ib_reject( p_cm_req_rec->h_cm_req, IB_REJ_INSUF_RESOURCES );
\r
126 IBSP_EXIT( IBSP_DBG_CM );
\r
130 incoming->cm_req_received = *p_cm_req_rec;
\r
131 cl_memcpy( &incoming->params, p_cm_req_rec->p_req_pdata,
\r
132 sizeof(struct cm_req_params) );
\r
133 incoming->cm_req_received.p_req_pdata = (const uint8_t*)&incoming->params;
\r
135 cl_spinlock_acquire( &socket_info->mutex );
\r
137 switch( socket_info->socket_state )
\r
140 if( cl_qlist_count( &socket_info->info.listen.list ) >= socket_info->info.listen.backlog )
\r
142 /* Already too many connection requests are queued */
\r
143 IBSP_TRACE1( IBSP_DBG_CM,
\r
144 ("already too many incoming connections, rejecting\n") );
\r
145 HeapFree( g_ibsp.heap, 0, incoming );
\r
146 ib_reject( p_cm_req_rec->h_cm_req, IB_REJ_USER_DEFINED );
\r
150 /* Add to the waiting list */
\r
151 cl_qlist_insert_head( &socket_info->info.listen.list, &incoming->item );
\r
154 mra.mra_length = 0;
\r
155 mra.p_mra_pdata = NULL;
\r
156 mra.svc_timeout = 0x15;
\r
157 ib_cm_mra( p_cm_req_rec->h_cm_req, &mra );
\r
159 ibsp_post_select_event( socket_info, FD_ACCEPT, 0 );
\r
162 case IBSP_DUPLICATING_REMOTE:
\r
166 HeapFree( g_ibsp.heap, 0, incoming );
\r
168 wait_cq_drain( socket_info );
\r
170 /* Non-blocking cancel since we're in CM callback context */
\r
171 ib_cm_cancel( socket_info->info.listen.handle, NULL );
\r
172 socket_info->info.listen.handle = NULL;
\r
175 cl_spinlock_release( &socket_info->mutex );
\r
176 CL_EXIT_ERROR( IBSP_DBG_CM, gdbg_lvl, ("rejecting\n") );
\r
177 ib_reject( p_cm_req_rec->h_cm_req, IB_REJ_USER_DEFINED );
\r
178 ibsp_dup_overlap_abort( socket_info );
\r
183 ret = ib_accept( socket_info, p_cm_req_rec );
\r
186 cl_spinlock_release( &socket_info->mutex );
\r
188 ("ib_accept for duplicate socket returned %d, rejecting\n",
\r
190 /* Call ib_destroy_socket for above ib_create_socket() call */
\r
191 ib_destroy_socket( socket_info );
\r
192 ib_reject( p_cm_req_rec->h_cm_req, IB_REJ_USER_DEFINED );
\r
193 ibsp_dup_overlap_abort( socket_info );
\r
194 IBSP_EXIT( IBSP_DBG_CM );
\r
201 IBSP_ERROR( ("socket is not listening anymore\n") );
\r
202 HeapFree( g_ibsp.heap, 0, incoming );
\r
203 /* We're closing down - let some other listen match. */
\r
204 ib_reject( p_cm_req_rec->h_cm_req, IB_REJ_INVALID_SID );
\r
208 cl_spinlock_release( &socket_info->mutex );
\r
210 IBSP_EXIT( IBSP_DBG_CM );
\r
215 * A user-specified callback that is invoked after receiving a connection
\r
216 * request reply message (REP).
\r
220 IN ib_cm_rep_rec_t *p_cm_rep_rec )
\r
222 struct ibsp_socket_info *socket_info =
\r
223 (struct ibsp_socket_info * __ptr64)p_cm_rep_rec->qp_context;
\r
224 ib_cm_rtu_t cm_rtu;
\r
225 ib_api_status_t status;
\r
227 CL_ENTER( IBSP_DBG_CM, gdbg_lvl );
\r
229 memset( &cm_rtu, 0, sizeof(cm_rtu) );
\r
231 cm_rtu.access_ctrl = IB_AC_RDMA_READ | IB_AC_RDMA_WRITE | IB_AC_LOCAL_WRITE;
\r
234 cm_rtu.sq_depth = QP_ATTRIB_SQ_DEPTH;
\r
235 cm_rtu.rq_depth = QP_ATTRIB_RQ_DEPTH;
\r
237 cm_rtu.pfn_cm_apr_cb = cm_apr_callback;
\r
238 cm_rtu.pfn_cm_dreq_cb = cm_dreq_callback;
\r
240 cl_spinlock_acquire( &socket_info->mutex );
\r
242 if( socket_info->socket_state == IBSP_CONNECT )
\r
244 status = ib_cm_rtu( p_cm_rep_rec->h_cm_rep, &cm_rtu );
\r
245 if( status != IB_SUCCESS )
\r
247 /* Note: a REJ has been automatically sent. */
\r
248 CL_ERROR( IBSP_DBG_CM, gdbg_lvl, ("ib_cm_rtu failed (0x%d)\n", status) );
\r
249 IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_BIND );
\r
250 ibsp_post_select_event( socket_info, FD_CONNECT, WSAENOBUFS );
\r
254 IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_CONNECTED );
\r
255 ibsp_post_select_event( socket_info, FD_CONNECT, 0 );
\r
258 else if( socket_info->socket_state == IBSP_DUPLICATING_NEW )
\r
260 status = ib_cm_rtu( p_cm_rep_rec->h_cm_rep, &cm_rtu );
\r
261 if( status != IB_SUCCESS )
\r
263 /* Note: a REJ has been automatically sent. */
\r
264 CL_ERROR( IBSP_DBG_CM, gdbg_lvl, ("ib_cm_rtu failed (0x%d)\n", status) );
\r
268 IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_CONNECTED );
\r
270 SetEvent( socket_info->info.connect.event );
\r
274 /* The socket might be closing */
\r
275 CL_ERROR( IBSP_DBG_CM, gdbg_lvl, ("socket %x not in connecting state (%s)\n",
\r
276 socket_info, IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );
\r
278 ib_reject( p_cm_rep_rec->h_cm_rep, IB_REJ_USER_DEFINED );
\r
281 cl_spinlock_release( &socket_info->mutex );
\r
283 CL_EXIT( IBSP_DBG_CM, gdbg_lvl );
\r
288 * A user-specified callback that is invoked after receiving a connection
\r
289 * ready to use message (RTU).
\r
293 IN ib_cm_rtu_rec_t *p_cm_rtu_rec )
\r
295 struct ibsp_socket_info *socket_info =
\r
296 (struct ibsp_socket_info * __ptr64)p_cm_rtu_rec->qp_context;
\r
298 CL_ENTER( IBSP_DBG_CM, gdbg_lvl );
\r
300 cl_spinlock_acquire( &socket_info->mutex );
\r
302 if( socket_info->socket_state == IBSP_ACCEPT )
\r
304 IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_CONNECTED );
\r
305 SetEvent( socket_info->info.accept.event );
\r
307 else if( socket_info->socket_state == IBSP_DUPLICATING_REMOTE )
\r
309 struct _recv_wr *wr;
\r
310 ib_api_status_t status;
\r
313 /* Repost all the WR to the new QP */
\r
314 cl_spinlock_acquire( &socket_info->recv_lock );
\r
316 while( socket_info->dup_cnt )
\r
318 if( (socket_info->recv_cnt + socket_info->dup_cnt) >
\r
319 QP_ATTRIB_RQ_DEPTH )
\r
321 CL_ASSERT( (socket_info->recv_cnt + socket_info->dup_cnt) <=
\r
322 QP_ATTRIB_RQ_DEPTH );
\r
323 /* TODO: Flag the socket as having failed. */
\r
328 /* Figure out the starting index in the duplicate array. */
\r
329 idx = socket_info->dup_idx - (uint8_t)socket_info->dup_cnt;
\r
330 if( idx >= QP_ATTRIB_RQ_DEPTH )
\r
332 /* The duplicates wrap over the end of the array. */
\r
333 idx += QP_ATTRIB_RQ_DEPTH;
\r
337 * Copy the duplicate work request from the duplicate array
\r
338 * to the receive array.
\r
340 socket_info->recv_wr[socket_info->recv_idx] =
\r
341 socket_info->dup_wr[idx];
\r
343 wr = &socket_info->recv_wr[socket_info->recv_idx];
\r
345 /* Update the work request ID. */
\r
346 wr->recv.wr_id = (uint64_t)(void* __ptr64)wr;
\r
349 * Increment the count before posting so it doesn't go
\r
350 * negative in the completion path.
\r
352 cl_atomic_inc( &socket_info->recv_cnt );
\r
354 status = ib_post_recv( socket_info->qp, &wr->recv, NULL );
\r
357 if( status == IB_SUCCESS )
\r
359 /* Update the index and wrap as needed */
\r
360 #if QP_ATTRIB_RQ_DEPTH == 256 || QP_ATTRIB_RQ_DEPTH == 128 || \
\r
361 QP_ATTRIB_RQ_DEPTH == 64 || QP_ATTRIB_RQ_DEPTH == 32 || \
\r
362 QP_ATTRIB_RQ_DEPTH == 16 || QP_ATTRIB_RQ_DEPTH == 8
\r
363 socket_info->recv_idx++;
\r
364 socket_info->recv_idx &= (QP_ATTRIB_RQ_DEPTH - 1);
\r
366 if( ++socket_info->recv_idx == QP_ATTRIB_RQ_DEPTH )
\r
367 socket_info->recv_idx = 0;
\r
370 cl_atomic_dec( &socket_info->dup_cnt );
\r
374 CL_ERROR( IBSP_DBG_CM, gdbg_lvl,
\r
375 ("ib_post_recv returned %s for reposted buffer\n",
\r
376 ib_get_err_str( status )) );
\r
378 cl_atomic_dec( &socket_info->recv_cnt );
\r
379 CL_ASSERT( status == IB_SUCCESS );
\r
380 /* TODO: Flag the socket as having failed. */
\r
385 cl_spinlock_release( &socket_info->recv_lock );
\r
387 socket_info->qp_error = 0;
\r
388 IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_CONNECTED );
\r
392 /* The Socket might be closing */
\r
393 CL_ERROR( IBSP_DBG_CM, gdbg_lvl,
\r
394 ("Got RTU while in socket_state %s - ignoring\n",
\r
395 IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );
\r
398 cl_spinlock_release( &socket_info->mutex );
\r
400 IBSP_EXIT( IBSP_DBG_CM );
\r
405 * A user-specified callback that is invoked after receiving a connection
\r
406 * rejection message (REJ).
\r
410 IN ib_cm_rej_rec_t *p_cm_rej_rec )
\r
412 struct ibsp_socket_info *socket_info =
\r
413 (struct ibsp_socket_info * __ptr64)p_cm_rej_rec->qp_context;
\r
415 IBSP_ENTER( IBSP_DBG_CM );
\r
417 IBSP_TRACE( IBSP_DBG_CONN, ("socket %p connect reject, reason=%d\n",
\r
418 socket_info, cl_ntoh16(p_cm_rej_rec->rej_status)) );
\r
420 cl_spinlock_acquire( &socket_info->mutex );
\r
422 switch( socket_info->socket_state )
\r
425 /* Remove from connection map. */
\r
426 ibsp_conn_remove( socket_info );
\r
428 IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_BIND );
\r
429 if( p_cm_rej_rec->rej_status == IB_REJ_TIMEOUT )
\r
430 ibsp_post_select_event( socket_info, FD_CONNECT, WSAETIMEDOUT );
\r
432 ibsp_post_select_event( socket_info, FD_CONNECT, WSAECONNREFUSED );
\r
436 /* Remove from connection map. */
\r
437 ibsp_conn_remove( socket_info );
\r
439 IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_BIND );
\r
440 /* Fall through. */
\r
442 case IBSP_DUPLICATING_NEW:
\r
443 /* Leave in that state. IBSPSocket will eventually return
\r
444 * an error becaus the socket is not connected. */
\r
445 SetEvent( socket_info->info.connect.event );
\r
449 IBSP_ERROR( ("socket %p got an REJ reason %d in state %s\n",
\r
450 socket_info, cl_ntoh16( p_cm_rej_rec->rej_status ),
\r
451 IBSP_SOCKET_STATE_STR(socket_info->socket_state)) );
\r
455 cl_spinlock_release( &socket_info->mutex );
\r
457 IBSP_EXIT( IBSP_DBG_CM );
\r
462 * A user-specified callback that is invoked after receiving a message
\r
463 * received acknowledgement.
\r
467 IN ib_cm_mra_rec_t *p_cm_mra_rec )
\r
470 CL_ENTER( IBSP_DBG_CM, gdbg_lvl );
\r
472 UNUSED_PARAM( p_cm_mra_rec );
\r
474 CL_EXIT( IBSP_DBG_CM, gdbg_lvl );
\r
479 * A user-specified callback that is invoked after receiving a disconnect
\r
480 * request message (DREQ).
\r
484 IN ib_cm_dreq_rec_t *p_cm_dreq_rec )
\r
486 ib_api_status_t status;
\r
487 ib_cm_drep_t cm_drep;
\r
488 struct disconnect_reason *reason;
\r
489 struct ibsp_socket_info *socket_info =
\r
490 (struct ibsp_socket_info * __ptr64)p_cm_dreq_rec->qp_context;
\r
492 IBSP_ENTER( IBSP_DBG_CM );
\r
493 IBSP_TRACE1( IBSP_DBG_CM,
\r
494 ("socket=%p state=%s\n",
\r
495 socket_info, IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );
\r
497 reason = (struct disconnect_reason * __ptr64)p_cm_dreq_rec->p_dreq_pdata;
\r
499 cl_spinlock_acquire( &socket_info->mutex );
\r
501 if( socket_info->socket_state == IBSP_CONNECTED )
\r
503 switch( reason->type )
\r
505 case DISC_DUPLICATING:
\r
510 IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_DUPLICATING_REMOTE );
\r
511 socket_info->qp_error = -1;
\r
512 socket_info->duplicate.identifier = reason->duplicating.identifier;
\r
513 socket_info->duplicate.dwProcessId = reason->duplicating.dwProcessId;
\r
515 /* Now, setup our listening callback. */
\r
516 socket_info->info.listen.listen_req_param.dwProcessId =
\r
517 reason->duplicating.dwProcessId;
\r
518 socket_info->info.listen.listen_req_param.identifier =
\r
519 reason->duplicating.identifier;
\r
521 ret = ib_listen( socket_info, &error );
\r
525 IBSP_ERROR_EXIT( ("ib_listen failed with %d\n", error) );
\r
526 /* Fall through. */
\r
529 /* Right now, treat anything as a normal disconnect. */
\r
530 IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_DISCONNECTED );
\r
531 /* We changed the state - remove from connection map. */
\r
532 ibsp_conn_remove( socket_info );
\r
533 socket_info->qp_error = WSAECONNRESET;
\r
539 cl_spinlock_release( &socket_info->mutex );
\r
541 memset( &cm_drep, 0, sizeof(cm_drep) );
\r
543 status = ib_cm_drep( p_cm_dreq_rec->h_cm_dreq, &cm_drep );
\r
544 if( status != IB_SUCCESS )
\r
545 IBSP_ERROR( ("ib_cm_drep returned %s\n", ib_get_err_str( status )) );
\r
547 IBSP_EXIT( IBSP_DBG_CM );
\r
552 * A user-specified callback that is invoked after receiving a disconnect
\r
557 IN ib_cm_drep_rec_t *p_cm_drep_rec )
\r
559 CL_ENTER( IBSP_DBG_CM, gdbg_lvl );
\r
560 UNUSED_PARAM( p_cm_drep_rec );
\r
561 CL_EXIT( IBSP_DBG_CM, gdbg_lvl );
\r
566 * A user-specified callback that is invoked after an error has occurred on
\r
567 * a listen request.
\r
570 listen_err_callback(
\r
571 IN ib_listen_err_rec_t *p_listen_err_rec )
\r
574 CL_ENTER( IBSP_DBG_CM, gdbg_lvl );
\r
576 UNUSED_PARAM( p_listen_err_rec );
\r
578 CL_ERROR( IBSP_DBG_CM, gdbg_lvl, ("not implemented") );
\r
582 CL_EXIT( IBSP_DBG_CM, gdbg_lvl );
\r
587 * A user-specified callback that is invoked after receiving a load
\r
588 * alternate path response message.
\r
592 IN ib_cm_apr_rec_t *p_cm_apr_rec )
\r
595 CL_ENTER( IBSP_DBG_CM, gdbg_lvl );
\r
597 UNUSED_PARAM( p_cm_apr_rec );
\r
599 CL_ERROR( IBSP_DBG_CM, gdbg_lvl, ("not implemented"));
\r
603 CL_EXIT( IBSP_DBG_CM, gdbg_lvl );
\r
608 * A user-specified callback that is invoked after receiving a load
\r
609 * alternate path message.
\r
615 IN ib_cm_lap_rec_t *p_cm_lap_rec )
\r
618 CL_ENTER( IBSP_DBG_CM, gdbg_lvl );
\r
620 UNUSED_PARAM( p_cm_lap_rec );
\r
622 CL_ERROR( IBSP_DBG_CM, gdbg_lvl, ("not implemented"));
\r
626 CL_EXIT( IBSP_DBG_CM, gdbg_lvl );
\r
630 /* Listen for an incoming connection. */
\r
633 IN struct ibsp_socket_info *socket_info,
\r
634 OUT LPINT lpErrno )
\r
636 ib_cm_listen_t param;
\r
637 ib_api_status_t status;
\r
639 CL_ENTER( IBSP_DBG_CM, gdbg_lvl );
\r
641 memset( ¶m, 0, sizeof(param) );
\r
643 param.svc_id = get_service_id_for_port( socket_info->local_addr.sin_port );
\r
644 if( socket_info->port )
\r
646 /* The socket is bound to an IP address */
\r
647 param.ca_guid = socket_info->port->hca->guid;
\r
648 param.port_guid = socket_info->port->guid;
\r
652 /* The socket is bound to INADDR_ANY */
\r
653 param.ca_guid = IB_ALL_CAS;
\r
654 param.port_guid = IB_ALL_PORTS;
\r
656 param.lid = IB_ALL_LIDS;
\r
658 param.p_compare_buffer = (uint8_t *) & socket_info->info.listen.listen_req_param;
\r
659 param.compare_length = sizeof(struct listen_req_param);
\r
660 param.compare_offset = offsetof(struct cm_req_params, listen_req_param);
\r
662 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p params: %x %x\n", __FUNCTION__,
\r
663 __LINE__, GetCurrentProcessId(),
\r
664 GetCurrentThreadId(), socket_info,
\r
665 socket_info->info.listen.listen_req_param.dwProcessId,
\r
666 socket_info->info.listen.listen_req_param.identifier));
\r
668 param.pfn_cm_req_cb = cm_req_callback;
\r
670 param.qp_type = IB_QPT_RELIABLE_CONN;
\r
672 status = ib_cm_listen( g_ibsp.al_handle, ¶m, listen_err_callback, socket_info, /* context */
\r
673 &socket_info->info.listen.handle );
\r
675 if( status != IB_SUCCESS )
\r
677 CL_EXIT_ERROR( IBSP_DBG_CM, gdbg_lvl, ("ib_cm_listen failed (0x%d)\n", status) );
\r
678 *lpErrno = ibal_to_wsa_error( status );
\r
679 return SOCKET_ERROR;
\r
682 STAT_INC( listen_num );
\r
684 CL_TRACE_EXIT( IBSP_DBG_CM, gdbg_lvl,
\r
685 ("started listening for port %d\n",
\r
686 CL_HTON16( socket_info->local_addr.sin_port )) );
\r
693 /* Reject all the queued incoming connection requests. */
\r
696 IN struct ibsp_socket_info *socket_info,
\r
699 cl_list_item_t *item;
\r
700 struct listen_incoming *incoming;
\r
702 socket_info->info.listen.backlog = backlog;
\r
705 cl_qlist_count( &socket_info->info.listen.list ) > (uint32_t)backlog )
\r
707 item = cl_qlist_remove_tail( &socket_info->info.listen.list );
\r
709 incoming = PARENT_STRUCT(item, struct listen_incoming, item);
\r
711 ib_reject( incoming->cm_req_received.h_cm_req, IB_REJ_USER_DEFINED );
\r
713 HeapFree( g_ibsp.heap, 0, incoming );
\r
718 /* Stop listening on the socket. */
\r
721 IN struct ibsp_socket_info *socket_info )
\r
723 ib_api_status_t status;
\r
725 IBSP_ENTER( IBSP_DBG_CM );
\r
727 /* We should be in the CLOSING state */
\r
728 CL_ASSERT( socket_info->socket_state == IBSP_CLOSING );
\r
730 status = ib_cm_cancel( socket_info->info.listen.handle, ib_sync_destroy );
\r
733 CL_ERROR( IBSP_DBG_CM, gdbg_lvl,
\r
734 ("ib_cm_cancel returned %s\n", ib_get_err_str( status )) );
\r
738 STAT_DEC( listen_num );
\r
741 /* We can empty the queue now. Since we are closing,
\r
742 * no new entry will be added. */
\r
743 cl_spinlock_acquire( &socket_info->mutex );
\r
744 ib_listen_backlog( socket_info, 0 );
\r
745 cl_spinlock_release( &socket_info->mutex );
\r
747 socket_info->info.listen.handle = NULL;
\r
749 IBSP_EXIT( IBSP_DBG_CM );
\r
755 IN struct ibsp_socket_info *socket_info,
\r
756 IN ib_path_rec_t *path_rec )
\r
758 ib_cm_req_t cm_req;
\r
759 ib_api_status_t status;
\r
760 struct cm_req_params params;
\r
762 IBSP_ENTER( IBSP_DBG_CM );
\r
764 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p \n", __FUNCTION__,
\r
765 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), socket_info));
\r
767 CL_TRACE( IBSP_DBG_CM, gdbg_lvl, ("From:\n") );
\r
768 DebugPrintSockAddr( IBSP_DBG_CM, gdbg_lvl, &socket_info->local_addr );
\r
769 CL_TRACE( IBSP_DBG_CM, gdbg_lvl, ("To:\n") );
\r
770 DebugPrintSockAddr( IBSP_DBG_CM, gdbg_lvl, &socket_info->peer_addr );
\r
772 /* Insert into the connection map. */
\r
773 if( !ibsp_conn_insert( socket_info ) )
\r
775 IBSP_EXIT( IBSP_DBG_CM );
\r
776 return WSAEADDRINUSE;
\r
779 memset( &cm_req, 0, sizeof(cm_req) );
\r
781 cm_req.svc_id = get_service_id_for_port( socket_info->peer_addr.sin_port );
\r
782 cm_req.max_cm_retries = CM_RETRIES;
\r
783 cm_req.p_primary_path = path_rec;
\r
784 cm_req.pfn_cm_rep_cb = cm_rep_callback;
\r
786 cm_req.p_req_pdata = (uint8_t *) & params;
\r
787 params.source = socket_info->local_addr;
\r
788 params.dest = socket_info->peer_addr;
\r
789 params.listen_req_param.dwProcessId = socket_info->duplicate.dwProcessId;
\r
790 params.listen_req_param.identifier = socket_info->duplicate.identifier;
\r
792 CL_TRACE( IBSP_DBG_CM, gdbg_lvl,
\r
793 ("ib_connect listen params: %x %x\n", params.listen_req_param.dwProcessId,
\r
794 params.listen_req_param.identifier) );
\r
795 CL_TRACE( IBSP_DBG_CM, gdbg_lvl,
\r
796 ("connecting to port %d, SID=%016I64x\n", socket_info->peer_addr.sin_port,
\r
799 cm_req.req_length = sizeof(struct cm_req_params);
\r
801 cm_req.qp_type = IB_QPT_RELIABLE_CONN;
\r
802 cm_req.h_qp = socket_info->qp;
\r
803 cm_req.resp_res = QP_ATTRIB_RESPONDER_RESOURCES;
\r
804 cm_req.init_depth = QP_ATTRIB_INITIATOR_DEPTH;
\r
806 cm_req.remote_resp_timeout =
\r
807 ib_path_rec_pkt_life( path_rec ) + CM_REMOTE_TIMEOUT;
\r
808 if( cm_req.remote_resp_timeout > 0x1F )
\r
809 cm_req.remote_resp_timeout = 0x1F;
\r
810 else if( cm_req.remote_resp_timeout < CM_MIN_REMOTE_TIMEOUT )
\r
811 cm_req.remote_resp_timeout = CM_MIN_REMOTE_TIMEOUT;
\r
813 cm_req.flow_ctrl = TRUE; /* HCAs must support end-to-end flow control. */
\r
815 cm_req.local_resp_timeout =
\r
816 ib_path_rec_pkt_life( path_rec ) + CM_LOCAL_TIMEOUT;
\r
817 if( cm_req.local_resp_timeout > 0x1F )
\r
818 cm_req.local_resp_timeout = 0x1F;
\r
819 else if( cm_req.local_resp_timeout < CM_MIN_LOCAL_TIMEOUT )
\r
820 cm_req.local_resp_timeout = CM_MIN_LOCAL_TIMEOUT;
\r
822 cm_req.rnr_nak_timeout = QP_ATTRIB_RNR_NAK_TIMEOUT;
\r
823 cm_req.rnr_retry_cnt = QP_ATTRIB_RNR_RETRY;
\r
824 cm_req.retry_cnt = QP_ATTRIB_RETRY_COUNT;
\r
825 cm_req.p_alt_path = NULL;
\r
826 cm_req.pfn_cm_mra_cb = cm_mra_callback;
\r
827 cm_req.pfn_cm_rej_cb = cm_rej_callback;
\r
829 status = ib_cm_req( &cm_req );
\r
830 if( status != IB_SUCCESS )
\r
832 /* Remove from connection map. */
\r
833 ibsp_conn_remove( socket_info );
\r
835 IBSP_ERROR_EXIT( ("ib_cm_req failed (0x%d)\n", status) );
\r
836 return WSAEHOSTUNREACH;
\r
839 IBSP_EXIT( IBSP_DBG_CM );
\r
840 /* Operation is pending */
\r
841 return WSAEWOULDBLOCK;
\r
847 IN const ib_cm_handle_t h_cm,
\r
848 IN const ib_rej_status_t rej_status )
\r
850 ib_cm_rej_t cm_rej;
\r
851 ib_api_status_t status;
\r
853 IBSP_ENTER( IBSP_DBG_CM );
\r
855 memset( &cm_rej, 0, sizeof(cm_rej) );
\r
856 cm_rej.rej_status = rej_status;
\r
858 status = ib_cm_rej( h_cm, &cm_rej );
\r
859 if( status != IB_SUCCESS )
\r
860 IBSP_ERROR( ("ib_cm_rej returned %s\n", ib_get_err_str( status )) );
\r
862 IBSP_EXIT( IBSP_DBG_CM );
\r
868 IN struct ibsp_socket_info *socket_info,
\r
869 IN ib_cm_req_rec_t *cm_req_received )
\r
871 ib_cm_rep_t cm_rep;
\r
872 ib_api_status_t status;
\r
874 IBSP_ENTER( IBSP_DBG_CM );
\r
876 /* Insert into the connection map. */
\r
877 if( !ibsp_conn_insert( socket_info ) )
\r
879 IBSP_EXIT( IBSP_DBG_CM );
\r
880 return WSAEADDRINUSE;
\r
883 memset( &cm_rep, 0, sizeof(cm_rep) );
\r
885 cm_rep.qp_type = IB_QPT_RELIABLE_CONN;
\r
886 cm_rep.h_qp = socket_info->qp;
\r
887 cm_rep.access_ctrl = IB_AC_RDMA_READ | IB_AC_RDMA_WRITE | IB_AC_LOCAL_WRITE;
\r
890 cm_rep.sq_depth = QP_ATTRIB_SQ_DEPTH;
\r
891 cm_rep.rq_depth = QP_ATTRIB_RQ_DEPTH;
\r
893 cm_rep.init_depth = QP_ATTRIB_INITIATOR_DEPTH;
\r
894 cm_rep.target_ack_delay = 10;
\r
895 cm_rep.failover_accepted = IB_FAILOVER_ACCEPT_UNSUPPORTED;
\r
896 cm_rep.flow_ctrl = cm_req_received->flow_ctrl;
\r
897 cm_rep.rnr_nak_timeout = QP_ATTRIB_RNR_NAK_TIMEOUT;
\r
898 cm_rep.rnr_retry_cnt = cm_req_received->rnr_retry_cnt;
\r
899 cm_rep.pfn_cm_mra_cb = cm_mra_callback;
\r
900 cm_rep.pfn_cm_rej_cb = cm_rej_callback;
\r
901 cm_rep.pfn_cm_rtu_cb = cm_rtu_callback;
\r
902 cm_rep.pfn_cm_lap_cb = cm_lap_callback;
\r
903 cm_rep.pfn_cm_dreq_cb = cm_dreq_callback;
\r
905 fzprint(("%s():%d:0x%x:0x%x: flow_ctrl=%d rnr_retry_cnt=%d\n", __FUNCTION__,
\r
906 __LINE__, GetCurrentProcessId(),
\r
907 GetCurrentThreadId(), cm_rep.flow_ctrl, cm_rep.rnr_retry_cnt));
\r
909 status = ib_cm_rep( cm_req_received->h_cm_req, &cm_rep );
\r
910 if( status != IB_SUCCESS )
\r
912 /* Remove from connection map. */
\r
913 ibsp_conn_remove( socket_info );
\r
916 ("ib_cm_rep failed (0x%d) at time %I64d\n",
\r
917 ib_get_err_str( status ), cl_get_time_stamp()) );
\r
921 IBSP_EXIT( IBSP_DBG_CM );
\r
928 IN struct ibsp_socket_info *socket_info,
\r
929 IN struct disconnect_reason *reason )
\r
931 ib_api_status_t status;
\r
932 ib_cm_dreq_t cm_dreq;
\r
933 ib_qp_mod_t qp_mod;
\r
935 IBSP_ENTER( IBSP_DBG_CM );
\r
937 memset( &cm_dreq, 0, sizeof(cm_dreq) );
\r
939 cm_dreq.qp_type = IB_QPT_RELIABLE_CONN;
\r
940 cm_dreq.h_qp = socket_info->qp;
\r
941 cm_dreq.pfn_cm_drep_cb = cm_drep_callback;
\r
943 cm_dreq.p_dreq_pdata = (uint8_t *) reason;
\r
944 cm_dreq.dreq_length = sizeof(struct disconnect_reason);
\r
946 status = ib_cm_dreq( &cm_dreq );
\r
949 * If both sides initiate disconnection, we might get
\r
950 * an invalid state or handle here.
\r
952 if( status != IB_SUCCESS && status != IB_INVALID_STATE &&
\r
953 status != IB_INVALID_HANDLE )
\r
955 IBSP_ERROR( ("ib_cm_dreq returned %s\n", ib_get_err_str( status )) );
\r
959 * Note that we don't care about getting the DREP - we move the QP to the
\r
960 * error state now and flush all posted work requests. If the
\r
961 * disconnection was graceful, we'll only have the pre-posted receives to
\r
962 * flush. If the disconnection is ungraceful, we don't care if we
\r
963 * interrupt transfers.
\r
966 /* Force the QP to error state to flush posted receives. */
\r
967 memset( &qp_mod, 0, sizeof(qp_mod) );
\r
968 qp_mod.req_state = IB_QPS_ERROR;
\r
969 status = ib_modify_qp( socket_info->qp, &qp_mod );
\r
970 if( status != IB_SUCCESS )
\r
972 socket_info->send_cnt = 0;
\r
973 socket_info->recv_cnt = 0;
\r
975 IBSP_EXIT( IBSP_DBG_CM );
\r