a25d4307cbc6d166e867064f030cbb83a6f09e8b
[mirror/winof/.git] / ulp / libibverbs / src / verbs.cpp
1 /*\r
2  * Copyright (c) 2005 Topspin Communications.  All rights reserved.\r
3  * Copyright (c) 2006, 2007 Cisco Systems, Inc.  All rights reserved.\r
4  * Copyright (c) 2008 Intel Corporation.  All rights reserved.\r
5  *\r
6  * This software is available to you under the OpenIB.org BSD license\r
7  * below:\r
8  *\r
9  *     Redistribution and use in source and binary forms, with or\r
10  *     without modification, are permitted provided that the following\r
11  *     conditions are met:\r
12  *\r
13  *      - Redistributions of source code must retain the above\r
14  *        copyright notice, this list of conditions and the following\r
15  *        disclaimer.\r
16  *\r
17  *      - Redistributions in binary form must reproduce the above\r
18  *        copyright notice, this list of conditions and the following\r
19  *        disclaimer in the documentation and/or other materials\r
20  *        provided with the distribution.\r
21  *\r
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
23  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
24  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV\r
25  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
26  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
27  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
28  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
29  * SOFTWARE.\r
30  */\r
31 \r
32 #include <windows.h>\r
33 #include <winsock2.h>\r
34 #include <stdio.h>\r
35 \r
36 #include <infiniband/verbs.h>\r
37 #include "ibverbs.h"\r
38 \r
39 struct verbs_cq\r
40 {\r
41         struct ibv_cq                           cq;\r
42         int                                                     channel_index;\r
43 };\r
44 \r
45 struct verbs_comp_channel\r
46 {\r
47         struct ibv_comp_channel         channel;\r
48         CRITICAL_SECTION                        lock;\r
49         struct verbs_cq                         *cq[MAXIMUM_WAIT_OBJECTS];\r
50         HANDLE                                          event[MAXIMUM_WAIT_OBJECTS];\r
51         int                                                     count;\r
52 };\r
53 \r
54 __declspec(dllexport)\r
55 int ibv_rate_to_mult(enum ibv_rate rate)\r
56 {\r
57         switch (rate) {\r
58         case IBV_RATE_2_5_GBPS: return  1;\r
59         case IBV_RATE_5_GBPS:   return  2;\r
60         case IBV_RATE_10_GBPS:  return  4;\r
61         case IBV_RATE_20_GBPS:  return  8;\r
62         case IBV_RATE_30_GBPS:  return 12;\r
63         case IBV_RATE_40_GBPS:  return 16;\r
64         case IBV_RATE_60_GBPS:  return 24;\r
65         case IBV_RATE_80_GBPS:  return 32;\r
66         case IBV_RATE_120_GBPS: return 48;\r
67         default:           return -1;\r
68         }\r
69 }\r
70 \r
71 __declspec(dllexport)\r
72 enum ibv_rate mult_to_ibv_rate(int mult)\r
73 {\r
74         switch (mult) {\r
75         case 1:  return IBV_RATE_2_5_GBPS;\r
76         case 2:  return IBV_RATE_5_GBPS;\r
77         case 4:  return IBV_RATE_10_GBPS;\r
78         case 8:  return IBV_RATE_20_GBPS;\r
79         case 12: return IBV_RATE_30_GBPS;\r
80         case 16: return IBV_RATE_40_GBPS;\r
81         case 24: return IBV_RATE_60_GBPS;\r
82         case 32: return IBV_RATE_80_GBPS;\r
83         case 48: return IBV_RATE_120_GBPS;\r
84         default: return IBV_RATE_MAX;\r
85         }\r
86 }\r
87 \r
88 static int ibv_find_gid_index(struct ibv_context *context, uint8_t port_num,\r
89                                                           union ibv_gid *gid)\r
90 {\r
91         union ibv_gid sgid;\r
92         int i = 0, ret;\r
93 \r
94         do {\r
95                 ret = ibv_query_gid(context, port_num, i++, &sgid);\r
96         } while (!ret && memcmp(&sgid, gid, sizeof *gid));\r
97 \r
98         return ret ? ret : i - 1;\r
99 }\r
100 \r
101 static void ibv_convert_ah_attr(struct ibv_context *context,\r
102                                                                 WV_ADDRESS_VECTOR *av, struct ibv_ah_attr *attr)\r
103 {\r
104         WV_GID gid;\r
105 \r
106         av->Route.Valid = attr->is_global;\r
107         if (av->Route.Valid) {\r
108                 context->cmd_if->QueryGid(attr->port_num, attr->grh.sgid_index, &gid);\r
109 \r
110                 memcpy(&av->Route.DGid, &attr->grh.dgid, sizeof(av->Route.DGid));\r
111                 memcpy(&av->Route.SGid, &gid, sizeof(av->Route.SGid));\r
112                 av->Route.TrafficClass = attr->grh.traffic_class;\r
113                 av->Route.FlowLabel =  htonl(attr->grh.flow_label);\r
114                 av->Route.HopLimit = attr->grh.hop_limit;\r
115         }\r
116 \r
117         av->DLid = htons(attr->dlid);\r
118         av->ServiceLevel = attr->sl;\r
119         av->SourcePathBits = attr->src_path_bits;\r
120         av->StaticRate = attr->static_rate;\r
121         av->PortNumber = attr->port_num;\r
122 }\r
123 \r
124 static void ibv_convert_av(struct ibv_context *context,\r
125                                                    struct ibv_ah_attr *attr, WV_ADDRESS_VECTOR *av)\r
126 {\r
127         WV_GID gid;\r
128 \r
129         attr->is_global = av->Route.Valid;\r
130         if (attr->is_global) {\r
131                 memcpy(&attr->grh.dgid, &av->Route.DGid, sizeof(attr->grh.dgid));\r
132                 attr->grh.flow_label = ntohl(av->Route.FlowLabel);\r
133                 attr->grh.traffic_class = av->Route.TrafficClass;\r
134                 attr->grh.hop_limit = av->Route.HopLimit;\r
135                 attr->grh.sgid_index = (uint8_t) ibv_find_gid_index(context, av->PortNumber,\r
136                                                                                                                         (ibv_gid *) &av->Route.SGid);\r
137         }\r
138 \r
139         attr->dlid = ntohs(av->DLid);\r
140         attr->sl = av->ServiceLevel;\r
141         attr->src_path_bits     = av->SourcePathBits;\r
142         attr->static_rate = av->StaticRate;\r
143         attr->port_num = av->PortNumber;\r
144 }\r
145 \r
146 __declspec(dllexport)\r
147 int ibv_query_device(struct ibv_context *context,\r
148                                          struct ibv_device_attr *device_attr)\r
149 {\r
150         WV_DEVICE_ATTRIBUTES attr;\r
151         HRESULT hr;\r
152 \r
153         hr = context->cmd_if->Query(&attr);\r
154         if (FAILED(hr)) {\r
155                 return hr;\r
156         }\r
157 \r
158         sprintf(device_attr->fw_ver, "0x%I64x", attr.FwVersion);\r
159         device_attr->node_guid = attr.NodeGuid;\r
160         device_attr->sys_image_guid = attr.SystemImageGuid;\r
161         device_attr->max_mr_size = attr.MaxMrSize;\r
162         device_attr->page_size_cap = attr.PageSizeCapabilityFlags;\r
163         device_attr->vendor_id = attr.VendorId;\r
164         device_attr->vendor_part_id = attr.VendorPartId;\r
165         device_attr->hw_ver = attr.HwVersion;\r
166         device_attr->max_qp = (int) attr.MaxQp;\r
167         device_attr->max_qp_wr = (int) attr.MaxQpWr;\r
168         device_attr->device_cap_flags = (int) attr.CapabilityFlags;\r
169         device_attr->max_sge = (int) attr.MaxSge;\r
170         device_attr->max_sge_rd = 0;\r
171         device_attr->max_cq = (int) attr.MaxCq;\r
172         device_attr->max_cqe = (int) attr.MaxCqEntries;\r
173         device_attr->max_mr = (int) attr.MaxMr;\r
174         device_attr->max_pd = (int) attr.MaxPd;\r
175         device_attr->max_qp_rd_atom = (int) attr.MaxQpResponderResources;;\r
176         device_attr->max_ee_rd_atom = 0;\r
177         device_attr->max_res_rd_atom = (int) attr.MaxResponderResources;\r
178         device_attr->max_qp_init_rd_atom = (int) attr.MaxQpInitiatorDepth;\r
179         device_attr->max_ee_init_rd_atom = 0;\r
180         device_attr->atomic_cap = (enum ibv_atomic_cap) attr.AtomicCapability;\r
181         device_attr->max_ee = 0;\r
182         device_attr->max_rdd = 0;\r
183         device_attr->max_mw = (int) attr.MaxMw;\r
184         device_attr->max_raw_ipv6_qp = 0;\r
185         device_attr->max_raw_ethy_qp = 0;\r
186         device_attr->max_mcast_grp = (int) attr.MaxMulticast;\r
187         device_attr->max_mcast_qp_attach = (int) attr.MaxQpAttach;\r
188         device_attr->max_total_mcast_qp_attach = (int) attr.MaxMulticastQp;\r
189         device_attr->max_ah = (int) attr.MaxAh;\r
190         device_attr->max_fmr = (int) attr.MaxFmr;\r
191         device_attr->max_map_per_fmr = (int) attr.MaxMapPerFmr;\r
192         device_attr->max_srq = (int) attr.MaxSrq;\r
193         device_attr->max_srq_wr = (int) attr.MaxSrqWr;\r
194         device_attr->max_srq_sge = (int) attr.MaxSrqSge;\r
195         device_attr->max_pkeys = (uint16_t) attr.MaxPkeys;\r
196         device_attr->local_ca_ack_delay = attr.LocalAckDelay;\r
197         device_attr->phys_port_cnt = attr.PhysPortCount;\r
198 \r
199         return 0;\r
200 }\r
201 \r
202 static enum ibv_mtu ibv_convert_mtu(UINT32 mtu)\r
203 {\r
204         switch (mtu) {\r
205         case 256:       return IBV_MTU_256;\r
206         case 512:       return IBV_MTU_512;\r
207         case 1024:      return IBV_MTU_1024;\r
208         case 2048:      return IBV_MTU_2048;\r
209         case 4096:      return IBV_MTU_4096;\r
210         default:        return (ibv_mtu) mtu;\r
211         }\r
212 }\r
213 \r
214 __declspec(dllexport)\r
215 int ibv_query_port(struct ibv_context *context, uint8_t port_num,\r
216                                    struct ibv_port_attr *port_attr)\r
217 {\r
218         WV_PORT_ATTRIBUTES attr;\r
219         HRESULT hr;\r
220         \r
221         hr = context->cmd_if->QueryPort(port_num, &attr);\r
222         if (FAILED(hr)) {\r
223                 return hr;\r
224         }\r
225 \r
226         port_attr->state = (enum ibv_port_state) attr.State;\r
227         port_attr->max_mtu = ibv_convert_mtu(attr.MaxMtu);\r
228         port_attr->active_mtu = ibv_convert_mtu(attr.ActiveMtu);\r
229         port_attr->gid_tbl_len = attr.GidTableLength;\r
230         port_attr->port_cap_flags = attr.PortCabilityFlags;\r
231         port_attr->max_msg_sz = attr.MaxMessageSize;\r
232         port_attr->bad_pkey_cntr = attr.BadPkeyCounter;\r
233         port_attr->qkey_viol_cntr = attr.QkeyViolationCounter;\r
234         port_attr->pkey_tbl_len = attr.PkeyTableLength;\r
235         port_attr->lid = ntohs(attr.Lid);\r
236         port_attr->sm_lid = ntohs(attr.SmLid);\r
237         port_attr->lmc = attr.Lmc;\r
238         port_attr->max_vl_num = attr.MaxVls;\r
239         port_attr->sm_sl = attr.SmSl;\r
240         port_attr->subnet_timeout = attr.SubnetTimeout;\r
241         port_attr->init_type_reply = attr.InitTypeReply;\r
242         port_attr->active_width = attr.ActiveWidth;\r
243         port_attr->active_speed = attr.ActiveSpeed;\r
244         port_attr->phys_state = attr.PhysicalState;\r
245 \r
246         return 0;\r
247 }\r
248 \r
249 __declspec(dllexport)\r
250 int ibv_query_gid(struct ibv_context *context, uint8_t port_num,\r
251                                   int index, union ibv_gid *gid)\r
252 {\r
253         return context->cmd_if->QueryGid(port_num, index, (WV_GID *) gid);\r
254 }\r
255 \r
256 __declspec(dllexport)\r
257 int ibv_query_pkey(struct ibv_context *context, uint8_t port_num,\r
258                                    int index, uint16_t *pkey)\r
259 {\r
260         return context->cmd_if->QueryPkey(port_num, (UINT16) index, pkey);\r
261 }\r
262 \r
263 __declspec(dllexport)\r
264 struct ibv_pd *ibv_alloc_pd(struct ibv_context *context)\r
265 {\r
266         struct ibv_pd *pd;\r
267         HRESULT hr;\r
268 \r
269         pd = new struct ibv_pd;\r
270         if (pd == NULL) {\r
271                 return NULL;\r
272         }\r
273 \r
274         pd->context = context;\r
275         hr = context->cmd_if->AllocateProtectionDomain(&pd->handle);\r
276         if (FAILED(hr)) {\r
277                 delete pd;\r
278                 return NULL;\r
279         }\r
280         return pd;\r
281 }\r
282 \r
283 __declspec(dllexport)\r
284 int ibv_dealloc_pd(struct ibv_pd *pd)\r
285 {\r
286         pd->handle->Release();\r
287         delete pd;\r
288         return 0;\r
289 }\r
290 \r
291 __declspec(dllexport)\r
292 struct ibv_mr *ibv_reg_mr(struct ibv_pd *pd, void *addr,\r
293                                                   size_t length, enum ibv_access_flags access)\r
294 {\r
295         struct ibv_mr *mr;\r
296         HRESULT hr;\r
297 \r
298         mr = new struct ibv_mr;\r
299         if (mr == NULL) {\r
300                 return NULL;\r
301         }\r
302 \r
303         mr->context = pd->context;\r
304         mr->pd = pd;\r
305         mr->addr = addr;\r
306         mr->length = length;\r
307         hr = pd->handle->RegisterMemory(addr, length, access, NULL,\r
308                                                                         (WV_MEMORY_KEYS *) &mr->lkey);\r
309         if (FAILED(hr)) {\r
310                 delete mr;\r
311                 return NULL;\r
312         }\r
313         return mr;\r
314 }\r
315 \r
316 __declspec(dllexport)\r
317 int ibv_dereg_mr(struct ibv_mr *mr)\r
318 {\r
319         return mr->pd->handle->DeregisterMemory(mr->lkey, NULL);\r
320 }\r
321 \r
322 __declspec(dllexport)\r
323 struct ibv_comp_channel *ibv_create_comp_channel(struct ibv_context *context)\r
324 {\r
325         struct verbs_comp_channel *vchan;\r
326 \r
327         vchan = new struct verbs_comp_channel;\r
328         if (vchan == NULL) {\r
329                 return NULL;\r
330         }\r
331 \r
332         InitializeCriticalSection(&vchan->lock);\r
333         vchan->count = 0;\r
334         vchan->channel.context = context;\r
335         vchan->channel.timeout = INFINITE;\r
336 \r
337         return &vchan->channel;\r
338 }\r
339 \r
340 __declspec(dllexport)\r
341 int ibv_destroy_comp_channel(struct ibv_comp_channel *channel)\r
342 {\r
343         struct verbs_comp_channel *vchan;\r
344 \r
345         vchan = CONTAINING_RECORD(channel, struct verbs_comp_channel, channel);\r
346         if (vchan->count > 0) {\r
347                 return -1;\r
348         }\r
349 \r
350         DeleteCriticalSection(&vchan->lock);    \r
351         delete vchan;\r
352         return 0;\r
353 }\r
354 \r
355 static int ibv_comp_channel_insert_cq(struct ibv_comp_channel *channel,\r
356                                                                           struct verbs_cq *cq)\r
357 {\r
358         struct verbs_comp_channel *vchan;\r
359         int ret = 0;\r
360 \r
361         vchan = CONTAINING_RECORD(channel, struct verbs_comp_channel, channel);\r
362 \r
363         EnterCriticalSection(&vchan->lock);\r
364         if (vchan->count == MAXIMUM_WAIT_OBJECTS) {\r
365                 ret = -1;\r
366                 goto out;\r
367         }\r
368 \r
369         vchan->cq[vchan->count] = cq;\r
370         vchan->event[vchan->count] = cq->cq.overlap.hEvent;\r
371         cq->channel_index = vchan->count++;\r
372 out:\r
373         LeaveCriticalSection(&vchan->lock);\r
374         return ret;\r
375 }\r
376 \r
377 /*\r
378  * TODO: we cannot call ibv_comp_channel_remove_cq() while another\r
379  * thread is calling ibv_get_cq_event().  If this is needed, then we\r
380  * need to halt the ibv_get_cq_event() thread, modify the event list,\r
381  * then restart the ibv_get_cq_event() thread.\r
382  */\r
383 static void ibv_comp_channel_remove_cq(struct ibv_comp_channel *channel,\r
384                                                                            struct verbs_cq *cq)\r
385 {\r
386         struct verbs_comp_channel *vchan;\r
387 \r
388         vchan = CONTAINING_RECORD(channel, struct verbs_comp_channel, channel);\r
389 \r
390         EnterCriticalSection(&vchan->lock);\r
391         vchan->count--;\r
392         vchan->cq[cq->channel_index] = vchan->cq[vchan->count];\r
393         vchan->event[cq->channel_index] = vchan->event[vchan->count];\r
394         vchan->cq[cq->channel_index]->channel_index = cq->channel_index;\r
395         LeaveCriticalSection(&vchan->lock);\r
396 }\r
397 \r
398 __declspec(dllexport)\r
399 struct ibv_cq *ibv_create_cq(struct ibv_context *context, int cqe, void *cq_context,\r
400                                                          struct ibv_comp_channel *channel, int comp_vector)\r
401 {\r
402         struct verbs_cq *vcq;\r
403         HRESULT hr;\r
404         SIZE_T entries;\r
405 \r
406         vcq = new struct verbs_cq;\r
407         if (vcq == NULL) {\r
408                 return NULL;\r
409         }\r
410 \r
411         vcq->cq.overlap.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);\r
412         if (vcq->cq.overlap.hEvent == NULL) {\r
413                 goto err1;\r
414         }\r
415 \r
416         vcq->cq.context = context;\r
417         vcq->cq.channel = channel;\r
418         vcq->cq.cq_context = cq_context;\r
419         vcq->cq.comp_events_completed = 0;\r
420 \r
421         entries = cqe;\r
422         hr = context->cmd_if->CreateCompletionQueue(&entries, &vcq->cq.handle);\r
423         if (FAILED(hr)) {\r
424                 goto err2;\r
425         }\r
426 \r
427         if (channel != NULL) {\r
428                 hr = ibv_comp_channel_insert_cq(channel, vcq);\r
429                 if (FAILED(hr)) {\r
430                         goto err3;\r
431                 }\r
432         }\r
433 \r
434         vcq->cq.cqe = (uint32_t) entries;\r
435         return &vcq->cq;\r
436 \r
437 err3:\r
438         vcq->cq.handle->Release();\r
439 err2:\r
440         CloseHandle(vcq->cq.overlap.hEvent);\r
441 err1:\r
442         delete vcq;\r
443         return NULL;\r
444 }\r
445 \r
446 __declspec(dllexport)\r
447 int ibv_resize_cq(struct ibv_cq *cq, int cqe)\r
448 {\r
449         HRESULT hr;\r
450         SIZE_T entries = cqe;\r
451 \r
452         hr = cq->handle->Resize(&entries);\r
453         if (SUCCEEDED(hr)) {\r
454                 cq->cqe = (int) entries;\r
455         }\r
456         return hr;\r
457 }\r
458 \r
459 __declspec(dllexport)\r
460 int ibv_req_notify_cq(struct ibv_cq *cq, int solicited_only)\r
461 {\r
462         HRESULT hr;\r
463         hr = cq->handle->Notify(solicited_only ? WvCqSolicited : WvCqNextCompletion,\r
464                                                         &cq->overlap);\r
465         if (SUCCEEDED(hr) || hr == WV_IO_PENDING) {\r
466                 return 0;\r
467         } else {\r
468                 return hr;\r
469         }\r
470 }\r
471 \r
472 __declspec(dllexport)\r
473 int ibv_poll_cq(struct ibv_cq *cq, int num_entries, struct ibv_wc *wc)\r
474 {\r
475         int n;\r
476 \r
477         num_entries = (int) cq->handle->Poll((WV_COMPLETION *) wc, num_entries);\r
478         for (n = 0; n < num_entries; n++) {\r
479                 wc[n].qp_num = ((ibv_qp *) wc[n].reserved)->qp_num;\r
480                 wc[n].src_qp = ntohl(wc[n].src_qp);\r
481                 wc[n].slid = ntohs(wc[n].slid);\r
482         }\r
483         return num_entries;\r
484 }\r
485 \r
486 __declspec(dllexport)\r
487 int ibv_destroy_cq(struct ibv_cq *cq)\r
488 {\r
489         struct verbs_cq *vcq;\r
490 \r
491         vcq = CONTAINING_RECORD(cq, struct verbs_cq, cq);\r
492 \r
493         cq->handle->CancelOverlappedRequests();\r
494 \r
495         if (cq->channel != NULL) {\r
496                 ibv_comp_channel_remove_cq(cq->channel, vcq);\r
497         }\r
498 \r
499         while (cq->comp_events_completed > 0)\r
500                 ; /* twiddle thumbs */\r
501 \r
502         cq->handle->Release();\r
503         delete cq;\r
504         return 0;\r
505 }\r
506 \r
507 __declspec(dllexport)\r
508 int ibv_get_cq_event(struct ibv_comp_channel *channel,\r
509                                          struct ibv_cq **cq, void **cq_context)\r
510 {\r
511         struct verbs_comp_channel *vchan;\r
512         struct verbs_cq *vcq;\r
513         HRESULT hr;\r
514 \r
515         vchan = CONTAINING_RECORD(channel, struct verbs_comp_channel, channel);\r
516         hr = WaitForMultipleObjects(vchan->count, vchan->event, FALSE,\r
517                                                                 vchan->channel.timeout);\r
518         if (hr == WAIT_TIMEOUT) {\r
519                 return hr;\r
520         } else if (hr == WAIT_FAILED) {\r
521                 return HRESULT_FROM_WIN32(GetLastError());\r
522         }\r
523 \r
524         EnterCriticalSection(&vchan->lock);\r
525         vcq = vchan->cq[hr];\r
526         vcq->cq.comp_events_completed++;\r
527         LeaveCriticalSection(&vchan->lock);\r
528 \r
529         *cq = &vcq->cq;\r
530         *cq_context = vcq->cq.cq_context;\r
531         return 0;\r
532 }\r
533 \r
534 __declspec(dllexport)\r
535 void ibv_ack_cq_events(struct ibv_cq *cq, unsigned int nevents)\r
536 {\r
537         struct verbs_comp_channel *vchan;\r
538 \r
539         if (cq->channel == NULL) {\r
540                 return;\r
541         }\r
542 \r
543         vchan = CONTAINING_RECORD(cq->channel, struct verbs_comp_channel, channel);\r
544         EnterCriticalSection(&vchan->lock);\r
545         cq->comp_events_completed -= nevents;\r
546         LeaveCriticalSection(&vchan->lock);\r
547 }\r
548 \r
549 __declspec(dllexport)\r
550 struct ibv_srq *ibv_create_srq(struct ibv_pd *pd,\r
551                                                            struct ibv_srq_init_attr *srq_init_attr)\r
552 {\r
553         struct ibv_srq *srq;\r
554         HRESULT hr;\r
555 \r
556         srq = new struct ibv_srq;\r
557         if (srq == NULL) {\r
558                 return NULL;\r
559         }\r
560 \r
561         srq->context = pd->context;\r
562         srq->srq_context = srq_init_attr->srq_context;\r
563         srq->pd = pd;\r
564 \r
565         hr = pd->handle->CreateSharedReceiveQueue(srq_init_attr->attr.max_wr,\r
566                                                                                           srq_init_attr->attr.max_sge,\r
567                                                                                           srq_init_attr->attr.srq_limit,\r
568                                                                                           &srq->handle);\r
569         if (FAILED(hr)) {\r
570                 delete srq;\r
571                 return NULL;\r
572         }\r
573 \r
574         return srq;\r
575 }\r
576 \r
577 __declspec(dllexport)\r
578 int ibv_modify_srq(struct ibv_srq *srq,\r
579                                    struct ibv_srq_attr *srq_attr,\r
580                                    enum ibv_srq_attr_mask srq_attr_mask)\r
581 {\r
582         ibv_srq_attr attr;\r
583 \r
584         ibv_query_srq(srq, &attr);\r
585         if (srq_attr_mask & IBV_SRQ_MAX_WR) {\r
586                 attr.max_wr = srq_attr->max_wr;\r
587         }\r
588         if (srq_attr_mask & IBV_SRQ_LIMIT) {\r
589                 attr.srq_limit = srq_attr->srq_limit;\r
590         }\r
591 \r
592         return srq->handle->Modify(attr.max_wr, attr.srq_limit);\r
593 }\r
594 \r
595 __declspec(dllexport)\r
596 int ibv_post_srq_recv(struct ibv_srq *srq,\r
597                                           struct ibv_recv_wr *recv_wr,\r
598                                           struct ibv_recv_wr **bad_recv_wr)\r
599 {\r
600         HRESULT hr = 0;\r
601 \r
602         for (*bad_recv_wr = recv_wr; *bad_recv_wr != NULL && SUCCEEDED(hr);\r
603                  *bad_recv_wr = (*bad_recv_wr)->next) {\r
604                 hr = srq->handle->PostReceive((*bad_recv_wr)->wr_id,\r
605                                                                           (WV_SGE *) (*bad_recv_wr)->sg_list,\r
606                                                                           (*bad_recv_wr)->num_sge);\r
607         }\r
608         return hr;\r
609 }\r
610 \r
611 __declspec(dllexport)\r
612 int ibv_query_srq(struct ibv_srq *srq, struct ibv_srq_attr *srq_attr)\r
613 {\r
614         SIZE_T max_wr, max_sge, srq_limit;\r
615         HRESULT hr;\r
616 \r
617         hr = srq->handle->Query(&max_wr, &max_sge, &srq_limit);\r
618         if (FAILED(hr)) {\r
619                 return hr;\r
620         }\r
621 \r
622         srq_attr->max_wr = (uint32_t) max_wr;\r
623         srq_attr->max_sge = (uint32_t) max_sge;\r
624         srq_attr->srq_limit = (uint32_t) srq_limit;\r
625         return 0;\r
626 }\r
627 \r
628 __declspec(dllexport)\r
629 int ibv_destroy_srq(struct ibv_srq *srq)\r
630 {\r
631         srq->handle->Release();\r
632         delete srq;\r
633         return 0;\r
634 }\r
635 \r
636 __declspec(dllexport)\r
637 struct ibv_qp *ibv_create_qp(struct ibv_pd *pd,\r
638                                                          struct ibv_qp_init_attr *qp_init_attr)\r
639 {\r
640         WV_QP_CREATE create;\r
641         ibv_qp_attr attr;\r
642         struct ibv_qp *qp;\r
643         HRESULT hr;\r
644 \r
645         qp = new struct ibv_qp;\r
646         if (qp == NULL) {\r
647                 return NULL;\r
648         }\r
649 \r
650         create.pSendCq = qp_init_attr->send_cq->handle;\r
651         create.pReceiveCq = qp_init_attr->recv_cq->handle;\r
652         create.pSharedReceiveQueue = (qp_init_attr->srq != NULL) ?\r
653                                                                  qp_init_attr->srq->handle : NULL;\r
654         create.Context = qp;\r
655         create.SendDepth = qp_init_attr->cap.max_send_wr;\r
656         create.SendSge = qp_init_attr->cap.max_send_sge;\r
657         create.ReceiveDepth = qp_init_attr->cap.max_recv_wr;\r
658         create.ReceiveSge = qp_init_attr->cap.max_recv_sge;\r
659         create.MaxInlineSend = qp_init_attr->cap.max_inline_data;\r
660         create.InitiatorDepth = 0;\r
661         create.ResponderResources = 0;\r
662         create.QpType = (WV_QP_TYPE) qp_init_attr->qp_type;\r
663         create.QpFlags = qp_init_attr->sq_sig_all ? WV_QP_SIGNAL_SENDS : 0;\r
664 \r
665         if (qp_init_attr->qp_type == IBV_QPT_UD) {\r
666                 hr = pd->handle->CreateDatagramQueuePair(&create, &qp->ud_handle);\r
667         } else {\r
668                 hr = pd->handle->CreateConnectQueuePair(&create, &qp->conn_handle);\r
669         }\r
670         if (FAILED(hr)) {\r
671                 goto err;\r
672         }\r
673 \r
674         if (qp_init_attr->qp_type == IBV_QPT_UD) {\r
675                 qp->ud_handle->QueryInterface(IID_IWVQueuePair, (LPVOID *) &qp->handle);\r
676         } else {\r
677                 qp->conn_handle->QueryInterface(IID_IWVQueuePair, (LPVOID *) &qp->handle);\r
678         }\r
679 \r
680         qp->context = pd->context;\r
681         qp->qp_context = qp_init_attr->qp_context;\r
682         qp->pd = pd;\r
683         qp->send_cq = qp_init_attr->send_cq;\r
684         qp->recv_cq = qp_init_attr->recv_cq;\r
685         qp->srq = qp_init_attr->srq;\r
686         qp->state = IBV_QPS_RESET;\r
687         /* qp_num set by ibv_query_qp */\r
688         qp->qp_type = qp_init_attr->qp_type;\r
689 \r
690         hr = ibv_query_qp(qp, &attr, (enum ibv_qp_attr_mask) 0xFFFFFFFF, qp_init_attr);\r
691         if (FAILED(hr)) {\r
692                 goto err;\r
693         }\r
694 \r
695         return qp;\r
696 \r
697 err:\r
698         delete qp;\r
699         return NULL;\r
700 }\r
701 \r
702 __declspec(dllexport)\r
703 int ibv_query_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr,\r
704                                  enum ibv_qp_attr_mask attr_mask,\r
705                                  struct ibv_qp_init_attr *init_attr)\r
706 {\r
707         WV_QP_ATTRIBUTES wv_attr;\r
708         HRESULT hr;\r
709 \r
710         hr = qp->handle->Query(&wv_attr);\r
711         if (FAILED(hr)) {\r
712                 return hr;\r
713         }\r
714 \r
715         /* ibv_qp exposes qp_num.  Save qp_num from query. */\r
716         qp->qp_num = ntohl(wv_attr.Qpn);\r
717 \r
718         init_attr->qp_context = qp->context;\r
719         init_attr->send_cq = qp->send_cq;\r
720         init_attr->recv_cq = qp->recv_cq;\r
721         init_attr->srq = qp->srq;\r
722         init_attr->cap.max_send_wr = (uint32_t) wv_attr.SendDepth;\r
723         init_attr->cap.max_recv_wr = (uint32_t) wv_attr.ReceiveDepth;\r
724         init_attr->cap.max_send_sge = (uint32_t) wv_attr.SendSge;\r
725         init_attr->cap.max_recv_sge = (uint32_t) wv_attr.ReceiveSge;\r
726         init_attr->cap.max_inline_data = (uint32_t) wv_attr.MaxInlineSend;\r
727         init_attr->qp_type = (enum ibv_qp_type) wv_attr.QpType;\r
728         init_attr->sq_sig_all = wv_attr.QpFlags & WV_QP_SIGNAL_SENDS;\r
729 \r
730         attr->qp_state = (enum ibv_qp_state) wv_attr.QpState;\r
731         attr->cur_qp_state = (enum ibv_qp_state) wv_attr.CurrentQpState;\r
732         attr->path_mtu = ibv_convert_mtu(wv_attr.PathMtu);\r
733         attr->path_mig_state = (enum ibv_mig_state) wv_attr.ApmState;\r
734         attr->qkey = ntohl(wv_attr.Qkey);\r
735         attr->rq_psn = ntohl(wv_attr.ReceivePsn);\r
736         attr->sq_psn = ntohl(wv_attr.SendPsn);\r
737         attr->dest_qp_num = ntohl(wv_attr.DestinationQpn);\r
738         attr->qp_access_flags = wv_attr.AccessFlags;\r
739         attr->cap = init_attr->cap;\r
740         ibv_convert_av(qp->context, &attr->ah_attr, &wv_attr.AddressVector);\r
741         if (wv_attr.AlternateAddressVector.DLid != 0) {\r
742                 ibv_convert_av(qp->context, &attr->alt_ah_attr, &wv_attr.AlternateAddressVector);\r
743         }\r
744         attr->pkey_index = wv_attr.PkeyIndex;\r
745         attr->alt_pkey_index = wv_attr.AlternatePkeyIndex;\r
746         attr->en_sqd_async_notify = 0;\r
747         attr->sq_draining = 0;\r
748         attr->max_rd_atomic = (uint8_t) wv_attr.InitiatorDepth;\r
749         attr->max_dest_rd_atomic = (uint8_t) wv_attr.ResponderResources;\r
750         attr->min_rnr_timer = wv_attr.RnrNakTimeout;\r
751         attr->port_num = wv_attr.AddressVector.PortNumber;\r
752         attr->timeout = wv_attr.LocalAckTimeout;\r
753         attr->retry_cnt = wv_attr.SequenceErrorRetryCount;\r
754         attr->rnr_retry = wv_attr.RnrRetryCount;\r
755         attr->alt_port_num = wv_attr.AlternateAddressVector.PortNumber;\r
756         attr->alt_timeout = wv_attr.AlternateLocalAckTimeout;\r
757 \r
758         return 0;\r
759 }\r
760 \r
761 __declspec(dllexport)\r
762 int ibv_modify_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr,\r
763                                   enum ibv_qp_attr_mask attr_mask)\r
764 {\r
765         WV_QP_ATTRIBUTES wv_attr;\r
766         HRESULT hr;\r
767 \r
768         wv_attr.SendDepth = attr->cap.max_send_wr;\r
769         wv_attr.SendSge = attr->cap.max_send_sge;\r
770         wv_attr.ReceiveDepth = attr->cap.max_recv_wr;\r
771         wv_attr.ReceiveSge = attr->cap.max_recv_sge;\r
772         wv_attr.MaxInlineSend = attr->cap.max_inline_data;\r
773         wv_attr.InitiatorDepth = attr->max_rd_atomic;\r
774         wv_attr.ResponderResources = attr->max_dest_rd_atomic;\r
775 \r
776         wv_attr.CurrentQpState = (WV_QP_STATE) attr->cur_qp_state;\r
777         wv_attr.QpState = (WV_QP_STATE) attr->qp_state;\r
778         wv_attr.ApmState = (WV_APM_STATE) attr->path_mig_state;\r
779         wv_attr.DestinationQpn = htonl(attr->dest_qp_num);\r
780         wv_attr.Qkey = htonl(attr->qkey);\r
781         wv_attr.SendPsn = htonl(attr->sq_psn);\r
782         wv_attr.ReceivePsn = htonl(attr->rq_psn);\r
783 \r
784         wv_attr.AccessFlags = attr->qp_access_flags;\r
785         wv_attr.QpFlags = 0;\r
786 \r
787         ibv_convert_ah_attr(qp->context, &wv_attr.AddressVector, &attr->ah_attr);\r
788         wv_attr.AddressVector.PortNumber = attr->port_num;\r
789         wv_attr.PathMtu = 0x80 << attr->path_mtu;\r
790         wv_attr.PkeyIndex = attr->pkey_index;\r
791         wv_attr.LocalAckTimeout = attr->timeout;\r
792 \r
793         if (attr_mask & IBV_QP_ALT_PATH) {\r
794                 ibv_convert_ah_attr(qp->context, &wv_attr.AlternateAddressVector,\r
795                                                         &attr->alt_ah_attr);\r
796                 wv_attr.AlternateAddressVector.PortNumber = attr->alt_port_num;\r
797                 wv_attr.AlternatePathMtu = 0x80 << attr->path_mtu;\r
798                 wv_attr.AlternatePkeyIndex = attr->alt_pkey_index;\r
799                 wv_attr.AlternateLocalAckTimeout = attr->alt_timeout;\r
800         }\r
801 \r
802         wv_attr.RnrNakTimeout = attr->min_rnr_timer;\r
803         wv_attr.SequenceErrorRetryCount = attr->retry_cnt;\r
804         wv_attr.RnrRetryCount = attr->rnr_retry;\r
805 \r
806         hr = qp->handle->Modify(&wv_attr, attr_mask, NULL);\r
807         if (SUCCEEDED(hr) && (attr_mask & IBV_QP_STATE)) {\r
808                 qp->state = attr->qp_state;\r
809         }\r
810 \r
811         return hr;\r
812 }\r
813 \r
814 __declspec(dllexport)\r
815 int ibv_post_send(struct ibv_qp *qp, struct ibv_send_wr *wr,\r
816                                   struct ibv_send_wr **bad_wr)\r
817 {\r
818         struct ibv_send_wr *cur_wr;\r
819         HRESULT hr = 0;\r
820         struct ibv_ah *ah;\r
821 \r
822         if ((qp->qp_type == IBV_QPT_UD) && (wr->next != NULL))\r
823                 return WV_NOT_SUPPORTED;\r
824 \r
825         for (cur_wr = wr; cur_wr != NULL; cur_wr = cur_wr->next) {\r
826                 if (qp->qp_type == IBV_QPT_UD) {\r
827                         ah = cur_wr->wr.ud.ah;\r
828                         cur_wr->wr.ud.ah = (struct ibv_ah *) ah->key;\r
829                         cur_wr->wr.ud.remote_qkey = htonl(cur_wr->wr.ud.remote_qkey);\r
830                         cur_wr->wr.ud.remote_qpn = htonl(cur_wr->wr.ud.remote_qpn);\r
831                 }\r
832 \r
833                 if ((cur_wr->opcode & 0x80000000) != 0) {\r
834                         cur_wr->opcode = (ibv_wr_opcode) (cur_wr->opcode & ~0x80000000);\r
835                         cur_wr->send_flags = (ibv_send_flags) (cur_wr->send_flags | WV_SEND_IMMEDIATE);\r
836                 }\r
837         }\r
838 \r
839         hr = qp->handle->PostSend((WV_SEND_REQUEST *) wr, (WV_SEND_REQUEST **) bad_wr);\r
840 \r
841         for (cur_wr = wr; cur_wr != NULL; cur_wr = cur_wr->next) {\r
842                 if (qp->qp_type == IBV_QPT_UD) {\r
843                         cur_wr->wr.ud.ah = ah;\r
844                         cur_wr->wr.ud.remote_qkey = ntohl(cur_wr->wr.ud.remote_qkey);\r
845                         cur_wr->wr.ud.remote_qpn = ntohl(cur_wr->wr.ud.remote_qpn);\r
846                 }\r
847 \r
848                 if ((cur_wr->send_flags & WV_SEND_IMMEDIATE) != 0) {\r
849                         cur_wr->send_flags = (ibv_send_flags) (cur_wr->send_flags & ~WV_SEND_IMMEDIATE);\r
850                         cur_wr->opcode = (ibv_wr_opcode) (cur_wr->opcode | 0x80000000);\r
851                 }\r
852         }\r
853 \r
854         return hr;\r
855 }\r
856 \r
857 __declspec(dllexport)\r
858 int ibv_post_recv(struct ibv_qp *qp, struct ibv_recv_wr *wr,\r
859                                   struct ibv_recv_wr **bad_wr)\r
860 {\r
861         HRESULT hr = 0;\r
862 \r
863         for (*bad_wr = wr; *bad_wr != NULL && SUCCEEDED(hr); *bad_wr = (*bad_wr)->next) {\r
864                 hr = qp->handle->PostReceive((*bad_wr)->wr_id, (WV_SGE *) (*bad_wr)->sg_list,\r
865                                                                          (*bad_wr)->num_sge);\r
866         }\r
867         return hr;\r
868 }\r
869 \r
870 __declspec(dllexport)\r
871 int ibv_destroy_qp(struct ibv_qp *qp)\r
872 {\r
873         qp->handle->CancelOverlappedRequests();\r
874         if (qp->qp_type == IBV_QPT_UD) {\r
875                 qp->ud_handle->Release();\r
876         } else {\r
877                 qp->conn_handle->Release();\r
878         }\r
879 \r
880         qp->handle->Release();\r
881         delete qp;\r
882         return 0;\r
883 }\r
884 \r
885 __declspec(dllexport)\r
886 struct ibv_ah *ibv_create_ah(struct ibv_pd *pd, struct ibv_ah_attr *attr)\r
887 {\r
888         WV_ADDRESS_VECTOR av;\r
889         struct ibv_ah *ah;\r
890         HRESULT hr;\r
891 \r
892         ah = new struct ibv_ah;\r
893         if (ah == NULL) {\r
894                 return NULL;\r
895         }\r
896 \r
897         ah->context = pd->context;\r
898         ah->pd = pd;\r
899         ibv_convert_ah_attr(pd->context, &av, attr);\r
900         hr = pd->handle->CreateAddressHandle(&av, &ah->handle, &ah->key);\r
901         if (FAILED(hr)) {\r
902                 delete ah;\r
903                 return NULL;\r
904         }\r
905         return ah;\r
906 }\r
907 \r
908 __declspec(dllexport)\r
909 int ibv_init_ah_from_wc(struct ibv_context *context, uint8_t port_num,\r
910                                                 struct ibv_wc *wc, struct ibv_grh *grh,\r
911                                                 struct ibv_ah_attr *ah_attr)\r
912 {\r
913         uint32_t flow_class;\r
914         int ret;\r
915 \r
916         memset(ah_attr, 0, sizeof *ah_attr);\r
917         ah_attr->dlid = wc->slid;\r
918         ah_attr->sl = wc->sl;\r
919         ah_attr->src_path_bits = wc->dlid_path_bits;\r
920         ah_attr->port_num = port_num;\r
921 \r
922         if (wc->wc_flags & IBV_WC_GRH) {\r
923                 ah_attr->is_global = 1;\r
924                 ah_attr->grh.dgid = grh->sgid;\r
925 \r
926                 ret = ibv_find_gid_index(context, port_num, &grh->dgid);\r
927                 if (ret < 0) {\r
928                         return ret;\r
929                 }\r
930 \r
931                 ah_attr->grh.sgid_index = (uint8_t) ret;\r
932                 flow_class = ntohl(grh->version_tclass_flow);\r
933                 ah_attr->grh.flow_label = flow_class & 0xFFFFF;\r
934                 ah_attr->grh.hop_limit = grh->hop_limit;\r
935                 ah_attr->grh.traffic_class = (flow_class >> 20) & 0xFF;\r
936         }\r
937         return 0;\r
938 }\r
939 \r
940 __declspec(dllexport)\r
941 struct ibv_ah *ibv_create_ah_from_wc(struct ibv_pd *pd, struct ibv_wc *wc,\r
942                                                                          struct ibv_grh *grh, uint8_t port_num)\r
943 {\r
944         struct ibv_ah_attr ah_attr;\r
945         int ret;\r
946 \r
947         ret = ibv_init_ah_from_wc(pd->context, port_num, wc, grh, &ah_attr);\r
948         if (ret != 0) {\r
949                 return NULL;\r
950         }\r
951 \r
952         return ibv_create_ah(pd, &ah_attr);\r
953 }\r
954 \r
955 __declspec(dllexport)\r
956 int ibv_destroy_ah(struct ibv_ah *ah)\r
957 {\r
958         ah->handle->Release();\r
959         delete ah;\r
960         return 0;\r
961 }\r
962 \r
963 __declspec(dllexport)\r
964 int ibv_attach_mcast(struct ibv_qp *qp, union ibv_gid *gid, uint16_t lid)\r
965 {\r
966         return qp->ud_handle->AttachMulticast((WV_GID *) gid, lid, NULL);\r
967 }\r
968 \r
969 __declspec(dllexport)\r
970 int ibv_detach_mcast(struct ibv_qp *qp, union ibv_gid *gid, uint16_t lid)\r
971 {\r
972         return qp->ud_handle->DetachMulticast((WV_GID *) gid, lid, NULL);\r
973 }\r