winverbs/nd: do not convert timeout status value
[mirror/winof/.git] / tests / cmtest / user / cmtest_main.c
1 /*\r
2  * Copyright (c) 2005 SilverStorm Technologies.  All rights reserved.\r
3  * Copyright (c) 1996-2002 Intel Corporation. All rights reserved. \r
4  * Portions Copyright (c) 2008 Microsoft Corp.  All rights reserved.\r
5  *\r
6  * This software is available to you under the OpenIB.org BSD license\r
7  * below:\r
8  *\r
9  *     Redistribution and use in source and binary forms, with or\r
10  *     without modification, are permitted provided that the following\r
11  *     conditions are met:\r
12  *\r
13  *      - Redistributions of source code must retain the above\r
14  *        copyright notice, this list of conditions and the following\r
15  *        disclaimer.\r
16  *\r
17  *      - Redistributions in binary form must reproduce the above\r
18  *        copyright notice, this list of conditions and the following\r
19  *        disclaimer in the documentation and/or other materials\r
20  *        provided with the distribution.\r
21  *\r
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
23  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
24  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
25  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
26  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
27  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
28  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
29  * SOFTWARE.\r
30  *\r
31  * $Id$\r
32  */\r
33 \r
34 \r
35 /*\r
36  * Abstract:\r
37  *      Command line interface for cmtest.\r
38  *\r
39  * Environment:\r
40  *      User Mode\r
41  */\r
42 \r
43 #include <stdio.h>\r
44 #include <stdlib.h>\r
45 #include <stdarg.h>\r
46 #include <ctype.h>\r
47 #include <complib/cl_atomic.h>\r
48 #include <complib/cl_debug.h>\r
49 #include <complib/cl_event.h>\r
50 #include <complib/cl_math.h>\r
51 #include <complib/cl_mutex.h>\r
52 #include <complib/cl_qlist.h>\r
53 #include <complib/cl_thread.h>\r
54 #include <complib/cl_timer.h>\r
55 #include <iba/ib_types.h>\r
56 #include <iba/ib_al.h>\r
57 \r
58 \r
59 /* Globals */\r
60 #define CMT_DBG_VERBOSE         1\r
61 \r
62 #define CMT_BASE_SVC_ID         0xFFEE\r
63 #define CMT_ACCESS_CTRL         (IB_AC_LOCAL_WRITE + IB_AC_RDMA_READ + IB_AC_RDMA_WRITE)\r
64 #define BAD_PKEY_INDEX          0xFFFF\r
65 \r
66 \r
67 typedef enum _cmtest_state\r
68 {\r
69         test_idle, test_connecting, test_transfering, test_disconnecting\r
70 \r
71 }       cmtest_state_t;\r
72 \r
73 \r
74 \r
75 typedef struct _ib_root\r
76 {\r
77         ib_al_handle_t          h_al;\r
78         ib_pd_handle_t          h_pd;\r
79 \r
80         /* Input parameters to control test. */\r
81         int32_t                         num_nodes;\r
82         uint32_t                        num_msgs;\r
83         boolean_t                       per_msg_buf;\r
84         cl_mutex_t                      mutex;\r
85 \r
86         cmtest_state_t          state;\r
87         atomic32_t                      num_connected;\r
88         uint32_t                        conn_index;             /* current connection id */\r
89         uint32_t                        total_sent;\r
90         uint32_t                        total_recv;\r
91 \r
92         uint32_t                        num_iter;\r
93 \r
94         uint32_t                        msg_size;\r
95 \r
96         ib_ca_handle_t          h_ca;\r
97         ib_net16_t                      l_lid;\r
98         ib_net16_t                      r_lid;\r
99         ib_net64_t                      ca_guid;\r
100         ib_net64_t                      port_guid;\r
101         uint8_t                         port_num;\r
102         uint16_t                        num_pkeys;\r
103         ib_net16_t                      *p_pkey_table;\r
104 \r
105         /* cm info */\r
106         boolean_t                       is_server;\r
107         ib_listen_handle_t      h_listen;\r
108         ib_path_rec_t           path_rec;\r
109 \r
110         /* CQ info. */\r
111         boolean_t                       is_polling;\r
112 \r
113         struct  _ib_node        *p_nodes;\r
114         ib_qp_create_t          qp_create;\r
115         ib_qp_mod_t                     qp_mod_reset;\r
116         ib_qp_mod_t                     qp_mod_init;\r
117 \r
118         /* reg mem info */\r
119         ib_mr_handle_t          h_mr;\r
120         uint32_t                        lkey;\r
121         uint32_t                        rkey;\r
122         uint8_t                         *p_mem;\r
123         uint8_t                         *p_mem_recv;\r
124         uint8_t                         *p_mem_send;\r
125 \r
126         uint64_t                        conn_start_time;\r
127 \r
128         /*\r
129          * Connection parameters are initialized once to improve connection\r
130          * establishment rate.\r
131          */\r
132         ib_cm_req_t                     cm_req;\r
133         ib_cm_rep_t                     cm_rep;\r
134         ib_cm_rtu_t                     cm_rtu;\r
135         ib_cm_dreq_t            cm_dreq;\r
136         ib_cm_drep_t            cm_drep;\r
137 \r
138         uint32_t                        inst_id;\r
139 \r
140 }       ib_root_t;\r
141 \r
142 \r
143 \r
144 typedef enum _cmnode_state\r
145 {\r
146         node_idle, node_conn, node_dreq_sent, node_dreq_rcvd\r
147 \r
148 }       cmnode_state_t;\r
149 \r
150 \r
151 \r
152 typedef struct  _ib_node\r
153 {\r
154         uint64_t                        id;\r
155 \r
156         ib_cq_handle_t          h_send_cq;\r
157         ib_cq_handle_t          h_recv_cq;\r
158         ib_qp_handle_t          h_qp;\r
159         uint32_t                        max_inline;\r
160 \r
161         cmnode_state_t          state;\r
162         ib_cm_handle_t          h_cm_req;\r
163         ib_cm_handle_t          h_cm_dreq;\r
164 \r
165         uint32_t                        send_cnt;\r
166         uint32_t                        recv_cnt;\r
167 \r
168 }       ib_node_t;\r
169 \r
170 \r
171 \r
172 uint32_t        cmt_dbg_lvl = 0x80000000;\r
173 \r
174 ib_root_t       g_root;\r
175 \r
176 \r
177 static char *wc_type_text[] = {\r
178         "IB_WC_SEND",\r
179         "IB_WC_RDMA_WRITE",\r
180         "IB_WC_RECV",\r
181         "IB_WC_RDMA_READ",\r
182         "IB_WC_MW_BIND",\r
183         "IB_WC_FETCH_ADD",\r
184         "IB_WC_COMPARE_SWAP",\r
185         "IB_WC_RECV_RDMA_WRITE"\r
186 };\r
187 \r
188 static char *wc_status_text[] = {\r
189         "IB_WCS_SUCCESS",\r
190         "IB_WCS_LOCAL_LEN_ERR",\r
191         "IB_WCS_LOCAL_OP_ERR",\r
192         "IB_WCS_LOCAL_EEC_OP_ERR",\r
193         "IB_WCS_LOCAL_PROTECTION_ERR",\r
194         "IB_WCS_WR_FLUSHED_ERR",\r
195         "IB_WCS_MEM_WINDOW_BIND_ERR",\r
196         "IB_WCS_REM_ACCESS_ERR",\r
197         "IB_WCS_REM_OP_ERR",\r
198         "IB_WCS_RNR_RETRY_ERR",\r
199         "IB_WCS_TIMEOUT_RETRY_ERR",\r
200         "IB_WCS_REM_INVALID_REQ_ERR",\r
201         "IB_WCS_REM_INVALID_RD_REQ_ERR",\r
202         "IB_WCS_INVALID_EECN",\r
203         "IB_WCS_INVALID_EEC_STATE",\r
204         "IB_WCS_UNMATCHED_RESPONSE",                    \r
205         "IB_WCS_CANCELED"                                               \r
206 };\r
207 \r
208 \r
209 \r
210 static void AL_API\r
211 __req_cb(\r
212         IN                              ib_cm_req_rec_t                         *p_cm_req_rec );\r
213 \r
214 static void AL_API\r
215 __rep_cb(\r
216         IN                              ib_cm_rep_rec_t                         *p_cm_rep_rec );\r
217 \r
218 static void AL_API\r
219 __rtu_cb(\r
220         IN                              ib_cm_rtu_rec_t                         *p_cm_rtu_rec );\r
221 \r
222 static void AL_API\r
223 __rej_cb(\r
224         IN                              ib_cm_rej_rec_t                         *p_cm_rej_rec );\r
225 \r
226 static void AL_API\r
227 __mra_cb(\r
228         IN                              ib_cm_mra_rec_t                         *p_cm_mra_rec );\r
229 \r
230 static void AL_API\r
231 __apr_cb(\r
232         IN                              ib_cm_apr_rec_t                         *p_cm_apr_rec );\r
233 \r
234 static void AL_API\r
235 __lap_cb(\r
236         IN                              ib_cm_lap_rec_t                         *p_cm_lap_rec );\r
237 \r
238 static void AL_API\r
239 __dreq_cb(\r
240         IN                              ib_cm_dreq_rec_t                        *p_cm_dreq_rec );\r
241 \r
242 static void AL_API\r
243 __drep_cb(\r
244         IN                              ib_cm_drep_rec_t                        *p_cm_drep_rec );\r
245 \r
246 static boolean_t\r
247 __poll_cq(\r
248         IN                              ib_node_t                                       *p_node,\r
249         IN                              ib_cq_handle_t                          h_cq );\r
250 \r
251 \r
252 /**********************************************************************\r
253  **********************************************************************/\r
254 static void\r
255 __show_usage()\r
256 {\r
257         printf( "\n------- cmtest - Usage and options ----------------------\n" );\r
258         printf( "Usage:   cmtest [options]\n");\r
259         printf( "Options:\n" );\r
260         printf( "-s\n"\r
261                         "--server\n"\r
262                         "          Directs cmtest to act as a Server\n" );\r
263         printf( "-l <lid>\n"\r
264                         "--local <lid>\n"\r
265                         "          Local endpoint LID; see vstat port_lid value.\n"\r
266                         "          LID Radix [0x Hex, 0 octal, else decimal]\n");\r
267         printf( "-r <lid>\n"\r
268                         "--remote <lid>\n"\r
269                         "          Remote endpoint LID\n"\r
270                         "          LID Radix [0x Hex, 0 octal, else decimal]\n" );\r
271         printf( "-c <number>\n"\r
272                         "--connect <number>\n"\r
273                         "          Total number of connections to open.\n"\r
274                         "          Default of 1.\n" );\r
275         printf( "-m <bytes>\n"\r
276                         "--msize <bytes>\n"\r
277                         "          Byte size of each message.\n"\r
278                         "          Default is 100 bytes.\n" );\r
279         printf( "-n <number>\n"\r
280                         "--nmsgs <number>\n"\r
281                         "          Number of messages to send at a time.\n" );\r
282         printf( "-p\n"\r
283                         "--permsg\n"\r
284                         "          Specify a separate buffer should be used per message.\n"\r
285                         "          Default is one buffer for all messages.\n" );\r
286         printf( "-i <number>\n"\r
287                         "--iterate <number>\n"\r
288                         "          Set the number of times to loop through 'nmsgs'.\n"\r
289                         "          Default of 1.\n" );\r
290         printf( "-v\n"\r
291                         "--verbose\n"\r
292                         "          Set verbosity level to debug console.\n" );\r
293         printf( "-h\n"\r
294                         "--help\n"\r
295                         "          Display this usage info then exit.\n\n" );\r
296 }\r
297 \r
298 \r
299 /* Windows support. */\r
300 struct option\r
301 {\r
302         const char              *long_name;\r
303         unsigned long   flag;\r
304         void                    *pfn_handler;\r
305         char                    short_name;\r
306 };\r
307 \r
308 static char                     *optarg;\r
309 \r
310 #define strtoull        strtoul\r
311 \r
312 \r
313 char\r
314 getopt_long(\r
315         int                                     argc,\r
316         char                            *argv[],\r
317         const char                      *short_option,\r
318         const struct option *long_option,\r
319         void                            *unused )\r
320 {\r
321         static int i = 1;\r
322         int j;\r
323         char            ret = 0;\r
324 \r
325         UNUSED_PARAM( unused );\r
326 \r
327         if( i == argc )\r
328                 return -1;\r
329 \r
330         if( argv[i][0] != '-' )\r
331                 return ret;\r
332 \r
333         /* find the first character of the value. */\r
334         for( j = 1; isalpha( argv[i][j] ); j++ )\r
335                 ;\r
336         optarg = &argv[i][j];\r
337 \r
338         if( argv[i][1] == '-' )\r
339         {\r
340                 /* Long option. */\r
341                 for( j = 0; long_option[j].long_name; j++ )\r
342                 {\r
343                         if( strncmp( &argv[i][2], long_option[j].long_name,\r
344                                 optarg - argv[i] - 2 ) )\r
345                         {\r
346                                 continue;\r
347                         }\r
348 \r
349                         switch( long_option[j].flag )\r
350                         {\r
351                         case 1:\r
352                                 if( *optarg == '\0' )\r
353                                         return 0;\r
354                         default:\r
355                                 break;\r
356                         }\r
357                         ret = long_option[j].short_name;\r
358                         break;\r
359                 }\r
360         }\r
361         else\r
362         {\r
363                 for( j = 0; short_option[j] != '\0'; j++ )\r
364                 {\r
365                         if( !isalpha( short_option[j] ) )\r
366                                 return 0;\r
367 \r
368                         if( short_option[j] == argv[i][1] )\r
369                         {\r
370                                 ret = short_option[j];\r
371                                 break;\r
372                         }\r
373 \r
374                         if( short_option[j+1] == ':' )\r
375                         {\r
376                                 if( *optarg == '\0' )\r
377                                         return 0;\r
378                                 j++;\r
379                         }\r
380                 }\r
381         }\r
382         i++;\r
383         return ret;\r
384 }\r
385 \r
386 \r
387 static boolean_t\r
388 __parse_options(\r
389         int                                                     argc,\r
390         char*                                           argv[] )\r
391 {\r
392         uint32_t                                        next_option;\r
393         const char* const                       short_option = "esl:r:c:m:n:i:pvh";\r
394 \r
395         /*\r
396                 In the array below, the 2nd parameter specified the number\r
397                 of arguments as follows:\r
398                 0: no arguments\r
399                 1: argument\r
400                 2: optional\r
401         */\r
402         const struct option long_option[] =\r
403         {\r
404                 {       "event",        2,      NULL,   'e'},\r
405                 {       "server",       2,      NULL,   's'},\r
406                 {       "local",        1,      NULL,   'l'},\r
407                 {       "remote",       1,      NULL,   'r'},\r
408                 {       "connect",      1,      NULL,   'c'},\r
409                 {       "msize",        1,      NULL,   'm'},\r
410                 {       "nmsgs",        1,      NULL,   'n'},\r
411                 {       "iterate",      1,      NULL,   'i'},\r
412                 {       "permsg",       0,      NULL,   'p'},\r
413                 {       "verbose",      0,      NULL,   'v'},\r
414                 {       "help",         0,      NULL,   'h'},\r
415                 {       NULL,           0,      NULL,    0 }    /* Required at end of array */\r
416         };\r
417 \r
418         /* Set the default options. */\r
419         g_root.msg_size = 100;\r
420         g_root.num_nodes = 1;\r
421         g_root.num_msgs = 0;\r
422         g_root.num_iter = 1;\r
423         g_root.is_polling = TRUE;\r
424 \r
425         /* parse cmd line arguments as input params */\r
426         do\r
427         {\r
428                 next_option = getopt_long( argc, argv, short_option,\r
429                         long_option, NULL );\r
430 \r
431                 switch( next_option )\r
432                 {\r
433                 case 's':\r
434                         g_root.is_server = TRUE;\r
435                         printf( "\tServer mode\n" );\r
436                         break;\r
437 \r
438                 case 'd':\r
439                         g_root.inst_id = strtoull( optarg, NULL, 0 );\r
440                         printf( "\tinstance_id..: %d\n", g_root.inst_id );\r
441                         break;\r
442 \r
443                 case 'c':\r
444                         g_root.num_nodes = strtoull( optarg, NULL, 0 );\r
445                         printf( "\tconnections..: %d\n", g_root.num_nodes );\r
446                         break;\r
447 \r
448                 case 'l':\r
449                         g_root.l_lid = (uint16_t)strtoull( optarg, NULL, 0 );\r
450                         printf( "\tlocal lid....: 0x%x\n", g_root.l_lid );\r
451                         g_root.l_lid = cl_hton16( g_root.l_lid );\r
452                         break;\r
453 \r
454                 case 'r':\r
455                         g_root.r_lid = (uint16_t)strtoull( optarg, NULL, 0 );\r
456                         printf( "\tremote lid...: 0x%x\n", g_root.r_lid );\r
457                         g_root.r_lid = cl_hton16( g_root.r_lid );\r
458                         break;\r
459 \r
460                 case 'm':\r
461                         g_root.msg_size = strtoull( optarg, NULL, 0 );\r
462                         printf( "\tmsg size.....: %d bytes\n", g_root.msg_size );\r
463                         break;\r
464 \r
465                 case 'n':\r
466                         g_root.num_msgs = strtoull( optarg, NULL, 0 );\r
467                         printf( "\tnum msgs.....: %d\n", g_root.num_msgs );\r
468                         break;\r
469 \r
470                 case 'i':\r
471                         g_root.num_iter = strtoull( optarg, NULL, 0 );\r
472                         printf( "\titerate......: %d\n", g_root.num_iter );\r
473                         break;\r
474 \r
475                 case 'p':\r
476                         g_root.per_msg_buf = TRUE;\r
477                         printf( "\tper message data buffer\n" );\r
478                         break;\r
479 \r
480                 case 'v':\r
481                         cmt_dbg_lvl = 0xFFFFFFFF;\r
482                         printf( "\tverbose\n" );\r
483                         break;\r
484 \r
485                 case 'e':\r
486                         g_root.is_polling = FALSE;\r
487                         printf( "\tevent driven completions\n" );\r
488                         break;\r
489 \r
490                 case 'h':\r
491                         __show_usage();\r
492                         return FALSE;\r
493 \r
494                 case -1:\r
495                         break;\r
496 \r
497                 default: /* something wrong */\r
498                         __show_usage();\r
499                         return FALSE;\r
500                 }\r
501         } while( next_option != -1 );\r
502 \r
503         return TRUE;\r
504 }\r
505 \r
506 \r
507 /**********************************************************************\r
508  **********************************************************************/\r
509 static void\r
510 __init_conn_info()\r
511 {\r
512         /* Initialize connection request parameters. */\r
513         g_root.cm_req.svc_id                    = CMT_BASE_SVC_ID + g_root.inst_id;\r
514         g_root.cm_req.max_cm_retries    = 5;\r
515         g_root.cm_req.p_primary_path    = &g_root.path_rec;\r
516         g_root.cm_req.pfn_cm_rep_cb             = __rep_cb;\r
517         g_root.cm_req.qp_type                   = IB_QPT_RELIABLE_CONN;\r
518         g_root.cm_req.resp_res                  = 3;\r
519         g_root.cm_req.init_depth                = 1;\r
520         g_root.cm_req.remote_resp_timeout = 20;\r
521         g_root.cm_req.flow_ctrl                 = TRUE;\r
522         g_root.cm_req.local_resp_timeout= 20;\r
523         g_root.cm_req.rnr_nak_timeout   = 6;\r
524         g_root.cm_req.rnr_retry_cnt             = 3;\r
525         g_root.cm_req.retry_cnt                 = 5;\r
526         g_root.cm_req.pfn_cm_mra_cb             = __mra_cb;\r
527         g_root.cm_req.pfn_cm_rej_cb             = __rej_cb;\r
528 \r
529         /* Initialize connection reply parameters. */\r
530         g_root.cm_rep.qp_type                   = IB_QPT_RELIABLE_CONN;\r
531         g_root.cm_rep.access_ctrl               = CMT_ACCESS_CTRL;\r
532         g_root.cm_rep.sq_depth                  = 0;\r
533         g_root.cm_rep.rq_depth                  = 0;\r
534         g_root.cm_rep.init_depth                = 1;\r
535         g_root.cm_rep.target_ack_delay  = 7;\r
536         g_root.cm_rep.failover_accepted = IB_FAILOVER_ACCEPT_UNSUPPORTED;\r
537         g_root.cm_rep.flow_ctrl                 = TRUE;\r
538         g_root.cm_rep.rnr_nak_timeout   = 7;\r
539         g_root.cm_rep.rnr_retry_cnt             = 6;\r
540         g_root.cm_rep.pfn_cm_rej_cb             = __rej_cb;\r
541         g_root.cm_rep.pfn_cm_mra_cb             = __mra_cb;\r
542         g_root.cm_rep.pfn_cm_rtu_cb             = __rtu_cb;\r
543         g_root.cm_rep.pfn_cm_lap_cb             = __lap_cb;\r
544         g_root.cm_rep.pfn_cm_dreq_cb    = __dreq_cb;\r
545 \r
546         /* Initialize connection RTU parameters. */\r
547         g_root.cm_rtu.pfn_cm_apr_cb             = __apr_cb;\r
548         g_root.cm_rtu.pfn_cm_dreq_cb    = __dreq_cb;\r
549 \r
550         /* Initialize disconnection request parameters. */\r
551         g_root.cm_dreq.pfn_cm_drep_cb   = __drep_cb;\r
552         g_root.cm_dreq.qp_type                  = IB_QPT_RELIABLE_CONN;\r
553 \r
554         /* Disconnection reply parameters are all zero. */\r
555 }\r
556 \r
557 \r
558 \r
559 static uint16_t\r
560 __get_pkey_index()\r
561 {\r
562         uint16_t        i;\r
563 \r
564         for( i = 0; i < g_root.num_pkeys; i++ )\r
565         {\r
566                 if( g_root.p_pkey_table[i] == g_root.path_rec.pkey )\r
567                         return i;\r
568         }\r
569 \r
570         return BAD_PKEY_INDEX;\r
571 }\r
572 \r
573 \r
574 \r
575 static void\r
576 __init_qp_info()\r
577 {\r
578         /* Set common QP attributes for all create calls. */\r
579         g_root.qp_create.qp_type = IB_QPT_RELIABLE_CONN;\r
580         if( g_root.num_msgs )\r
581         {\r
582                 g_root.qp_create.sq_depth = g_root.num_msgs;\r
583                 g_root.qp_create.rq_depth = g_root.num_msgs;\r
584         }\r
585         else\r
586         {\r
587                 /* Minimal queue depth of one. */\r
588                 g_root.qp_create.sq_depth = 1;\r
589                 g_root.qp_create.rq_depth = 1;\r
590         }\r
591 \r
592         g_root.qp_create.sq_signaled = FALSE;\r
593         g_root.qp_create.sq_sge = 1;\r
594         g_root.qp_create.rq_sge = 1;\r
595 \r
596         /* Set the QP attributes when modifying the QP to the reset state. */\r
597         g_root.qp_mod_reset.req_state = IB_QPS_RESET;\r
598 \r
599         /* Set the QP attributes when modifying the QP to the init state. */\r
600         g_root.qp_mod_init.req_state = IB_QPS_INIT;\r
601         g_root.qp_mod_init.state.init.access_ctrl = CMT_ACCESS_CTRL;\r
602         g_root.qp_mod_init.state.init.primary_port = g_root.port_num;\r
603         g_root.qp_mod_init.state.init.pkey_index = __get_pkey_index();\r
604 }\r
605 \r
606 \r
607 \r
608 static ib_api_status_t\r
609 __post_recvs(\r
610         IN                              ib_node_t                                       *p_node )\r
611 {\r
612         ib_api_status_t status = IB_SUCCESS;\r
613         ib_recv_wr_t    recv_wr;\r
614         ib_recv_wr_t    *p_recv_failure;\r
615         ib_local_ds_t   ds_array;\r
616         uint32_t                i;\r
617 \r
618         CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
619 \r
620         if( !g_root.num_msgs )\r
621         {\r
622                 CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
623                 return IB_SUCCESS;\r
624         }\r
625 \r
626         cl_memclr( &recv_wr, sizeof( ib_recv_wr_t ) );\r
627         ds_array.length = g_root.msg_size;\r
628         ds_array.lkey = g_root.lkey;\r
629         recv_wr.ds_array = &ds_array;\r
630         recv_wr.num_ds = (( g_root.msg_size <= 4 )? 0: 1 );\r
631 \r
632         for( i = 0; i < g_root.num_msgs; i++ )\r
633         {\r
634                 CL_PRINT( CMT_DBG_VERBOSE, cmt_dbg_lvl, (".") );\r
635 \r
636                 if( g_root.per_msg_buf )\r
637                 {\r
638                         ds_array.vaddr = (uintn_t)(g_root.p_mem_recv + (i * g_root.msg_size) +\r
639                                         (p_node->id * g_root.num_msgs * g_root.msg_size));\r
640                 }\r
641                 else\r
642                 {\r
643                         ds_array.vaddr = (uintn_t)g_root.p_mem;\r
644                 }\r
645 \r
646                 recv_wr.wr_id = i;\r
647                 \r
648                 status = ib_post_recv( p_node->h_qp, &recv_wr, &p_recv_failure );\r
649                 if( status != IB_SUCCESS )\r
650                 {\r
651                         printf( "ib_post_recv failed [%s]!\n", ib_get_err_str(status) );\r
652                         break;\r
653                 }\r
654         }\r
655 \r
656         CL_PRINT( CMT_DBG_VERBOSE, cmt_dbg_lvl, ("\n") );\r
657         CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
658         return status;\r
659 }\r
660 \r
661 \r
662 \r
663 static void AL_API\r
664 __ca_async_event_cb(\r
665         ib_async_event_rec_t    *p_err_rec )\r
666 {\r
667         CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
668         \r
669         CL_TRACE( CMT_DBG_VERBOSE, cmt_dbg_lvl, \r
670                 ( "p_err_rec->code is %d\n", p_err_rec->code ) );\r
671         \r
672         CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
673 }\r
674 \r
675 \r
676 \r
677 static void AL_API\r
678 __cancel_listen_cb(\r
679         IN                              void                                            *context )\r
680 {\r
681         CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
682         if( !context )\r
683                 printf( "%s NULL context\n", __FUNCTION__ );\r
684         CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
685 }\r
686 \r
687 \r
688 \r
689 /* We need to halt the test and recover from the reject error. */\r
690 static void AL_API\r
691 __rej_cb(\r
692         IN                              ib_cm_rej_rec_t                         *p_cm_rej_rec )\r
693 {\r
694         CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
695 \r
696         /*\r
697          * Note - because this callback exits the app, any output beyond the\r
698          * the first time may report junk.  There have been instances where\r
699          * the callback is invoked more times than there are connection requests\r
700          * but that behavior disapeared if the call to exit below is removed.\r
701          */\r
702         printf( "Connection was rejected, status: 0x%x\n",\r
703                 p_cm_rej_rec->rej_status );\r
704 \r
705         CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
706         exit( 1 );\r
707 }\r
708 \r
709 \r
710 \r
711 static void AL_API\r
712 __req_cb(\r
713         IN                              ib_cm_req_rec_t                         *p_cm_req_rec )\r
714 {\r
715         ib_api_status_t status;\r
716         ib_node_t               *p_node;\r
717 \r
718         CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
719         \r
720         CL_ASSERT( p_cm_req_rec );\r
721 \r
722         /* Record the starting time for the server. */\r
723         if( !g_root.conn_start_time )\r
724                 g_root.conn_start_time = cl_get_time_stamp( );\r
725 \r
726         /*\r
727          * Do not send replies until the server is ready to establish all\r
728          * connections.\r
729          */\r
730         cl_mutex_acquire( &g_root.mutex );\r
731         p_node = &g_root.p_nodes[g_root.conn_index++];\r
732 \r
733         if( g_root.state == test_connecting )\r
734         {\r
735                 /* Get a node for this connection and send the reply. */\r
736                 g_root.cm_rep.h_qp = p_node->h_qp;\r
737                 status = ib_cm_rep( p_cm_req_rec->h_cm_req, &g_root.cm_rep );\r
738                 if( status != IB_SUCCESS )\r
739                 {\r
740                         printf( "Call to ib_cm_rep failed\n" );\r
741                         exit( 1 );\r
742                 }\r
743         }\r
744         else\r
745         {\r
746                 p_node->h_cm_req = p_cm_req_rec->h_cm_req;\r
747         }\r
748         cl_mutex_release( &g_root.mutex );\r
749 \r
750         CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
751 }\r
752 \r
753 \r
754 \r
755 static void AL_API\r
756 __rep_cb(\r
757         IN                              ib_cm_rep_rec_t                         *p_cm_rep_rec )\r
758 {\r
759         ib_api_status_t status;\r
760         ib_node_t               *p_node;\r
761         uint8_t                 pdata[IB_RTU_PDATA_SIZE];\r
762         ib_cm_mra_t             mra;\r
763 \r
764         CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
765         CL_ASSERT( p_cm_rep_rec );\r
766         \r
767         p_node = (ib_node_t *)p_cm_rep_rec->qp_context;\r
768         CL_ASSERT( p_node );\r
769 \r
770         mra.p_mra_pdata = NULL;\r
771         mra.mra_length = 0;\r
772         mra.svc_timeout = 0xff;\r
773 \r
774         ib_cm_mra( p_cm_rep_rec->h_cm_rep, &mra );\r
775 \r
776         __post_recvs( p_node );\r
777 \r
778         /* Mark that we're connected before sending the RTU. */\r
779         p_node->state = node_conn;\r
780 \r
781         g_root.cm_rtu.p_rtu_pdata = pdata;\r
782         g_root.cm_rtu.rtu_length = IB_RTU_PDATA_SIZE;\r
783 \r
784         status = ib_cm_rtu( p_cm_rep_rec->h_cm_rep, &g_root.cm_rtu );\r
785         if( status != IB_SUCCESS )\r
786         {\r
787                 printf( "Call to ib_cm_rtu returned %s\n", ib_get_err_str( status ) );\r
788                 exit( 1 );\r
789         }\r
790 \r
791         cl_atomic_inc( &g_root.num_connected );\r
792 \r
793         CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
794 }\r
795 \r
796 \r
797 \r
798 static void AL_API\r
799 __rtu_cb(\r
800         IN                              ib_cm_rtu_rec_t                         *p_cm_rtu_rec )\r
801 {\r
802         ib_node_t               *p_node;\r
803 \r
804         CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
805         CL_ASSERT( p_cm_rtu_rec );\r
806         \r
807         p_node = (ib_node_t*)p_cm_rtu_rec->qp_context;\r
808         p_node->state = node_conn;\r
809 \r
810         __post_recvs( p_node );\r
811         cl_atomic_inc( &g_root.num_connected );\r
812 \r
813         CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
814 }\r
815 \r
816 \r
817 \r
818 static void AL_API\r
819 __mra_cb(\r
820         IN                              ib_cm_mra_rec_t                         *p_cm_mra_rec )\r
821 {\r
822         CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
823         CL_ASSERT( p_cm_mra_rec );\r
824         CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
825 }\r
826 \r
827 \r
828 \r
829 static void AL_API\r
830 __apr_cb(\r
831         IN                              ib_cm_apr_rec_t                         *p_cm_apr_rec )\r
832 {\r
833         CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
834         CL_ASSERT( p_cm_apr_rec );\r
835         CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
836 }\r
837 \r
838 \r
839 \r
840 static void AL_API\r
841 __lap_cb(\r
842         IN                              ib_cm_lap_rec_t                         *p_cm_lap_rec )\r
843 {\r
844         CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
845         CL_ASSERT( p_cm_lap_rec );\r
846         CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
847 }\r
848 \r
849 \r
850 \r
851 static void AL_API\r
852 __dreq_cb(\r
853         IN                              ib_cm_dreq_rec_t                        *p_cm_dreq_rec )\r
854 {\r
855         ib_node_t               *p_node;\r
856         ib_api_status_t status;\r
857 \r
858         CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
859         CL_ASSERT( p_cm_dreq_rec );\r
860         p_node = (ib_node_t*)p_cm_dreq_rec->qp_context;\r
861         CL_ASSERT( p_node );\r
862 \r
863         /*\r
864          * Record that we've already received a DREQ to avoid trying to\r
865          * disconnect the QP a second time.  Synchronize with the DREQ call\r
866          * using the mutex.\r
867          */\r
868         cl_mutex_acquire( &g_root.mutex );\r
869 \r
870         /* If we need to send or receive more data, don't disconnect yet. */\r
871         if( g_root.state == test_disconnecting )\r
872         {\r
873                 /* Send the DREP. */\r
874                 status = ib_cm_drep( p_cm_dreq_rec->h_cm_dreq, &g_root.cm_drep );\r
875 \r
876                 /* If the DREP was successful, we're done with this connection. */\r
877                 if( status == IB_SUCCESS )\r
878                 {\r
879                         p_node->state = node_idle;\r
880                         cl_atomic_dec( &g_root.num_connected );\r
881                 }\r
882         }\r
883         else\r
884         {\r
885                 /* Record that we need to disconnect, but don't send the DREP yet. */\r
886                 p_node->state = node_dreq_rcvd;\r
887                 p_node->h_cm_dreq = p_cm_dreq_rec->h_cm_dreq;\r
888         }\r
889         cl_mutex_release( &g_root.mutex );\r
890 \r
891         CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
892 }\r
893 \r
894 \r
895 \r
896 static void AL_API\r
897 __drep_cb(\r
898         IN                              ib_cm_drep_rec_t                        *p_cm_drep_rec )\r
899 {\r
900         ib_node_t               *p_node;\r
901 \r
902         CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
903         CL_ASSERT( p_cm_drep_rec );\r
904         p_node = (ib_node_t*)p_cm_drep_rec->qp_context;\r
905         CL_ASSERT( p_node );\r
906 \r
907         /* We're done with this connection. */\r
908         cl_mutex_acquire( &g_root.mutex );\r
909         p_node->state = node_idle;\r
910         cl_atomic_dec( &g_root.num_connected );\r
911         cl_mutex_release( &g_root.mutex );\r
912 \r
913         CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
914 }\r
915 \r
916 \r
917 \r
918 static void AL_API\r
919 __cq_cb(\r
920         IN              const   ib_cq_handle_t                          h_cq,\r
921         IN                              void*                                           cq_context )\r
922 {\r
923         ib_node_t               *p_node = (ib_node_t*)cq_context;\r
924 \r
925         CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
926         if( !g_root.is_polling )\r
927         {\r
928                 if( !__poll_cq( p_node, h_cq ) )\r
929                         exit( 1 );\r
930         }\r
931         CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
932 }\r
933 \r
934 \r
935 static ib_api_status_t\r
936 __create_qp(\r
937         IN                      ib_node_t                       *p_node )\r
938 {\r
939         ib_api_status_t status;\r
940         ib_qp_attr_t    attr;\r
941 \r
942         /* Set the per node QP attributes. */\r
943         g_root.qp_create.h_sq_cq = p_node->h_send_cq; \r
944         g_root.qp_create.h_rq_cq = p_node->h_recv_cq;\r
945 \r
946         /* Allocate the QP. */\r
947         status = ib_create_qp( g_root.h_pd, &g_root.qp_create, p_node, NULL,\r
948                 &p_node->h_qp );\r
949         if( status != IB_SUCCESS )\r
950         {\r
951                 printf( "[%d] ib_create_qp failed [%s]!\n", __LINE__, \r
952                         ib_get_err_str(status) );\r
953                 return status;\r
954         }\r
955 \r
956         /* Store the max inline size. */\r
957         status = ib_query_qp( p_node->h_qp, &attr );\r
958         if( status != IB_SUCCESS )\r
959                 p_node->max_inline = 0;\r
960         else\r
961                 p_node->max_inline = attr.sq_max_inline;\r
962 \r
963         /*\r
964          * Transition the QP to the initialize state.  This prevents the CM\r
965          * from having to make this QP transition and improves the connection\r
966          * establishment rate.\r
967          */\r
968         status = ib_modify_qp( p_node->h_qp, &g_root.qp_mod_reset );\r
969         if( status != IB_SUCCESS )\r
970         {\r
971                 printf( "ib_modify_qp to IB_QPS_RESET returned %s\n",\r
972                         ib_get_err_str(status) );\r
973                 return status;\r
974         }\r
975 \r
976         status = ib_modify_qp( p_node->h_qp, &g_root.qp_mod_init );\r
977         if( status != IB_SUCCESS )\r
978         {\r
979                 printf( "ib_modify_qp to IB_QPS_INIT returned %s\n",\r
980                         ib_get_err_str(status) );\r
981                 return status;\r
982         }\r
983 \r
984         return status;\r
985 }\r
986 \r
987 \r
988 \r
989 /*\r
990  * Allocate new QPs for all nodes.\r
991  */\r
992 static ib_api_status_t\r
993 __create_qps()\r
994 {\r
995         uint64_t                start_time, total_time;\r
996         int32_t                 i;\r
997         ib_api_status_t status;\r
998 \r
999         printf( "Creating QPs...\n" );\r
1000         start_time = cl_get_time_stamp();\r
1001 \r
1002         for( i = 0; i < g_root.num_nodes; i++ )\r
1003         {\r
1004                 /* Allocate a new QP. */\r
1005                 status = __create_qp( &g_root.p_nodes[i] );\r
1006                 if( status != IB_SUCCESS )\r
1007                         break;\r
1008         }\r
1009 \r
1010         total_time = cl_get_time_stamp() - start_time;\r
1011         printf( "Allocation time: %"PRId64" ms\n", total_time/1000 );\r
1012 \r
1013         return status;\r
1014 }\r
1015 \r
1016 \r
1017 \r
1018 /*\r
1019  * Destroy all QPs for all nodes.\r
1020  */\r
1021 static void\r
1022 __destroy_qps()\r
1023 {\r
1024         uint64_t                start_time, total_time;\r
1025         int32_t                 i;\r
1026 \r
1027         printf( "Destroying QPs...\n" );\r
1028         start_time = cl_get_time_stamp();\r
1029 \r
1030         for( i = 0; i < g_root.num_nodes; i++ )\r
1031         {\r
1032                 /* Destroy the QP. */\r
1033                 if( g_root.p_nodes[i].h_qp )\r
1034                 {\r
1035                         ib_destroy_qp( g_root.p_nodes[i].h_qp, ib_sync_destroy );\r
1036                         g_root.p_nodes[i].h_qp = NULL;\r
1037                 }\r
1038         }\r
1039 \r
1040         total_time = cl_get_time_stamp() - start_time;\r
1041         printf( "Destruction time: %"PRId64" ms\n", total_time/1000 );\r
1042 }\r
1043 \r
1044 \r
1045 \r
1046 static boolean_t\r
1047 __init_node(\r
1048         IN OUT          ib_node_t*                      p_node )\r
1049 {\r
1050         ib_api_status_t status;\r
1051         ib_cq_create_t  cq_create;\r
1052 \r
1053         CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
1054 \r
1055         /* Create the CQs. */\r
1056         cl_memclr( &cq_create, sizeof(ib_cq_create_t) );\r
1057         if( g_root.num_msgs )\r
1058                 cq_create.size = g_root.num_msgs;\r
1059         else\r
1060                 cq_create.size = 1;     /* minimal of one entry */\r
1061 \r
1062         cq_create.pfn_comp_cb = __cq_cb;\r
1063         status = ib_create_cq( g_root.h_ca, &cq_create, p_node, NULL,\r
1064                 &p_node->h_send_cq );\r
1065         if( status != IB_SUCCESS )\r
1066         {\r
1067                 printf( "ib_create_cq failed for send CQ [%s]!\n",\r
1068                         ib_get_err_str(status) );\r
1069                 return FALSE;\r
1070         }\r
1071         if( !g_root.is_polling )\r
1072         {\r
1073                 status = ib_rearm_cq( p_node->h_send_cq, FALSE );\r
1074                 if( status != IB_SUCCESS )\r
1075                 {\r
1076                         printf( "ib_rearm_cq failed for send CQ [%s]!\n",\r
1077                                 ib_get_err_str(status) );\r
1078                         return FALSE;\r
1079                 }\r
1080         }\r
1081 \r
1082         status = ib_create_cq( g_root.h_ca, &cq_create, p_node, NULL,\r
1083                         &p_node->h_recv_cq );\r
1084         if( status != IB_SUCCESS )\r
1085         {\r
1086                 printf( "ib_create_cq failed for recv CQ [%s]!\n",\r
1087                         ib_get_err_str(status) );\r
1088                 return FALSE;\r
1089         }\r
1090         if( !g_root.is_polling )\r
1091         {\r
1092                 status = ib_rearm_cq( p_node->h_recv_cq, FALSE );\r
1093                 if( status != IB_SUCCESS )\r
1094                 {\r
1095                         printf( "ib_rearm_cq failed for recv CQ [%s]!\n",\r
1096                                 ib_get_err_str(status) );\r
1097                         return FALSE;\r
1098                 }\r
1099         }\r
1100 \r
1101         CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
1102         return TRUE;\r
1103 }\r
1104 \r
1105 static boolean_t\r
1106 __destroy_node(\r
1107         IN      OUT                     ib_node_t*                                      p_node )\r
1108 {\r
1109         ib_api_status_t status = IB_SUCCESS;\r
1110         CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
1111         if (!p_node )\r
1112                 return (FALSE);\r
1113         if ( p_node->h_send_cq )\r
1114         {\r
1115                 status = ib_destroy_cq( p_node->h_send_cq, ib_sync_destroy );\r
1116                 p_node->h_send_cq = NULL;\r
1117                 if( status != IB_SUCCESS )\r
1118                 {\r
1119                         printf( "ib_destroy_cq failed for send CQ [%s]!\n",\r
1120                                 ib_get_err_str(status) );\r
1121                 }\r
1122         }\r
1123         if (p_node->h_recv_cq)\r
1124         {\r
1125                 status = ib_destroy_cq( p_node->h_recv_cq, ib_sync_destroy );\r
1126                 p_node->h_recv_cq = NULL;\r
1127                 if( status != IB_SUCCESS )\r
1128                 {\r
1129                         printf( "ib_destroy_cq failed for recv CQ [%s]!\n",\r
1130                                 ib_get_err_str(status) );\r
1131                 }\r
1132         }\r
1133 \r
1134         CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
1135         return (status == IB_SUCCESS);\r
1136 }\r
1137 \r
1138 \r
1139 \r
1140 static boolean_t\r
1141 __create_nodes()\r
1142 {\r
1143         int32_t                 i;\r
1144 \r
1145         CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
1146         for( i = 0; i < g_root.num_nodes; i++ )\r
1147         {\r
1148                 g_root.p_nodes[i].id = i;\r
1149 \r
1150                 CL_PRINT( CMT_DBG_VERBOSE, cmt_dbg_lvl, \r
1151                         ("--> create connection %d of instance %d\n", i, g_root.inst_id) );\r
1152                 \r
1153                 if( !__init_node( &g_root.p_nodes[i] ) )\r
1154                         return FALSE;\r
1155         }\r
1156 \r
1157         CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
1158         return TRUE;\r
1159 }\r
1160 \r
1161 static boolean_t\r
1162 __destroy_nodes()\r
1163 {\r
1164         int32_t                 i;\r
1165 \r
1166         CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
1167 \r
1168         for( i = 0; i < g_root.num_nodes; i++ )\r
1169         {\r
1170                 if( !__destroy_node( &g_root.p_nodes[i] ) )\r
1171                         return FALSE;\r
1172         }\r
1173         CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
1174         return TRUE;\r
1175 }\r
1176 \r
1177 /* query function called by ib_query() */\r
1178 static void AL_API\r
1179 __sa_query_cb(\r
1180         IN                              ib_query_rec_t                          *p_query_rec )\r
1181 {\r
1182         ib_path_rec_t   *p_path;\r
1183         ib_api_status_t status;\r
1184 \r
1185         CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
1186 \r
1187         CL_ASSERT( p_query_rec );\r
1188 \r
1189         if( p_query_rec->status != IB_SUCCESS )\r
1190         {\r
1191                 printf( "ib_query failed [%d]\n", p_query_rec->status ); \r
1192                 return;\r
1193         }\r
1194 \r
1195         if( p_query_rec->query_type != IB_QUERY_PATH_REC_BY_LIDS )\r
1196         {\r
1197                 printf( "Unexpected query type returned.\n" ); \r
1198                 return;\r
1199         }\r
1200 \r
1201         if( !p_query_rec->p_result_mad )\r
1202         {\r
1203                 printf( "No result MAD returned from ib_query.\n" ); \r
1204                 return;\r
1205         }\r
1206 \r
1207         /* copy the 1st (zero'th) path record to local storage. */\r
1208         p_path = ib_get_query_path_rec( p_query_rec->p_result_mad, 0 );\r
1209         memcpy( (void*)&g_root.path_rec, (void*)p_path, \r
1210                 sizeof(ib_path_rec_t) );\r
1211 \r
1212         CL_TRACE( CMT_DBG_VERBOSE, cmt_dbg_lvl,\r
1213                 ( "path{ slid:0x%x, dlid:0x%x }\n", \r
1214                 g_root.path_rec.slid, g_root.path_rec.dlid) );\r
1215 \r
1216         /* release response MAD(s) back to AL pool */\r
1217         if( p_query_rec->p_result_mad )\r
1218         {\r
1219                 status = ib_put_mad( p_query_rec->p_result_mad );\r
1220                 if( status != IB_SUCCESS )\r
1221                 {\r
1222                         printf( "ib_put_mad() failed [%s]\n",\r
1223                                 ib_get_err_str(status) );\r
1224                 }\r
1225         }\r
1226 \r
1227         CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
1228 }\r
1229 \r
1230 \r
1231 \r
1232 static boolean_t\r
1233 __query_for_path()\r
1234 {\r
1235         ib_api_status_t status;\r
1236         ib_query_req_t  query_rec;\r
1237         ib_lid_pair_t   lid_pair;\r
1238 \r
1239         /* Query the SA for a path record. */\r
1240         query_rec.query_type = IB_QUERY_PATH_REC_BY_LIDS;\r
1241 \r
1242         lid_pair.src_lid = g_root.l_lid;\r
1243         lid_pair.dest_lid = g_root.r_lid;\r
1244 \r
1245         query_rec.p_query_input = (void*)&lid_pair;\r
1246         query_rec.port_guid = g_root.port_guid;\r
1247         query_rec.timeout_ms = 5 * 1000;        // seconds\r
1248         query_rec.retry_cnt = 2;\r
1249         query_rec.flags = IB_FLAGS_SYNC;\r
1250         query_rec.query_context = &g_root;\r
1251         query_rec.pfn_query_cb = __sa_query_cb;\r
1252 \r
1253         status = ib_query( g_root.h_al, &query_rec, NULL );\r
1254         if( ( status != IB_SUCCESS ) || ( !g_root.path_rec.dlid ) )\r
1255         {\r
1256                 printf( "ib_query failed.\n" );\r
1257                 return FALSE;\r
1258         }\r
1259 \r
1260         return TRUE;\r
1261 }\r
1262 \r
1263 \r
1264 \r
1265 static boolean_t\r
1266 __create_messages()\r
1267 {\r
1268         ib_mr_create_t  mr_create;\r
1269         uint32_t                buf_size;\r
1270         ib_api_status_t status;\r
1271 \r
1272         /* If we're not sending messages, just return. */\r
1273         if( !g_root.num_msgs || !g_root.msg_size )\r
1274                 return TRUE;\r
1275 \r
1276         /* Allocate the message memory - we ignore the data, so just one buffer. */\r
1277         if( g_root.per_msg_buf )\r
1278                 buf_size = (g_root.num_nodes * g_root.num_msgs * g_root.msg_size) << 1;\r
1279         else\r
1280                 buf_size = g_root.msg_size;\r
1281         g_root.p_mem = (uint8_t*)cl_zalloc( buf_size );\r
1282         if( !g_root.p_mem )\r
1283         {\r
1284                 printf( "Not enough memory for transfers!\n" );\r
1285                 return FALSE;\r
1286         }\r
1287         memset (g_root.p_mem, 0xae, buf_size);\r
1288         g_root.p_mem_recv = g_root.p_mem;\r
1289         g_root.p_mem_send = g_root.p_mem + (buf_size >> 1);\r
1290 \r
1291         /* Register the memory with AL. */\r
1292         mr_create.vaddr = g_root.p_mem;\r
1293         mr_create.length = buf_size;\r
1294         mr_create.access_ctrl = IB_AC_LOCAL_WRITE | IB_AC_MW_BIND;\r
1295         status = ib_reg_mem( g_root.h_pd, &mr_create, &g_root.lkey, \r
1296                 &g_root.rkey, &g_root.h_mr );\r
1297         if( status != IB_SUCCESS )\r
1298         {\r
1299                 printf( "ib_reg_mem failed [%s]!\n", ib_get_err_str(status) );\r
1300                 return FALSE;\r
1301         }\r
1302 \r
1303         return TRUE;\r
1304 }\r
1305 \r
1306 \r
1307 \r
1308 /*\r
1309  * PnP callback handler.  Record the port GUID of an active port.\r
1310  */\r
1311 static ib_api_status_t AL_API\r
1312 __pnp_cb(\r
1313         IN                                      ib_pnp_rec_t                            *p_pnp_rec )\r
1314 {\r
1315         ib_pnp_port_rec_t*      p_port_rec;\r
1316         uint32_t                        size;\r
1317 \r
1318         p_port_rec = (ib_pnp_port_rec_t*)p_pnp_rec;\r
1319 \r
1320         /*\r
1321          * Ignore PNP events that are not related to port active, or if\r
1322          * we already have an active port.\r
1323          */\r
1324         if( p_pnp_rec->pnp_event != IB_PNP_PORT_ACTIVE || g_root.port_guid )\r
1325                 return IB_SUCCESS;\r
1326 \r
1327         /* Find the proper port for the given local LID. */\r
1328         if( g_root.l_lid )\r
1329         {\r
1330                 if( g_root.l_lid != p_port_rec->p_port_attr->lid )\r
1331                         return IB_SUCCESS;\r
1332         }\r
1333         else\r
1334         {\r
1335                 g_root.l_lid = p_port_rec->p_port_attr->lid;\r
1336                 printf( "\tlocal lid....: x%x\n", g_root.l_lid );\r
1337         }\r
1338 \r
1339         /* Record the active port information. */\r
1340         g_root.ca_guid = p_port_rec->p_ca_attr->ca_guid;\r
1341         g_root.port_num = p_port_rec->p_port_attr->port_num;\r
1342 \r
1343         /* Record the PKEYs available on the active port. */\r
1344         size = sizeof( ib_net16_t ) * p_port_rec->p_port_attr->num_pkeys;\r
1345         g_root.p_pkey_table = (ib_net16_t *)cl_zalloc( size );\r
1346         if( !g_root.p_pkey_table )\r
1347                 return IB_SUCCESS;\r
1348         g_root.num_pkeys = p_port_rec->p_port_attr->num_pkeys;\r
1349         cl_memcpy( g_root.p_pkey_table,\r
1350                 p_port_rec->p_port_attr->p_pkey_table, size );\r
1351 \r
1352         /* Set the port_guid last to indicate that we're ready. */\r
1353         g_root.port_guid = p_port_rec->p_port_attr->port_guid;\r
1354         return IB_SUCCESS;\r
1355 }\r
1356 \r
1357 \r
1358 /*\r
1359  * Register for PnP events and wait until a port becomes active.\r
1360  */\r
1361 static boolean_t\r
1362 __reg_pnp()\r
1363 {\r
1364         ib_api_status_t         status;\r
1365         ib_pnp_req_t            pnp_req;\r
1366         ib_pnp_handle_t         h_pnp;\r
1367 \r
1368         cl_memclr( &pnp_req, sizeof( ib_pnp_req_t ) );\r
1369         pnp_req.pnp_class = IB_PNP_PORT;\r
1370         pnp_req.pnp_context = &g_root;\r
1371         pnp_req.pfn_pnp_cb = __pnp_cb;\r
1372 \r
1373         /* Register for PnP events. */\r
1374         status = ib_reg_pnp( g_root.h_al, &pnp_req, &h_pnp );\r
1375         if( status != IB_SUCCESS )\r
1376         {\r
1377                 printf( "ib_reg_pnp failed [%s]!\n", ib_get_err_str(status) );\r
1378                 return FALSE;\r
1379         }\r
1380 \r
1381         /* Wait until a port goes active. */\r
1382         while( !g_root.port_guid )\r
1383                 cl_thread_suspend( 10 );\r
1384 \r
1385         /* Deregister from PnP. */\r
1386         ib_dereg_pnp( h_pnp, NULL );\r
1387 \r
1388         return TRUE;\r
1389 }\r
1390 \r
1391 \r
1392 \r
1393 static boolean_t\r
1394 __init_root()\r
1395 {\r
1396         ib_api_status_t status;\r
1397 \r
1398         CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
1399 \r
1400         cl_mutex_construct( &g_root.mutex );\r
1401         if( cl_mutex_init( &g_root.mutex ) != CL_SUCCESS )\r
1402                 return FALSE;\r
1403 \r
1404         /* Open AL. */\r
1405         status = ib_open_al( &g_root.h_al );\r
1406         if( status != IB_SUCCESS )\r
1407         {\r
1408                 printf( "ib_open_al failed [%s]!\n", ib_get_err_str(status) );\r
1409                 return FALSE;\r
1410         }\r
1411 \r
1412         /* Register for PnP events, and wait until we have an active port. */\r
1413         if( !__reg_pnp() )\r
1414                 return FALSE;\r
1415 \r
1416         /* Open the CA. */\r
1417         status = ib_open_ca( g_root.h_al,\r
1418                                                  g_root.ca_guid,\r
1419                                                  __ca_async_event_cb,\r
1420                                                  &g_root,\r
1421                                                  &g_root.h_ca );\r
1422         if( status != IB_SUCCESS )\r
1423         {\r
1424                 printf( "ib_open_ca failed [%s]!\n", ib_get_err_str(status) );\r
1425                 return FALSE;\r
1426         }\r
1427 \r
1428         /* Create a PD. */\r
1429         status = ib_alloc_pd( g_root.h_ca, IB_PDT_NORMAL, &g_root, \r
1430                 &g_root.h_pd );\r
1431         if( status != IB_SUCCESS )\r
1432         {\r
1433                 printf( "ib_alloc_pd failed [%s]!\n", ib_get_err_str(status) );\r
1434                 return FALSE;\r
1435         }\r
1436 \r
1437         /* Get a path record to the remote side. */\r
1438         if( !__query_for_path() )\r
1439         {\r
1440                 printf( "Unable to query for path record!\n" );\r
1441                 return FALSE;\r
1442         }\r
1443 \r
1444         /* Allocate and register memory for the messages. */\r
1445         if( !__create_messages() )\r
1446         {\r
1447                 printf( "Unable to create messages!\n" );\r
1448                 return FALSE;\r
1449         }\r
1450 \r
1451         /* Create the connection endpoints. */\r
1452         g_root.p_nodes = (ib_node_t*)cl_zalloc(\r
1453                 sizeof(ib_node_t) * g_root.num_nodes );\r
1454         if( !g_root.p_nodes )\r
1455         {\r
1456                 printf( "Unable to allocate nodes\n" ); \r
1457                 return FALSE;\r
1458         }\r
1459 \r
1460         CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
1461         return TRUE;\r
1462 }\r
1463 \r
1464 \r
1465 \r
1466 static void\r
1467 __cleanup()\r
1468 {\r
1469         if( g_root.h_listen )\r
1470                 ib_cm_cancel( g_root.h_listen, __cancel_listen_cb );\r
1471 \r
1472         /* Close AL if it was opened. */\r
1473         if( g_root.h_al )\r
1474                 ib_close_al( g_root.h_al );\r
1475 \r
1476         cl_mutex_destroy( &g_root.mutex );\r
1477 \r
1478         if( g_root.p_mem )\r
1479                 cl_free( g_root.p_mem );\r
1480 \r
1481         if( g_root.p_pkey_table )\r
1482                 cl_free( g_root.p_pkey_table );\r
1483 \r
1484         /* Free all allocated memory. */\r
1485         if( g_root.p_nodes )\r
1486                 cl_free( g_root.p_nodes );\r
1487 }\r
1488 \r
1489 \r
1490 \r
1491 /*\r
1492  * Have the server start listening for connections.\r
1493  */\r
1494 static boolean_t\r
1495 __listen()\r
1496 {\r
1497         ib_cm_listen_t  cm_listen;\r
1498         ib_api_status_t status;\r
1499 \r
1500         cl_memclr( &cm_listen, sizeof( ib_cm_listen_t ) );\r
1501 \r
1502         /* The server side listens. */\r
1503         cm_listen.svc_id = CMT_BASE_SVC_ID + g_root.inst_id;\r
1504 \r
1505         cm_listen.pfn_cm_req_cb = __req_cb;\r
1506 \r
1507         cm_listen.qp_type = IB_QPT_RELIABLE_CONN;\r
1508 \r
1509         status = ib_cm_listen( g_root.h_al,\r
1510                                                    &cm_listen, \r
1511                                                    &g_root,\r
1512                                                    &g_root.h_listen );\r
1513         if( status != IB_SUCCESS )\r
1514         {\r
1515                 printf( "ib_cm_listen failed [%s]!\n", ib_get_err_str(status) );\r
1516                 return FALSE;\r
1517         }\r
1518         return TRUE;\r
1519 }\r
1520 \r
1521 \r
1522 \r
1523 /*\r
1524  * Initiate all client connection requests.\r
1525  */\r
1526 static ib_api_status_t\r
1527 __conn_reqs()\r
1528 {\r
1529         ib_api_status_t status;\r
1530         int32_t                 i;\r
1531         uint8_t                 pdata[IB_REQ_PDATA_SIZE];\r
1532 \r
1533         g_root.cm_req.p_req_pdata = pdata;\r
1534         g_root.cm_req.req_length = IB_REQ_PDATA_SIZE;\r
1535 \r
1536         /* Request a connection for each client. */\r
1537         for( i = 0; i < g_root.num_nodes; i++ )\r
1538         {\r
1539                 g_root.cm_req.h_qp = g_root.p_nodes[i].h_qp;\r
1540 \r
1541                 status = ib_cm_req( &g_root.cm_req );\r
1542                 if( status != IB_SUCCESS )\r
1543                 {\r
1544                         printf( "ib_cm_req failed [%s]!\n", ib_get_err_str(status) );\r
1545                         return status;\r
1546                 }\r
1547         }\r
1548         return IB_SUCCESS;\r
1549 }\r
1550 \r
1551 \r
1552 \r
1553 /*\r
1554  * Send any connection replies waiting to be sent.\r
1555  */\r
1556 static ib_api_status_t\r
1557 __conn_reps()\r
1558 {\r
1559         ib_api_status_t status;\r
1560         uintn_t                 i;\r
1561         uint8_t                 pdata[IB_REP_PDATA_SIZE];\r
1562 \r
1563         g_root.cm_rep.p_rep_pdata = pdata;\r
1564         g_root.cm_rep.rep_length = IB_REP_PDATA_SIZE;\r
1565 \r
1566         /* Send a reply for each connection that requires one. */\r
1567         for( i = 0; i < g_root.conn_index; i++ )\r
1568         {\r
1569                 g_root.cm_rep.h_qp = g_root.p_nodes[i].h_qp;\r
1570                 status = ib_cm_rep( g_root.p_nodes[i].h_cm_req, &g_root.cm_rep );\r
1571                 if( status != IB_SUCCESS )\r
1572                 {\r
1573                         printf( "ib_cm_rep failed [%s]!\n", ib_get_err_str(status) );\r
1574                         return status;\r
1575                 }\r
1576         }\r
1577         return IB_SUCCESS;\r
1578 }\r
1579 \r
1580 \r
1581 \r
1582 /*\r
1583  * Establish all connections.\r
1584  */\r
1585 static ib_api_status_t\r
1586 __connect()\r
1587 {\r
1588         uint64_t                total_time;\r
1589         ib_api_status_t status;\r
1590 \r
1591         CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
1592 \r
1593         printf( "Connecting...\n" );\r
1594         cl_mutex_acquire( &g_root.mutex );\r
1595         g_root.state = test_connecting;\r
1596 \r
1597         /* Initiate the connections. */\r
1598         if( g_root.is_server )\r
1599         {\r
1600                 /*\r
1601                  * Send any replies.  Note that we hold the mutex while sending the\r
1602                  * replies since we need to use the global cm_rep structure.\r
1603                  */\r
1604                 status = __conn_reps();\r
1605                 cl_mutex_release( &g_root.mutex );\r
1606         }\r
1607         else\r
1608         {\r
1609                 cl_mutex_release( &g_root.mutex );\r
1610                 g_root.conn_start_time = cl_get_time_stamp();\r
1611                 status = __conn_reqs();\r
1612         }\r
1613 \r
1614         if( status != IB_SUCCESS )\r
1615                 return status;\r
1616 \r
1617         /* Wait for all connections to complete. */\r
1618         while( g_root.num_connected < g_root.num_nodes )\r
1619                 cl_thread_suspend( 0 );\r
1620 \r
1621         /* Calculate the total connection time. */\r
1622         total_time = cl_get_time_stamp() - g_root.conn_start_time;\r
1623         g_root.state = test_idle;\r
1624 \r
1625         /* Reset connection information for next test. */\r
1626         g_root.conn_index = 0;\r
1627         g_root.conn_start_time = 0;\r
1628 \r
1629         printf( "Connect time: %"PRId64" ms\n", total_time/1000 );\r
1630 \r
1631         CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
1632         return status;\r
1633 }\r
1634 \r
1635 \r
1636 \r
1637 static void\r
1638 __disconnect()\r
1639 {\r
1640         ib_api_status_t status;\r
1641         int32_t                 i;\r
1642         ib_node_t               *p_node;\r
1643         uint64_t                total_time, start_time;\r
1644 \r
1645         printf( "Disconnecting...\n" );\r
1646 \r
1647         /* Initiate the disconnection process. */\r
1648         cl_mutex_acquire( &g_root.mutex );\r
1649         g_root.state = test_disconnecting;\r
1650         start_time = cl_get_time_stamp();\r
1651         cl_mutex_release( &g_root.mutex );\r
1652 \r
1653         /* We hold the mutex to prevent calling ib_cm_drep at the same time. */\r
1654         for( i = 0; i < g_root.num_nodes; i++ )\r
1655         {\r
1656                 p_node = &g_root.p_nodes[i];\r
1657 \r
1658                 /*\r
1659                  * Send the DREQ.  Note that some of these may fail, since the\r
1660                  * remote side may be disconnecting at the same time.  Call DREQ\r
1661                  * only if we haven't called DREP yet.\r
1662                  */\r
1663                 cl_mutex_acquire( &g_root.mutex );\r
1664                 switch( p_node->state )\r
1665                 {\r
1666                 case node_conn:\r
1667                         g_root.cm_dreq.h_qp = p_node->h_qp;\r
1668                         status = ib_cm_dreq( &g_root.cm_dreq );\r
1669                         if( status == IB_SUCCESS )\r
1670                                 p_node->state = node_dreq_sent;\r
1671                         break;\r
1672 \r
1673                 case node_dreq_rcvd:\r
1674                         status = ib_cm_drep( p_node->h_cm_dreq, &g_root.cm_drep );\r
1675 \r
1676                         /* If the DREP was successful, we're done with this connection. */\r
1677                         if( status == IB_SUCCESS )\r
1678                         {\r
1679                                 p_node->state = node_idle;\r
1680                                 cl_atomic_dec( &g_root.num_connected );\r
1681                         }\r
1682                         break;\r
1683 \r
1684                 default:\r
1685                         /* Node is already disconnected. */\r
1686                         break;\r
1687                 }\r
1688                 cl_mutex_release( &g_root.mutex );\r
1689         }\r
1690 \r
1691         /* Wait for all disconnections to complete. */\r
1692         while( g_root.num_connected )\r
1693                 cl_thread_suspend( 0 );\r
1694 \r
1695         if( g_root.h_listen )\r
1696         {\r
1697                 ib_cm_cancel( g_root.h_listen, __cancel_listen_cb );\r
1698                 g_root.h_listen = NULL;\r
1699         }\r
1700         /* Calculate the total connection time. */\r
1701         total_time = cl_get_time_stamp() - start_time;\r
1702         g_root.state = test_idle;\r
1703 \r
1704         printf( "Disconnect time: %"PRId64" ms\n", total_time/1000 );\r
1705 }\r
1706 \r
1707 \r
1708 \r
1709 /*\r
1710  * Send the requested number of messages on each connection.\r
1711  */\r
1712 static boolean_t\r
1713 __send_msgs()\r
1714 {\r
1715         ib_api_status_t status;\r
1716         int32_t                 i;\r
1717         uint32_t                m;\r
1718         ib_send_wr_t    send_wr;\r
1719         ib_send_wr_t    *p_send_failure;\r
1720         ib_local_ds_t   ds_array;\r
1721 \r
1722         CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
1723 \r
1724         /* For each connection... */\r
1725         for( i = 0; i < g_root.num_nodes; i++ )\r
1726         {\r
1727                 /* Send the specified number of messages. */\r
1728                 for( m = 0; m < g_root.num_msgs; m++ )\r
1729                 {\r
1730                         /* Get the buffer for this message. */\r
1731                         if( g_root.per_msg_buf )\r
1732                         {\r
1733                                 ds_array.vaddr = (uintn_t)(g_root.p_mem_send +\r
1734                                         (i * g_root.num_msgs) + (m * g_root.msg_size));\r
1735                         }\r
1736                         else\r
1737                         {\r
1738                                 ds_array.vaddr = (uintn_t)g_root.p_mem;\r
1739                         }\r
1740                         ds_array.length = g_root.msg_size;\r
1741                         ds_array.lkey = g_root.lkey;\r
1742 \r
1743                         /* Format the send WR for this message. */\r
1744                         send_wr.ds_array = &ds_array;\r
1745                         send_wr.send_opt = IB_SEND_OPT_SIGNALED | IB_SEND_OPT_SOLICITED;\r
1746                         send_wr.send_opt |= ((g_root.msg_size <= 4)? IB_SEND_OPT_IMMEDIATE : 0x0 );\r
1747                         send_wr.wr_type = WR_SEND;\r
1748                         send_wr.num_ds = ((g_root.msg_size <= 4)? 0 : 1 );\r
1749                         send_wr.p_next = NULL;\r
1750                         send_wr.wr_id = m;\r
1751 \r
1752                         if( g_root.msg_size < g_root.p_nodes[i].max_inline )\r
1753                                 send_wr.send_opt |= IB_SEND_OPT_INLINE;\r
1754 \r
1755                         /* Torpedoes away!  Send the message. */\r
1756                         CL_PRINT( CMT_DBG_VERBOSE, cmt_dbg_lvl, (".") );\r
1757                         status = ib_post_send( g_root.p_nodes[i].h_qp, &send_wr,\r
1758                                 &p_send_failure );\r
1759                         if( status != IB_SUCCESS )\r
1760                         {\r
1761                                 printf( "ib_post_send failed [%s]!\n",\r
1762                                         ib_get_err_str(status) );\r
1763                                 return FALSE;\r
1764                         }\r
1765                 }\r
1766         }\r
1767         \r
1768         CL_PRINT( CMT_DBG_VERBOSE, cmt_dbg_lvl, ("\n") );\r
1769         CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
1770         return TRUE;\r
1771 }\r
1772 \r
1773 \r
1774 \r
1775 /*\r
1776  * Remove num_msgs completions from the specified CQ.\r
1777  */\r
1778 static boolean_t\r
1779 __poll_cq(\r
1780         IN                              ib_node_t                                       *p_node,\r
1781         IN                              ib_cq_handle_t                          h_cq )\r
1782 {\r
1783         ib_api_status_t status = IB_SUCCESS;\r
1784         ib_wc_t                 free_wc[2];\r
1785         ib_wc_t                 *p_free_wc, *p_done_wc;\r
1786 \r
1787         CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
1788 \r
1789         while( status != IB_NOT_FOUND )\r
1790         {\r
1791                 /* Get all completions. */\r
1792                 p_free_wc = &free_wc[0];\r
1793                 free_wc[0].p_next = &free_wc[1];\r
1794                 free_wc[1].p_next = NULL;\r
1795                 p_done_wc = NULL;\r
1796 \r
1797                 status = ib_poll_cq( h_cq, &p_free_wc, &p_done_wc );\r
1798 \r
1799                 /* Continue polling if nothing is done. */\r
1800                 if( status == IB_NOT_FOUND )\r
1801                         break;\r
1802 \r
1803                 /* Abort if an error occurred. */\r
1804                 if( status != IB_SUCCESS )\r
1805                 {\r
1806                         printf( "Error polling status = %#x( wc_status =%s)\n", \r
1807                                 status,\r
1808                                 ((p_done_wc != NULL )? wc_status_text[p_done_wc->status]:"N/A") );\r
1809                         return FALSE;\r
1810                 }\r
1811 \r
1812                 while( p_done_wc )\r
1813                 {\r
1814                         switch( p_done_wc->status )\r
1815                         {\r
1816                         case IB_WCS_SUCCESS:\r
1817                                 CL_PRINT( CMT_DBG_VERBOSE, cmt_dbg_lvl,\r
1818                                         ("Got a completion: \n\ttype....:%s\n\twr_id...:%"PRIx64"\n"\r
1819                                         "status....:%s\n", wc_type_text[p_done_wc->wc_type],\r
1820                                         p_done_wc->wr_id, wc_status_text[p_done_wc->status] ) );\r
1821 \r
1822                                 if( p_done_wc->wc_type == IB_WC_RECV )\r
1823                                 {\r
1824                                         CL_ASSERT( p_done_wc->wr_id == p_node->recv_cnt );\r
1825                                         if( p_done_wc->length != g_root.msg_size )\r
1826                                         {\r
1827                                                 printf( "Error: received %d bytes, expected %d.\n",\r
1828                                                         p_done_wc->length, g_root.msg_size );\r
1829                                         }\r
1830 \r
1831                                         p_node->recv_cnt++;\r
1832                                         g_root.total_recv++;\r
1833                                 }\r
1834                                 else\r
1835                                 {\r
1836                                         CL_ASSERT( p_done_wc->wr_id == p_node->send_cnt );\r
1837                                         p_node->send_cnt++;\r
1838                                         g_root.total_sent++;\r
1839                                 }\r
1840                                 break;\r
1841 \r
1842                         default:\r
1843                                 printf( "[%d] Bad completion type(%s) status(%s)\n",\r
1844                                         __LINE__, wc_type_text[p_done_wc->wc_type],\r
1845                                         wc_status_text[p_done_wc->status] );\r
1846                                 return FALSE;\r
1847                         }\r
1848                         p_done_wc = p_done_wc->p_next;\r
1849                 }\r
1850         }\r
1851 \r
1852         if( !g_root.is_polling )\r
1853         {\r
1854                 status = ib_rearm_cq(h_cq, FALSE);\r
1855                 if (status != IB_SUCCESS)\r
1856                 {\r
1857                         printf("Failed to rearm CQ %p\n", h_cq );\r
1858                         return FALSE;\r
1859                 }\r
1860         }\r
1861 \r
1862         CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
1863         return TRUE;\r
1864 }\r
1865 \r
1866 \r
1867 \r
1868 /*\r
1869  * Remove num_msgs completions from all send CQs for all connections.\r
1870  */\r
1871 static boolean_t\r
1872 __poll_send_cqs()\r
1873 {\r
1874         ib_node_t               *p_node;\r
1875         int32_t                 i;\r
1876 \r
1877         for( i = 0; i < g_root.num_nodes; i++ )\r
1878         {\r
1879                 p_node = &g_root.p_nodes[i];\r
1880                 while( p_node->send_cnt < g_root.num_msgs )\r
1881                 {\r
1882                         if( !g_root.is_polling )\r
1883                                 cl_thread_suspend( 0 );\r
1884                         else if( !__poll_cq( p_node, p_node->h_send_cq ) )\r
1885                                 return FALSE;\r
1886                 }\r
1887         }\r
1888         return TRUE;\r
1889 }\r
1890 \r
1891 \r
1892 \r
1893 /*\r
1894  * Remove num_msgs completions from all receive CQs for all connections.\r
1895  */\r
1896 static boolean_t\r
1897 __poll_recv_cqs()\r
1898 {\r
1899         ib_node_t               *p_node;\r
1900         int32_t                 i;\r
1901 \r
1902         for( i = 0; i < g_root.num_nodes; i++ )\r
1903         {\r
1904                 p_node = &g_root.p_nodes[i];\r
1905                 while( p_node->recv_cnt < g_root.num_msgs )\r
1906                 {\r
1907                         if( !g_root.is_polling )\r
1908                                 cl_thread_suspend( 0 );\r
1909                         else if( !__poll_cq( p_node, p_node->h_recv_cq ) )\r
1910                                 return FALSE;\r
1911                 }\r
1912         }\r
1913         return TRUE;\r
1914 }\r
1915 \r
1916 \r
1917 \r
1918 /**********************************************************************\r
1919  **********************************************************************/\r
1920 \r
1921 int __cdecl\r
1922 main(\r
1923         int                                                     argc,\r
1924         char*                                           argv[] )\r
1925 {\r
1926         uint64_t                                        start_time, total_time;\r
1927         uint64_t                                        total_xfer;\r
1928         uint32_t                                        i;\r
1929 \r
1930         cl_memclr( &g_root, sizeof(ib_root_t) );\r
1931 \r
1932         /* Set defaults. */\r
1933         if( !__parse_options( argc, argv ) )\r
1934                 return 1;\r
1935 \r
1936         /* Initialize the root - open all common HCA resources. */\r
1937         if( !__init_root() )\r
1938         {\r
1939                 printf( "__init_root failed\n" );\r
1940                 __cleanup();\r
1941                 return 1;\r
1942         }\r
1943 \r
1944         /*\r
1945          * Execute the test the specified number of times.  Abort the test\r
1946          * if any errors occur.\r
1947          */\r
1948         total_xfer = g_root.num_msgs * g_root.msg_size * g_root.num_nodes;\r
1949         for( i = 0; i < g_root.num_iter; i++ )\r
1950         {\r
1951                 printf( "----- Iteration: %d, %d connections -----\n",\r
1952                         i, g_root.num_nodes );\r
1953 \r
1954                 /* Initialize the connection parameters. */\r
1955                 __init_conn_info();\r
1956                 __init_qp_info();\r
1957                 __create_nodes();\r
1958                 /* Start listening for connections if we're the server. */\r
1959                 if( g_root.is_server )\r
1960                         __listen();\r
1961 \r
1962                 cl_thread_suspend(1000);\r
1963                 /* Allocate a new set of QPs for the connections. */\r
1964                 if( __create_qps() != IB_SUCCESS )\r
1965                 {\r
1966                         printf( "Unable to allocate QPs for test.\n" );\r
1967                         break;\r
1968                 }\r
1969 \r
1970                 /* Establish all connections. */\r
1971                 if( __connect() != IB_SUCCESS )\r
1972                 {\r
1973                         printf( "Failed to establish connections.\n" );\r
1974                         break;\r
1975                 }\r
1976 \r
1977                 printf( "Transfering data...\n" );\r
1978                 g_root.state = test_transfering;\r
1979                 start_time = cl_get_time_stamp();\r
1980 \r
1981                 if( g_root.num_msgs )\r
1982                 {\r
1983                         if( g_root.is_server )\r
1984                         {\r
1985                                 /* The server initiate the sends to avoid race conditions. */\r
1986                                 if( !__send_msgs() )\r
1987                                         break;\r
1988 \r
1989                                 /* Get all send completions. */\r
1990                                 if( !__poll_send_cqs() )\r
1991                                         break;\r
1992 \r
1993                                 /* Get all receive completions. */\r
1994                                 if( !__poll_recv_cqs() )\r
1995                                         break;\r
1996                         }\r
1997                         else\r
1998                         {\r
1999                                 /* Get all receive completions. */\r
2000                                 if( !__poll_recv_cqs() )\r
2001                                         break;\r
2002 \r
2003                                 /* Reply to the sends. */\r
2004                                 if( !__send_msgs() )\r
2005                                         break;\r
2006 \r
2007                                 /* Get all send completions. */\r
2008                                 if( !__poll_send_cqs() )\r
2009                                         break;\r
2010                         }\r
2011                 }\r
2012 \r
2013                 total_time = cl_get_time_stamp() - start_time;\r
2014                 g_root.state = test_idle;\r
2015 \r
2016                 printf( "Data transfer time: %"PRId64" ms, %d messages/conn, "\r
2017                         "%"PRId64" total bytes", total_time/1000,\r
2018                         g_root.num_msgs, total_xfer );\r
2019                 if ( total_xfer > (4*1024*1024) )\r
2020                 {\r
2021                         double mb;\r
2022                         mb = ((double)total_xfer / (1024.0*1024.0))\r
2023                                 / ((double)total_time / 1000000.0);\r
2024                         printf(" %4.2f MB/s",mb);\r
2025                 }\r
2026                 printf("\n");\r
2027 \r
2028                 /* Disconnect all connections. */\r
2029                 __disconnect();\r
2030                 __destroy_qps();\r
2031                 __destroy_nodes();\r
2032         }\r
2033 \r
2034         __cleanup();\r
2035         return 0;\r
2036 }\r