2 * Copyright (c) 2005 SilverStorm Technologies. All rights reserved.
\r
3 * Copyright (c) 1996-2002 Intel Corporation. All rights reserved.
\r
5 * This software is available to you under the OpenIB.org BSD license
\r
8 * Redistribution and use in source and binary forms, with or
\r
9 * without modification, are permitted provided that the following
\r
10 * conditions are met:
\r
12 * - Redistributions of source code must retain the above
\r
13 * copyright notice, this list of conditions and the following
\r
16 * - Redistributions in binary form must reproduce the above
\r
17 * copyright notice, this list of conditions and the following
\r
18 * disclaimer in the documentation and/or other materials
\r
19 * provided with the distribution.
\r
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
\r
22 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
\r
23 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
\r
24 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
\r
25 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
\r
26 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
\r
27 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
\r
36 * Command line interface for cmtest.
\r
46 #include <complib/cl_atomic.h>
\r
47 #include <complib/cl_debug.h>
\r
48 #include <complib/cl_event.h>
\r
49 #include <complib/cl_math.h>
\r
50 #include <complib/cl_mutex.h>
\r
51 #include <complib/cl_qlist.h>
\r
52 #include <complib/cl_thread.h>
\r
53 #include <complib/cl_timer.h>
\r
54 #include <iba/ib_types.h>
\r
55 #include <iba/ib_al.h>
\r
59 #define CMT_DBG_VERBOSE 1
\r
61 #define CMT_BASE_SVC_ID 0xFFEE
\r
62 #define CMT_ACCESS_CTRL (IB_AC_LOCAL_WRITE + IB_AC_RDMA_READ + IB_AC_RDMA_WRITE)
\r
63 #define BAD_PKEY_INDEX 0xFFFF
\r
66 typedef enum _cmtest_state
\r
68 test_idle, test_connecting, test_transfering, test_disconnecting
\r
74 typedef struct _ib_root
\r
76 ib_al_handle_t h_al;
\r
77 ib_pd_handle_t h_pd;
\r
79 /* Input parameters to control test. */
\r
82 boolean_t per_msg_buf;
\r
85 cmtest_state_t state;
\r
86 atomic32_t num_connected;
\r
87 uint32_t conn_index; /* current connection id */
\r
88 uint32_t total_sent;
\r
89 uint32_t total_recv;
\r
95 ib_ca_handle_t h_ca;
\r
99 ib_net64_t port_guid;
\r
101 uint16_t num_pkeys;
\r
102 ib_net16_t *p_pkey_table;
\r
105 boolean_t is_server;
\r
106 ib_listen_handle_t h_listen;
\r
107 ib_path_rec_t path_rec;
\r
110 boolean_t is_polling;
\r
112 struct _ib_node *p_nodes;
\r
113 ib_qp_create_t qp_create;
\r
114 ib_qp_mod_t qp_mod_reset;
\r
115 ib_qp_mod_t qp_mod_init;
\r
118 ib_mr_handle_t h_mr;
\r
122 uint8_t *p_mem_recv;
\r
123 uint8_t *p_mem_send;
\r
125 uint64_t conn_start_time;
\r
128 * Connection parameters are initialized once to improve connection
\r
129 * establishment rate.
\r
131 ib_cm_req_t cm_req;
\r
132 ib_cm_rep_t cm_rep;
\r
133 ib_cm_rtu_t cm_rtu;
\r
134 ib_cm_dreq_t cm_dreq;
\r
135 ib_cm_drep_t cm_drep;
\r
143 typedef enum _cmnode_state
\r
145 node_idle, node_conn, node_dreq_sent, node_dreq_rcvd
\r
151 typedef struct _ib_node
\r
155 ib_cq_handle_t h_send_cq;
\r
156 ib_cq_handle_t h_recv_cq;
\r
157 ib_qp_handle_t h_qp;
\r
158 uint32_t max_inline;
\r
160 cmnode_state_t state;
\r
161 ib_cm_handle_t h_cm_req;
\r
162 ib_cm_handle_t h_cm_dreq;
\r
171 uint32_t cmt_dbg_lvl = 0x80000000;
\r
176 static char *wc_type_text[] = {
\r
178 "IB_WC_RDMA_WRITE",
\r
183 "IB_WC_COMPARE_SWAP",
\r
184 "IB_WC_RECV_RDMA_WRITE"
\r
187 static char *wc_status_text[] = {
\r
189 "IB_WCS_LOCAL_LEN_ERR",
\r
190 "IB_WCS_LOCAL_OP_ERR",
\r
191 "IB_WCS_LOCAL_EEC_OP_ERR",
\r
192 "IB_WCS_LOCAL_PROTECTION_ERR",
\r
193 "IB_WCS_WR_FLUSHED_ERR",
\r
194 "IB_WCS_MEM_WINDOW_BIND_ERR",
\r
195 "IB_WCS_REM_ACCESS_ERR",
\r
196 "IB_WCS_REM_OP_ERR",
\r
197 "IB_WCS_RNR_RETRY_ERR",
\r
198 "IB_WCS_TIMEOUT_RETRY_ERR",
\r
199 "IB_WCS_REM_INVALID_REQ_ERR",
\r
200 "IB_WCS_REM_INVALID_RD_REQ_ERR",
\r
201 "IB_WCS_INVALID_EECN",
\r
202 "IB_WCS_INVALID_EEC_STATE",
\r
203 "IB_WCS_UNMATCHED_RESPONSE",
\r
211 IN ib_cm_req_rec_t *p_cm_req_rec );
\r
215 IN ib_cm_rep_rec_t *p_cm_rep_rec );
\r
219 IN ib_cm_rtu_rec_t *p_cm_rtu_rec );
\r
223 IN ib_cm_rej_rec_t *p_cm_rej_rec );
\r
227 IN ib_cm_mra_rec_t *p_cm_mra_rec );
\r
231 IN ib_cm_apr_rec_t *p_cm_apr_rec );
\r
235 IN ib_cm_lap_rec_t *p_cm_lap_rec );
\r
239 IN ib_cm_dreq_rec_t *p_cm_dreq_rec );
\r
243 IN ib_cm_drep_rec_t *p_cm_drep_rec );
\r
247 IN ib_node_t *p_node,
\r
248 IN ib_cq_handle_t h_cq );
\r
251 /**********************************************************************
\r
252 **********************************************************************/
\r
256 printf( "\n------- cmtest - Usage and options ----------------------\n" );
\r
257 printf( "Usage: cmtest [options]\n");
\r
258 printf( "Options:\n" );
\r
261 " This option directs cmtest to act as a Server\n" );
\r
262 printf( "-l <lid>\n"
\r
264 " This option specifies the local endpoint.\n" );
\r
265 printf( "-r <lid>\n"
\r
267 " This option specifies the remote endpoint.\n" );
\r
268 printf( "-c <number>\n"
\r
269 "--connect <number>\n"
\r
270 " This option specifies the number of connections to open.\n"
\r
271 " Default of 1.\n" );
\r
272 printf( "-m <bytes>\n"
\r
273 "--msize <bytes>\n"
\r
274 " This option specifies the byte size of each message.\n"
\r
275 " Default is 100 bytes.\n" );
\r
276 printf( "-n <number>\n"
\r
277 "--nmsgs <number>\n"
\r
278 " This option specifies the number of messages to send at a time.\n" );
\r
281 " This option indicates if a separate buffer should be used per message.\n"
\r
282 " Default is one buffer for all messages.\n" );
\r
283 printf( "-i <number>\n"
\r
284 "--iterate <number>\n"
\r
285 " This option specifies the number of times to loop through 'nmsgs'.\n"
\r
286 " Default of 1.\n" );
\r
289 " This option enables verbosity level to debug console.\n" );
\r
292 " Display this usage info then exit.\n\n" );
\r
296 /* Windows support. */
\r
299 const char *long_name;
\r
300 unsigned long flag;
\r
305 static char *optarg;
\r
307 #define strtoull strtoul
\r
314 const char *short_option,
\r
315 const struct option *long_option,
\r
322 UNUSED_PARAM( unused );
\r
327 if( argv[i][0] != '-' )
\r
330 /* find the first character of the value. */
\r
331 for( j = 1; isalpha( argv[i][j] ); j++ )
\r
333 optarg = &argv[i][j];
\r
335 if( argv[i][1] == '-' )
\r
338 for( j = 0; long_option[j].long_name; j++ )
\r
340 if( strncmp( &argv[i][2], long_option[j].long_name,
\r
341 optarg - argv[i] - 2 ) )
\r
346 switch( long_option[j].flag )
\r
349 if( *optarg == '\0' )
\r
354 ret = long_option[j].short_name;
\r
360 for( j = 0; short_option[j] != '\0'; j++ )
\r
362 if( !isalpha( short_option[j] ) )
\r
365 if( short_option[j] == argv[i][1] )
\r
367 ret = short_option[j];
\r
371 if( short_option[j+1] == ':' )
\r
373 if( *optarg == '\0' )
\r
389 uint32_t next_option;
\r
390 const char* const short_option = "esl:r:c:m:n:i:pvh";
\r
393 In the array below, the 2nd parameter specified the number
\r
394 of arguments as follows:
\r
399 const struct option long_option[] =
\r
401 { "event", 2, NULL, 'e'},
\r
402 { "server", 2, NULL, 's'},
\r
403 { "local", 1, NULL, 'l'},
\r
404 { "remote", 1, NULL, 'r'},
\r
405 { "connect", 1, NULL, 'c'},
\r
406 { "msize", 1, NULL, 'm'},
\r
407 { "nmsgs", 1, NULL, 'n'},
\r
408 { "iterate", 1, NULL, 'i'},
\r
409 { "permsg", 0, NULL, 'p'},
\r
410 { "verbose", 0, NULL, 'v'},
\r
411 { "help", 0, NULL, 'h'},
\r
412 { NULL, 0, NULL, 0 } /* Required at end of array */
\r
415 /* Set the default options. */
\r
416 g_root.msg_size = 100;
\r
417 g_root.num_nodes = 1;
\r
418 g_root.num_msgs = 0;
\r
419 g_root.num_iter = 1;
\r
420 g_root.is_polling = TRUE;
\r
422 /* parse cmd line arguments as input params */
\r
425 next_option = getopt_long( argc, argv, short_option,
\r
426 long_option, NULL );
\r
428 switch( next_option )
\r
431 g_root.is_server = TRUE;
\r
432 printf( "\tServer mode\n" );
\r
436 g_root.inst_id = strtoull( optarg, NULL, 0 );
\r
437 printf( "\tinstance_id..: %d\n", g_root.inst_id );
\r
441 g_root.num_nodes = strtoull( optarg, NULL, 0 );
\r
442 printf( "\tconnections..: %d\n", g_root.num_nodes );
\r
446 g_root.l_lid = cl_ntoh16( (uint16_t)strtoull( optarg, NULL, 0 ) );
\r
447 printf( "\tlocal lid....: x%x\n", g_root.l_lid );
\r
451 g_root.r_lid = cl_ntoh16( (uint16_t)strtoull( optarg, NULL, 0 ) );
\r
452 printf( "\tremote lid...: x%x\n", g_root.r_lid );
\r
456 g_root.msg_size = strtoull( optarg, NULL, 0 );
\r
457 printf( "\tmsg size.....: %d bytes\n", g_root.msg_size );
\r
461 g_root.num_msgs = strtoull( optarg, NULL, 0 );
\r
462 printf( "\tnum msgs.....: %d\n", g_root.num_msgs );
\r
466 g_root.num_iter = strtoull( optarg, NULL, 0 );
\r
467 printf( "\titerate......: %d\n", g_root.num_iter );
\r
471 g_root.per_msg_buf = TRUE;
\r
472 printf( "\tper message data buffer\n" );
\r
476 cmt_dbg_lvl = 0xFFFFFFFF;
\r
477 printf( "\tverbose\n" );
\r
481 g_root.is_polling = FALSE;
\r
482 printf( "\tevent driven completions\n" );
\r
492 default: /* something wrong */
\r
496 } while( next_option != -1 );
\r
502 /**********************************************************************
\r
503 **********************************************************************/
\r
507 /* Initialize connection request parameters. */
\r
508 g_root.cm_req.svc_id = CMT_BASE_SVC_ID + g_root.inst_id;
\r
509 g_root.cm_req.max_cm_retries = 5;
\r
510 g_root.cm_req.p_primary_path = &g_root.path_rec;
\r
511 g_root.cm_req.pfn_cm_rep_cb = __rep_cb;
\r
512 g_root.cm_req.qp_type = IB_QPT_RELIABLE_CONN;
\r
513 g_root.cm_req.resp_res = 3;
\r
514 g_root.cm_req.init_depth = 1;
\r
515 g_root.cm_req.remote_resp_timeout = 20;
\r
516 g_root.cm_req.flow_ctrl = TRUE;
\r
517 g_root.cm_req.local_resp_timeout = 20;
\r
518 g_root.cm_req.rnr_nak_timeout = 6;
\r
519 g_root.cm_req.rnr_retry_cnt = 3;
\r
520 g_root.cm_req.retry_cnt = 5;
\r
521 g_root.cm_req.pfn_cm_mra_cb = __mra_cb;
\r
522 g_root.cm_req.pfn_cm_rej_cb = __rej_cb;
\r
524 /* Initialize connection reply parameters. */
\r
525 g_root.cm_rep.qp_type = IB_QPT_RELIABLE_CONN;
\r
526 g_root.cm_rep.access_ctrl = CMT_ACCESS_CTRL;
\r
527 g_root.cm_rep.sq_depth = 0;
\r
528 g_root.cm_rep.rq_depth = 0;
\r
529 g_root.cm_rep.init_depth = 1;
\r
530 g_root.cm_rep.target_ack_delay = 7;
\r
531 g_root.cm_rep.failover_accepted = IB_FAILOVER_ACCEPT_UNSUPPORTED;
\r
532 g_root.cm_rep.flow_ctrl = TRUE;
\r
533 g_root.cm_rep.rnr_nak_timeout = 7;
\r
534 g_root.cm_rep.rnr_retry_cnt = 6;
\r
535 g_root.cm_rep.pfn_cm_rej_cb = __rej_cb;
\r
536 g_root.cm_rep.pfn_cm_mra_cb = __mra_cb;
\r
537 g_root.cm_rep.pfn_cm_rtu_cb = __rtu_cb;
\r
538 g_root.cm_rep.pfn_cm_lap_cb = __lap_cb;
\r
539 g_root.cm_rep.pfn_cm_dreq_cb = __dreq_cb;
\r
541 /* Initialize connection RTU parameters. */
\r
542 g_root.cm_rtu.pfn_cm_apr_cb = __apr_cb;
\r
543 g_root.cm_rtu.pfn_cm_dreq_cb = __dreq_cb;
\r
545 /* Initialize disconnection request parameters. */
\r
546 g_root.cm_dreq.pfn_cm_drep_cb = __drep_cb;
\r
547 g_root.cm_dreq.qp_type = IB_QPT_RELIABLE_CONN;
\r
549 /* Disconnection reply parameters are all zero. */
\r
559 for( i = 0; i < g_root.num_pkeys; i++ )
\r
561 if( g_root.p_pkey_table[i] == g_root.path_rec.pkey )
\r
565 return BAD_PKEY_INDEX;
\r
573 /* Set common QP attributes for all create calls. */
\r
574 g_root.qp_create.qp_type = IB_QPT_RELIABLE_CONN;
\r
575 if( g_root.num_msgs )
\r
577 g_root.qp_create.sq_depth = g_root.num_msgs;
\r
578 g_root.qp_create.rq_depth = g_root.num_msgs;
\r
582 /* Minimal queue depth of one. */
\r
583 g_root.qp_create.sq_depth = 1;
\r
584 g_root.qp_create.rq_depth = 1;
\r
587 g_root.qp_create.sq_signaled = FALSE;
\r
588 g_root.qp_create.sq_sge = 1;
\r
589 g_root.qp_create.rq_sge = 1;
\r
591 /* Set the QP attributes when modifying the QP to the reset state. */
\r
592 g_root.qp_mod_reset.req_state = IB_QPS_RESET;
\r
594 /* Set the QP attributes when modifying the QP to the init state. */
\r
595 g_root.qp_mod_init.req_state = IB_QPS_INIT;
\r
596 g_root.qp_mod_init.state.init.access_ctrl = CMT_ACCESS_CTRL;
\r
597 g_root.qp_mod_init.state.init.primary_port = g_root.port_num;
\r
598 g_root.qp_mod_init.state.init.pkey_index = __get_pkey_index();
\r
603 static ib_api_status_t
\r
605 IN ib_node_t *p_node )
\r
607 ib_api_status_t status = IB_SUCCESS;
\r
608 ib_recv_wr_t recv_wr;
\r
609 ib_recv_wr_t *p_recv_failure;
\r
610 ib_local_ds_t ds_array;
\r
613 CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );
\r
615 if( !g_root.num_msgs )
\r
617 CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );
\r
621 cl_memclr( &recv_wr, sizeof( ib_recv_wr_t ) );
\r
622 ds_array.length = g_root.msg_size;
\r
623 ds_array.lkey = g_root.lkey;
\r
624 recv_wr.ds_array = &ds_array;
\r
625 recv_wr.num_ds = (( g_root.msg_size <= 4 )? 0: 1 );
\r
627 for( i = 0; i < g_root.num_msgs; i++ )
\r
629 CL_PRINT( CMT_DBG_VERBOSE, cmt_dbg_lvl, (".") );
\r
631 if( g_root.per_msg_buf )
\r
633 ds_array.vaddr = (uintn_t)(g_root.p_mem_recv + (i * g_root.msg_size) +
\r
634 (p_node->id * g_root.num_msgs * g_root.msg_size));
\r
638 ds_array.vaddr = (uintn_t)g_root.p_mem;
\r
643 status = ib_post_recv( p_node->h_qp, &recv_wr, &p_recv_failure );
\r
644 if( status != IB_SUCCESS )
\r
646 printf( "ib_post_recv failed [%s]!\n", ib_get_err_str(status) );
\r
651 CL_PRINT( CMT_DBG_VERBOSE, cmt_dbg_lvl, ("\n") );
\r
652 CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );
\r
659 __ca_async_event_cb(
\r
660 ib_async_event_rec_t *p_err_rec )
\r
662 CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );
\r
664 CL_TRACE( CMT_DBG_VERBOSE, cmt_dbg_lvl,
\r
665 ( "p_err_rec->code is %d\n", p_err_rec->code ) );
\r
667 CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );
\r
673 __cm_listen_err_cb(
\r
674 IN ib_listen_err_rec_t *p_listen_err_rec )
\r
676 CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );
\r
677 if( !p_listen_err_rec )
\r
678 printf( "__listen_err_cb NULL p_listen_err_rec\n" );
\r
679 CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );
\r
685 __cancel_listen_cb(
\r
688 CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );
\r
690 printf( "__cancel_listen_cb NULL context\n" );
\r
691 CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );
\r
696 /* We need to halt the test and recover from the reject error. */
\r
699 IN ib_cm_rej_rec_t *p_cm_rej_rec )
\r
701 CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );
\r
704 * Note - because this callback exits the app, any output beyond the
\r
705 * the first time may report junk. There have been instances where
\r
706 * the callback is invoked more times than there are connection requests
\r
707 * but that behavior disapeared if the call to exit below is removed.
\r
709 printf( "Connection was rejected, status: 0x%x\n",
\r
710 p_cm_rej_rec->rej_status );
\r
712 CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );
\r
720 IN ib_cm_req_rec_t *p_cm_req_rec )
\r
722 ib_api_status_t status;
\r
725 CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );
\r
727 CL_ASSERT( p_cm_req_rec );
\r
729 /* Record the starting time for the server. */
\r
730 if( !g_root.conn_start_time )
\r
731 g_root.conn_start_time = cl_get_time_stamp( );
\r
734 * Do not send replies until the server is ready to establish all
\r
737 cl_mutex_acquire( &g_root.mutex );
\r
738 p_node = &g_root.p_nodes[g_root.conn_index++];
\r
740 if( g_root.state == test_connecting )
\r
742 /* Get a node for this connection and send the reply. */
\r
743 g_root.cm_rep.h_qp = p_node->h_qp;
\r
744 status = ib_cm_rep( p_cm_req_rec->h_cm_req, &g_root.cm_rep );
\r
745 if( status != IB_SUCCESS )
\r
747 printf( "Call to ib_cm_rep failed\n" );
\r
753 p_node->h_cm_req = p_cm_req_rec->h_cm_req;
\r
755 cl_mutex_release( &g_root.mutex );
\r
757 CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );
\r
764 IN ib_cm_rep_rec_t *p_cm_rep_rec )
\r
766 ib_api_status_t status;
\r
768 uint8_t pdata[IB_RTU_PDATA_SIZE];
\r
771 CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );
\r
772 CL_ASSERT( p_cm_rep_rec );
\r
774 p_node = (ib_node_t*)p_cm_rep_rec->qp_context;
\r
775 CL_ASSERT( p_node );
\r
777 mra.p_mra_pdata = NULL;
\r
778 mra.mra_length = 0;
\r
779 mra.svc_timeout = 0xff;
\r
781 ib_cm_mra( p_cm_rep_rec->h_cm_rep, &mra );
\r
783 __post_recvs( p_node );
\r
785 /* Mark that we're connected before sending the RTU. */
\r
786 p_node->state = node_conn;
\r
788 g_root.cm_rtu.p_rtu_pdata = pdata;
\r
789 g_root.cm_rtu.rtu_length = IB_RTU_PDATA_SIZE;
\r
791 status = ib_cm_rtu( p_cm_rep_rec->h_cm_rep, &g_root.cm_rtu );
\r
792 if( status != IB_SUCCESS )
\r
794 printf( "Call to ib_cm_rtu returned %s\n", ib_get_err_str( status ) );
\r
798 cl_atomic_inc( &g_root.num_connected );
\r
800 CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );
\r
807 IN ib_cm_rtu_rec_t *p_cm_rtu_rec )
\r
811 CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );
\r
812 CL_ASSERT( p_cm_rtu_rec );
\r
814 p_node = (ib_node_t*)p_cm_rtu_rec->qp_context;
\r
815 p_node->state = node_conn;
\r
817 __post_recvs( p_node );
\r
818 cl_atomic_inc( &g_root.num_connected );
\r
820 CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );
\r
827 IN ib_cm_mra_rec_t *p_cm_mra_rec )
\r
829 CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );
\r
830 CL_ASSERT( p_cm_mra_rec );
\r
831 CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );
\r
838 IN ib_cm_apr_rec_t *p_cm_apr_rec )
\r
840 CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );
\r
841 CL_ASSERT( p_cm_apr_rec );
\r
842 CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );
\r
849 IN ib_cm_lap_rec_t *p_cm_lap_rec )
\r
851 CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );
\r
852 CL_ASSERT( p_cm_lap_rec );
\r
853 CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );
\r
860 IN ib_cm_dreq_rec_t *p_cm_dreq_rec )
\r
863 ib_api_status_t status;
\r
865 CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );
\r
866 CL_ASSERT( p_cm_dreq_rec );
\r
867 p_node = (ib_node_t*)p_cm_dreq_rec->qp_context;
\r
868 CL_ASSERT( p_node );
\r
871 * Record that we've already received a DREQ to avoid trying to
\r
872 * disconnect the QP a second time. Synchronize with the DREQ call
\r
875 cl_mutex_acquire( &g_root.mutex );
\r
877 /* If we need to send or receive more data, don't disconnect yet. */
\r
878 if( g_root.state == test_disconnecting )
\r
880 /* Send the DREP. */
\r
881 status = ib_cm_drep( p_cm_dreq_rec->h_cm_dreq, &g_root.cm_drep );
\r
883 /* If the DREP was successful, we're done with this connection. */
\r
884 if( status == IB_SUCCESS )
\r
886 p_node->state = node_idle;
\r
887 cl_atomic_dec( &g_root.num_connected );
\r
892 /* Record that we need to disconnect, but don't send the DREP yet. */
\r
893 p_node->state = node_dreq_rcvd;
\r
894 p_node->h_cm_dreq = p_cm_dreq_rec->h_cm_dreq;
\r
896 cl_mutex_release( &g_root.mutex );
\r
898 CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );
\r
905 IN ib_cm_drep_rec_t *p_cm_drep_rec )
\r
909 CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );
\r
910 CL_ASSERT( p_cm_drep_rec );
\r
911 p_node = (ib_node_t*)p_cm_drep_rec->qp_context;
\r
912 CL_ASSERT( p_node );
\r
914 /* We're done with this connection. */
\r
915 cl_mutex_acquire( &g_root.mutex );
\r
916 p_node->state = node_idle;
\r
917 cl_atomic_dec( &g_root.num_connected );
\r
918 cl_mutex_release( &g_root.mutex );
\r
920 CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );
\r
927 IN const ib_cq_handle_t h_cq,
\r
928 IN void* cq_context )
\r
930 ib_node_t *p_node = (ib_node_t*)cq_context;
\r
932 CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );
\r
933 if( !g_root.is_polling )
\r
935 if( !__poll_cq( p_node, h_cq ) )
\r
938 CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );
\r
942 static ib_api_status_t
\r
944 IN ib_node_t *p_node )
\r
946 ib_api_status_t status;
\r
949 /* Set the per node QP attributes. */
\r
950 g_root.qp_create.h_sq_cq = p_node->h_send_cq;
\r
951 g_root.qp_create.h_rq_cq = p_node->h_recv_cq;
\r
953 /* Allocate the QP. */
\r
954 status = ib_create_qp( g_root.h_pd, &g_root.qp_create, p_node, NULL,
\r
956 if( status != IB_SUCCESS )
\r
958 printf( "[%d] ib_create_qp failed [%s]!\n", __LINE__,
\r
959 ib_get_err_str(status) );
\r
963 /* Store the max inline size. */
\r
964 status = ib_query_qp( p_node->h_qp, &attr );
\r
965 if( status != IB_SUCCESS )
\r
966 p_node->max_inline = 0;
\r
968 p_node->max_inline = attr.sq_max_inline;
\r
971 * Transition the QP to the initialize state. This prevents the CM
\r
972 * from having to make this QP transition and improves the connection
\r
973 * establishment rate.
\r
975 status = ib_modify_qp( p_node->h_qp, &g_root.qp_mod_reset );
\r
976 if( status != IB_SUCCESS )
\r
978 printf( "ib_modify_qp to IB_QPS_RESET returned %s\n",
\r
979 ib_get_err_str(status) );
\r
983 status = ib_modify_qp( p_node->h_qp, &g_root.qp_mod_init );
\r
984 if( status != IB_SUCCESS )
\r
986 printf( "ib_modify_qp to IB_QPS_INIT returned %s\n",
\r
987 ib_get_err_str(status) );
\r
997 * Allocate new QPs for all nodes.
\r
999 static ib_api_status_t
\r
1002 uint64_t start_time, total_time;
\r
1004 ib_api_status_t status;
\r
1006 printf( "Creating QPs...\n" );
\r
1007 start_time = cl_get_time_stamp();
\r
1009 for( i = 0; i < g_root.num_nodes; i++ )
\r
1011 /* Allocate a new QP. */
\r
1012 status = __create_qp( &g_root.p_nodes[i] );
\r
1013 if( status != IB_SUCCESS )
\r
1017 total_time = cl_get_time_stamp() - start_time;
\r
1018 printf( "Allocation time: %"PRId64" ms\n", total_time/1000 );
\r
1026 * Destroy all QPs for all nodes.
\r
1031 uint64_t start_time, total_time;
\r
1034 printf( "Destroying QPs...\n" );
\r
1035 start_time = cl_get_time_stamp();
\r
1037 for( i = 0; i < g_root.num_nodes; i++ )
\r
1039 /* Destroy the QP. */
\r
1040 if( g_root.p_nodes[i].h_qp )
\r
1042 ib_destroy_qp( g_root.p_nodes[i].h_qp, ib_sync_destroy );
\r
1043 g_root.p_nodes[i].h_qp = NULL;
\r
1047 total_time = cl_get_time_stamp() - start_time;
\r
1048 printf( "Destruction time: %"PRId64" ms\n", total_time/1000 );
\r
1055 IN OUT ib_node_t* p_node )
\r
1057 ib_api_status_t status;
\r
1058 ib_cq_create_t cq_create;
\r
1060 CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );
\r
1062 /* Create the CQs. */
\r
1063 cl_memclr( &cq_create, sizeof(ib_cq_create_t) );
\r
1064 if( g_root.num_msgs )
\r
1065 cq_create.size = g_root.num_msgs;
\r
1067 cq_create.size = 1; /* minimal of one entry */
\r
1069 cq_create.pfn_comp_cb = __cq_cb;
\r
1070 status = ib_create_cq( g_root.h_ca, &cq_create, p_node, NULL,
\r
1071 &p_node->h_send_cq );
\r
1072 if( status != IB_SUCCESS )
\r
1074 printf( "ib_create_cq failed for send CQ [%s]!\n",
\r
1075 ib_get_err_str(status) );
\r
1078 if( !g_root.is_polling )
\r
1080 status = ib_rearm_cq( p_node->h_send_cq, FALSE );
\r
1081 if( status != IB_SUCCESS )
\r
1083 printf( "ib_rearm_cq failed for send CQ [%s]!\n",
\r
1084 ib_get_err_str(status) );
\r
1089 status = ib_create_cq( g_root.h_ca, &cq_create, p_node, NULL,
\r
1090 &p_node->h_recv_cq );
\r
1091 if( status != IB_SUCCESS )
\r
1093 printf( "ib_create_cq failed for recv CQ [%s]!\n",
\r
1094 ib_get_err_str(status) );
\r
1097 if( !g_root.is_polling )
\r
1099 status = ib_rearm_cq( p_node->h_recv_cq, FALSE );
\r
1100 if( status != IB_SUCCESS )
\r
1102 printf( "ib_rearm_cq failed for recv CQ [%s]!\n",
\r
1103 ib_get_err_str(status) );
\r
1108 CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );
\r
1114 IN OUT ib_node_t* p_node )
\r
1116 ib_api_status_t status = IB_SUCCESS;
\r
1117 CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );
\r
1120 if ( p_node->h_send_cq )
\r
1122 status = ib_destroy_cq( p_node->h_send_cq, ib_sync_destroy );
\r
1123 p_node->h_send_cq = NULL;
\r
1124 if( status != IB_SUCCESS )
\r
1126 printf( "ib_destroy_cq failed for send CQ [%s]!\n",
\r
1127 ib_get_err_str(status) );
\r
1130 if (p_node->h_recv_cq)
\r
1132 status = ib_destroy_cq( p_node->h_recv_cq, ib_sync_destroy );
\r
1133 p_node->h_recv_cq = NULL;
\r
1134 if( status != IB_SUCCESS )
\r
1136 printf( "ib_destroy_cq failed for recv CQ [%s]!\n",
\r
1137 ib_get_err_str(status) );
\r
1141 CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );
\r
1142 return (status == IB_SUCCESS);
\r
1152 CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );
\r
1153 for( i = 0; i < g_root.num_nodes; i++ )
\r
1155 g_root.p_nodes[i].id = i;
\r
1157 CL_PRINT( CMT_DBG_VERBOSE, cmt_dbg_lvl,
\r
1158 ("--> create connection %d of instance %d\n", i, g_root.inst_id) );
\r
1160 if( !__init_node( &g_root.p_nodes[i] ) )
\r
1164 CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );
\r
1173 CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );
\r
1175 for( i = 0; i < g_root.num_nodes; i++ )
\r
1177 if( !__destroy_node( &g_root.p_nodes[i] ) )
\r
1180 CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );
\r
1184 /* query function called by ib_query() */
\r
1187 IN ib_query_rec_t *p_query_rec )
\r
1189 ib_path_rec_t *p_path;
\r
1190 ib_api_status_t status;
\r
1192 CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );
\r
1194 CL_ASSERT( p_query_rec );
\r
1196 if( p_query_rec->status != IB_SUCCESS )
\r
1198 printf( "ib_query failed [%d]\n", p_query_rec->status );
\r
1202 if( p_query_rec->query_type != IB_QUERY_PATH_REC_BY_LIDS )
\r
1204 printf( "Unexpected query type returned.\n" );
\r
1208 if( !p_query_rec->p_result_mad )
\r
1210 printf( "No result MAD returned from ib_query.\n" );
\r
1214 /* copy the 1st (zero'th) path record to local storage. */
\r
1215 p_path = ib_get_query_path_rec( p_query_rec->p_result_mad, 0 );
\r
1216 memcpy( (void*)&g_root.path_rec, (void*)p_path,
\r
1217 sizeof(ib_path_rec_t) );
\r
1219 CL_TRACE( CMT_DBG_VERBOSE, cmt_dbg_lvl,
\r
1220 ( "path{ slid:0x%x, dlid:0x%x }\n",
\r
1221 g_root.path_rec.slid, g_root.path_rec.dlid) );
\r
1223 /* release response MAD(s) back to AL pool */
\r
1224 if( p_query_rec->p_result_mad )
\r
1226 status = ib_put_mad( p_query_rec->p_result_mad );
\r
1227 if( status != IB_SUCCESS )
\r
1229 printf( "ib_put_mad() failed [%s]\n",
\r
1230 ib_get_err_str(status) );
\r
1234 CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );
\r
1240 __query_for_path()
\r
1242 ib_api_status_t status;
\r
1243 ib_query_req_t query_rec;
\r
1244 ib_lid_pair_t lid_pair;
\r
1246 /* Query the SA for a path record. */
\r
1247 query_rec.query_type = IB_QUERY_PATH_REC_BY_LIDS;
\r
1249 lid_pair.src_lid = g_root.l_lid;
\r
1250 lid_pair.dest_lid = g_root.r_lid;
\r
1252 query_rec.p_query_input = (void*)&lid_pair;
\r
1253 query_rec.port_guid = g_root.port_guid;
\r
1254 query_rec.timeout_ms = 5 * 1000; // seconds
\r
1255 query_rec.retry_cnt = 2;
\r
1256 query_rec.flags = IB_FLAGS_SYNC;
\r
1257 query_rec.query_context = &g_root;
\r
1258 query_rec.pfn_query_cb = __sa_query_cb;
\r
1260 status = ib_query( g_root.h_al, &query_rec, NULL );
\r
1261 if( ( status != IB_SUCCESS ) || ( !g_root.path_rec.dlid ) )
\r
1263 printf( "ib_query failed.\n" );
\r
1273 __create_messages()
\r
1275 ib_mr_create_t mr_create;
\r
1276 uint32_t buf_size;
\r
1277 ib_api_status_t status;
\r
1279 /* If we're not sending messages, just return. */
\r
1280 if( !g_root.num_msgs || !g_root.msg_size )
\r
1283 /* Allocate the message memory - we ignore the data, so just one buffer. */
\r
1284 if( g_root.per_msg_buf )
\r
1285 buf_size = (g_root.num_nodes * g_root.num_msgs * g_root.msg_size) << 1;
\r
1287 buf_size = g_root.msg_size;
\r
1288 g_root.p_mem = cl_zalloc( buf_size );
\r
1289 if( !g_root.p_mem )
\r
1291 printf( "Not enough memory for transfers!\n" );
\r
1294 memset (g_root.p_mem, 0xae, buf_size);
\r
1295 g_root.p_mem_recv = g_root.p_mem;
\r
1296 g_root.p_mem_send = g_root.p_mem + (buf_size >> 1);
\r
1298 /* Register the memory with AL. */
\r
1299 mr_create.vaddr = g_root.p_mem;
\r
1300 mr_create.length = buf_size;
\r
1301 mr_create.access_ctrl = IB_AC_LOCAL_WRITE | IB_AC_MW_BIND;
\r
1302 status = ib_reg_mem( g_root.h_pd, &mr_create, &g_root.lkey,
\r
1303 &g_root.rkey, &g_root.h_mr );
\r
1304 if( status != IB_SUCCESS )
\r
1306 printf( "ib_reg_mem failed [%s]!\n", ib_get_err_str(status) );
\r
1316 * PnP callback handler. Record the port GUID of an active port.
\r
1318 static ib_api_status_t
\r
1320 IN ib_pnp_rec_t *p_pnp_rec )
\r
1322 ib_pnp_port_rec_t* p_port_rec;
\r
1325 p_port_rec = (ib_pnp_port_rec_t*)p_pnp_rec;
\r
1328 * Ignore PNP events that are not related to port active, or if
\r
1329 * we already have an active port.
\r
1331 if( p_pnp_rec->pnp_event != IB_PNP_PORT_ACTIVE || g_root.port_guid )
\r
1332 return IB_SUCCESS;
\r
1334 /* Find the proper port for the given local LID. */
\r
1335 if( g_root.l_lid )
\r
1337 if( g_root.l_lid != p_port_rec->p_port_attr->lid )
\r
1338 return IB_SUCCESS;
\r
1342 g_root.l_lid = p_port_rec->p_port_attr->lid;
\r
1343 printf( "\tlocal lid....: x%x\n", g_root.l_lid );
\r
1346 /* Record the active port information. */
\r
1347 g_root.ca_guid = p_port_rec->p_ca_attr->ca_guid;
\r
1348 g_root.port_num = p_port_rec->p_port_attr->port_num;
\r
1350 /* Record the PKEYs available on the active port. */
\r
1351 size = sizeof( ib_net16_t ) * p_port_rec->p_port_attr->num_pkeys;
\r
1352 g_root.p_pkey_table = cl_zalloc( size );
\r
1353 if( !g_root.p_pkey_table )
\r
1354 return IB_SUCCESS;
\r
1355 g_root.num_pkeys = p_port_rec->p_port_attr->num_pkeys;
\r
1356 cl_memcpy( g_root.p_pkey_table,
\r
1357 p_port_rec->p_port_attr->p_pkey_table, size );
\r
1359 /* Set the port_guid last to indicate that we're ready. */
\r
1360 g_root.port_guid = p_port_rec->p_port_attr->port_guid;
\r
1361 return IB_SUCCESS;
\r
1366 * Register for PnP events and wait until a port becomes active.
\r
1371 ib_api_status_t status;
\r
1372 ib_pnp_req_t pnp_req;
\r
1373 ib_pnp_handle_t h_pnp;
\r
1375 cl_memclr( &pnp_req, sizeof( ib_pnp_req_t ) );
\r
1376 pnp_req.pnp_class = IB_PNP_PORT;
\r
1377 pnp_req.pnp_context = &g_root;
\r
1378 pnp_req.pfn_pnp_cb = __pnp_cb;
\r
1380 /* Register for PnP events. */
\r
1381 status = ib_reg_pnp( g_root.h_al, &pnp_req, &h_pnp );
\r
1382 if( status != IB_SUCCESS )
\r
1384 printf( "ib_reg_pnp failed [%s]!\n", ib_get_err_str(status) );
\r
1388 /* Wait until a port goes active. */
\r
1389 while( !g_root.port_guid )
\r
1390 cl_thread_suspend( 10 );
\r
1392 /* Deregister from PnP. */
\r
1393 ib_dereg_pnp( h_pnp, NULL );
\r
1403 ib_api_status_t status;
\r
1405 CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );
\r
1407 cl_mutex_construct( &g_root.mutex );
\r
1408 if( cl_mutex_init( &g_root.mutex ) != CL_SUCCESS )
\r
1412 status = ib_open_al( &g_root.h_al );
\r
1413 if( status != IB_SUCCESS )
\r
1415 printf( "ib_open_al failed [%s]!\n", ib_get_err_str(status) );
\r
1419 /* Register for PnP events, and wait until we have an active port. */
\r
1420 if( !__reg_pnp() )
\r
1423 /* Open the CA. */
\r
1424 status = ib_open_ca( g_root.h_al, g_root.ca_guid,
\r
1425 __ca_async_event_cb, &g_root, &g_root.h_ca );
\r
1426 if( status != IB_SUCCESS )
\r
1428 printf( "ib_open_ca failed [%s]!\n", ib_get_err_str(status) );
\r
1432 /* Create a PD. */
\r
1433 status = ib_alloc_pd( g_root.h_ca, IB_PDT_NORMAL, &g_root,
\r
1435 if( status != IB_SUCCESS )
\r
1437 printf( "ib_alloc_pd failed [%s]!\n", ib_get_err_str(status) );
\r
1441 /* Get a path record to the remote side. */
\r
1442 if( !__query_for_path() )
\r
1444 printf( "Unable to query for path record!\n" );
\r
1448 /* Allocate and register memory for the messages. */
\r
1449 if( !__create_messages() )
\r
1451 printf( "Unable to create messages!\n" );
\r
1455 /* Create the connection endpoints. */
\r
1456 g_root.p_nodes = (ib_node_t*)cl_zalloc(
\r
1457 sizeof(ib_node_t) * g_root.num_nodes );
\r
1458 if( !g_root.p_nodes )
\r
1460 printf( "Unable to allocate nodes\n" );
\r
1464 CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );
\r
1473 if( g_root.h_listen )
\r
1474 ib_cm_cancel( g_root.h_listen, __cancel_listen_cb );
\r
1476 /* Close AL if it was opened. */
\r
1478 ib_close_al( g_root.h_al );
\r
1480 cl_mutex_destroy( &g_root.mutex );
\r
1482 if( g_root.p_mem )
\r
1483 cl_free( g_root.p_mem );
\r
1485 if( g_root.p_pkey_table )
\r
1486 cl_free( g_root.p_pkey_table );
\r
1488 /* Free all allocated memory. */
\r
1489 if( g_root.p_nodes )
\r
1490 cl_free( g_root.p_nodes );
\r
1496 * Have the server start listening for connections.
\r
1501 ib_cm_listen_t cm_listen;
\r
1502 ib_api_status_t status;
\r
1504 cl_memclr( &cm_listen, sizeof( ib_cm_listen_t ) );
\r
1506 /* The server side listens. */
\r
1507 cm_listen.svc_id = CMT_BASE_SVC_ID + g_root.inst_id;
\r
1509 cm_listen.pfn_cm_req_cb = __req_cb;
\r
1511 cm_listen.qp_type = IB_QPT_RELIABLE_CONN;
\r
1513 status = ib_cm_listen( g_root.h_al, &cm_listen,
\r
1514 __cm_listen_err_cb, &g_root, &g_root.h_listen );
\r
1515 if( status != IB_SUCCESS )
\r
1517 printf( "ib_cm_listen failed [%s]!\n", ib_get_err_str(status) );
\r
1526 * Initiate all client connection requests.
\r
1528 static ib_api_status_t
\r
1531 ib_api_status_t status;
\r
1533 uint8_t pdata[IB_REQ_PDATA_SIZE];
\r
1535 g_root.cm_req.p_req_pdata = pdata;
\r
1536 g_root.cm_req.req_length = IB_REQ_PDATA_SIZE;
\r
1538 /* Request a connection for each client. */
\r
1539 for( i = 0; i < g_root.num_nodes; i++ )
\r
1541 g_root.cm_req.h_qp = g_root.p_nodes[i].h_qp;
\r
1543 status = ib_cm_req( &g_root.cm_req );
\r
1544 if( status != IB_SUCCESS )
\r
1546 printf( "ib_cm_req failed [%s]!\n", ib_get_err_str(status) );
\r
1550 return IB_SUCCESS;
\r
1556 * Send any connection replies waiting to be sent.
\r
1558 static ib_api_status_t
\r
1561 ib_api_status_t status;
\r
1563 uint8_t pdata[IB_REP_PDATA_SIZE];
\r
1565 g_root.cm_rep.p_rep_pdata = pdata;
\r
1566 g_root.cm_rep.rep_length = IB_REP_PDATA_SIZE;
\r
1568 /* Send a reply for each connection that requires one. */
\r
1569 for( i = 0; i < g_root.conn_index; i++ )
\r
1571 g_root.cm_rep.h_qp = g_root.p_nodes[i].h_qp;
\r
1572 status = ib_cm_rep( g_root.p_nodes[i].h_cm_req, &g_root.cm_rep );
\r
1573 if( status != IB_SUCCESS )
\r
1575 printf( "ib_cm_rep failed [%s]!\n", ib_get_err_str(status) );
\r
1579 return IB_SUCCESS;
\r
1585 * Establish all connections.
\r
1587 static ib_api_status_t
\r
1590 uint64_t total_time;
\r
1591 ib_api_status_t status;
\r
1593 CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );
\r
1595 printf( "Connecting...\n" );
\r
1596 cl_mutex_acquire( &g_root.mutex );
\r
1597 g_root.state = test_connecting;
\r
1599 /* Initiate the connections. */
\r
1600 if( g_root.is_server )
\r
1603 * Send any replies. Note that we hold the mutex while sending the
\r
1604 * replies since we need to use the global cm_rep structure.
\r
1606 status = __conn_reps();
\r
1607 cl_mutex_release( &g_root.mutex );
\r
1611 cl_mutex_release( &g_root.mutex );
\r
1612 g_root.conn_start_time = cl_get_time_stamp();
\r
1613 status = __conn_reqs();
\r
1616 if( status != IB_SUCCESS )
\r
1619 /* Wait for all connections to complete. */
\r
1620 while( g_root.num_connected < g_root.num_nodes )
\r
1621 cl_thread_suspend( 0 );
\r
1623 /* Calculate the total connection time. */
\r
1624 total_time = cl_get_time_stamp() - g_root.conn_start_time;
\r
1625 g_root.state = test_idle;
\r
1627 /* Reset connection information for next test. */
\r
1628 g_root.conn_index = 0;
\r
1629 g_root.conn_start_time = 0;
\r
1631 printf( "Connect time: %"PRId64" ms\n", total_time/1000 );
\r
1633 CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );
\r
1642 ib_api_status_t status;
\r
1644 ib_node_t *p_node;
\r
1645 uint64_t total_time, start_time;
\r
1647 printf( "Disconnecting...\n" );
\r
1649 /* Initiate the disconnection process. */
\r
1650 cl_mutex_acquire( &g_root.mutex );
\r
1651 g_root.state = test_disconnecting;
\r
1652 start_time = cl_get_time_stamp();
\r
1653 cl_mutex_release( &g_root.mutex );
\r
1655 /* We hold the mutex to prevent calling ib_cm_drep at the same time. */
\r
1656 for( i = 0; i < g_root.num_nodes; i++ )
\r
1658 p_node = &g_root.p_nodes[i];
\r
1661 * Send the DREQ. Note that some of these may fail, since the
\r
1662 * remote side may be disconnecting at the same time. Call DREQ
\r
1663 * only if we haven't called DREP yet.
\r
1665 cl_mutex_acquire( &g_root.mutex );
\r
1666 switch( p_node->state )
\r
1669 g_root.cm_dreq.h_qp = p_node->h_qp;
\r
1670 status = ib_cm_dreq( &g_root.cm_dreq );
\r
1671 if( status == IB_SUCCESS )
\r
1672 p_node->state = node_dreq_sent;
\r
1675 case node_dreq_rcvd:
\r
1676 status = ib_cm_drep( p_node->h_cm_dreq, &g_root.cm_drep );
\r
1678 /* If the DREP was successful, we're done with this connection. */
\r
1679 if( status == IB_SUCCESS )
\r
1681 p_node->state = node_idle;
\r
1682 cl_atomic_dec( &g_root.num_connected );
\r
1687 /* Node is already disconnected. */
\r
1690 cl_mutex_release( &g_root.mutex );
\r
1693 /* Wait for all disconnections to complete. */
\r
1694 while( g_root.num_connected )
\r
1695 cl_thread_suspend( 0 );
\r
1697 if( g_root.h_listen )
\r
1699 ib_cm_cancel( g_root.h_listen, __cancel_listen_cb );
\r
1700 g_root.h_listen = NULL;
\r
1702 /* Calculate the total connection time. */
\r
1703 total_time = cl_get_time_stamp() - start_time;
\r
1704 g_root.state = test_idle;
\r
1706 printf( "Disconnect time: %"PRId64" ms\n", total_time/1000 );
\r
1712 * Send the requested number of messages on each connection.
\r
1717 ib_api_status_t status;
\r
1720 ib_send_wr_t send_wr;
\r
1721 ib_send_wr_t *p_send_failure;
\r
1722 ib_local_ds_t ds_array;
\r
1724 CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );
\r
1726 /* For each connection... */
\r
1727 for( i = 0; i < g_root.num_nodes; i++ )
\r
1729 /* Send the specified number of messages. */
\r
1730 for( m = 0; m < g_root.num_msgs; m++ )
\r
1732 /* Get the buffer for this message. */
\r
1733 if( g_root.per_msg_buf )
\r
1735 ds_array.vaddr = (uintn_t)(g_root.p_mem_send +
\r
1736 (i * g_root.num_msgs) + (m * g_root.msg_size));
\r
1740 ds_array.vaddr = (uintn_t)g_root.p_mem;
\r
1742 ds_array.length = g_root.msg_size;
\r
1743 ds_array.lkey = g_root.lkey;
\r
1745 /* Format the send WR for this message. */
\r
1746 send_wr.ds_array = &ds_array;
\r
1747 send_wr.send_opt = IB_SEND_OPT_SIGNALED | IB_SEND_OPT_SOLICITED;
\r
1748 send_wr.send_opt |= ((g_root.msg_size <= 4)? IB_SEND_OPT_IMMEDIATE : 0x0 );
\r
1749 send_wr.wr_type = WR_SEND;
\r
1750 send_wr.num_ds = ((g_root.msg_size <= 4)? 0 : 1 );
\r
1751 send_wr.p_next = NULL;
\r
1752 send_wr.wr_id = m;
\r
1754 if( g_root.msg_size < g_root.p_nodes[i].max_inline )
\r
1755 send_wr.send_opt |= IB_SEND_OPT_INLINE;
\r
1757 /* Torpedoes away! Send the message. */
\r
1758 CL_PRINT( CMT_DBG_VERBOSE, cmt_dbg_lvl, (".") );
\r
1759 status = ib_post_send( g_root.p_nodes[i].h_qp, &send_wr,
\r
1760 &p_send_failure );
\r
1761 if( status != IB_SUCCESS )
\r
1763 printf( "ib_post_send failed [%s]!\n",
\r
1764 ib_get_err_str(status) );
\r
1770 CL_PRINT( CMT_DBG_VERBOSE, cmt_dbg_lvl, ("\n") );
\r
1771 CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );
\r
1778 * Remove num_msgs completions from the specified CQ.
\r
1782 IN ib_node_t *p_node,
\r
1783 IN ib_cq_handle_t h_cq )
\r
1785 ib_api_status_t status = IB_SUCCESS;
\r
1786 ib_wc_t free_wc[2];
\r
1787 ib_wc_t *p_free_wc, *p_done_wc;
\r
1789 CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );
\r
1791 while( status != IB_NOT_FOUND )
\r
1793 /* Get all completions. */
\r
1794 p_free_wc = &free_wc[0];
\r
1795 free_wc[0].p_next = &free_wc[1];
\r
1796 free_wc[1].p_next = NULL;
\r
1799 status = ib_poll_cq( h_cq, &p_free_wc, &p_done_wc );
\r
1801 /* Continue polling if nothing is done. */
\r
1802 if( status == IB_NOT_FOUND )
\r
1805 /* Abort if an error occurred. */
\r
1806 if( status != IB_SUCCESS )
\r
1808 printf( "Error polling status = %#x( wc_status =%s)\n",
\r
1810 ((p_done_wc != NULL )? wc_status_text[p_done_wc->status]:"N/A") );
\r
1814 while( p_done_wc )
\r
1816 switch( p_done_wc->status )
\r
1818 case IB_WCS_SUCCESS:
\r
1819 CL_PRINT( CMT_DBG_VERBOSE, cmt_dbg_lvl,
\r
1820 ("Got a completion: \n\ttype....:%s\n\twr_id...:%"PRIx64"\n"
\r
1821 "status....:%s\n", wc_type_text[p_done_wc->wc_type],
\r
1822 p_done_wc->wr_id, wc_status_text[p_done_wc->status] ) );
\r
1824 if( p_done_wc->wc_type == IB_WC_RECV )
\r
1826 CL_ASSERT( p_done_wc->wr_id == p_node->recv_cnt );
\r
1827 if( p_done_wc->length != g_root.msg_size )
\r
1829 printf( "Error: received %d bytes, expected %d.\n",
\r
1830 p_done_wc->length, g_root.msg_size );
\r
1833 p_node->recv_cnt++;
\r
1834 g_root.total_recv++;
\r
1838 CL_ASSERT( p_done_wc->wr_id == p_node->send_cnt );
\r
1839 p_node->send_cnt++;
\r
1840 g_root.total_sent++;
\r
1845 printf( "[%d] Bad completion type(%s) status(%s)\n",
\r
1846 __LINE__, wc_type_text[p_done_wc->wc_type],
\r
1847 wc_status_text[p_done_wc->status] );
\r
1850 p_done_wc = p_done_wc->p_next;
\r
1854 if( !g_root.is_polling )
\r
1856 status = ib_rearm_cq(h_cq, FALSE);
\r
1857 if (status != IB_SUCCESS)
\r
1859 printf("Failed to rearm CQ %p\n", h_cq );
\r
1864 CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );
\r
1871 * Remove num_msgs completions from all send CQs for all connections.
\r
1876 ib_node_t *p_node;
\r
1879 for( i = 0; i < g_root.num_nodes; i++ )
\r
1881 p_node = &g_root.p_nodes[i];
\r
1882 while( p_node->send_cnt < g_root.num_msgs )
\r
1884 if( !g_root.is_polling )
\r
1885 cl_thread_suspend( 0 );
\r
1886 else if( !__poll_cq( p_node, p_node->h_send_cq ) )
\r
1896 * Remove num_msgs completions from all receive CQs for all connections.
\r
1901 ib_node_t *p_node;
\r
1904 for( i = 0; i < g_root.num_nodes; i++ )
\r
1906 p_node = &g_root.p_nodes[i];
\r
1907 while( p_node->recv_cnt < g_root.num_msgs )
\r
1909 if( !g_root.is_polling )
\r
1910 cl_thread_suspend( 0 );
\r
1911 else if( !__poll_cq( p_node, p_node->h_recv_cq ) )
\r
1920 /**********************************************************************
\r
1921 **********************************************************************/
\r
1927 uint64_t start_time, total_time;
\r
1928 uint64_t total_xfer;
\r
1931 cl_memclr( &g_root, sizeof(ib_root_t) );
\r
1933 /* Set defaults. */
\r
1934 if( !__parse_options( argc, argv ) )
\r
1937 /* Initialize the root - open all common HCA resources. */
\r
1938 if( !__init_root() )
\r
1940 printf( "__init_root failed\n" );
\r
1946 * Execute the test the specified number of times. Abort the test
\r
1947 * if any errors occur.
\r
1949 total_xfer = g_root.num_msgs * g_root.msg_size * g_root.num_nodes;
\r
1950 for( i = 0; i < g_root.num_iter; i++ )
\r
1952 printf( "----- Iteration: %d, %d connections -----\n",
\r
1953 i, g_root.num_nodes );
\r
1955 /* Initialize the connection parameters. */
\r
1956 __init_conn_info();
\r
1959 /* Start listening for connections if we're the server. */
\r
1960 if( g_root.is_server )
\r
1963 /* Allocate a new set of QPs for the connections. */
\r
1964 if( __create_qps() != IB_SUCCESS )
\r
1966 printf( "Unable to allocate QPs for test.\n" );
\r
1970 /* Establish all connections. */
\r
1971 if( __connect() != IB_SUCCESS )
\r
1973 printf( "Failed to establish connections.\n" );
\r
1977 printf( "Transfering data...\n" );
\r
1978 g_root.state = test_transfering;
\r
1979 start_time = cl_get_time_stamp();
\r
1981 if( g_root.num_msgs )
\r
1983 if( g_root.is_server )
\r
1985 /* The server initiate the sends to avoid race conditions. */
\r
1986 if( !__send_msgs() )
\r
1989 /* Get all send completions. */
\r
1990 if( !__poll_send_cqs() )
\r
1993 /* Get all receive completions. */
\r
1994 if( !__poll_recv_cqs() )
\r
1999 /* Get all receive completions. */
\r
2000 if( !__poll_recv_cqs() )
\r
2003 /* Reply to the sends. */
\r
2004 if( !__send_msgs() )
\r
2007 /* Get all send completions. */
\r
2008 if( !__poll_send_cqs() )
\r
2013 total_time = cl_get_time_stamp() - start_time;
\r
2014 g_root.state = test_idle;
\r
2016 printf( "Data transfer time: %"PRId64" ms, %d messages/conn, "
\r
2017 "%"PRId64" total bytes\n", total_time/1000,
\r
2018 g_root.num_msgs, total_xfer );
\r
2020 /* Disconnect all connections. */
\r
2023 __destroy_nodes();
\r