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