winverbs: delete critical sections when no longer needed
[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 NDConvertWVStatus(hr);\r
57         }\r
58 \r
59         hr = m_pWvProvider->TranslateAddress(pAddress, &m_DevAddress);\r
60         if (FAILED(hr)) {\r
61                 return NDConvertWVStatus(hr);\r
62         }\r
63 \r
64         hr = m_pWvProvider->OpenDevice(m_DevAddress.DeviceGuid, &m_pWvDevice);\r
65         if (FAILED(hr)) {\r
66                 return NDConvertWVStatus(hr);\r
67         }\r
68 \r
69         hr = m_pWvDevice->AllocateProtectionDomain(&m_pWvPd);\r
70         if (FAILED(hr)) {\r
71                 return NDConvertWVStatus(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         DeleteCriticalSection(&m_Lock);\r
100 }\r
101 \r
102 STDMETHODIMP CNDAdapter::\r
103 QueryInterface(REFIID riid, LPVOID FAR* ppvObj)\r
104 {\r
105         if (riid != IID_IUnknown && riid != IID_INDAdapter) {\r
106                 *ppvObj = NULL;\r
107                 return E_NOINTERFACE;\r
108         }\r
109 \r
110         *ppvObj = this;\r
111         AddRef();\r
112         return ND_SUCCESS;\r
113 }\r
114 \r
115 STDMETHODIMP_(ULONG) CNDAdapter::\r
116 AddRef(void)\r
117 {\r
118         return CNDBase::AddRef();\r
119 }\r
120 \r
121 STDMETHODIMP_(ULONG) CNDAdapter::\r
122 Release(void)\r
123 {\r
124         return CNDBase::Release();\r
125 }\r
126 \r
127 STDMETHODIMP CNDAdapter::\r
128 CancelOverlappedRequests(void)\r
129 {\r
130         m_pWvPd->CancelOverlappedRequests();\r
131         return ND_SUCCESS;\r
132 }\r
133 \r
134 STDMETHODIMP CNDAdapter::\r
135 GetOverlappedResult(OVERLAPPED *pOverlapped,\r
136                                         SIZE_T *pNumberOfBytesTransferred, BOOL bWait)\r
137 {\r
138         DLIST_ENTRY *entry;\r
139         ND_MR *mr;\r
140         HRESULT hr;\r
141 \r
142         ::GetOverlappedResult(GetFileHandle(), pOverlapped,\r
143                                                   (LPDWORD) pNumberOfBytesTransferred, bWait);\r
144         hr = (HRESULT) pOverlapped->Internal;\r
145 \r
146         if (FAILED(hr)) {\r
147                 EnterCriticalSection(&m_Lock);\r
148                 for (entry = m_MrList.Next; entry != &m_MrList; entry = entry->Next) {\r
149                         mr = CONTAINING_RECORD(entry, ND_MR, Entry);\r
150                         if (mr->Context == pOverlapped) {\r
151                                 DListRemove(entry);\r
152                                 delete mr;\r
153                                 break;\r
154                         }\r
155                 }\r
156                 LeaveCriticalSection(&m_Lock);\r
157         }\r
158 \r
159         return NDConvertWVStatus(hr);\r
160 }\r
161 \r
162 STDMETHODIMP_(HANDLE) CNDAdapter::\r
163 GetFileHandle(void)\r
164 {\r
165         return m_pWvProvider->GetFileHandle();\r
166 }\r
167 \r
168 STDMETHODIMP CNDAdapter::\r
169 Query(DWORD VersionRequested, ND_ADAPTER_INFO* pInfo, SIZE_T* pBufferSize)\r
170 {\r
171         WV_DEVICE_ATTRIBUTES attr;\r
172         HRESULT hr;\r
173 \r
174         if (VersionRequested != 1) {\r
175                 return ND_NOT_SUPPORTED;\r
176         }\r
177 \r
178         if (*pBufferSize < sizeof(ND_ADAPTER_INFO)) {\r
179                 hr = ND_BUFFER_OVERFLOW;\r
180                 goto out;\r
181         }\r
182 \r
183         hr = m_pWvDevice->Query(&attr);\r
184         if (FAILED(hr)) {\r
185                 goto out;\r
186         }\r
187 \r
188         pInfo->VendorId                                 = attr.VendorId;\r
189         pInfo->DeviceId                                 = attr.VendorPartId;\r
190         pInfo->MaxInboundSge                    = min(attr.MaxSge, ND_MAX_SGE);\r
191         pInfo->MaxInboundRequests               = attr.MaxQpWr;\r
192         pInfo->MaxInboundLength                 = 1 << 31;\r
193         pInfo->MaxOutboundSge                   = min(attr.MaxSge, ND_MAX_SGE);\r
194         pInfo->MaxOutboundRequests              = attr.MaxQpWr;\r
195         pInfo->MaxOutboundLength                = 1 << 31;\r
196         pInfo->MaxInlineData                    = attr.MaxInlineSend;\r
197         pInfo->MaxInboundReadLimit              = attr.MaxQpResponderResources;\r
198         pInfo->MaxOutboundReadLimit             = attr.MaxQpInitiatorDepth;\r
199         pInfo->MaxCqEntries                             = attr.MaxCqEntries;\r
200         pInfo->MaxRegistrationSize              = attr.MaxMrSize;\r
201         pInfo->MaxWindowSize                    = attr.MaxMrSize;\r
202         pInfo->LargeRequestThreshold    = 0;\r
203         pInfo->MaxCallerData                    = ND_PRIVATE_DATA_SIZE;\r
204         pInfo->MaxCalleeData                    = ND_PRIVATE_DATA_SIZE;\r
205 \r
206 out:\r
207         *pBufferSize = sizeof(ND_ADAPTER_INFO);\r
208         return NDConvertWVStatus(hr);\r
209 }\r
210 \r
211 STDMETHODIMP CNDAdapter::\r
212 Control(DWORD IoControlCode, const void* pInBuffer, SIZE_T InBufferSize,\r
213                 void* pOutBuffer, SIZE_T OutBufferSize, SIZE_T* pBytesReturned,\r
214                 OVERLAPPED* pOverlapped)\r
215 {\r
216         return DeviceIoControl(GetFileHandle(), IoControlCode,\r
217                                                    (LPVOID) pInBuffer, (DWORD) InBufferSize,\r
218                                                    pOutBuffer, (DWORD) OutBufferSize,\r
219                                                    (LPDWORD) pBytesReturned, pOverlapped) ?\r
220                                                    ND_SUCCESS : HRESULT_FROM_WIN32(GetLastError());\r
221 }\r
222 \r
223 STDMETHODIMP CNDAdapter::\r
224 CreateCompletionQueue(SIZE_T nEntries, INDCompletionQueue** ppCq)\r
225 {\r
226         return CNDCompletionQueue::CreateInstance(this, nEntries, ppCq);\r
227 }\r
228 \r
229 STDMETHODIMP CNDAdapter::\r
230 RegisterMemory(const void* pBuffer, SIZE_T BufferSize,\r
231                            OVERLAPPED* pOverlapped, ND_MR_HANDLE* phMr)\r
232 {\r
233         ND_MR *mr;\r
234         HRESULT hr;\r
235         DWORD flags;\r
236 \r
237         mr = new ND_MR;\r
238         if (mr == NULL) {\r
239                 return ND_NO_MEMORY;\r
240         }\r
241 \r
242         mr->Context = pOverlapped;\r
243         EnterCriticalSection(&m_Lock);\r
244         DListInsertHead(&mr->Entry, &m_MrList);\r
245         LeaveCriticalSection(&m_Lock);\r
246 \r
247         // TODO: restrict access when MWs are implemented\r
248         flags = WV_ACCESS_REMOTE_READ | WV_ACCESS_REMOTE_WRITE |\r
249                         WV_ACCESS_REMOTE_ATOMIC | WV_ACCESS_LOCAL_WRITE | WV_ACCESS_MW_BIND;\r
250         hr = m_pWvPd->RegisterMemory(pBuffer, BufferSize, flags, pOverlapped, &mr->Keys);\r
251         if (SUCCEEDED(hr) || hr == WV_IO_PENDING) {\r
252                 *phMr = (ND_MR_HANDLE) mr;\r
253         } else {\r
254                 CleanupMr(mr);\r
255         }\r
256 \r
257         return NDConvertWVStatus(hr);\r
258 }\r
259 \r
260 STDMETHODIMP CNDAdapter::\r
261 DeregisterMemory(ND_MR_HANDLE hMr, OVERLAPPED* pOverlapped)\r
262 {\r
263         ND_MR *mr;\r
264         HRESULT hr;\r
265 \r
266         mr = (ND_MR *) hMr;\r
267         hr = m_pWvPd->DeregisterMemory(mr->Keys.Lkey, pOverlapped);\r
268         if (SUCCEEDED(hr) || hr == WV_IO_PENDING) {\r
269                 CleanupMr(mr);\r
270         }\r
271         return NDConvertWVStatus(hr);\r
272 }\r
273 \r
274 void CNDAdapter::\r
275 CleanupMr(ND_MR *pMr)\r
276 {\r
277         EnterCriticalSection(&m_Lock);\r
278         DListRemove(&pMr->Entry);\r
279         LeaveCriticalSection(&m_Lock);\r
280         delete pMr;\r
281 }\r
282 \r
283 STDMETHODIMP CNDAdapter::\r
284 CreateMemoryWindow(ND_RESULT* pInvalidateResult, INDMemoryWindow** ppMw)\r
285 {\r
286         // TODO: do something with pInvalidateResult\r
287         return CNDMemoryWindow::CreateInstance(this, ppMw);\r
288 }\r
289 \r
290 STDMETHODIMP CNDAdapter::\r
291 CreateConnector(INDConnector** ppConnector)\r
292 {\r
293         return CNDConnector::CreateInstance(this, ppConnector);\r
294 }\r
295 \r
296 STDMETHODIMP CNDAdapter::\r
297 Listen(SIZE_T Backlog, INT Protocol, USHORT Port,\r
298            USHORT* pAssignedPort, INDListen** ppListen)\r
299 {\r
300         return CNDListen::CreateInstance(this, Backlog, Protocol, Port,\r
301                                                                          pAssignedPort, ppListen);\r
302 }\r