72411bd9bb4339636a4aff6ad06be2f208dfd504
[mirror/winof/.git] / ulp / librdmacm / src / cma.cpp
1 /*\r
2  * Copyright (c) 2005-2009 Intel Corporation.  All rights reserved.\r
3  *\r
4  * This software is available to you under the OpenIB.org BSD license\r
5  * below:\r
6  *\r
7  *     Redistribution and use in source and binary forms, with or\r
8  *     without modification, are permitted provided that the following\r
9  *     conditions are met:\r
10  *\r
11  *      - Redistributions of source code must retain the above\r
12  *        copyright notice, this list of conditions and the following\r
13  *        disclaimer.\r
14  *\r
15  *      - Redistributions in binary form must reproduce the above\r
16  *        copyright notice, this list of conditions and the following\r
17  *        disclaimer in the documentation and/or other materials\r
18  *        provided with the distribution.\r
19  *\r
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
21  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
22  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV\r
23  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
24  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
25  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
26  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
27  * SOFTWARE.\r
28  */\r
29 \r
30 #include <windows.h>\r
31 #include <winsock2.h>\r
32 #include <stdio.h>\r
33 #include <iphlpapi.h>\r
34 \r
35 #include <rdma/rdma_cma.h>\r
36 #include <infiniband/verbs.h>\r
37 #include <comp_channel.h>\r
38 #include <iba/ibat.h>\r
39 #include "cma.h"\r
40 #include "..\..\..\etc\user\comp_channel.cpp"\r
41 \r
42 static struct ibvw_windata windata;\r
43 \r
44 enum cma_state\r
45 {\r
46         cma_idle,\r
47         cma_listening,\r
48         cma_get_request,\r
49         cma_addr_bind,\r
50         cma_addr_resolve,\r
51         cma_route_resolve,\r
52         cma_passive_connect,\r
53         cma_active_connect,\r
54         cma_active_accept,\r
55         cma_accepting,\r
56         cma_connected,\r
57         cma_active_disconnect,\r
58         cma_passive_disconnect,\r
59         cma_disconnected,\r
60         cma_destroying\r
61 };\r
62 \r
63 #define CMA_DEFAULT_BACKLOG             16\r
64 \r
65 struct cma_id_private\r
66 {\r
67         struct rdma_cm_id                       id;\r
68         enum cma_state                          state;\r
69         struct cma_device                       *cma_dev;\r
70         int                                                     backlog;\r
71         int                                                     index;\r
72         volatile LONG                           refcnt;\r
73         struct rdma_cm_id                       **req_list;\r
74 };\r
75 \r
76 struct cma_device\r
77 {\r
78         struct ibv_context      *verbs;\r
79         uint64_t                        guid;\r
80         int                                     port_cnt;\r
81         uint8_t                         max_initiator_depth;\r
82         uint8_t                         max_responder_resources;\r
83 };\r
84 \r
85 struct cma_event {\r
86         struct rdma_cm_event    event;\r
87         uint8_t                                 private_data[56];\r
88         struct cma_id_private   *id_priv;\r
89 };\r
90 \r
91 static struct cma_device *cma_dev_array;\r
92 static int cma_dev_cnt;\r
93 \r
94 static void ucma_cleanup(void)\r
95 {\r
96         if (cma_dev_cnt > 0) {\r
97                 while (cma_dev_cnt > 0) {\r
98                         ibv_close_device(cma_dev_array[--cma_dev_cnt].verbs);\r
99                 }\r
100                 delete cma_dev_array;\r
101                 cma_dev_cnt = 0;\r
102         }\r
103         if (windata.prov != NULL) {\r
104                 ibvw_release_windata(&windata, IBVW_WINDATA_VERSION);\r
105                 windata.prov = NULL;\r
106         }\r
107 }\r
108 \r
109 static int ucma_init(void)\r
110 {\r
111         struct ibv_device **dev_list = NULL;\r
112         struct cma_device *cma_dev;\r
113         struct ibv_device_attr attr;\r
114         int i, ret;\r
115 \r
116         EnterCriticalSection(&lock);\r
117         if (cma_dev_cnt > 0) {\r
118                 goto out;\r
119         }\r
120 \r
121         ret = ibvw_get_windata(&windata, IBVW_WINDATA_VERSION);\r
122         if (ret) {\r
123                 goto err;\r
124         }\r
125 \r
126         dev_list = ibv_get_device_list(&cma_dev_cnt);\r
127         if (dev_list == NULL) {\r
128                 ret = -1;\r
129                 goto err;\r
130         }\r
131 \r
132         cma_dev_array = new struct cma_device[cma_dev_cnt];\r
133         if (cma_dev_array == NULL) {\r
134                 ret = -1;\r
135                 goto err;\r
136         }\r
137 \r
138         for (i = 0; dev_list[i]; ++i) {\r
139                 cma_dev = &cma_dev_array[i];\r
140 \r
141                 cma_dev->guid = ibv_get_device_guid(dev_list[i]);\r
142                 cma_dev->verbs = ibv_open_device(dev_list[i]);\r
143                 if (cma_dev->verbs == NULL) {\r
144                         ret = -1;\r
145                         goto err;\r
146                 }\r
147 \r
148                 ret = ibv_query_device(cma_dev->verbs, &attr);\r
149                 if (ret) {\r
150                         goto err;\r
151                 }\r
152 \r
153                 cma_dev->port_cnt = attr.phys_port_cnt;\r
154                 cma_dev->max_initiator_depth = (uint8_t) attr.max_qp_init_rd_atom;\r
155                 cma_dev->max_responder_resources = (uint8_t) attr.max_qp_rd_atom;\r
156         }\r
157         ibv_free_device_list(dev_list);\r
158 out:\r
159         LeaveCriticalSection(&lock);\r
160         return 0;\r
161 \r
162 err:\r
163         ucma_cleanup();\r
164         LeaveCriticalSection(&lock);\r
165         if (dev_list) {\r
166                 ibv_free_device_list(dev_list);\r
167         }\r
168         return ret;\r
169 }\r
170 \r
171 __declspec(dllexport)\r
172 struct ibv_context **rdma_get_devices(int *num_devices)\r
173 {\r
174         struct ibv_context **devs = NULL;\r
175         int i;\r
176 \r
177         if (!cma_dev_cnt && ucma_init()) {\r
178                 goto out;\r
179         }\r
180 \r
181         devs = new struct ibv_context *[cma_dev_cnt + 1];\r
182         if (devs == NULL) {\r
183                 goto out;\r
184         }\r
185 \r
186         for (i = 0; i < cma_dev_cnt; i++) {\r
187                 devs[i] = cma_dev_array[i].verbs;\r
188         }\r
189         devs[i] = NULL;\r
190 out:\r
191         if (num_devices != NULL) {\r
192                 *num_devices = devs ? cma_dev_cnt : 0;\r
193         }\r
194         return devs;\r
195 }\r
196 \r
197 __declspec(dllexport)\r
198 void rdma_free_devices(struct ibv_context **list)\r
199 {\r
200         delete list;\r
201 }\r
202 \r
203 __declspec(dllexport)\r
204 struct rdma_event_channel *rdma_create_event_channel(void)\r
205 {\r
206         struct rdma_event_channel *channel;\r
207 \r
208         if (!cma_dev_cnt && ucma_init()) {\r
209                 return NULL;\r
210         }\r
211 \r
212         channel = new struct rdma_event_channel;\r
213         if (channel == NULL) {\r
214                 return NULL;\r
215         }\r
216 \r
217         CompChannelInit(windata.comp_mgr, &channel->channel, INFINITE);\r
218         return channel;\r
219 }\r
220 \r
221 __declspec(dllexport)\r
222 void rdma_destroy_event_channel(struct rdma_event_channel *channel)\r
223 {\r
224         CompChannelCleanup(&channel->channel);\r
225         delete channel;\r
226 }\r
227 \r
228 __declspec(dllexport)\r
229 int rdma_create_id(struct rdma_event_channel *channel,\r
230                                    struct rdma_cm_id **id, void *context,\r
231                                    enum rdma_port_space ps)\r
232 {\r
233         struct cma_id_private *id_priv;\r
234         HRESULT hr;\r
235 \r
236         hr = cma_dev_cnt ? 0 : ucma_init();\r
237         if (hr) {\r
238                 return hr;\r
239         }\r
240 \r
241         id_priv = new struct cma_id_private;\r
242         if (id_priv == NULL) {\r
243                 return NULL;\r
244         }\r
245 \r
246         RtlZeroMemory(id_priv, sizeof(struct cma_id_private));\r
247         id_priv->refcnt = 1;\r
248         id_priv->id.context = context;\r
249         id_priv->id.channel = channel;\r
250         id_priv->id.ps = ps;\r
251         CompEntryInit(&channel->channel, &id_priv->id.comp_entry);\r
252 \r
253         if (ps == RDMA_PS_TCP) {\r
254                 hr = windata.prov->CreateConnectEndpoint(&id_priv->id.ep.connect);\r
255         } else {\r
256                 hr = windata.prov->CreateDatagramEndpoint(&id_priv->id.ep.datagram);\r
257         }\r
258         if (FAILED(hr)) {\r
259                 goto err;\r
260         }\r
261 \r
262         *id = &id_priv->id;\r
263         return 0;\r
264 \r
265 err:\r
266         delete id_priv;\r
267         return hr;\r
268 }\r
269 \r
270 static void ucma_destroy_listen(struct cma_id_private *id_priv)\r
271 {\r
272         while (--id_priv->backlog >= 0) {\r
273                 if (id_priv->req_list[id_priv->backlog] != NULL) {\r
274                         InterlockedDecrement(&id_priv->refcnt);\r
275                         rdma_destroy_id(id_priv->req_list[id_priv->backlog]);\r
276                 }\r
277         }\r
278 \r
279         delete id_priv->req_list;\r
280 }\r
281 \r
282 __declspec(dllexport)\r
283 int rdma_destroy_id(struct rdma_cm_id *id)\r
284 {\r
285         struct cma_id_private *id_priv;\r
286 \r
287         id_priv = CONTAINING_RECORD(id, struct cma_id_private, id);\r
288 \r
289         EnterCriticalSection(&lock);\r
290         id_priv->state = cma_destroying;\r
291         LeaveCriticalSection(&lock);\r
292 \r
293         if (id->ps == RDMA_PS_TCP) {\r
294                 id->ep.connect->CancelOverlappedRequests();\r
295         } else {\r
296                 id->ep.datagram->CancelOverlappedRequests();\r
297         }\r
298 \r
299         if (CompEntryCancel(&id->comp_entry) != NULL) {\r
300                 InterlockedDecrement(&id_priv->refcnt);\r
301         }\r
302 \r
303         if (id_priv->backlog > 0) {\r
304                 ucma_destroy_listen(id_priv);\r
305         }\r
306 \r
307         if (id_priv->id.ps == RDMA_PS_TCP) {\r
308                 id_priv->id.ep.connect->Release();\r
309         } else {\r
310                 id_priv->id.ep.datagram->Release();\r
311         }\r
312 \r
313         InterlockedDecrement(&id_priv->refcnt);\r
314         while (id_priv->refcnt) {\r
315                 Sleep(0);\r
316         }\r
317         delete id_priv;\r
318         return 0;\r
319 }\r
320 \r
321 static int ucma_addrlen(struct sockaddr *addr)\r
322 {\r
323         if (addr->sa_family == PF_INET) {\r
324                 return sizeof(struct sockaddr_in);\r
325         } else {\r
326                 return sizeof(struct sockaddr_in6);\r
327         }\r
328 }\r
329 \r
330 static int ucma_get_device(struct cma_id_private *id_priv, uint64_t guid)\r
331 {\r
332         struct cma_device *cma_dev;\r
333         int i;\r
334 \r
335         for (i = 0; i < cma_dev_cnt; i++) {\r
336                 cma_dev = &cma_dev_array[i];\r
337                 if (cma_dev->guid == guid) {\r
338                         id_priv->cma_dev = cma_dev;\r
339                         id_priv->id.verbs = cma_dev->verbs;\r
340                         return 0;\r
341                 }\r
342         }\r
343         return -1;\r
344 }\r
345 \r
346 static int ucma_query_connect(struct rdma_cm_id *id, struct rdma_conn_param *param)\r
347 {\r
348         struct cma_id_private *id_priv;\r
349         WV_CONNECT_ATTRIBUTES attr;\r
350         HRESULT hr;\r
351 \r
352         id_priv = CONTAINING_RECORD(id, struct cma_id_private, id);\r
353         hr = id->ep.connect->Query(&attr);\r
354         if (FAILED(hr)) {\r
355                 return hr;\r
356         }\r
357 \r
358         RtlCopyMemory(&id->route.addr.src_addr, &attr.LocalAddress,\r
359                                   sizeof attr.LocalAddress);\r
360         RtlCopyMemory(&id->route.addr.dst_addr, &attr.PeerAddress,\r
361                                   sizeof attr.PeerAddress);\r
362 \r
363         if (param != NULL) {\r
364                 RtlCopyMemory((void *) param->private_data, attr.Param.Data,\r
365                                           attr.Param.DataLength);\r
366                 param->private_data_len = (uint8_t) attr.Param.DataLength;\r
367                 param->responder_resources = (uint8_t) attr.Param.ResponderResources;\r
368                 param->initiator_depth = (uint8_t) attr.Param.InitiatorDepth;\r
369                 param->flow_control = 1;\r
370                 param->retry_count = attr.Param.RetryCount;\r
371                 param->rnr_retry_count = attr.Param.RnrRetryCount;\r
372         }\r
373 \r
374         if (id_priv->cma_dev == NULL && attr.Device.DeviceGuid != 0) {\r
375                 hr = ucma_get_device(id_priv, attr.Device.DeviceGuid);\r
376                 if (FAILED(hr)) {\r
377                         return hr;\r
378                 }\r
379 \r
380                 id->route.addr.addr.ibaddr.pkey = attr.Device.Pkey;\r
381                 id_priv->id.port_num = attr.Device.PortNumber;\r
382         }\r
383 \r
384         return 0;\r
385 }\r
386 \r
387 static int ucma_query_datagram(struct rdma_cm_id *id, struct rdma_ud_param *param)\r
388 {\r
389         struct cma_id_private *id_priv;\r
390         WV_DATAGRAM_ATTRIBUTES attr;\r
391         HRESULT hr;\r
392 \r
393         id_priv = CONTAINING_RECORD(id, struct cma_id_private, id);\r
394         hr = id->ep.datagram->Query(&attr);\r
395         if (FAILED(hr)) {\r
396                 return hr;\r
397         }\r
398 \r
399         RtlCopyMemory(&id->route.addr.src_addr, &attr.LocalAddress,\r
400                                   sizeof attr.LocalAddress);\r
401         RtlCopyMemory(&id->route.addr.dst_addr, &attr.PeerAddress,\r
402                                   sizeof attr.PeerAddress);\r
403 \r
404         if (param != NULL) {\r
405                 RtlCopyMemory((void *) param->private_data, attr.Param.Data,\r
406                                           attr.Param.DataLength);\r
407                 param->private_data_len = (uint8_t) attr.Param.DataLength;\r
408                 // ucma_convert_av(&attr.Param.AddressVector, param->ah_attr)\r
409                 param->qp_num = attr.Param.Qpn;\r
410                 param->qkey = attr.Param.Qkey;\r
411         }\r
412 \r
413         if (id_priv->cma_dev == NULL && attr.Device.DeviceGuid != 0) {\r
414                 hr = ucma_get_device(id_priv, attr.Device.DeviceGuid);\r
415                 if (FAILED(hr))\r
416                         return hr;\r
417                 id->route.addr.addr.ibaddr.pkey = attr.Device.Pkey;\r
418                 id_priv->id.port_num = attr.Device.PortNumber;\r
419         }\r
420         return 0;\r
421 }\r
422 \r
423 __declspec(dllexport)\r
424 int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)\r
425 {\r
426         struct cma_id_private *id_priv;\r
427         HRESULT hr;\r
428 \r
429         if (id->ps == RDMA_PS_TCP) {\r
430                 hr = id->ep.connect->BindAddress(addr);\r
431                 if (SUCCEEDED(hr)) {\r
432                         hr = ucma_query_connect(id, NULL);\r
433                 }\r
434         } else {\r
435                 hr = id->ep.datagram->BindAddress(addr);\r
436                 if (SUCCEEDED(hr)) {\r
437                         hr = ucma_query_datagram(id, NULL);\r
438                 }\r
439         }\r
440 \r
441         if (SUCCEEDED(hr)) {\r
442                 id_priv = CONTAINING_RECORD(id, struct cma_id_private, id);\r
443                 id_priv->state = cma_addr_bind;\r
444         }\r
445         return hr;\r
446 }\r
447 \r
448 __declspec(dllexport)\r
449 int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,\r
450                                           struct sockaddr *dst_addr, int timeout_ms)\r
451 {\r
452         struct cma_id_private *id_priv;\r
453         WV_SOCKADDR addr;\r
454         SOCKET s;\r
455         DWORD size;\r
456         HRESULT hr;\r
457 \r
458         id_priv = CONTAINING_RECORD(id, struct cma_id_private, id);\r
459         if (id_priv->state == cma_idle) {\r
460                 if (src_addr == NULL) {\r
461                         if (id->ps == RDMA_PS_TCP) {\r
462                                 s = socket(dst_addr->sa_family, SOCK_STREAM, IPPROTO_TCP);\r
463                         } else {\r
464                                 s = socket(dst_addr->sa_family, SOCK_DGRAM, IPPROTO_UDP);\r
465                         }\r
466                         if (s == INVALID_SOCKET) {\r
467                                 return WSAGetLastError();\r
468                         }\r
469 \r
470                         hr = WSAIoctl(s, SIO_ROUTING_INTERFACE_QUERY, dst_addr, ucma_addrlen(dst_addr),\r
471                                                   &addr, sizeof addr, &size, NULL, NULL);\r
472                         closesocket(s);\r
473                         if (FAILED(hr)) {\r
474                                 return WSAGetLastError();\r
475                         }\r
476                         src_addr = &addr.Sa;\r
477                 }\r
478 \r
479                 hr = rdma_bind_addr(id, src_addr);\r
480                 if (FAILED(hr)) {\r
481                         return hr;\r
482                 }\r
483         }\r
484 \r
485         RtlCopyMemory(&id->route.addr.dst_addr, dst_addr, ucma_addrlen(dst_addr));\r
486         id_priv->state = cma_addr_resolve;\r
487 \r
488         id_priv->refcnt++;\r
489         CompEntryPost(&id->comp_entry);\r
490         return 0;\r
491 }\r
492 \r
493 __declspec(dllexport)\r
494 int rdma_resolve_route(struct rdma_cm_id *id, int timeout_ms)\r
495 {\r
496         struct cma_id_private *id_priv;\r
497         IBAT_PATH_BLOB path;\r
498         HRESULT hr;\r
499 \r
500         hr = IBAT::Resolve(&id->route.addr.src_addr, &id->route.addr.dst_addr, &path);\r
501         if (FAILED(hr)) {\r
502                 return hr;\r
503         }\r
504 \r
505         hr = (id->ps == RDMA_PS_TCP) ?\r
506                  id->ep.connect->Modify(WV_EP_OPTION_ROUTE, &path, sizeof path) :\r
507                  id->ep.datagram->Modify(WV_EP_OPTION_ROUTE, &path, sizeof path);\r
508         if (FAILED(hr)) {\r
509                 return hr;\r
510         }\r
511 \r
512         id_priv = CONTAINING_RECORD(id, struct cma_id_private, id);\r
513         id_priv->state = cma_route_resolve;\r
514 \r
515         id_priv->refcnt++;\r
516         CompEntryPost(&id->comp_entry);\r
517         return 0;\r
518 }\r
519 \r
520 static int ucma_modify_qp_init(struct cma_id_private *id_priv, struct ibv_qp *qp)\r
521 {\r
522         struct ibv_qp_attr qp_attr;\r
523         UINT16 index;\r
524         HRESULT hr;\r
525 \r
526         RtlZeroMemory(&qp_attr, sizeof qp_attr);\r
527         qp_attr.qp_state = IBV_QPS_INIT;\r
528         qp_attr.port_num = id_priv->id.port_num;\r
529         hr = qp->context->cmd_if->FindPkey(id_priv->id.port_num,\r
530                                                                            id_priv->id.route.addr.addr.ibaddr.pkey,\r
531                                                                            &index);\r
532         if (FAILED(hr)) {\r
533                 return hr;\r
534         }\r
535 \r
536         qp_attr.pkey_index = index;\r
537         return ibv_modify_qp(qp, &qp_attr, (enum ibv_qp_attr_mask)\r
538                                                  (IBV_QP_STATE | IBV_QP_PKEY_INDEX | IBV_QP_PORT));\r
539 }\r
540 \r
541 static int ucma_init_ud_qp(struct cma_id_private *id_priv, struct ibv_qp *qp)\r
542 {\r
543         struct ibv_qp_attr qp_attr;\r
544         int qp_attr_mask, ret;\r
545 \r
546         ret = ucma_modify_qp_init(id_priv, qp);\r
547         if (ret) {\r
548                 return ret;\r
549         }\r
550 \r
551         qp_attr.qp_state = IBV_QPS_RTR;\r
552         ret = ibv_modify_qp(qp, &qp_attr, IBV_QP_STATE);\r
553         if (ret) {\r
554                 return ret;\r
555         }\r
556 \r
557         qp_attr.qp_state = IBV_QPS_RTS;\r
558         qp_attr.sq_psn = 0;\r
559         return ibv_modify_qp(qp, &qp_attr, (enum ibv_qp_attr_mask)\r
560                                                  (IBV_QP_STATE | IBV_QP_SQ_PSN));\r
561 }\r
562 \r
563 __declspec(dllexport)\r
564 int rdma_create_qp(struct rdma_cm_id *id, struct ibv_pd *pd,\r
565                                    struct ibv_qp_init_attr *qp_init_attr)\r
566 {\r
567         struct cma_id_private *id_priv;\r
568         struct ibv_qp *qp;\r
569         int ret;\r
570 \r
571         id_priv = CONTAINING_RECORD(id, struct cma_id_private, id);\r
572         if (id->verbs != pd->context) {\r
573                 return -1;\r
574         }\r
575 \r
576         qp = ibv_create_qp(pd, qp_init_attr);\r
577         if (!qp) {\r
578                 return -1;\r
579         }\r
580 \r
581         if (id->ps == RDMA_PS_TCP) {\r
582                 ret = ucma_modify_qp_init(id_priv, qp);\r
583         } else {\r
584                 ret = ucma_init_ud_qp(id_priv, qp);\r
585         }\r
586         if (ret) {\r
587                 goto err;\r
588         }\r
589 \r
590         id->qp = qp;\r
591         return 0;\r
592 err:\r
593         ibv_destroy_qp(qp);\r
594         return ret;\r
595 }\r
596 \r
597 __declspec(dllexport)\r
598 void rdma_destroy_qp(struct rdma_cm_id *id)\r
599 {\r
600         ibv_destroy_qp(id->qp);\r
601 }\r
602 \r
603 static int ucma_valid_param(struct cma_id_private *id_priv,\r
604                                                         struct rdma_conn_param *conn_param)\r
605 {\r
606         if (id_priv->id.ps != RDMA_PS_TCP) {\r
607                 return 0;\r
608         }\r
609 \r
610         if ((conn_param->responder_resources > id_priv->cma_dev->max_responder_resources) ||\r
611                 (conn_param->initiator_depth > id_priv->cma_dev->max_initiator_depth)) {\r
612                 return -1;\r
613         }\r
614 \r
615         return 0;\r
616 }\r
617 \r
618 __declspec(dllexport)\r
619 int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)\r
620 {\r
621         struct cma_id_private *id_priv;\r
622         WV_CONNECT_PARAM attr;\r
623         HRESULT hr;\r
624         \r
625         id_priv = CONTAINING_RECORD(id, struct cma_id_private, id);\r
626         hr = ucma_valid_param(id_priv, conn_param);\r
627         if (FAILED(hr)) {\r
628                 return hr;\r
629         }\r
630 \r
631         RtlZeroMemory(&attr, sizeof attr);\r
632         attr.ResponderResources = conn_param->responder_resources;\r
633         attr.InitiatorDepth = conn_param->initiator_depth;\r
634         attr.RetryCount = conn_param->retry_count;\r
635         attr.RnrRetryCount = conn_param->rnr_retry_count;\r
636         if ((attr.DataLength = conn_param->private_data_len)) {\r
637                 RtlCopyMemory(attr.Data, conn_param->private_data, attr.DataLength);\r
638         }\r
639 \r
640         id_priv->state = cma_active_connect;\r
641         id_priv->refcnt++;\r
642         id->comp_entry.Busy = 1;\r
643         hr = id->ep.connect->Connect(id->qp->conn_handle, &id->route.addr.dst_addr,\r
644                                                                  &attr, &id->comp_entry.Overlap);\r
645         if (FAILED(hr) && hr != WV_IO_PENDING) {\r
646                 id_priv->refcnt--;\r
647                 id->comp_entry.Busy = 0;\r
648                 id_priv->state = cma_route_resolve;\r
649                 return hr;\r
650         }\r
651 \r
652         return 0;\r
653 }\r
654 \r
655 static int ucma_get_request(struct cma_id_private *listen, int index)\r
656 {\r
657         struct cma_id_private *id_priv = NULL;\r
658         HRESULT hr;\r
659 \r
660         EnterCriticalSection(&lock);\r
661         if (listen->state != cma_listening) {\r
662                 hr = WV_INVALID_PARAMETER;\r
663                 goto err1;\r
664         }\r
665 \r
666         InterlockedIncrement(&listen->refcnt);\r
667         hr = rdma_create_id(listen->id.channel, &listen->req_list[index],\r
668                                                 listen, listen->id.ps);\r
669         if (FAILED(hr)) {\r
670                 goto err2;\r
671         }\r
672 \r
673         id_priv = CONTAINING_RECORD(listen->req_list[index], struct cma_id_private, id);\r
674         id_priv->index = index;\r
675         id_priv->state = cma_get_request;\r
676 \r
677         id_priv->refcnt++;\r
678         id_priv->id.comp_entry.Busy = 1;\r
679         if (listen->id.ps == RDMA_PS_TCP) {\r
680                 hr = listen->id.ep.connect->GetRequest(id_priv->id.ep.connect,\r
681                                                                                            &id_priv->id.comp_entry.Overlap);\r
682         } else {\r
683                 hr = listen->id.ep.datagram->GetRequest(id_priv->id.ep.datagram,\r
684                                                                                                 &id_priv->id.comp_entry.Overlap);\r
685         }\r
686         if (FAILED(hr) && hr != WV_IO_PENDING) {\r
687                 id_priv->id.comp_entry.Busy = 0;\r
688                 id_priv->refcnt--;\r
689                 goto err2;\r
690         }\r
691         LeaveCriticalSection(&lock);\r
692 \r
693         return 0;\r
694 \r
695 err2:\r
696         InterlockedDecrement(&listen->refcnt);\r
697 err1:\r
698         LeaveCriticalSection(&lock);\r
699         if (id_priv != NULL) {\r
700                 rdma_destroy_id(&id_priv->id);\r
701         }\r
702         return hr;\r
703 }\r
704 \r
705 __declspec(dllexport)\r
706 int rdma_listen(struct rdma_cm_id *id, int backlog)\r
707 {\r
708         struct cma_id_private *id_priv, *req_id;\r
709         HRESULT hr;\r
710         int i;\r
711 \r
712         if (backlog <= 0) {\r
713                 backlog = CMA_DEFAULT_BACKLOG;\r
714         }\r
715 \r
716         id_priv = CONTAINING_RECORD(id, struct cma_id_private, id);\r
717         id_priv->req_list = new struct rdma_cm_id*[backlog];\r
718         if (id_priv->req_list == NULL) {\r
719                 return -1;\r
720         }\r
721 \r
722         RtlZeroMemory(id_priv->req_list, sizeof(struct rdma_cm_id *) * backlog);\r
723         id_priv->backlog = backlog;\r
724 \r
725         id_priv->state = cma_listening;\r
726         hr = (id->ps == RDMA_PS_TCP) ?\r
727                  id->ep.connect->Listen(backlog) : id->ep.datagram->Listen(backlog);\r
728         if (FAILED(hr)) {\r
729                 return hr;\r
730         }\r
731 \r
732         for (i = 0; i < backlog; i++) {\r
733                 hr = ucma_get_request(id_priv, i);\r
734                 if (FAILED(hr)) {\r
735                         return hr;\r
736                 }\r
737         }\r
738 \r
739         return 0;\r
740 }\r
741 \r
742 __declspec(dllexport)\r
743 int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)\r
744 {\r
745         struct cma_id_private *id_priv;\r
746         WV_CONNECT_PARAM attr;\r
747         HRESULT hr;\r
748 \r
749         id_priv = CONTAINING_RECORD(id, struct cma_id_private, id);\r
750         hr = ucma_valid_param(id_priv, conn_param);\r
751         if (FAILED(hr)) {\r
752                 return hr;\r
753         }\r
754 \r
755         RtlZeroMemory(&attr, sizeof attr);\r
756         attr.ResponderResources = conn_param->responder_resources;\r
757         attr.InitiatorDepth = conn_param->initiator_depth;\r
758         attr.RetryCount = conn_param->retry_count;\r
759         attr.RnrRetryCount = conn_param->rnr_retry_count;\r
760         if ((attr.DataLength = conn_param->private_data_len)) {\r
761                 RtlCopyMemory(attr.Data, conn_param->private_data, attr.DataLength);\r
762         }\r
763 \r
764         id_priv->state = cma_accepting;\r
765         id_priv->refcnt++;\r
766         id->comp_entry.Busy = 1;\r
767         hr = id->ep.connect->Accept(id->qp->conn_handle, &attr,\r
768                                                                 &id->comp_entry.Overlap);\r
769         if (FAILED(hr) && hr != WV_IO_PENDING) {\r
770                 id_priv->refcnt--;\r
771                 id->comp_entry.Busy = 0;\r
772                 id_priv->state = cma_disconnected;\r
773                 return hr;\r
774         }\r
775 \r
776         return 0;\r
777 }\r
778 \r
779 __declspec(dllexport)\r
780 int rdma_reject(struct rdma_cm_id *id, const void *private_data,\r
781                                 uint8_t private_data_len)\r
782 {\r
783         struct cma_id_private *id_priv;\r
784         HRESULT hr;\r
785 \r
786         id_priv = CONTAINING_RECORD(id, struct cma_id_private, id);\r
787         id_priv->state = cma_disconnected;\r
788         hr = id->ep.connect->Reject(private_data, private_data_len);\r
789         if (FAILED(hr)) {\r
790                 return hr;\r
791         }\r
792         return 0;\r
793 }\r
794 \r
795 __declspec(dllexport)\r
796 int rdma_notify(struct rdma_cm_id *id, enum ibv_event_type event)\r
797 {\r
798         return 0;\r
799 }\r
800 \r
801 __declspec(dllexport)\r
802 int rdma_disconnect(struct rdma_cm_id *id)\r
803 {\r
804         struct cma_id_private *id_priv;\r
805         HRESULT hr;\r
806 \r
807         id_priv = CONTAINING_RECORD(id, struct cma_id_private, id);\r
808         if (id_priv->state == cma_connected) {\r
809                 id_priv->state = cma_active_disconnect;\r
810         } else {\r
811                 id_priv->state = cma_disconnected;\r
812         }\r
813         hr = id->ep.connect->Disconnect(NULL);\r
814         if (FAILED(hr)) {\r
815                 return hr;\r
816         }\r
817 \r
818         return 0;\r
819 }\r
820 \r
821 __declspec(dllexport)\r
822 int rdma_ack_cm_event(struct rdma_cm_event *event)\r
823 {\r
824         struct cma_event *evt;\r
825         struct cma_id_private *listen;\r
826 \r
827         evt = CONTAINING_RECORD(event, struct cma_event, event);\r
828         InterlockedDecrement(&evt->id_priv->refcnt);\r
829         if (evt->event.listen_id) {\r
830                 listen = CONTAINING_RECORD(evt->event.listen_id, struct cma_id_private, id);\r
831                 InterlockedDecrement(&listen->refcnt);\r
832         }\r
833         delete evt;\r
834         return 0;\r
835 }\r
836 \r
837 static int ucma_process_conn_req(struct cma_event *event)\r
838 {\r
839         struct cma_id_private *listen, *id_priv;\r
840         struct cma_event_channel *chan;\r
841 \r
842         listen = (struct cma_id_private *) event->id_priv->id.context;\r
843         id_priv = event->id_priv;\r
844 \r
845         ucma_get_request(listen, id_priv->index);\r
846 \r
847         if (SUCCEEDED(event->event.status)) {\r
848                 event->event.status = ucma_query_connect(&id_priv->id,\r
849                                                                                                  &event->event.param.conn);\r
850         }\r
851 \r
852         if (SUCCEEDED(event->event.status)) {\r
853                 event->event.event = RDMA_CM_EVENT_CONNECT_REQUEST;\r
854                 id_priv->state = cma_passive_connect;\r
855                 event->event.listen_id = &listen->id;\r
856         } else {\r
857                 InterlockedDecrement(&listen->refcnt);\r
858                 InterlockedDecrement(&id_priv->refcnt);\r
859                 rdma_destroy_id(&id_priv->id);\r
860         }\r
861 \r
862         return event->event.status;\r
863 }\r
864 \r
865 static int ucma_process_conn_resp(struct cma_event *event)\r
866 {\r
867         struct rdma_cm_id *id;\r
868         WV_CONNECT_PARAM attr;\r
869         HRESULT hr;\r
870 \r
871         if (FAILED(event->event.status)) {\r
872                 goto err;\r
873         }\r
874 \r
875         RtlZeroMemory(&attr, sizeof(attr));\r
876         event->id_priv->state = cma_accepting;\r
877 \r
878         id = &event->id_priv->id;\r
879         id->comp_entry.Busy = 1;\r
880         hr = id->ep.connect->Accept(id->qp->conn_handle, &attr,\r
881                                                                 &id->comp_entry.Overlap);\r
882         if (FAILED(hr) && hr != WV_IO_PENDING) {\r
883                 id->comp_entry.Busy = 0;\r
884                 event->event.status = hr;\r
885                 goto err;\r
886         }\r
887 \r
888         return WV_IO_PENDING;\r
889 \r
890 err:\r
891         event->event.event = (event->event.status == WV_REJECTED) ?\r
892                                                  RDMA_CM_EVENT_REJECTED :\r
893                                                  RDMA_CM_EVENT_CONNECT_ERROR;\r
894         event->id_priv->state = cma_disconnected;\r
895         return 0;\r
896 }\r
897 \r
898 static void ucma_process_establish(struct cma_event *event)\r
899 {\r
900         struct cma_id_private *id_priv = event->id_priv;\r
901 \r
902         if (SUCCEEDED(event->event.status)) {\r
903                 event->event.status = ucma_query_connect(&id_priv->id,\r
904                                                                                                  &event->event.param.conn);\r
905         }\r
906 \r
907         if (SUCCEEDED(event->event.status)) {\r
908                 event->event.event = RDMA_CM_EVENT_ESTABLISHED;\r
909 \r
910                 id_priv->state = cma_connected;\r
911                 InterlockedIncrement(&id_priv->refcnt);\r
912                 id_priv->id.comp_entry.Busy = 1;\r
913                 id_priv->id.ep.connect->NotifyDisconnect(&id_priv->id.comp_entry.Overlap);\r
914         } else {\r
915                 event->event.event = RDMA_CM_EVENT_CONNECT_ERROR;\r
916                 event->id_priv->state = cma_disconnected;\r
917         }\r
918 }\r
919 \r
920 static int ucma_process_event(struct cma_event *event)\r
921 {\r
922         struct cma_id_private *listen, *id_priv;\r
923         WV_CONNECT_ATTRIBUTES attr;\r
924         HRESULT hr = 0;\r
925 \r
926         id_priv = event->id_priv;\r
927 \r
928         EnterCriticalSection(&lock);\r
929         switch (id_priv->state) {\r
930         case cma_get_request:\r
931                 listen = (struct cma_id_private *) id_priv->id.context;\r
932                 if (listen->state != cma_listening) {\r
933                         InterlockedDecrement(&id_priv->refcnt);\r
934                         hr = WV_CANCELLED;\r
935                         break;\r
936                 }\r
937 \r
938                 listen->req_list[id_priv->index] = NULL;\r
939                 LeaveCriticalSection(&lock);\r
940                 return ucma_process_conn_req(event);\r
941         case cma_addr_resolve:\r
942                 event->event.event = RDMA_CM_EVENT_ADDR_RESOLVED;\r
943                 break;\r
944         case cma_route_resolve:\r
945                 event->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED;\r
946                 break;\r
947         case cma_active_connect:\r
948                 hr = ucma_process_conn_resp(event);\r
949                 break;\r
950         case cma_accepting:\r
951                 ucma_process_establish(event);\r
952                 break;\r
953         case cma_connected:\r
954                 event->event.event = RDMA_CM_EVENT_DISCONNECTED;\r
955                 id_priv->state = cma_passive_disconnect;\r
956                 break;\r
957         case cma_active_disconnect:\r
958                 event->event.event = RDMA_CM_EVENT_DISCONNECTED;\r
959                 id_priv->state = cma_disconnected;\r
960                 break;\r
961         default:\r
962                 InterlockedDecrement(&id_priv->refcnt);\r
963                 hr = WV_CANCELLED;\r
964         }\r
965         LeaveCriticalSection(&lock);\r
966 \r
967         return hr;\r
968 }\r
969 \r
970 __declspec(dllexport)\r
971 int rdma_get_cm_event(struct rdma_event_channel *channel,\r
972                                           struct rdma_cm_event **event)\r
973 {\r
974         struct cma_event *evt;\r
975         struct rdma_cm_id *id;\r
976         COMP_ENTRY *entry;\r
977         DWORD bytes, ret;\r
978 \r
979         evt = new struct cma_event;\r
980         if (evt == NULL) {\r
981                 return -1;\r
982         }\r
983 \r
984         do {\r
985                 RtlZeroMemory(evt, sizeof(struct cma_event));\r
986 \r
987                 ret = CompChannelPoll(&channel->channel, &entry);\r
988                 if (ret) {\r
989                         delete evt;\r
990                         return ret;\r
991                 }\r
992 \r
993                 id = CONTAINING_RECORD(entry, struct rdma_cm_id, comp_entry);\r
994                 evt->id_priv = CONTAINING_RECORD(id, struct cma_id_private, id);\r
995                 evt->event.id = id;\r
996                 evt->event.param.conn.private_data = evt->private_data;\r
997                 evt->event.status = id->ep.connect->\r
998                                                         GetOverlappedResult(&entry->Overlap, &bytes, FALSE);\r
999 \r
1000                 ret = ucma_process_event(evt);\r
1001         } while (ret);\r
1002         \r
1003         *event = &evt->event;\r
1004         return 0;\r
1005 }\r
1006 \r
1007 \r
1008 __declspec(dllexport)\r
1009 int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr,\r
1010                                                 void *context)\r
1011 {\r
1012         return WV_NOT_SUPPORTED;\r
1013 }\r
1014 \r
1015 __declspec(dllexport)\r
1016 int rdma_leave_multicast(struct rdma_cm_id *id, struct sockaddr *addr)\r
1017 {\r
1018         return WV_NOT_SUPPORTED;\r
1019 }\r
1020 \r
1021 __declspec(dllexport)\r
1022 const char *rdma_event_str(enum rdma_cm_event_type event)\r
1023 {\r
1024         switch (event) {\r
1025         case RDMA_CM_EVENT_ADDR_RESOLVED:\r
1026                 return "RDMA_CM_EVENT_ADDR_RESOLVED";\r
1027         case RDMA_CM_EVENT_ADDR_ERROR:\r
1028                 return "RDMA_CM_EVENT_ADDR_ERROR";\r
1029         case RDMA_CM_EVENT_ROUTE_RESOLVED:\r
1030                 return "RDMA_CM_EVENT_ROUTE_RESOLVED";\r
1031         case RDMA_CM_EVENT_ROUTE_ERROR:\r
1032                 return "RDMA_CM_EVENT_ROUTE_ERROR";\r
1033         case RDMA_CM_EVENT_CONNECT_REQUEST:\r
1034                 return "RDMA_CM_EVENT_CONNECT_REQUEST";\r
1035         case RDMA_CM_EVENT_CONNECT_RESPONSE:\r
1036                 return "RDMA_CM_EVENT_CONNECT_RESPONSE";\r
1037         case RDMA_CM_EVENT_CONNECT_ERROR:\r
1038                 return "RDMA_CM_EVENT_CONNECT_ERROR";\r
1039         case RDMA_CM_EVENT_UNREACHABLE:\r
1040                 return "RDMA_CM_EVENT_UNREACHABLE";\r
1041         case RDMA_CM_EVENT_REJECTED:\r
1042                 return "RDMA_CM_EVENT_REJECTED";\r
1043         case RDMA_CM_EVENT_ESTABLISHED:\r
1044                 return "RDMA_CM_EVENT_ESTABLISHED";\r
1045         case RDMA_CM_EVENT_DISCONNECTED:\r
1046                 return "RDMA_CM_EVENT_DISCONNECTED";\r
1047         case RDMA_CM_EVENT_DEVICE_REMOVAL:\r
1048                 return "RDMA_CM_EVENT_DEVICE_REMOVAL";\r
1049         case RDMA_CM_EVENT_MULTICAST_JOIN:\r
1050                 return "RDMA_CM_EVENT_MULTICAST_JOIN";\r
1051         case RDMA_CM_EVENT_MULTICAST_ERROR:\r
1052                 return "RDMA_CM_EVENT_MULTICAST_ERROR";\r
1053         case RDMA_CM_EVENT_ADDR_CHANGE:\r
1054                 return "RDMA_CM_EVENT_ADDR_CHANGE";\r
1055         case RDMA_CM_EVENT_TIMEWAIT_EXIT:\r
1056                 return "RDMA_CM_EVENT_TIMEWAIT_EXIT";\r
1057         default:\r
1058                 return "UNKNOWN EVENT";\r
1059         }\r
1060 }\r
1061 \r
1062 __declspec(dllexport)\r
1063 int rdma_set_option(struct rdma_cm_id *id, int level, int optname,\r
1064                                         void *optval, size_t optlen)\r
1065 {\r
1066         return WV_NOT_SUPPORTED;\r
1067 }\r
1068 \r
1069 __declspec(dllexport)\r
1070 int rdma_migrate_id(struct rdma_cm_id *id, struct rdma_event_channel *channel)\r
1071 {\r
1072         id->channel = channel;\r
1073         return 0;\r
1074 }\r