af633386eba00e30688591f80a149932e364b33a
[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 \r
35 IWVProvider *prov;\r
36 \r
37 struct verbs_device\r
38 {\r
39         struct ibv_device       device;\r
40         uint64_t                        guid;\r
41         uint8_t                         phys_port_cnt;\r
42 };\r
43 \r
44 struct verbs_port\r
45 {\r
46         OVERLAPPED                      overlap;\r
47         DWORD                           event_flag;\r
48 };\r
49 \r
50 #define EVENT_PORT_NONE 0xFF\r
51 \r
52 struct verbs_context\r
53 {\r
54         struct ibv_context      context;\r
55         struct verbs_device     device;\r
56         HANDLE                          *event;\r
57         struct verbs_port       *port;\r
58         uint8_t                         event_port_index;\r
59 };\r
60 \r
61 __declspec(dllexport)\r
62 IWVProvider *ibv_get_winverbs(void)\r
63 {\r
64         HRESULT hr;\r
65 \r
66         if (prov == NULL) {\r
67                 hr = WvGetObject(IID_IWVProvider, (LPVOID*) &prov);\r
68                 if (FAILED(hr)) {\r
69                         return NULL;\r
70                 }\r
71         }\r
72 \r
73         prov->AddRef();\r
74         return prov;\r
75 }\r
76 \r
77 __declspec(dllexport)\r
78 struct ibv_device **ibv_get_device_list(int *num)\r
79 {\r
80         WV_DEVICE_ATTRIBUTES attr;\r
81         struct verbs_device *dev_array;\r
82         struct ibv_device **pdev_array;\r
83         NET64 *guid;\r
84         SIZE_T size, cnt;\r
85         HRESULT hr;\r
86 \r
87         if (prov == NULL) {\r
88                 hr = WvGetObject(IID_IWVProvider, (LPVOID*) &prov);\r
89                 if (FAILED(hr)) {\r
90                         goto err1;\r
91                 }       \r
92         }\r
93 \r
94         cnt = 0;\r
95         size = sizeof(NET64);\r
96 \r
97         while ((size / sizeof(NET64)) > cnt) {\r
98                 if (cnt > 0) {\r
99                         delete guid;\r
100                 }\r
101 \r
102                 cnt = size / sizeof(NET64);\r
103                 guid = new NET64[cnt];\r
104                 if (guid == NULL) {\r
105                         goto err1;\r
106                 }\r
107 \r
108                 hr = prov->QueryDeviceList(guid, &size);\r
109                 if (FAILED(hr)) {\r
110                         goto err2;\r
111                 }\r
112         }\r
113 \r
114         size /= sizeof(NET64);\r
115         dev_array = new struct verbs_device[size];\r
116         pdev_array = new struct ibv_device*[size + 1];\r
117         if (dev_array == NULL || pdev_array == NULL) {\r
118                 goto err2;\r
119         }\r
120 \r
121         for (cnt = 0; cnt < size; cnt++) {\r
122                 pdev_array[cnt] = &dev_array[cnt].device;\r
123                 hr = prov->QueryDevice(guid[cnt], &attr);\r
124                 if (FAILED(hr)) {\r
125                         goto err3;\r
126                 }\r
127 \r
128                 sprintf(dev_array[cnt].device.name, "ibv_device_0x%I64x", guid[cnt]);\r
129                 dev_array[cnt].device.node_type = IBV_NODE_UNKNOWN;\r
130                 dev_array[cnt].device.transport_type = (ibv_transport_type) attr.DeviceType;\r
131                 dev_array[cnt].guid = guid[cnt];\r
132                 dev_array[cnt].phys_port_cnt = attr.PhysPortCount;\r
133         }\r
134 \r
135         pdev_array[cnt] = NULL;\r
136         if (num != NULL) {\r
137                 *num = (int) size;\r
138         }\r
139         return pdev_array;\r
140 \r
141 err3:\r
142         ibv_free_device_list(pdev_array);\r
143 err2:\r
144         delete guid;\r
145 err1:\r
146         return NULL;\r
147 }\r
148 \r
149 __declspec(dllexport)\r
150 void ibv_free_device_list(struct ibv_device **list)\r
151 {\r
152         delete CONTAINING_RECORD(list[0], struct verbs_device, device);\r
153         delete list;\r
154 }\r
155 \r
156 __declspec(dllexport)\r
157 const char *ibv_get_device_name(struct ibv_device *device)\r
158 {\r
159         return device->name;\r
160 }\r
161 \r
162 __declspec(dllexport)\r
163 uint64_t ibv_get_device_guid(struct ibv_device *device)\r
164 {\r
165         return CONTAINING_RECORD(device, struct verbs_device, device)->guid;\r
166 }\r
167 \r
168 __declspec(dllexport)\r
169 struct ibv_context *ibv_open_device(struct ibv_device *device)\r
170 {\r
171         struct verbs_device *vdev;\r
172         struct verbs_context *vcontext;\r
173         HRESULT hr;\r
174         int i;\r
175 \r
176         vdev = CONTAINING_RECORD(device, struct verbs_device, device);\r
177         vcontext = new struct verbs_context;\r
178         if (vcontext == NULL) {\r
179                 return NULL;\r
180         }\r
181         memcpy(&vcontext->device, vdev, sizeof(struct verbs_device));\r
182         vcontext->event_port_index = EVENT_PORT_NONE;\r
183         vcontext->context.timeout = INFINITE;\r
184 \r
185         vcontext->port = new struct verbs_port[vdev->phys_port_cnt];\r
186         if (vcontext->port == NULL) {\r
187                 goto err1;\r
188         }\r
189 \r
190         vcontext->event = new HANDLE[vdev->phys_port_cnt];\r
191         if (vcontext->event == NULL) {\r
192                 goto err2;\r
193         }\r
194 \r
195         hr = prov->OpenDevice(vdev->guid, &vcontext->context.cmd_if);\r
196         if (FAILED(hr)) {\r
197                 goto err3;\r
198         }\r
199 \r
200         for (i = 0; i < vdev->phys_port_cnt; i++) {\r
201                 vcontext->event[i] = CreateEvent(NULL, FALSE, FALSE, NULL);\r
202                 if (vcontext->event[i] == NULL) {\r
203                         goto err4;\r
204                 }\r
205                 vcontext->port[i].overlap.hEvent = vcontext->event[i];\r
206                 vcontext->port[i].event_flag = 0;\r
207 \r
208                 vcontext->context.cmd_if->Notify((UINT8) i + 1,\r
209                                                                                  &vcontext->port[i].overlap,\r
210                                                                                  &vcontext->port[i].event_flag);\r
211         }\r
212 \r
213         return &vcontext->context;\r
214 \r
215 err4:\r
216         while (--i >= 0) {\r
217                 CloseHandle(vcontext->event[i]);\r
218         }\r
219 err3:\r
220         delete vcontext->event;\r
221 err2:\r
222         delete vcontext->port;\r
223 err1:\r
224         delete vcontext;\r
225         return NULL;\r
226 }\r
227 \r
228 __declspec(dllexport)\r
229 int ibv_close_device(struct ibv_context *context)\r
230 {\r
231         struct verbs_context *vcontext;\r
232         int i;\r
233 \r
234         vcontext = CONTAINING_RECORD(context, struct verbs_context, context);\r
235         context->cmd_if->CancelOverlappedRequests();\r
236 \r
237         for (i = 0; i < vcontext->device.phys_port_cnt; i++) {\r
238                 CloseHandle(vcontext->event[i]);\r
239         }\r
240 \r
241         context->cmd_if->Release();\r
242         delete vcontext->event;\r
243         delete vcontext->port;\r
244         delete vcontext;\r
245         return 0;\r
246 }\r
247 \r
248 static enum ibv_event_type ibv_get_port_event_state(struct verbs_context *vcontext)\r
249 {\r
250         WV_PORT_ATTRIBUTES attr;\r
251         HRESULT hr;\r
252 \r
253         hr = vcontext->context.cmd_if->QueryPort(vcontext->event_port_index + 1, &attr);\r
254         if (FAILED(hr)) {\r
255                 return IBV_EVENT_PORT_ERR;\r
256         }\r
257 \r
258         return (attr.State == WvPortActive) ?\r
259                    IBV_EVENT_PORT_ACTIVE : IBV_EVENT_PORT_ERR;\r
260 }\r
261 \r
262 static int ibv_report_port_event(struct verbs_context *vcontext,\r
263                                                                  struct ibv_async_event *event)\r
264 {\r
265         struct verbs_port *port;\r
266         int ret = 0;\r
267 \r
268         port = &vcontext->port[vcontext->event_port_index];\r
269         event->element.port_num = vcontext->event_port_index + 1;\r
270 \r
271         if (port->event_flag & WV_EVENT_ERROR) {\r
272                 event->event_type = IBV_EVENT_DEVICE_FATAL;\r
273                 port->event_flag = 0;\r
274         } else if (port->event_flag & WV_EVENT_STATE) {\r
275                 event->event_type = ibv_get_port_event_state(vcontext);\r
276                 port->event_flag = 0;\r
277         } else if (port->event_flag & WV_EVENT_MANAGEMENT) {\r
278                 event->event_type = IBV_EVENT_SM_CHANGE;\r
279                 port->event_flag = 0;\r
280         } else if (port->event_flag & WV_EVENT_LINK_ADDRESS) {\r
281                 event->event_type = IBV_EVENT_LID_CHANGE;\r
282                 port->event_flag &= ~WV_EVENT_LINK_ADDRESS;\r
283         } else if (port->event_flag & WV_EVENT_PARTITION) {\r
284                 event->event_type = IBV_EVENT_PKEY_CHANGE;\r
285                 port->event_flag &= ~WV_EVENT_PARTITION;\r
286         } else {\r
287                 port->event_flag = 0;\r
288                 ret = -1;\r
289         }\r
290         \r
291         if (port->event_flag == 0) {\r
292                 vcontext->context.cmd_if->Notify(vcontext->event_port_index + 1,\r
293                                                                                  &port->overlap, &port->event_flag);\r
294                 vcontext->event_port_index = EVENT_PORT_NONE;\r
295         }\r
296         return ret;\r
297 }\r
298 \r
299 __declspec(dllexport)\r
300 int ibv_get_async_event(struct ibv_context *context,\r
301                                                 struct ibv_async_event *event)\r
302 {\r
303         struct verbs_context *vcontext;\r
304         HRESULT hr;\r
305         int i;\r
306 \r
307         vcontext = CONTAINING_RECORD(context, struct verbs_context, context);\r
308         if (vcontext->event_port_index != EVENT_PORT_NONE) {\r
309                 if (ibv_report_port_event(vcontext, event) == 0) {\r
310                         return 0;\r
311                 }\r
312         }\r
313 \r
314         hr = WaitForMultipleObjects(vcontext->device.phys_port_cnt,\r
315                                                                 vcontext->event, FALSE, context->timeout);\r
316         if (hr == WAIT_TIMEOUT) {\r
317                 return hr;\r
318         } else if (hr == WAIT_FAILED) {\r
319                 return HRESULT_FROM_WIN32(GetLastError());\r
320         }\r
321 \r
322         vcontext->event_port_index = (UINT8) hr;\r
323         return ibv_report_port_event(vcontext, event);\r
324 }\r
325 \r
326 __declspec(dllexport)\r
327 void ibv_ack_async_event(struct ibv_async_event *event)\r
328 {\r
329         // Only device/port level events are currently supported\r
330         // nothing to do here at the moment\r
331 }\r