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