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