winverbs/nd: do not convert timeout status value
[mirror/winof/.git] / ulp / libibverbs / src / device.cpp
1 /*\r
2  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.\r
3  * Copyright (c) 2006, 2007 Cisco Systems, Inc.  All rights reserved.\r
4  *\r
5  * This software is available to you under the OpenIB.org BSD license\r
6  * below:\r
7  *\r
8  *     Redistribution and use in source and binary forms, with or\r
9  *     without modification, are permitted provided that the following\r
10  *     conditions are met:\r
11  *\r
12  *      - Redistributions of source code must retain the above\r
13  *        copyright notice, this list of conditions and the following\r
14  *        disclaimer.\r
15  *\r
16  *      - Redistributions in binary form must reproduce the above\r
17  *        copyright notice, this list of conditions and the following\r
18  *        disclaimer in the documentation and/or other materials\r
19  *        provided with the distribution.\r
20  *\r
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
22  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
23  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV\r
24  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
25  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
26  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
27  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
28  * SOFTWARE.\r
29  */\r
30 \r
31 #include <stdio.h>\r
32 #include <infiniband/verbs.h>\r
33 #include <rdma/winverbs.h>\r
34 #include "..\..\..\etc\user\comp_channel.cpp"\r
35 \r
36 CRITICAL_SECTION lock;\r
37 IWVProvider *prov;\r
38 COMP_MANAGER comp_mgr;\r
39 static DWORD ref;\r
40 \r
41 struct verbs_device\r
42 {\r
43         struct ibv_device       device;\r
44         uint64_t                        guid;\r
45         uint8_t                         phys_port_cnt;\r
46 };\r
47 \r
48 struct verbs_port\r
49 {\r
50         COMP_ENTRY                      comp_entry;\r
51         DWORD                           event_flag;\r
52         uint8_t                         port_num;\r
53 };\r
54 \r
55 struct verbs_context\r
56 {\r
57         struct ibv_context      context;\r
58         struct verbs_device     device;\r
59         uint8_t                         closing;\r
60         struct verbs_port       *port;\r
61         verbs_port                      *event_port;\r
62 };\r
63 \r
64 static int ibv_acquire(void)\r
65 {\r
66         HRESULT hr;\r
67 \r
68         EnterCriticalSection(&lock);\r
69         if (ref++ == 0) {\r
70                 hr = WvGetObject(IID_IWVProvider, (LPVOID*) &prov);\r
71                 if (FAILED(hr)) {\r
72                         goto err1;\r
73                 }\r
74                 hr = CompManagerOpen(&comp_mgr);\r
75                 if (FAILED(hr)) {\r
76                         goto err2;\r
77                 }\r
78                 hr = CompManagerMonitor(&comp_mgr, prov->GetFileHandle(), 0);\r
79                 if (FAILED(hr)) {\r
80                         goto err3;\r
81                 }\r
82         }\r
83         LeaveCriticalSection(&lock);\r
84         return 0;\r
85 \r
86 err3:\r
87         CompManagerClose(&comp_mgr);\r
88 err2:\r
89         prov->Release();\r
90 err1:\r
91         ref--;\r
92         LeaveCriticalSection(&lock);\r
93         return hr;\r
94 }\r
95 \r
96 static void ibv_release(void)\r
97 {\r
98         EnterCriticalSection(&lock);\r
99         if (--ref == 0) {\r
100                 CompManagerClose(&comp_mgr);\r
101                 prov->Release();\r
102         }\r
103         LeaveCriticalSection(&lock);\r
104 }\r
105 \r
106 __declspec(dllexport)\r
107 int ibvw_get_windata(struct ibvw_windata *windata, int version)\r
108 {\r
109         int ret;\r
110 \r
111         if (version != IBVW_WINDATA_VERSION || ibv_acquire()) {\r
112                 return -1;\r
113         }\r
114 \r
115         prov->AddRef();\r
116         windata->prov = prov;\r
117         windata->comp_mgr = &comp_mgr;\r
118         return 0;\r
119 }\r
120 \r
121 __declspec(dllexport)\r
122 void ibvw_release_windata(struct ibvw_windata *windata, int version)\r
123 {\r
124         prov->Release();\r
125         ibv_release();\r
126 }\r
127 \r
128 __declspec(dllexport)\r
129 struct ibv_device **ibv_get_device_list(int *num)\r
130 {\r
131         WV_DEVICE_ATTRIBUTES attr;\r
132         struct verbs_device *dev_array;\r
133         struct ibv_device **pdev_array;\r
134         NET64 *guid;\r
135         SIZE_T size, cnt;\r
136         HRESULT hr;\r
137 \r
138         if (ibv_acquire()) {\r
139                 goto err1;\r
140         }\r
141 \r
142         cnt = 0;\r
143         size = sizeof(NET64);\r
144 \r
145         while ((size / sizeof(NET64)) > cnt) {\r
146                 if (cnt > 0) {\r
147                         delete guid;\r
148                 }\r
149 \r
150                 cnt = size / sizeof(NET64);\r
151                 guid = new NET64[cnt];\r
152                 if (guid == NULL) {\r
153                         goto err1;\r
154                 }\r
155 \r
156                 hr = prov->QueryDeviceList(guid, &size);\r
157                 if (FAILED(hr)) {\r
158                         goto err2;\r
159                 }\r
160         }\r
161 \r
162         size /= sizeof(NET64);\r
163         dev_array = new struct verbs_device[size];\r
164         pdev_array = new struct ibv_device*[size + 1];\r
165         if (dev_array == NULL || pdev_array == NULL) {\r
166                 goto err2;\r
167         }\r
168 \r
169         for (cnt = 0; cnt < size; cnt++) {\r
170                 pdev_array[cnt] = &dev_array[cnt].device;\r
171                 hr = prov->QueryDevice(guid[cnt], &attr);\r
172                 if (FAILED(hr)) {\r
173                         goto err3;\r
174                 }\r
175 \r
176                 sprintf(dev_array[cnt].device.name, "ibv_device%d", cnt);\r
177                 dev_array[cnt].device.node_type = IBV_NODE_UNKNOWN;\r
178                 dev_array[cnt].device.transport_type = (ibv_transport_type) attr.DeviceType;\r
179                 dev_array[cnt].guid = guid[cnt];\r
180                 dev_array[cnt].phys_port_cnt = attr.PhysPortCount;\r
181         }\r
182 \r
183         pdev_array[cnt] = NULL;\r
184         if (num != NULL) {\r
185                 *num = (int) size;\r
186         }\r
187         return pdev_array;\r
188 \r
189 err3:\r
190         ibv_free_device_list(pdev_array);\r
191 err2:\r
192         delete guid;\r
193 err1:\r
194         return NULL;\r
195 }\r
196 \r
197 __declspec(dllexport)\r
198 void ibv_free_device_list(struct ibv_device **list)\r
199 {\r
200         ibv_release();\r
201         delete CONTAINING_RECORD(list[0], struct verbs_device, device);\r
202         delete list;\r
203 }\r
204 \r
205 __declspec(dllexport)\r
206 const char *ibv_get_device_name(struct ibv_device *device)\r
207 {\r
208         return device->name;\r
209 }\r
210 \r
211 __declspec(dllexport)\r
212 uint64_t ibv_get_device_guid(struct ibv_device *device)\r
213 {\r
214         return CONTAINING_RECORD(device, struct verbs_device, device)->guid;\r
215 }\r
216 \r
217 __declspec(dllexport)\r
218 struct ibv_context *ibv_open_device(struct ibv_device *device)\r
219 {\r
220         struct verbs_device *vdev;\r
221         struct verbs_context *vcontext;\r
222         HRESULT hr;\r
223         int i;\r
224 \r
225         vdev = CONTAINING_RECORD(device, struct verbs_device, device);\r
226         vcontext = new struct verbs_context;\r
227         if (vcontext == NULL) {\r
228                 return NULL;\r
229         }\r
230 \r
231         ibv_acquire();\r
232         memcpy(&vcontext->device, vdev, sizeof(struct verbs_device));\r
233         vcontext->context.device = &vcontext->device.device;\r
234         vcontext->event_port = NULL;\r
235         vcontext->closing = 0;\r
236         CompChannelInit(&comp_mgr, &vcontext->context.channel, INFINITE);\r
237 \r
238         vcontext->port = new struct verbs_port[vdev->phys_port_cnt];\r
239         if (vcontext->port == NULL) {\r
240                 goto err1;\r
241         }\r
242 \r
243         hr = prov->OpenDevice(vdev->guid, &vcontext->context.cmd_if);\r
244         if (FAILED(hr)) {\r
245                 goto err2;\r
246         }\r
247 \r
248         for (i = 0; i < vdev->phys_port_cnt; i++) {\r
249                 vcontext->port[i].port_num = (uint8_t) i + 1;\r
250                 vcontext->port[i].event_flag = 0;\r
251                 CompEntryInit(&vcontext->context.channel, &vcontext->port[i].comp_entry);\r
252                 vcontext->port[i].comp_entry.Busy = 1;\r
253                 vcontext->context.cmd_if->Notify(vcontext->port[i].port_num,\r
254                                                                                  &vcontext->port[i].comp_entry.Overlap,\r
255                                                                                  &vcontext->port[i].event_flag);\r
256         }\r
257 \r
258         return &vcontext->context;\r
259 \r
260 err2:\r
261         delete vcontext->port;\r
262 err1:\r
263         delete vcontext;\r
264         ibv_release();\r
265         return NULL;\r
266 }\r
267 \r
268 __declspec(dllexport)\r
269 int ibv_close_device(struct ibv_context *context)\r
270 {\r
271         struct verbs_context *vcontext;\r
272         int i;\r
273 \r
274         vcontext = CONTAINING_RECORD(context, struct verbs_context, context);\r
275         vcontext->closing = 1;\r
276         context->cmd_if->CancelOverlappedRequests();\r
277 \r
278         for (i = 0; i < vcontext->device.phys_port_cnt; i++) {\r
279                 CompEntryCancel(&vcontext->port[i].comp_entry);\r
280         }\r
281 \r
282         context->cmd_if->Release();\r
283         CompChannelCleanup(&vcontext->context.channel);\r
284         ibv_release();\r
285         delete vcontext->port;\r
286         delete vcontext;\r
287         return 0;\r
288 }\r
289 \r
290 static enum ibv_event_type ibv_get_port_event_state(struct verbs_context *vcontext)\r
291 {\r
292         WV_PORT_ATTRIBUTES attr;\r
293         HRESULT hr;\r
294 \r
295         hr = vcontext->context.cmd_if->QueryPort(vcontext->event_port->port_num, &attr);\r
296         if (FAILED(hr)) {\r
297                 return IBV_EVENT_PORT_ERR;\r
298         }\r
299 \r
300         return (attr.State == WvPortActive) ?\r
301                    IBV_EVENT_PORT_ACTIVE : IBV_EVENT_PORT_ERR;\r
302 }\r
303 \r
304 static int ibv_report_port_event(struct verbs_context *vcontext,\r
305                                                                  struct ibv_async_event *event)\r
306 {\r
307         struct verbs_port *port;\r
308         int ret = 0;\r
309 \r
310         port = vcontext->event_port;\r
311         event->element.port_num = port->port_num;\r
312 \r
313         if (port->event_flag & WV_EVENT_ERROR) {\r
314                 event->event_type = IBV_EVENT_DEVICE_FATAL;\r
315                 port->event_flag = 0;\r
316         } else if (port->event_flag & WV_EVENT_STATE) {\r
317                 event->event_type = ibv_get_port_event_state(vcontext);\r
318                 port->event_flag = 0;\r
319         } else if (port->event_flag & WV_EVENT_MANAGEMENT) {\r
320                 event->event_type = IBV_EVENT_SM_CHANGE;\r
321                 port->event_flag = 0;\r
322         } else if (port->event_flag & WV_EVENT_LINK_ADDRESS) {\r
323                 event->event_type = IBV_EVENT_LID_CHANGE;\r
324                 port->event_flag &= ~WV_EVENT_LINK_ADDRESS;\r
325         } else if (port->event_flag & WV_EVENT_PARTITION) {\r
326                 event->event_type = IBV_EVENT_PKEY_CHANGE;\r
327                 port->event_flag &= ~WV_EVENT_PARTITION;\r
328         } else {\r
329                 port->event_flag = 0;\r
330                 ret = -1;\r
331         }\r
332         \r
333         if (port->event_flag == 0 && !vcontext->closing) {\r
334                 port->comp_entry.Busy = 1;\r
335                 vcontext->context.cmd_if->Notify(vcontext->event_port->port_num,\r
336                                                                                  &port->comp_entry.Overlap,\r
337                                                                                  &port->event_flag);\r
338                 vcontext->event_port = NULL;\r
339         }\r
340         return ret;\r
341 }\r
342 \r
343 __declspec(dllexport)\r
344 int ibv_get_async_event(struct ibv_context *context,\r
345                                                 struct ibv_async_event *event)\r
346 {\r
347         struct verbs_context *vcontext;\r
348         COMP_ENTRY *entry;\r
349         int ret;\r
350 \r
351         vcontext = CONTAINING_RECORD(context, struct verbs_context, context);\r
352         if (vcontext->event_port) {\r
353                 if (ibv_report_port_event(vcontext, event) == 0) {\r
354                         return 0;\r
355                 }\r
356         }\r
357 \r
358         ret = CompChannelPoll(&context->channel, &entry);\r
359         if (!ret) {\r
360                 vcontext->event_port = CONTAINING_RECORD(entry, struct verbs_port, comp_entry);\r
361                 ret = ibv_report_port_event(vcontext, event);\r
362         }\r
363 \r
364         return ret;\r
365 }\r
366 \r
367 __declspec(dllexport)\r
368 void ibv_ack_async_event(struct ibv_async_event *event)\r
369 {\r
370         // Only device/port level events are currently supported\r
371         // nothing to do here at the moment\r
372 }\r