netdirect: add winverbs ND provider
[mirror/winof/.git] / ulp / netdirect / user / nd_adapter.cpp
1 /*\r
2  * Copyright (c) 2009 Intel Corporation. All rights reserved.\r
3  *\r
4  * This software is available to you under the OpenIB.org BSD license\r
5  * below:\r
6  *\r
7  *     Redistribution and use in source and binary forms, with or\r
8  *     without modification, are permitted provided that the following\r
9  *     conditions are met:\r
10  *\r
11  *      - Redistributions of source code must retain the above\r
12  *        copyright notice, this list of conditions and the following\r
13  *        disclaimer.\r
14  *\r
15  *      - Redistributions in binary form must reproduce the above\r
16  *        copyright notice, this list of conditions and the following\r
17  *        disclaimer in the documentation and/or other materials\r
18  *        provided with the distribution.\r
19  *\r
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
21  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
22  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
23  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
24  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
25  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
26  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
27  * SOFTWARE.\r
28  */\r
29 \r
30 #include "nd_adapter.h"\r
31 #include "nd_cq.h"\r
32 #include "nd_listen.h"\r
33 #include "nd_connect.h"\r
34 #include "nd_mw.h"\r
35 #include "nd_ep.h"\r
36 \r
37 \r
38 CNDAdapter::CNDAdapter(CNDProvider *pProvider)\r
39 {\r
40         pProvider->AddRef();\r
41         m_pProvider = pProvider;\r
42         m_pWvProvider = NULL;\r
43         m_pWvDevice = NULL;\r
44         m_pWvPd = NULL;\r
45         DListInit(&m_MrList);\r
46         InitializeCriticalSection(&m_Lock);\r
47 }\r
48 \r
49 STDMETHODIMP CNDAdapter::\r
50 Init(const struct sockaddr *pAddress, SIZE_T AddressLength)\r
51 {\r
52         HRESULT hr;\r
53 \r
54         hr = WvGetObject(IID_IWVProvider, (LPVOID *) &m_pWvProvider);\r
55         if (FAILED(hr)) {\r
56                 return hr;\r
57         }\r
58 \r
59         hr = m_pWvProvider->TranslateAddress(pAddress, &m_DevAddress);\r
60         if (FAILED(hr)) {\r
61                 return hr;\r
62         }\r
63 \r
64         hr = m_pWvProvider->OpenDevice(m_DevAddress.DeviceGuid, &m_pWvDevice);\r
65         if (FAILED(hr)) {\r
66                 return hr;\r
67         }\r
68 \r
69         hr = m_pWvDevice->AllocateProtectionDomain(&m_pWvPd);\r
70         if (FAILED(hr)) {\r
71                 return hr;\r
72         }\r
73 \r
74         RtlCopyMemory(&m_Address, pAddress, AddressLength);\r
75         return ND_SUCCESS;\r
76 }\r
77 \r
78 CNDAdapter::~CNDAdapter(void)\r
79 {\r
80         ND_MR   *mr;\r
81 \r
82         while (!DListEmpty(&m_MrList)) {\r
83                 mr = CONTAINING_RECORD(m_MrList.Next, ND_MR, Entry);\r
84                 DListRemove(&mr->Entry);\r
85                 m_pWvPd->DeregisterMemory(mr->Keys.Lkey, NULL);\r
86                 delete mr;\r
87         }\r
88 \r
89         if (m_pWvPd != NULL) {\r
90                 m_pWvPd->Release();\r
91         }\r
92         if (m_pWvDevice != NULL) {\r
93                 m_pWvDevice->Release();\r
94         }\r
95         if (m_pWvProvider != NULL) {\r
96                 m_pWvProvider->Release();\r
97         }\r
98         m_pProvider->Release();\r
99 }\r
100 \r
101 STDMETHODIMP CNDAdapter::\r
102 QueryInterface(REFIID riid, LPVOID FAR* ppvObj)\r
103 {\r
104         if (riid != IID_IUnknown && riid != IID_INDAdapter) {\r
105                 *ppvObj = NULL;\r
106                 return E_NOINTERFACE;\r
107         }\r
108 \r
109         *ppvObj = this;\r
110         AddRef();\r
111         return ND_SUCCESS;\r
112 }\r
113 \r
114 STDMETHODIMP_(ULONG) CNDAdapter::\r
115 AddRef(void)\r
116 {\r
117         return CNDBase::AddRef();\r
118 }\r
119 \r
120 STDMETHODIMP_(ULONG) CNDAdapter::\r
121 Release(void)\r
122 {\r
123         return CNDBase::Release();\r
124 }\r
125 \r
126 STDMETHODIMP CNDAdapter::\r
127 CancelOverlappedRequests(void)\r
128 {\r
129         m_pWvPd->CancelOverlappedRequests();\r
130         return ND_SUCCESS;\r
131 }\r
132 \r
133 STDMETHODIMP CNDAdapter::\r
134 GetOverlappedResult(OVERLAPPED *pOverlapped,\r
135                                         SIZE_T *pNumberOfBytesTransferred, BOOL bWait)\r
136 {\r
137         DLIST_ENTRY *entry;\r
138         ND_MR *mr;\r
139         HRESULT hr;\r
140 \r
141         ::GetOverlappedResult(GetFileHandle(), pOverlapped,\r
142                                                   (LPDWORD) pNumberOfBytesTransferred, bWait);\r
143         hr = (HRESULT) pOverlapped->Internal;\r
144 \r
145         if (FAILED(hr)) {\r
146                 EnterCriticalSection(&m_Lock);\r
147                 for (entry = m_MrList.Next; entry != &m_MrList; entry = entry->Next) {\r
148                         mr = CONTAINING_RECORD(entry, ND_MR, Entry);\r
149                         if (mr->Context == pOverlapped) {\r
150                                 DListRemove(entry);\r
151                                 delete mr;\r
152                                 break;\r
153                         }\r
154                 }\r
155                 LeaveCriticalSection(&m_Lock);\r
156         }\r
157 \r
158         return hr;\r
159 }\r
160 \r
161 STDMETHODIMP_(HANDLE) CNDAdapter::\r
162 GetFileHandle(void)\r
163 {\r
164         return m_pWvProvider->GetFileHandle();\r
165 }\r
166 \r
167 STDMETHODIMP CNDAdapter::\r
168 Query(DWORD VersionRequested, ND_ADAPTER_INFO* pInfo, SIZE_T* pBufferSize)\r
169 {\r
170         WV_DEVICE_ATTRIBUTES attr;\r
171         HRESULT hr;\r
172 \r
173         if (VersionRequested != 1) {\r
174                 return ND_NOT_SUPPORTED;\r
175         }\r
176 \r
177         if (*pBufferSize < sizeof(ND_ADAPTER_INFO)) {\r
178                 hr = ND_BUFFER_OVERFLOW;\r
179                 goto out;\r
180         }\r
181 \r
182         hr = m_pWvDevice->Query(&attr);\r
183         if (FAILED(hr)) {\r
184                 goto out;\r
185         }\r
186 \r
187         pInfo->VendorId                                 = attr.VendorId;\r
188         pInfo->DeviceId                                 = attr.VendorPartId;\r
189         pInfo->MaxInboundSge                    = min(attr.MaxSge, ND_MAX_SGE);\r
190         pInfo->MaxInboundRequests               = attr.MaxQpWr;\r
191         pInfo->MaxInboundLength                 = 1 << 31;\r
192         pInfo->MaxOutboundSge                   = min(attr.MaxSge, ND_MAX_SGE);\r
193         pInfo->MaxOutboundRequests              = attr.MaxQpWr;\r
194         pInfo->MaxOutboundLength                = 1 << 31;\r
195         pInfo->MaxInlineData                    = attr.MaxInlineSend;\r
196         pInfo->MaxInboundReadLimit              = attr.MaxQpResponderResources;\r
197         pInfo->MaxOutboundReadLimit             = attr.MaxQpInitiatorDepth;\r
198         pInfo->MaxCqEntries                             = attr.MaxCqEntries;\r
199         pInfo->MaxRegistrationSize              = attr.MaxMrSize;\r
200         pInfo->MaxWindowSize                    = attr.MaxMrSize;\r
201         pInfo->LargeRequestThreshold    = 0;\r
202         pInfo->MaxCallerData                    = ND_PRIVATE_DATA_SIZE;\r
203         pInfo->MaxCalleeData                    = ND_PRIVATE_DATA_SIZE;\r
204 \r
205 out:\r
206         *pBufferSize = sizeof(ND_ADAPTER_INFO);\r
207         return hr;\r
208 }\r
209 \r
210 STDMETHODIMP CNDAdapter::\r
211 Control(DWORD IoControlCode, const void* pInBuffer, SIZE_T InBufferSize,\r
212                 void* pOutBuffer, SIZE_T OutBufferSize, SIZE_T* pBytesReturned,\r
213                 OVERLAPPED* pOverlapped)\r
214 {\r
215         return DeviceIoControl(GetFileHandle(), IoControlCode,\r
216                                                    (LPVOID) pInBuffer, (DWORD) InBufferSize,\r
217                                                    pOutBuffer, (DWORD) OutBufferSize,\r
218                                                    (LPDWORD) pBytesReturned, pOverlapped) ?\r
219                                                    ND_SUCCESS : HRESULT_FROM_WIN32(GetLastError());\r
220 }\r
221 \r
222 STDMETHODIMP CNDAdapter::\r
223 CreateCompletionQueue(SIZE_T nEntries, INDCompletionQueue** ppCq)\r
224 {\r
225         return CNDCompletionQueue::CreateInstance(this, nEntries, ppCq);\r
226 }\r
227 \r
228 STDMETHODIMP CNDAdapter::\r
229 RegisterMemory(const void* pBuffer, SIZE_T BufferSize,\r
230                            OVERLAPPED* pOverlapped, ND_MR_HANDLE* phMr)\r
231 {\r
232         ND_MR *mr;\r
233         HRESULT hr;\r
234         DWORD flags;\r
235 \r
236         mr = new ND_MR;\r
237         if (mr == NULL) {\r
238                 return ND_NO_MEMORY;\r
239         }\r
240 \r
241         mr->Context = pOverlapped;\r
242         EnterCriticalSection(&m_Lock);\r
243         DListInsertHead(&mr->Entry, &m_MrList);\r
244         LeaveCriticalSection(&m_Lock);\r
245 \r
246         // TODO: restrict access when MWs are implemented\r
247         flags = WV_ACCESS_REMOTE_READ | WV_ACCESS_REMOTE_WRITE |\r
248                         WV_ACCESS_REMOTE_ATOMIC | WV_ACCESS_LOCAL_WRITE | WV_ACCESS_MW_BIND;\r
249         hr = m_pWvPd->RegisterMemory(pBuffer, BufferSize, flags, pOverlapped, &mr->Keys);\r
250         if (FAILED(hr)) {\r
251                 CleanupMr(mr);\r
252         } else {\r
253                 *phMr = (ND_MR_HANDLE) mr;\r
254         }\r
255 \r
256         return hr;\r
257 }\r
258 \r
259 STDMETHODIMP CNDAdapter::\r
260 DeregisterMemory(ND_MR_HANDLE hMr, OVERLAPPED* pOverlapped)\r
261 {\r
262         ND_MR *mr;\r
263         HRESULT hr;\r
264 \r
265         mr = (ND_MR *) hMr;\r
266         hr = m_pWvPd->DeregisterMemory(mr->Keys.Lkey, pOverlapped);\r
267         if (SUCCEEDED(hr) || hr == WV_IO_PENDING) {\r
268                 CleanupMr(mr);\r
269         }\r
270         return hr;\r
271 }\r
272 \r
273 void CNDAdapter::\r
274 CleanupMr(ND_MR *pMr)\r
275 {\r
276         EnterCriticalSection(&m_Lock);\r
277         DListRemove(&pMr->Entry);\r
278         LeaveCriticalSection(&m_Lock);\r
279         delete pMr;\r
280 }\r
281 \r
282 STDMETHODIMP CNDAdapter::\r
283 CreateMemoryWindow(ND_RESULT* pInvalidateResult, INDMemoryWindow** ppMw)\r
284 {\r
285         // TODO: do something with pInvalidateResult\r
286         return CNDMemoryWindow::CreateInstance(this, ppMw);\r
287 }\r
288 \r
289 STDMETHODIMP CNDAdapter::\r
290 CreateConnector(INDConnector** ppConnector)\r
291 {\r
292         return CNDConnector::CreateInstance(this, ppConnector);\r
293 }\r
294 \r
295 STDMETHODIMP CNDAdapter::\r
296 Listen(SIZE_T Backlog, INT Protocol, USHORT Port,\r
297            USHORT* pAssignedPort, INDListen** ppListen)\r
298 {\r
299         return CNDListen::CreateInstance(this, Backlog, Protocol, Port,\r
300                                                                          pAssignedPort, ppListen);\r
301 }\r