Set property svn:keywords "id" on all repository
[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  *\r
5  * This software is available to you under the OpenIB.org BSD license\r
6  * below:\r
7  *\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
11  *\r
12  *      - Redistributions of source code must retain the above\r
13  *        copyright notice, this list of conditions and the following\r
14  *        disclaimer.\r
15  *\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
20  *\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
28  * SOFTWARE.\r
29  *\r
30  * $Id$\r
31  */\r
32 \r
33 \r
34 /*\r
35  * Abstract:\r
36  *      Command line interface for cmtest.\r
37  *\r
38  * Environment:\r
39  *      User Mode\r
40  */\r
41 \r
42 #include <stdio.h>\r
43 #include <stdlib.h>\r
44 #include <stdarg.h>\r
45 #include <ctype.h>\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
56 \r
57 \r
58 /* Globals */\r
59 #define CMT_DBG_VERBOSE         1\r
60 \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
64 \r
65 \r
66 typedef enum _cmtest_state\r
67 {\r
68         test_idle, test_connecting, test_transfering, test_disconnecting\r
69 \r
70 }       cmtest_state_t;\r
71 \r
72 \r
73 \r
74 typedef struct _ib_root\r
75 {\r
76         ib_al_handle_t          h_al;\r
77         ib_pd_handle_t          h_pd;\r
78 \r
79         /* Input parameters to control test. */\r
80         int32_t                         num_nodes;\r
81         uint32_t                        num_msgs;\r
82         boolean_t                       per_msg_buf;\r
83         cl_mutex_t                      mutex;\r
84 \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
90 \r
91         uint32_t                        num_iter;\r
92 \r
93         uint32_t                        msg_size;\r
94 \r
95         ib_ca_handle_t          h_ca;\r
96         ib_net16_t                      l_lid;\r
97         ib_net16_t                      r_lid;\r
98         ib_net64_t                      ca_guid;\r
99         ib_net64_t                      port_guid;\r
100         uint8_t                         port_num;\r
101         uint16_t                        num_pkeys;\r
102         ib_net16_t                      *p_pkey_table;\r
103 \r
104         /* cm info */\r
105         boolean_t                       is_server;\r
106         ib_listen_handle_t      h_listen;\r
107         ib_path_rec_t           path_rec;\r
108 \r
109         /* CQ info. */\r
110         boolean_t                       is_polling;\r
111 \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
116 \r
117         /* reg mem info */\r
118         ib_mr_handle_t          h_mr;\r
119         uint32_t                        lkey;\r
120         uint32_t                        rkey;\r
121         uint8_t                         *p_mem;\r
122         uint8_t                         *p_mem_recv;\r
123         uint8_t                         *p_mem_send;\r
124 \r
125         uint64_t                        conn_start_time;\r
126 \r
127         /*\r
128          * Connection parameters are initialized once to improve connection\r
129          * establishment rate.\r
130          */\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
136 \r
137         uint32_t                        inst_id;\r
138 \r
139 }       ib_root_t;\r
140 \r
141 \r
142 \r
143 typedef enum _cmnode_state\r
144 {\r
145         node_idle, node_conn, node_dreq_sent, node_dreq_rcvd\r
146 \r
147 }       cmnode_state_t;\r
148 \r
149 \r
150 \r
151 typedef struct  _ib_node\r
152 {\r
153         uint64_t                        id;\r
154 \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
159 \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
163 \r
164         uint32_t                        send_cnt;\r
165         uint32_t                        recv_cnt;\r
166 \r
167 }       ib_node_t;\r
168 \r
169 \r
170 \r
171 uint32_t        cmt_dbg_lvl = 0x80000000;\r
172 \r
173 ib_root_t       g_root;\r
174 \r
175 \r
176 static char *wc_type_text[] = {\r
177         "IB_WC_SEND",\r
178         "IB_WC_RDMA_WRITE",\r
179         "IB_WC_RECV",\r
180         "IB_WC_RDMA_READ",\r
181         "IB_WC_MW_BIND",\r
182         "IB_WC_FETCH_ADD",\r
183         "IB_WC_COMPARE_SWAP",\r
184         "IB_WC_RECV_RDMA_WRITE"\r
185 };\r
186 \r
187 static char *wc_status_text[] = {\r
188         "IB_WCS_SUCCESS",\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
204         "IB_WCS_CANCELED"                                               \r
205 };\r
206 \r
207 \r
208 \r
209 static void\r
210 __req_cb(\r
211         IN                              ib_cm_req_rec_t                         *p_cm_req_rec );\r
212 \r
213 static void\r
214 __rep_cb(\r
215         IN                              ib_cm_rep_rec_t                         *p_cm_rep_rec );\r
216 \r
217 static void\r
218 __rtu_cb(\r
219         IN                              ib_cm_rtu_rec_t                         *p_cm_rtu_rec );\r
220 \r
221 static void\r
222 __rej_cb(\r
223         IN                              ib_cm_rej_rec_t                         *p_cm_rej_rec );\r
224 \r
225 static void\r
226 __mra_cb(\r
227         IN                              ib_cm_mra_rec_t                         *p_cm_mra_rec );\r
228 \r
229 static void\r
230 __apr_cb(\r
231         IN                              ib_cm_apr_rec_t                         *p_cm_apr_rec );\r
232 \r
233 static void\r
234 __lap_cb(\r
235         IN                              ib_cm_lap_rec_t                         *p_cm_lap_rec );\r
236 \r
237 static void\r
238 __dreq_cb(\r
239         IN                              ib_cm_dreq_rec_t                        *p_cm_dreq_rec );\r
240 \r
241 static void\r
242 __drep_cb(\r
243         IN                              ib_cm_drep_rec_t                        *p_cm_drep_rec );\r
244 \r
245 static boolean_t\r
246 __poll_cq(\r
247         IN                              ib_node_t                                       *p_node,\r
248         IN                              ib_cq_handle_t                          h_cq );\r
249 \r
250 \r
251 /**********************************************************************\r
252  **********************************************************************/\r
253 static void\r
254 __show_usage()\r
255 {\r
256         printf( "\n------- cmtest - Usage and options ----------------------\n" );\r
257         printf( "Usage:   cmtest [options]\n");\r
258         printf( "Options:\n" );\r
259         printf( "-s\n"\r
260                         "--server\n"\r
261                         "          This option directs cmtest to act as a Server\n" );\r
262         printf( "-l <lid>\n"\r
263                         "--local <lid>\n"\r
264                         "          This option specifies the local endpoint.\n" );\r
265         printf( "-r <lid>\n"\r
266                         "--remote <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
279         printf( "-p\n"\r
280                         "--permsg\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
287         printf( "-v\n"\r
288                         "--verbose\n"\r
289                         "          This option enables verbosity level to debug console.\n" );\r
290         printf( "-h\n"\r
291                         "--help\n"\r
292                         "          Display this usage info then exit.\n\n" );\r
293 }\r
294 \r
295 \r
296 /* Windows support. */\r
297 struct option\r
298 {\r
299         const char              *long_name;\r
300         unsigned long   flag;\r
301         void                    *pfn_handler;\r
302         char                    short_name;\r
303 };\r
304 \r
305 static char                     *optarg;\r
306 \r
307 #define strtoull        strtoul\r
308 \r
309 \r
310 char\r
311 getopt_long(\r
312         int                                     argc,\r
313         char                            *argv[],\r
314         const char                      *short_option,\r
315         const struct option *long_option,\r
316         void                            *unused )\r
317 {\r
318         static int i = 1;\r
319         int j;\r
320         char            ret = 0;\r
321 \r
322         UNUSED_PARAM( unused );\r
323 \r
324         if( i == argc )\r
325                 return -1;\r
326 \r
327         if( argv[i][0] != '-' )\r
328                 return ret;\r
329 \r
330         /* find the first character of the value. */\r
331         for( j = 1; isalpha( argv[i][j] ); j++ )\r
332                 ;\r
333         optarg = &argv[i][j];\r
334 \r
335         if( argv[i][1] == '-' )\r
336         {\r
337                 /* Long option. */\r
338                 for( j = 0; long_option[j].long_name; j++ )\r
339                 {\r
340                         if( strncmp( &argv[i][2], long_option[j].long_name,\r
341                                 optarg - argv[i] - 2 ) )\r
342                         {\r
343                                 continue;\r
344                         }\r
345 \r
346                         switch( long_option[j].flag )\r
347                         {\r
348                         case 1:\r
349                                 if( *optarg == '\0' )\r
350                                         return 0;\r
351                         default:\r
352                                 break;\r
353                         }\r
354                         ret = long_option[j].short_name;\r
355                         break;\r
356                 }\r
357         }\r
358         else\r
359         {\r
360                 for( j = 0; short_option[j] != '\0'; j++ )\r
361                 {\r
362                         if( !isalpha( short_option[j] ) )\r
363                                 return 0;\r
364 \r
365                         if( short_option[j] == argv[i][1] )\r
366                         {\r
367                                 ret = short_option[j];\r
368                                 break;\r
369                         }\r
370 \r
371                         if( short_option[j+1] == ':' )\r
372                         {\r
373                                 if( *optarg == '\0' )\r
374                                         return 0;\r
375                                 j++;\r
376                         }\r
377                 }\r
378         }\r
379         i++;\r
380         return ret;\r
381 }\r
382 \r
383 \r
384 static boolean_t\r
385 __parse_options(\r
386         int                                                     argc,\r
387         char*                                           argv[] )\r
388 {\r
389         uint32_t                                        next_option;\r
390         const char* const                       short_option = "esl:r:c:m:n:i:pvh";\r
391 \r
392         /*\r
393                 In the array below, the 2nd parameter specified the number\r
394                 of arguments as follows:\r
395                 0: no arguments\r
396                 1: argument\r
397                 2: optional\r
398         */\r
399         const struct option long_option[] =\r
400         {\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
413         };\r
414 \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
421 \r
422         /* parse cmd line arguments as input params */\r
423         do\r
424         {\r
425                 next_option = getopt_long( argc, argv, short_option,\r
426                         long_option, NULL );\r
427 \r
428                 switch( next_option )\r
429                 {\r
430                 case 's':\r
431                         g_root.is_server = TRUE;\r
432                         printf( "\tServer mode\n" );\r
433                         break;\r
434 \r
435                 case 'd':\r
436                         g_root.inst_id = strtoull( optarg, NULL, 0 );\r
437                         printf( "\tinstance_id..: %d\n", g_root.inst_id );\r
438                         break;\r
439 \r
440                 case 'c':\r
441                         g_root.num_nodes = strtoull( optarg, NULL, 0 );\r
442                         printf( "\tconnections..: %d\n", g_root.num_nodes );\r
443                         break;\r
444 \r
445                 case 'l':\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
448                         break;\r
449 \r
450                 case 'r':\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
453                         break;\r
454 \r
455                 case 'm':\r
456                         g_root.msg_size = strtoull( optarg, NULL, 0 );\r
457                         printf( "\tmsg size.....: %d bytes\n", g_root.msg_size );\r
458                         break;\r
459 \r
460                 case 'n':\r
461                         g_root.num_msgs = strtoull( optarg, NULL, 0 );\r
462                         printf( "\tnum msgs.....: %d\n", g_root.num_msgs );\r
463                         break;\r
464 \r
465                 case 'i':\r
466                         g_root.num_iter = strtoull( optarg, NULL, 0 );\r
467                         printf( "\titerate......: %d\n", g_root.num_iter );\r
468                         break;\r
469 \r
470                 case 'p':\r
471                         g_root.per_msg_buf = TRUE;\r
472                         printf( "\tper message data buffer\n" );\r
473                         break;\r
474 \r
475                 case 'v':\r
476                         cmt_dbg_lvl = 0xFFFFFFFF;\r
477                         printf( "\tverbose\n" );\r
478                         break;\r
479 \r
480                 case 'e':\r
481                         g_root.is_polling = FALSE;\r
482                         printf( "\tevent driven completions\n" );\r
483                         break;\r
484 \r
485                 case 'h':\r
486                         __show_usage();\r
487                         return FALSE;\r
488 \r
489                 case -1:\r
490                         break;\r
491 \r
492                 default: /* something wrong */\r
493                         __show_usage();\r
494                         return FALSE;\r
495                 }\r
496         } while( next_option != -1 );\r
497 \r
498         return TRUE;\r
499 }\r
500 \r
501 \r
502 /**********************************************************************\r
503  **********************************************************************/\r
504 static void\r
505 __init_conn_info()\r
506 {\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
523 \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
540 \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
544 \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
548 \r
549         /* Disconnection reply parameters are all zero. */\r
550 }\r
551 \r
552 \r
553 \r
554 static uint16_t\r
555 __get_pkey_index()\r
556 {\r
557         uint16_t        i;\r
558 \r
559         for( i = 0; i < g_root.num_pkeys; i++ )\r
560         {\r
561                 if( g_root.p_pkey_table[i] == g_root.path_rec.pkey )\r
562                         return i;\r
563         }\r
564 \r
565         return BAD_PKEY_INDEX;\r
566 }\r
567 \r
568 \r
569 \r
570 static void\r
571 __init_qp_info()\r
572 {\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
576         {\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
579         }\r
580         else\r
581         {\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
585         }\r
586 \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
590 \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
593 \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
599 }\r
600 \r
601 \r
602 \r
603 static ib_api_status_t\r
604 __post_recvs(\r
605         IN                              ib_node_t                                       *p_node )\r
606 {\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
611         uint32_t                i;\r
612 \r
613         CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
614 \r
615         if( !g_root.num_msgs )\r
616         {\r
617                 CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
618                 return IB_SUCCESS;\r
619         }\r
620 \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
626 \r
627         for( i = 0; i < g_root.num_msgs; i++ )\r
628         {\r
629                 CL_PRINT( CMT_DBG_VERBOSE, cmt_dbg_lvl, (".") );\r
630 \r
631                 if( g_root.per_msg_buf )\r
632                 {\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
635                 }\r
636                 else\r
637                 {\r
638                         ds_array.vaddr = (uintn_t)g_root.p_mem;\r
639                 }\r
640 \r
641                 recv_wr.wr_id = i;\r
642                 \r
643                 status = ib_post_recv( p_node->h_qp, &recv_wr, &p_recv_failure );\r
644                 if( status != IB_SUCCESS )\r
645                 {\r
646                         printf( "ib_post_recv failed [%s]!\n", ib_get_err_str(status) );\r
647                         break;\r
648                 }\r
649         }\r
650 \r
651         CL_PRINT( CMT_DBG_VERBOSE, cmt_dbg_lvl, ("\n") );\r
652         CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
653         return status;\r
654 }\r
655 \r
656 \r
657 \r
658 static void\r
659 __ca_async_event_cb(\r
660         ib_async_event_rec_t    *p_err_rec )\r
661 {\r
662         CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
663         \r
664         CL_TRACE( CMT_DBG_VERBOSE, cmt_dbg_lvl, \r
665                 ( "p_err_rec->code is %d\n", p_err_rec->code ) );\r
666         \r
667         CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
668 }\r
669 \r
670 \r
671 \r
672 static void\r
673 __cm_listen_err_cb(\r
674         IN                              ib_listen_err_rec_t                     *p_listen_err_rec )\r
675 {\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
680 }\r
681 \r
682 \r
683 \r
684 static void\r
685 __cancel_listen_cb(\r
686         IN                              void                                            *context )\r
687 {\r
688         CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
689         if( !context )\r
690                 printf( "__cancel_listen_cb NULL context\n" );\r
691         CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
692 }\r
693 \r
694 \r
695 \r
696 /* We need to halt the test and recover from the reject error. */\r
697 static void\r
698 __rej_cb(\r
699         IN                              ib_cm_rej_rec_t                         *p_cm_rej_rec )\r
700 {\r
701         CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
702 \r
703         /*\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
708          */\r
709         printf( "Connection was rejected, status: 0x%x\n",\r
710                 p_cm_rej_rec->rej_status );\r
711 \r
712         CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
713         exit( 1 );\r
714 }\r
715 \r
716 \r
717 \r
718 static void\r
719 __req_cb(\r
720         IN                              ib_cm_req_rec_t                         *p_cm_req_rec )\r
721 {\r
722         ib_api_status_t status;\r
723         ib_node_t               *p_node;\r
724 \r
725         CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
726         \r
727         CL_ASSERT( p_cm_req_rec );\r
728 \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
732 \r
733         /*\r
734          * Do not send replies until the server is ready to establish all\r
735          * connections.\r
736          */\r
737         cl_mutex_acquire( &g_root.mutex );\r
738         p_node = &g_root.p_nodes[g_root.conn_index++];\r
739 \r
740         if( g_root.state == test_connecting )\r
741         {\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
746                 {\r
747                         printf( "Call to ib_cm_rep failed\n" );\r
748                         exit( 1 );\r
749                 }\r
750         }\r
751         else\r
752         {\r
753                 p_node->h_cm_req = p_cm_req_rec->h_cm_req;\r
754         }\r
755         cl_mutex_release( &g_root.mutex );\r
756 \r
757         CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
758 }\r
759 \r
760 \r
761 \r
762 static void\r
763 __rep_cb(\r
764         IN                              ib_cm_rep_rec_t                         *p_cm_rep_rec )\r
765 {\r
766         ib_api_status_t status;\r
767         ib_node_t               *p_node;\r
768         uint8_t                 pdata[IB_RTU_PDATA_SIZE];\r
769         ib_cm_mra_t             mra;\r
770 \r
771         CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
772         CL_ASSERT( p_cm_rep_rec );\r
773         \r
774         p_node = (ib_node_t*)p_cm_rep_rec->qp_context;\r
775         CL_ASSERT( p_node );\r
776 \r
777         mra.p_mra_pdata = NULL;\r
778         mra.mra_length = 0;\r
779         mra.svc_timeout = 0xff;\r
780 \r
781         ib_cm_mra( p_cm_rep_rec->h_cm_rep, &mra );\r
782 \r
783         __post_recvs( p_node );\r
784 \r
785         /* Mark that we're connected before sending the RTU. */\r
786         p_node->state = node_conn;\r
787 \r
788         g_root.cm_rtu.p_rtu_pdata = pdata;\r
789         g_root.cm_rtu.rtu_length = IB_RTU_PDATA_SIZE;\r
790 \r
791         status = ib_cm_rtu( p_cm_rep_rec->h_cm_rep, &g_root.cm_rtu );\r
792         if( status != IB_SUCCESS )\r
793         {\r
794                 printf( "Call to ib_cm_rtu returned %s\n", ib_get_err_str( status ) );\r
795                 exit( 1 );\r
796         }\r
797 \r
798         cl_atomic_inc( &g_root.num_connected );\r
799 \r
800         CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
801 }\r
802 \r
803 \r
804 \r
805 static void\r
806 __rtu_cb(\r
807         IN                              ib_cm_rtu_rec_t                         *p_cm_rtu_rec )\r
808 {\r
809         ib_node_t               *p_node;\r
810 \r
811         CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
812         CL_ASSERT( p_cm_rtu_rec );\r
813         \r
814         p_node = (ib_node_t*)p_cm_rtu_rec->qp_context;\r
815         p_node->state = node_conn;\r
816 \r
817         __post_recvs( p_node );\r
818         cl_atomic_inc( &g_root.num_connected );\r
819 \r
820         CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
821 }\r
822 \r
823 \r
824 \r
825 static void\r
826 __mra_cb(\r
827         IN                              ib_cm_mra_rec_t                         *p_cm_mra_rec )\r
828 {\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
832 }\r
833 \r
834 \r
835 \r
836 static void\r
837 __apr_cb(\r
838         IN                              ib_cm_apr_rec_t                         *p_cm_apr_rec )\r
839 {\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
843 }\r
844 \r
845 \r
846 \r
847 static void\r
848 __lap_cb(\r
849         IN                              ib_cm_lap_rec_t                         *p_cm_lap_rec )\r
850 {\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
854 }\r
855 \r
856 \r
857 \r
858 static void\r
859 __dreq_cb(\r
860         IN                              ib_cm_dreq_rec_t                        *p_cm_dreq_rec )\r
861 {\r
862         ib_node_t               *p_node;\r
863         ib_api_status_t status;\r
864 \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
869 \r
870         /*\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
873          * using the mutex.\r
874          */\r
875         cl_mutex_acquire( &g_root.mutex );\r
876 \r
877         /* If we need to send or receive more data, don't disconnect yet. */\r
878         if( g_root.state == test_disconnecting )\r
879         {\r
880                 /* Send the DREP. */\r
881                 status = ib_cm_drep( p_cm_dreq_rec->h_cm_dreq, &g_root.cm_drep );\r
882 \r
883                 /* If the DREP was successful, we're done with this connection. */\r
884                 if( status == IB_SUCCESS )\r
885                 {\r
886                         p_node->state = node_idle;\r
887                         cl_atomic_dec( &g_root.num_connected );\r
888                 }\r
889         }\r
890         else\r
891         {\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
895         }\r
896         cl_mutex_release( &g_root.mutex );\r
897 \r
898         CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
899 }\r
900 \r
901 \r
902 \r
903 static void\r
904 __drep_cb(\r
905         IN                              ib_cm_drep_rec_t                        *p_cm_drep_rec )\r
906 {\r
907         ib_node_t               *p_node;\r
908 \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
913 \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
919 \r
920         CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
921 }\r
922 \r
923 \r
924 \r
925 static void\r
926 __cq_cb(\r
927         IN              const   ib_cq_handle_t                          h_cq,\r
928         IN                              void*                                           cq_context )\r
929 {\r
930         ib_node_t               *p_node = (ib_node_t*)cq_context;\r
931 \r
932         CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
933         if( !g_root.is_polling )\r
934         {\r
935                 if( !__poll_cq( p_node, h_cq ) )\r
936                         exit( 1 );\r
937         }\r
938         CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
939 }\r
940 \r
941 \r
942 static ib_api_status_t\r
943 __create_qp(\r
944         IN                      ib_node_t                       *p_node )\r
945 {\r
946         ib_api_status_t status;\r
947         ib_qp_attr_t    attr;\r
948 \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
952 \r
953         /* Allocate the QP. */\r
954         status = ib_create_qp( g_root.h_pd, &g_root.qp_create, p_node, NULL,\r
955                 &p_node->h_qp );\r
956         if( status != IB_SUCCESS )\r
957         {\r
958                 printf( "[%d] ib_create_qp failed [%s]!\n", __LINE__, \r
959                         ib_get_err_str(status) );\r
960                 return status;\r
961         }\r
962 \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
967         else\r
968                 p_node->max_inline = attr.sq_max_inline;\r
969 \r
970         /*\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
974          */\r
975         status = ib_modify_qp( p_node->h_qp, &g_root.qp_mod_reset );\r
976         if( status != IB_SUCCESS )\r
977         {\r
978                 printf( "ib_modify_qp to IB_QPS_RESET returned %s\n",\r
979                         ib_get_err_str(status) );\r
980                 return status;\r
981         }\r
982 \r
983         status = ib_modify_qp( p_node->h_qp, &g_root.qp_mod_init );\r
984         if( status != IB_SUCCESS )\r
985         {\r
986                 printf( "ib_modify_qp to IB_QPS_INIT returned %s\n",\r
987                         ib_get_err_str(status) );\r
988                 return status;\r
989         }\r
990 \r
991         return status;\r
992 }\r
993 \r
994 \r
995 \r
996 /*\r
997  * Allocate new QPs for all nodes.\r
998  */\r
999 static ib_api_status_t\r
1000 __create_qps()\r
1001 {\r
1002         uint64_t                start_time, total_time;\r
1003         int32_t                 i;\r
1004         ib_api_status_t status;\r
1005 \r
1006         printf( "Creating QPs...\n" );\r
1007         start_time = cl_get_time_stamp();\r
1008 \r
1009         for( i = 0; i < g_root.num_nodes; i++ )\r
1010         {\r
1011                 /* Allocate a new QP. */\r
1012                 status = __create_qp( &g_root.p_nodes[i] );\r
1013                 if( status != IB_SUCCESS )\r
1014                         break;\r
1015         }\r
1016 \r
1017         total_time = cl_get_time_stamp() - start_time;\r
1018         printf( "Allocation time: %"PRId64" ms\n", total_time/1000 );\r
1019 \r
1020         return status;\r
1021 }\r
1022 \r
1023 \r
1024 \r
1025 /*\r
1026  * Destroy all QPs for all nodes.\r
1027  */\r
1028 static void\r
1029 __destroy_qps()\r
1030 {\r
1031         uint64_t                start_time, total_time;\r
1032         int32_t                 i;\r
1033 \r
1034         printf( "Destroying QPs...\n" );\r
1035         start_time = cl_get_time_stamp();\r
1036 \r
1037         for( i = 0; i < g_root.num_nodes; i++ )\r
1038         {\r
1039                 /* Destroy the QP. */\r
1040                 if( g_root.p_nodes[i].h_qp )\r
1041                 {\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
1044                 }\r
1045         }\r
1046 \r
1047         total_time = cl_get_time_stamp() - start_time;\r
1048         printf( "Destruction time: %"PRId64" ms\n", total_time/1000 );\r
1049 }\r
1050 \r
1051 \r
1052 \r
1053 static boolean_t\r
1054 __init_node(\r
1055         IN OUT          ib_node_t*                      p_node )\r
1056 {\r
1057         ib_api_status_t status;\r
1058         ib_cq_create_t  cq_create;\r
1059 \r
1060         CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
1061 \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
1066         else\r
1067                 cq_create.size = 1;     /* minimal of one entry */\r
1068 \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
1073         {\r
1074                 printf( "ib_create_cq failed for send CQ [%s]!\n",\r
1075                         ib_get_err_str(status) );\r
1076                 return FALSE;\r
1077         }\r
1078         if( !g_root.is_polling )\r
1079         {\r
1080                 status = ib_rearm_cq( p_node->h_send_cq, FALSE );\r
1081                 if( status != IB_SUCCESS )\r
1082                 {\r
1083                         printf( "ib_rearm_cq failed for send CQ [%s]!\n",\r
1084                                 ib_get_err_str(status) );\r
1085                         return FALSE;\r
1086                 }\r
1087         }\r
1088 \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
1092         {\r
1093                 printf( "ib_create_cq failed for recv CQ [%s]!\n",\r
1094                         ib_get_err_str(status) );\r
1095                 return FALSE;\r
1096         }\r
1097         if( !g_root.is_polling )\r
1098         {\r
1099                 status = ib_rearm_cq( p_node->h_recv_cq, FALSE );\r
1100                 if( status != IB_SUCCESS )\r
1101                 {\r
1102                         printf( "ib_rearm_cq failed for recv CQ [%s]!\n",\r
1103                                 ib_get_err_str(status) );\r
1104                         return FALSE;\r
1105                 }\r
1106         }\r
1107 \r
1108         CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
1109         return TRUE;\r
1110 }\r
1111 \r
1112 static boolean_t\r
1113 __destroy_node(\r
1114         IN      OUT                     ib_node_t*                                      p_node )\r
1115 {\r
1116         ib_api_status_t status = IB_SUCCESS;\r
1117         CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
1118         if (!p_node )\r
1119                 return (FALSE);\r
1120         if ( p_node->h_send_cq )\r
1121         {\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
1125                 {\r
1126                         printf( "ib_destroy_cq failed for send CQ [%s]!\n",\r
1127                                 ib_get_err_str(status) );\r
1128                 }\r
1129         }\r
1130         if (p_node->h_recv_cq)\r
1131         {\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
1135                 {\r
1136                         printf( "ib_destroy_cq failed for recv CQ [%s]!\n",\r
1137                                 ib_get_err_str(status) );\r
1138                 }\r
1139         }\r
1140 \r
1141         CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
1142         return (status == IB_SUCCESS);\r
1143 }\r
1144 \r
1145 \r
1146 \r
1147 static boolean_t\r
1148 __create_nodes()\r
1149 {\r
1150         int32_t                 i;\r
1151 \r
1152         CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
1153         for( i = 0; i < g_root.num_nodes; i++ )\r
1154         {\r
1155                 g_root.p_nodes[i].id = i;\r
1156 \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
1159                 \r
1160                 if( !__init_node( &g_root.p_nodes[i] ) )\r
1161                         return FALSE;\r
1162         }\r
1163 \r
1164         CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
1165         return TRUE;\r
1166 }\r
1167 \r
1168 static boolean_t\r
1169 __destroy_nodes()\r
1170 {\r
1171         int32_t                 i;\r
1172 \r
1173         CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
1174 \r
1175         for( i = 0; i < g_root.num_nodes; i++ )\r
1176         {\r
1177                 if( !__destroy_node( &g_root.p_nodes[i] ) )\r
1178                         return FALSE;\r
1179         }\r
1180         CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
1181         return TRUE;\r
1182 }\r
1183 \r
1184 /* query function called by ib_query() */\r
1185 static void\r
1186 __sa_query_cb(\r
1187         IN                              ib_query_rec_t                          *p_query_rec )\r
1188 {\r
1189         ib_path_rec_t   *p_path;\r
1190         ib_api_status_t status;\r
1191 \r
1192         CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
1193 \r
1194         CL_ASSERT( p_query_rec );\r
1195 \r
1196         if( p_query_rec->status != IB_SUCCESS )\r
1197         {\r
1198                 printf( "ib_query failed [%d]\n", p_query_rec->status ); \r
1199                 return;\r
1200         }\r
1201 \r
1202         if( p_query_rec->query_type != IB_QUERY_PATH_REC_BY_LIDS )\r
1203         {\r
1204                 printf( "Unexpected query type returned.\n" ); \r
1205                 return;\r
1206         }\r
1207 \r
1208         if( !p_query_rec->p_result_mad )\r
1209         {\r
1210                 printf( "No result MAD returned from ib_query.\n" ); \r
1211                 return;\r
1212         }\r
1213 \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
1218 \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
1222 \r
1223         /* release response MAD(s) back to AL pool */\r
1224         if( p_query_rec->p_result_mad )\r
1225         {\r
1226                 status = ib_put_mad( p_query_rec->p_result_mad );\r
1227                 if( status != IB_SUCCESS )\r
1228                 {\r
1229                         printf( "ib_put_mad() failed [%s]\n",\r
1230                                 ib_get_err_str(status) );\r
1231                 }\r
1232         }\r
1233 \r
1234         CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
1235 }\r
1236 \r
1237 \r
1238 \r
1239 static boolean_t\r
1240 __query_for_path()\r
1241 {\r
1242         ib_api_status_t status;\r
1243         ib_query_req_t  query_rec;\r
1244         ib_lid_pair_t   lid_pair;\r
1245 \r
1246         /* Query the SA for a path record. */\r
1247         query_rec.query_type = IB_QUERY_PATH_REC_BY_LIDS;\r
1248 \r
1249         lid_pair.src_lid = g_root.l_lid;\r
1250         lid_pair.dest_lid = g_root.r_lid;\r
1251 \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
1259 \r
1260         status = ib_query( g_root.h_al, &query_rec, NULL );\r
1261         if( ( status != IB_SUCCESS ) || ( !g_root.path_rec.dlid ) )\r
1262         {\r
1263                 printf( "ib_query failed.\n" );\r
1264                 return FALSE;\r
1265         }\r
1266 \r
1267         return TRUE;\r
1268 }\r
1269 \r
1270 \r
1271 \r
1272 static boolean_t\r
1273 __create_messages()\r
1274 {\r
1275         ib_mr_create_t  mr_create;\r
1276         uint32_t                buf_size;\r
1277         ib_api_status_t status;\r
1278 \r
1279         /* If we're not sending messages, just return. */\r
1280         if( !g_root.num_msgs || !g_root.msg_size )\r
1281                 return TRUE;\r
1282 \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
1286         else\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
1290         {\r
1291                 printf( "Not enough memory for transfers!\n" );\r
1292                 return FALSE;\r
1293         }\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
1297 \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
1305         {\r
1306                 printf( "ib_reg_mem failed [%s]!\n", ib_get_err_str(status) );\r
1307                 return FALSE;\r
1308         }\r
1309 \r
1310         return TRUE;\r
1311 }\r
1312 \r
1313 \r
1314 \r
1315 /*\r
1316  * PnP callback handler.  Record the port GUID of an active port.\r
1317  */\r
1318 static ib_api_status_t\r
1319 __pnp_cb(\r
1320         IN                                      ib_pnp_rec_t                            *p_pnp_rec )\r
1321 {\r
1322         ib_pnp_port_rec_t*      p_port_rec;\r
1323         uint32_t                        size;\r
1324 \r
1325         p_port_rec = (ib_pnp_port_rec_t*)p_pnp_rec;\r
1326 \r
1327         /*\r
1328          * Ignore PNP events that are not related to port active, or if\r
1329          * we already have an active port.\r
1330          */\r
1331         if( p_pnp_rec->pnp_event != IB_PNP_PORT_ACTIVE || g_root.port_guid )\r
1332                 return IB_SUCCESS;\r
1333 \r
1334         /* Find the proper port for the given local LID. */\r
1335         if( g_root.l_lid )\r
1336         {\r
1337                 if( g_root.l_lid != p_port_rec->p_port_attr->lid )\r
1338                         return IB_SUCCESS;\r
1339         }\r
1340         else\r
1341         {\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
1344         }\r
1345 \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
1349 \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
1358 \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
1362 }\r
1363 \r
1364 \r
1365 /*\r
1366  * Register for PnP events and wait until a port becomes active.\r
1367  */\r
1368 static boolean_t\r
1369 __reg_pnp()\r
1370 {\r
1371         ib_api_status_t         status;\r
1372         ib_pnp_req_t            pnp_req;\r
1373         ib_pnp_handle_t         h_pnp;\r
1374 \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
1379 \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
1383         {\r
1384                 printf( "ib_reg_pnp failed [%s]!\n", ib_get_err_str(status) );\r
1385                 return FALSE;\r
1386         }\r
1387 \r
1388         /* Wait until a port goes active. */\r
1389         while( !g_root.port_guid )\r
1390                 cl_thread_suspend( 10 );\r
1391 \r
1392         /* Deregister from PnP. */\r
1393         ib_dereg_pnp( h_pnp, NULL );\r
1394 \r
1395         return TRUE;\r
1396 }\r
1397 \r
1398 \r
1399 \r
1400 static boolean_t\r
1401 __init_root()\r
1402 {\r
1403         ib_api_status_t status;\r
1404 \r
1405         CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
1406 \r
1407         cl_mutex_construct( &g_root.mutex );\r
1408         if( cl_mutex_init( &g_root.mutex ) != CL_SUCCESS )\r
1409                 return FALSE;\r
1410 \r
1411         /* Open AL. */\r
1412         status = ib_open_al( &g_root.h_al );\r
1413         if( status != IB_SUCCESS )\r
1414         {\r
1415                 printf( "ib_open_al failed [%s]!\n", ib_get_err_str(status) );\r
1416                 return FALSE;\r
1417         }\r
1418 \r
1419         /* Register for PnP events, and wait until we have an active port. */\r
1420         if( !__reg_pnp() )\r
1421                 return FALSE;\r
1422 \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
1427         {\r
1428                 printf( "ib_open_ca failed [%s]!\n", ib_get_err_str(status) );\r
1429                 return FALSE;\r
1430         }\r
1431 \r
1432         /* Create a PD. */\r
1433         status = ib_alloc_pd( g_root.h_ca, IB_PDT_NORMAL, &g_root, \r
1434                 &g_root.h_pd );\r
1435         if( status != IB_SUCCESS )\r
1436         {\r
1437                 printf( "ib_alloc_pd failed [%s]!\n", ib_get_err_str(status) );\r
1438                 return FALSE;\r
1439         }\r
1440 \r
1441         /* Get a path record to the remote side. */\r
1442         if( !__query_for_path() )\r
1443         {\r
1444                 printf( "Unable to query for path record!\n" );\r
1445                 return FALSE;\r
1446         }\r
1447 \r
1448         /* Allocate and register memory for the messages. */\r
1449         if( !__create_messages() )\r
1450         {\r
1451                 printf( "Unable to create messages!\n" );\r
1452                 return FALSE;\r
1453         }\r
1454 \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
1459         {\r
1460                 printf( "Unable to allocate nodes\n" ); \r
1461                 return FALSE;\r
1462         }\r
1463 \r
1464         CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
1465         return TRUE;\r
1466 }\r
1467 \r
1468 \r
1469 \r
1470 static void\r
1471 __cleanup()\r
1472 {\r
1473         if( g_root.h_listen )\r
1474                 ib_cm_cancel( g_root.h_listen, __cancel_listen_cb );\r
1475 \r
1476         /* Close AL if it was opened. */\r
1477         if( g_root.h_al )\r
1478                 ib_close_al( g_root.h_al );\r
1479 \r
1480         cl_mutex_destroy( &g_root.mutex );\r
1481 \r
1482         if( g_root.p_mem )\r
1483                 cl_free( g_root.p_mem );\r
1484 \r
1485         if( g_root.p_pkey_table )\r
1486                 cl_free( g_root.p_pkey_table );\r
1487 \r
1488         /* Free all allocated memory. */\r
1489         if( g_root.p_nodes )\r
1490                 cl_free( g_root.p_nodes );\r
1491 }\r
1492 \r
1493 \r
1494 \r
1495 /*\r
1496  * Have the server start listening for connections.\r
1497  */\r
1498 static boolean_t\r
1499 __listen()\r
1500 {\r
1501         ib_cm_listen_t  cm_listen;\r
1502         ib_api_status_t status;\r
1503 \r
1504         cl_memclr( &cm_listen, sizeof( ib_cm_listen_t ) );\r
1505 \r
1506         /* The server side listens. */\r
1507         cm_listen.svc_id = CMT_BASE_SVC_ID + g_root.inst_id;\r
1508 \r
1509         cm_listen.pfn_cm_req_cb = __req_cb;\r
1510 \r
1511         cm_listen.qp_type = IB_QPT_RELIABLE_CONN;\r
1512 \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
1516         {\r
1517                 printf( "ib_cm_listen failed [%s]!\n", ib_get_err_str(status) );\r
1518                 return FALSE;\r
1519         }\r
1520         return TRUE;\r
1521 }\r
1522 \r
1523 \r
1524 \r
1525 /*\r
1526  * Initiate all client connection requests.\r
1527  */\r
1528 static ib_api_status_t\r
1529 __conn_reqs()\r
1530 {\r
1531         ib_api_status_t status;\r
1532         int32_t                 i;\r
1533         uint8_t                 pdata[IB_REQ_PDATA_SIZE];\r
1534 \r
1535         g_root.cm_req.p_req_pdata = pdata;\r
1536         g_root.cm_req.req_length = IB_REQ_PDATA_SIZE;\r
1537 \r
1538         /* Request a connection for each client. */\r
1539         for( i = 0; i < g_root.num_nodes; i++ )\r
1540         {\r
1541                 g_root.cm_req.h_qp = g_root.p_nodes[i].h_qp;\r
1542 \r
1543                 status = ib_cm_req( &g_root.cm_req );\r
1544                 if( status != IB_SUCCESS )\r
1545                 {\r
1546                         printf( "ib_cm_req failed [%s]!\n", ib_get_err_str(status) );\r
1547                         return status;\r
1548                 }\r
1549         }\r
1550         return IB_SUCCESS;\r
1551 }\r
1552 \r
1553 \r
1554 \r
1555 /*\r
1556  * Send any connection replies waiting to be sent.\r
1557  */\r
1558 static ib_api_status_t\r
1559 __conn_reps()\r
1560 {\r
1561         ib_api_status_t status;\r
1562         uintn_t                 i;\r
1563         uint8_t                 pdata[IB_REP_PDATA_SIZE];\r
1564 \r
1565         g_root.cm_rep.p_rep_pdata = pdata;\r
1566         g_root.cm_rep.rep_length = IB_REP_PDATA_SIZE;\r
1567 \r
1568         /* Send a reply for each connection that requires one. */\r
1569         for( i = 0; i < g_root.conn_index; i++ )\r
1570         {\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
1574                 {\r
1575                         printf( "ib_cm_rep failed [%s]!\n", ib_get_err_str(status) );\r
1576                         return status;\r
1577                 }\r
1578         }\r
1579         return IB_SUCCESS;\r
1580 }\r
1581 \r
1582 \r
1583 \r
1584 /*\r
1585  * Establish all connections.\r
1586  */\r
1587 static ib_api_status_t\r
1588 __connect()\r
1589 {\r
1590         uint64_t                total_time;\r
1591         ib_api_status_t status;\r
1592 \r
1593         CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
1594 \r
1595         printf( "Connecting...\n" );\r
1596         cl_mutex_acquire( &g_root.mutex );\r
1597         g_root.state = test_connecting;\r
1598 \r
1599         /* Initiate the connections. */\r
1600         if( g_root.is_server )\r
1601         {\r
1602                 /*\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
1605                  */\r
1606                 status = __conn_reps();\r
1607                 cl_mutex_release( &g_root.mutex );\r
1608         }\r
1609         else\r
1610         {\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
1614         }\r
1615 \r
1616         if( status != IB_SUCCESS )\r
1617                 return status;\r
1618 \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
1622 \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
1626 \r
1627         /* Reset connection information for next test. */\r
1628         g_root.conn_index = 0;\r
1629         g_root.conn_start_time = 0;\r
1630 \r
1631         printf( "Connect time: %"PRId64" ms\n", total_time/1000 );\r
1632 \r
1633         CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
1634         return status;\r
1635 }\r
1636 \r
1637 \r
1638 \r
1639 static void\r
1640 __disconnect()\r
1641 {\r
1642         ib_api_status_t status;\r
1643         int32_t                 i;\r
1644         ib_node_t               *p_node;\r
1645         uint64_t                total_time, start_time;\r
1646 \r
1647         printf( "Disconnecting...\n" );\r
1648 \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
1654 \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
1657         {\r
1658                 p_node = &g_root.p_nodes[i];\r
1659 \r
1660                 /*\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
1664                  */\r
1665                 cl_mutex_acquire( &g_root.mutex );\r
1666                 switch( p_node->state )\r
1667                 {\r
1668                 case node_conn:\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
1673                         break;\r
1674 \r
1675                 case node_dreq_rcvd:\r
1676                         status = ib_cm_drep( p_node->h_cm_dreq, &g_root.cm_drep );\r
1677 \r
1678                         /* If the DREP was successful, we're done with this connection. */\r
1679                         if( status == IB_SUCCESS )\r
1680                         {\r
1681                                 p_node->state = node_idle;\r
1682                                 cl_atomic_dec( &g_root.num_connected );\r
1683                         }\r
1684                         break;\r
1685 \r
1686                 default:\r
1687                         /* Node is already disconnected. */\r
1688                         break;\r
1689                 }\r
1690                 cl_mutex_release( &g_root.mutex );\r
1691         }\r
1692 \r
1693         /* Wait for all disconnections to complete. */\r
1694         while( g_root.num_connected )\r
1695                 cl_thread_suspend( 0 );\r
1696 \r
1697         if( g_root.h_listen )\r
1698         {\r
1699                 ib_cm_cancel( g_root.h_listen, __cancel_listen_cb );\r
1700                 g_root.h_listen = NULL;\r
1701         }\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
1705 \r
1706         printf( "Disconnect time: %"PRId64" ms\n", total_time/1000 );\r
1707 }\r
1708 \r
1709 \r
1710 \r
1711 /*\r
1712  * Send the requested number of messages on each connection.\r
1713  */\r
1714 static boolean_t\r
1715 __send_msgs()\r
1716 {\r
1717         ib_api_status_t status;\r
1718         int32_t                 i;\r
1719         uint32_t                m;\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
1723 \r
1724         CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
1725 \r
1726         /* For each connection... */\r
1727         for( i = 0; i < g_root.num_nodes; i++ )\r
1728         {\r
1729                 /* Send the specified number of messages. */\r
1730                 for( m = 0; m < g_root.num_msgs; m++ )\r
1731                 {\r
1732                         /* Get the buffer for this message. */\r
1733                         if( g_root.per_msg_buf )\r
1734                         {\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
1737                         }\r
1738                         else\r
1739                         {\r
1740                                 ds_array.vaddr = (uintn_t)g_root.p_mem;\r
1741                         }\r
1742                         ds_array.length = g_root.msg_size;\r
1743                         ds_array.lkey = g_root.lkey;\r
1744 \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
1753 \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
1756 \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
1762                         {\r
1763                                 printf( "ib_post_send failed [%s]!\n",\r
1764                                         ib_get_err_str(status) );\r
1765                                 return FALSE;\r
1766                         }\r
1767                 }\r
1768         }\r
1769         \r
1770         CL_PRINT( CMT_DBG_VERBOSE, cmt_dbg_lvl, ("\n") );\r
1771         CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
1772         return TRUE;\r
1773 }\r
1774 \r
1775 \r
1776 \r
1777 /*\r
1778  * Remove num_msgs completions from the specified CQ.\r
1779  */\r
1780 static boolean_t\r
1781 __poll_cq(\r
1782         IN                              ib_node_t                                       *p_node,\r
1783         IN                              ib_cq_handle_t                          h_cq )\r
1784 {\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
1788 \r
1789         CL_ENTER( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
1790 \r
1791         while( status != IB_NOT_FOUND )\r
1792         {\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
1797                 p_done_wc = NULL;\r
1798 \r
1799                 status = ib_poll_cq( h_cq, &p_free_wc, &p_done_wc );\r
1800 \r
1801                 /* Continue polling if nothing is done. */\r
1802                 if( status == IB_NOT_FOUND )\r
1803                         break;\r
1804 \r
1805                 /* Abort if an error occurred. */\r
1806                 if( status != IB_SUCCESS )\r
1807                 {\r
1808                         printf( "Error polling status = %#x( wc_status =%s)\n", \r
1809                                 status,\r
1810                                 ((p_done_wc != NULL )? wc_status_text[p_done_wc->status]:"N/A") );\r
1811                         return FALSE;\r
1812                 }\r
1813 \r
1814                 while( p_done_wc )\r
1815                 {\r
1816                         switch( p_done_wc->status )\r
1817                         {\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
1823 \r
1824                                 if( p_done_wc->wc_type == IB_WC_RECV )\r
1825                                 {\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
1828                                         {\r
1829                                                 printf( "Error: received %d bytes, expected %d.\n",\r
1830                                                         p_done_wc->length, g_root.msg_size );\r
1831                                         }\r
1832 \r
1833                                         p_node->recv_cnt++;\r
1834                                         g_root.total_recv++;\r
1835                                 }\r
1836                                 else\r
1837                                 {\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
1841                                 }\r
1842                                 break;\r
1843 \r
1844                         default:\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
1848                                 return FALSE;\r
1849                         }\r
1850                         p_done_wc = p_done_wc->p_next;\r
1851                 }\r
1852         }\r
1853 \r
1854         if( !g_root.is_polling )\r
1855         {\r
1856                 status = ib_rearm_cq(h_cq, FALSE);\r
1857                 if (status != IB_SUCCESS)\r
1858                 {\r
1859                         printf("Failed to rearm CQ %p\n", h_cq );\r
1860                         return FALSE;\r
1861                 }\r
1862         }\r
1863 \r
1864         CL_EXIT( CMT_DBG_VERBOSE, cmt_dbg_lvl );\r
1865         return TRUE;\r
1866 }\r
1867 \r
1868 \r
1869 \r
1870 /*\r
1871  * Remove num_msgs completions from all send CQs for all connections.\r
1872  */\r
1873 static boolean_t\r
1874 __poll_send_cqs()\r
1875 {\r
1876         ib_node_t               *p_node;\r
1877         int32_t                 i;\r
1878 \r
1879         for( i = 0; i < g_root.num_nodes; i++ )\r
1880         {\r
1881                 p_node = &g_root.p_nodes[i];\r
1882                 while( p_node->send_cnt < g_root.num_msgs )\r
1883                 {\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
1887                                 return FALSE;\r
1888                 }\r
1889         }\r
1890         return TRUE;\r
1891 }\r
1892 \r
1893 \r
1894 \r
1895 /*\r
1896  * Remove num_msgs completions from all receive CQs for all connections.\r
1897  */\r
1898 static boolean_t\r
1899 __poll_recv_cqs()\r
1900 {\r
1901         ib_node_t               *p_node;\r
1902         int32_t                 i;\r
1903 \r
1904         for( i = 0; i < g_root.num_nodes; i++ )\r
1905         {\r
1906                 p_node = &g_root.p_nodes[i];\r
1907                 while( p_node->recv_cnt < g_root.num_msgs )\r
1908                 {\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
1912                                 return FALSE;\r
1913                 }\r
1914         }\r
1915         return TRUE;\r
1916 }\r
1917 \r
1918 \r
1919 \r
1920 /**********************************************************************\r
1921  **********************************************************************/\r
1922 int __cdecl\r
1923 main(\r
1924         int                                                     argc,\r
1925         char*                                           argv[] )\r
1926 {\r
1927         uint64_t                                        start_time, total_time;\r
1928         uint64_t                                        total_xfer;\r
1929         uint32_t                                        i;\r
1930 \r
1931         cl_memclr( &g_root, sizeof(ib_root_t) );\r
1932 \r
1933         /* Set defaults. */\r
1934         if( !__parse_options( argc, argv ) )\r
1935                 return 1;\r
1936 \r
1937         /* Initialize the root - open all common HCA resources. */\r
1938         if( !__init_root() )\r
1939         {\r
1940                 printf( "__init_root failed\n" );\r
1941                 __cleanup();\r
1942                 return 1;\r
1943         }\r
1944 \r
1945         /*\r
1946          * Execute the test the specified number of times.  Abort the test\r
1947          * if any errors occur.\r
1948          */\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
1951         {\r
1952                 printf( "----- Iteration: %d, %d connections -----\n",\r
1953                         i, g_root.num_nodes );\r
1954 \r
1955                 /* Initialize the connection parameters. */\r
1956                 __init_conn_info();\r
1957                 __init_qp_info();\r
1958                 __create_nodes();\r
1959                 /* Start listening for connections if we're the server. */\r
1960                 if( g_root.is_server )\r
1961                         __listen();\r
1962 \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\n", total_time/1000,\r
2018                         g_root.num_msgs, total_xfer );\r
2019 \r
2020                 /* Disconnect all connections. */\r
2021                 __disconnect();\r
2022                 __destroy_qps();\r
2023                 __destroy_nodes();\r
2024         }\r
2025 \r
2026         __cleanup();\r
2027         return 0;\r
2028 }\r