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