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