mthca/mlx4: add check to validate output data sizes
[mirror/winof/.git] / hw / mlx4 / kernel / hca / qp.c
1 /*\r
2  * Copyright (c) 2005 SilverStorm Technologies.  All rights reserved.\r
3  * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. \r
4  * Portions Copyright (c) 2008 Microsoft Corporation.  All rights reserved.\r
5  *\r
6  * This software is available to you under the OpenIB.org BSD license\r
7  * below:\r
8  *\r
9  *     Redistribution and use in source and binary forms, with or\r
10  *     without modification, are permitted provided that the following\r
11  *     conditions are met:\r
12  *\r
13  *      - Redistributions of source code must retain the above\r
14  *        copyright notice, this list of conditions and the following\r
15  *        disclaimer.\r
16  *\r
17  *      - Redistributions in binary form must reproduce the above\r
18  *        copyright notice, this list of conditions and the following\r
19  *        disclaimer in the documentation and/or other materials\r
20  *        provided with the distribution.\r
21  *\r
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
23  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
24  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
25  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
26  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
27  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
28  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
29  * SOFTWARE.\r
30  *\r
31  * $Id: al.c 1611 2006-08-20 14:48:55Z sleybo $\r
32  */\r
33 \r
34 #include "precomp.h"\r
35 \r
36 #if defined(EVENT_TRACING)\r
37 #ifdef offsetof\r
38 #undef offsetof\r
39 #endif\r
40 #include "qp.tmh"\r
41 #endif\r
42 \r
43 \r
44 ib_api_status_t\r
45 mlnx_query_qp (\r
46         IN              const   ib_qp_handle_t                          h_qp,\r
47                 OUT                     ib_qp_attr_t                            *p_qp_attr,\r
48         IN      OUT                     ci_umv_buf_t                            *p_umv_buf )\r
49 {\r
50         ib_api_status_t         status;\r
51         struct ib_qp *p_ib_qp = (struct ib_qp *)h_qp;\r
52         struct ib_qp_attr qp_attr;\r
53         struct ib_qp_init_attr qp_init_attr;\r
54         int qp_attr_mask = 0;\r
55         int err;\r
56 \r
57         UNREFERENCED_PARAMETER(p_umv_buf);\r
58         \r
59         HCA_ENTER( HCA_DBG_QP);\r
60 \r
61         // sanity checks\r
62         if (!p_qp_attr) {\r
63                 status =  IB_INVALID_PARAMETER;\r
64                 goto err_parm;\r
65         }\r
66 \r
67         // convert structures\r
68         memset( &qp_attr, 0, sizeof(struct ib_qp_attr) );\r
69         err = p_ib_qp->device->query_qp( p_ib_qp, &qp_attr, \r
70                 qp_attr_mask, &qp_init_attr);\r
71         if (err){\r
72                 status = errno_to_iberr(err);\r
73                 HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_PD,\r
74                         ("ib_query_qp failed (%#x)\n", status));\r
75                 goto err_query_qp;\r
76         }\r
77 \r
78         status = from_qp_attr( p_ib_qp, &qp_attr, p_qp_attr );\r
79 \r
80 err_query_qp:\r
81 err_parm:\r
82         HCA_EXIT(HCA_DBG_QP);\r
83         return status;\r
84 }\r
85 \r
86 static ib_api_status_t\r
87 __create_qp (\r
88         IN              const   ib_pd_handle_t                          h_pd,\r
89         IN              const   uint8_t                                         port_num,\r
90         IN              const   void                                            *qp_uctx,\r
91         IN                              ci_async_event_cb_t                     event_handler,\r
92         IN              const   ib_qp_create_t                          *p_create_attr,\r
93                 OUT                     ib_qp_attr_t                            *p_qp_attr,\r
94                 OUT                     ib_qp_handle_t                          *ph_qp,\r
95         IN      OUT                     ci_umv_buf_t                            *p_umv_buf )\r
96 {\r
97         int err;\r
98         ib_api_status_t         status;\r
99         struct ib_qp * p_ib_qp;\r
100         struct ib_qp_init_attr qp_init_attr;\r
101         struct ib_ucontext *p_uctx = NULL;\r
102         struct ib_pd *p_ib_pd = (struct ib_pd *)h_pd;\r
103         struct ibv_create_qp *p_req = NULL;\r
104         \r
105         HCA_ENTER(HCA_DBG_QP);\r
106 \r
107         if( p_umv_buf && p_umv_buf->command ) {\r
108                 // sanity checks \r
109                 if (p_umv_buf->input_size < sizeof(struct ibv_create_qp) ||\r
110                         p_umv_buf->output_size < sizeof(struct ibv_create_qp_resp) ||\r
111                         !p_umv_buf->p_inout_buf) {\r
112                         status = IB_INVALID_PARAMETER;\r
113                         goto err_inval_params;\r
114                 }\r
115                 p_req = (struct ibv_create_qp*)(ULONG_PTR)p_umv_buf->p_inout_buf;\r
116                 p_uctx = p_ib_pd->p_uctx;\r
117         }\r
118 \r
119         // prepare the parameters\r
120         RtlZeroMemory(&qp_init_attr, sizeof(qp_init_attr));\r
121         qp_init_attr.event_handler = event_handler;\r
122         qp_init_attr.qp_context = (void*)qp_uctx;\r
123         qp_init_attr.send_cq = (struct ib_cq *)p_create_attr->h_sq_cq;\r
124         qp_init_attr.recv_cq = (struct ib_cq *)p_create_attr->h_rq_cq;\r
125         qp_init_attr.srq = (struct ib_srq *)p_create_attr->h_srq;\r
126         if( p_umv_buf && p_umv_buf->command ) {\r
127                 qp_init_attr.cap.max_recv_sge = p_req->max_recv_sge;\r
128                 qp_init_attr.cap.max_send_sge = p_req->max_send_sge;\r
129                 qp_init_attr.cap.max_recv_wr = p_req->max_recv_wr;\r
130                 qp_init_attr.cap.max_send_wr = p_req->max_send_wr;\r
131                 qp_init_attr.cap.max_inline_data = p_req->max_inline_data;\r
132         }\r
133         else {\r
134                 qp_init_attr.cap.max_recv_sge = p_create_attr->rq_sge;\r
135                 qp_init_attr.cap.max_send_sge = p_create_attr->sq_sge;\r
136                 qp_init_attr.cap.max_recv_wr = p_create_attr->rq_depth;\r
137                 qp_init_attr.cap.max_send_wr = p_create_attr->sq_depth;\r
138                 qp_init_attr.cap.max_inline_data = 0;   /* absent in IBAL */\r
139         }\r
140         qp_init_attr.sq_sig_type = (p_create_attr->sq_signaled) ? IB_SIGNAL_ALL_WR : IB_SIGNAL_REQ_WR;\r
141         qp_init_attr.qp_type = to_qp_type(p_create_attr->qp_type);\r
142         qp_init_attr.port_num = port_num;\r
143         qp_init_attr.create_flags |= IB_QP_CREATE_IPOIB_UD_LSO;\r
144 \r
145         // create qp            \r
146         p_ib_qp = ibv_create_qp( p_ib_pd, &qp_init_attr, p_uctx, p_umv_buf );\r
147         if (IS_ERR(p_ib_qp)) {\r
148                 err = PTR_ERR(p_ib_qp);\r
149                 HCA_PRINT(TRACE_LEVEL_ERROR  , HCA_DBG_QP,\r
150                         ("ibv_create_qp failed (%d)\n", err));\r
151                 status = errno_to_iberr(err);\r
152                 goto err_create_qp;\r
153         }\r
154 \r
155         // Query QP to obtain requested attributes\r
156         if (p_qp_attr) {\r
157                 status = mlnx_query_qp((ib_qp_handle_t)p_ib_qp, p_qp_attr, p_umv_buf);\r
158                 if (status != IB_SUCCESS)\r
159                         goto err_query_qp;\r
160         }\r
161         \r
162         // return the results\r
163         if (ph_qp) *ph_qp = (ib_qp_handle_t)p_ib_qp;\r
164 \r
165         status = IB_SUCCESS;\r
166         goto end;\r
167 \r
168 err_query_qp:\r
169         ib_destroy_qp( p_ib_qp );\r
170 err_create_qp:\r
171 err_inval_params:\r
172 end:\r
173         if (p_umv_buf && p_umv_buf->command) \r
174                 p_umv_buf->status = status;\r
175         if (status != IB_SUCCESS)\r
176                 HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_QP,\r
177                         ("completes with ERROR status %x\n", status));\r
178         HCA_EXIT(HCA_DBG_QP);\r
179         return status;\r
180 }\r
181 \r
182 ib_api_status_t\r
183 mlnx_create_spl_qp (\r
184         IN              const   ib_pd_handle_t                          h_pd,\r
185         IN              const   uint8_t                                         port_num,\r
186         IN              const   void                                            *qp_uctx,\r
187         IN                              ci_async_event_cb_t                     event_handler,\r
188         IN              const   ib_qp_create_t                          *p_create_attr,\r
189                 OUT                     ib_qp_attr_t                            *p_qp_attr,\r
190                 OUT                     ib_qp_handle_t                          *ph_qp )\r
191 {\r
192         ib_api_status_t         status;\r
193 \r
194         HCA_ENTER(HCA_DBG_SHIM);\r
195 \r
196         status = __create_qp( h_pd, port_num,\r
197                 qp_uctx, event_handler, p_create_attr, p_qp_attr, ph_qp, NULL );\r
198                 \r
199         if (status != IB_SUCCESS)\r
200                 HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_QP,\r
201                         ("completes with ERROR status %x\n", status));\r
202         HCA_EXIT(HCA_DBG_QP);\r
203         return status;\r
204 }\r
205 \r
206 ib_api_status_t\r
207 mlnx_create_qp (\r
208         IN              const   ib_pd_handle_t                          h_pd,\r
209         IN              const   void                                            *qp_uctx,\r
210         IN                              ci_async_event_cb_t                     event_handler,\r
211         IN              const   ib_qp_create_t                          *p_create_attr,\r
212                 OUT                     ib_qp_attr_t                            *p_qp_attr,\r
213                 OUT                     ib_qp_handle_t                          *ph_qp,\r
214         IN      OUT                     ci_umv_buf_t                            *p_umv_buf )\r
215 {\r
216         ib_api_status_t         status;\r
217 \r
218         //NB: algorithm of mthca_alloc_sqp() requires port_num\r
219         // PRM states, that special pares are created in couples, so\r
220         // looks like we can put here port_num = 1 always\r
221         uint8_t port_num = 1;\r
222 \r
223         HCA_ENTER(HCA_DBG_QP);\r
224 \r
225         status = __create_qp( h_pd, port_num,\r
226                 qp_uctx, event_handler, p_create_attr, p_qp_attr, ph_qp, p_umv_buf );\r
227                 \r
228         if (status != IB_SUCCESS)\r
229                 HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_QP,\r
230                         ("completes with ERROR status %x\n", status));\r
231         HCA_EXIT(HCA_DBG_QP);\r
232         return status;\r
233 }\r
234 \r
235 ib_api_status_t\r
236 mlnx_modify_qp (\r
237         IN              const   ib_qp_handle_t                          h_qp,\r
238         IN              const   ib_qp_mod_t                                     *p_modify_attr,\r
239                 OUT                     ib_qp_attr_t                            *p_qp_attr OPTIONAL,\r
240         IN      OUT                     ci_umv_buf_t                            *p_umv_buf OPTIONAL )\r
241 {\r
242         int err;\r
243         ib_api_status_t         status;\r
244         struct ib_qp_attr qp_attr;\r
245         int qp_attr_mask;\r
246         struct ib_qp *p_ib_qp = (struct ib_qp *)h_qp;\r
247 \r
248         HCA_ENTER(HCA_DBG_QP);\r
249 \r
250         // sanity checks\r
251         if( p_umv_buf && p_umv_buf->command ) {\r
252                 // sanity checks \r
253                 if (p_umv_buf->output_size < sizeof(struct ibv_modify_qp_resp) ||\r
254                         !p_umv_buf->p_inout_buf) {\r
255                         status = IB_INVALID_PARAMETER;\r
256                         goto err_inval_params;\r
257                 }\r
258         }\r
259         \r
260         // fill parameters \r
261         status = to_qp_attr( p_ib_qp, from_qp_type(p_ib_qp->qp_type), \r
262                 p_modify_attr,  &qp_attr, &qp_attr_mask );\r
263         if (status == IB_NOT_DONE)\r
264                 goto query_qp;\r
265         if (status != IB_SUCCESS ) \r
266                 goto err_mode_unsupported;\r
267 \r
268         // modify QP\r
269         err = p_ib_qp->device->modify_qp( p_ib_qp, &qp_attr, qp_attr_mask, NULL);\r
270         if (err) {\r
271                 HCA_PRINT(TRACE_LEVEL_ERROR, HCA_DBG_QP,\r
272                         ("ibv_modify_qp failed (%d)\n", err));\r
273                 status = errno_to_iberr(err);\r
274                 goto err_modify_qp;\r
275         }\r
276 \r
277         // Query QP to obtain requested attributes\r
278 query_qp:       \r
279         if (p_qp_attr) {\r
280                 status = mlnx_query_qp ((ib_qp_handle_t)p_ib_qp, p_qp_attr, p_umv_buf);\r
281                 if (status != IB_SUCCESS)\r
282                                 goto err_query_qp;\r
283         }\r
284         \r
285         if( p_umv_buf && p_umv_buf->command ) {\r
286                 struct ibv_modify_qp_resp resp;\r
287                 resp.attr_mask = qp_attr_mask;\r
288                 resp.qp_state = qp_attr.qp_state;\r
289                 err = to_umv_buf(p_umv_buf, &resp, sizeof(struct ibv_modify_qp_resp));\r
290                 if (err) {\r
291                         HCA_PRINT(TRACE_LEVEL_ERROR  , HCA_DBG_SHIM  ,("to_umv_buf failed (%d)\n", err));\r
292                         status = errno_to_iberr(err);\r
293                         goto err_copy;\r
294                 }\r
295         }\r
296 \r
297         status = IB_SUCCESS;\r
298 \r
299 err_copy:       \r
300 err_query_qp:\r
301 err_modify_qp:  \r
302 err_mode_unsupported:\r
303 err_inval_params:\r
304         if (p_umv_buf && p_umv_buf->command) \r
305                 p_umv_buf->status = status;\r
306         if (status != IB_SUCCESS) {\r
307                 HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_QP,\r
308                         ("completes with ERROR status %x\n", status));\r
309         }\r
310         HCA_EXIT(HCA_DBG_QP);\r
311         return status;\r
312 }\r
313 \r
314 ib_api_status_t\r
315 mlnx_ndi_modify_qp (\r
316         IN              const   ib_qp_handle_t                          h_qp,\r
317         IN              const   ib_qp_mod_t                                     *p_modify_attr,\r
318                 OUT                     ib_qp_attr_t                            *p_qp_attr OPTIONAL,\r
319         IN              const   uint32_t                                        buf_size,\r
320         IN                              uint8_t* const                          p_outbuf)\r
321 {\r
322         ci_umv_buf_t umv_buf;\r
323         ib_api_status_t status;\r
324         struct ibv_modify_qp_resp resp;\r
325         void *buf = &resp;\r
326 \r
327         HCA_ENTER(HCA_DBG_QP);\r
328 \r
329         if (buf_size < sizeof(resp.qp_state)) {\r
330                 status = IB_INVALID_PARAMETER;\r
331                 goto out;\r
332         }\r
333 \r
334         /* imitate umv_buf */\r
335         umv_buf.command = TRUE; /* special case for NDI. Usually it's TRUE */\r
336         umv_buf.input_size = 0;\r
337         umv_buf.output_size = sizeof(struct ibv_modify_qp_resp);\r
338         umv_buf.p_inout_buf = (ULONG_PTR)buf;\r
339 \r
340         status = mlnx_modify_qp ( h_qp, p_modify_attr, p_qp_attr, &umv_buf );\r
341 \r
342         if (status == IB_SUCCESS) {\r
343                 cl_memclr( p_outbuf, buf_size );\r
344                 *p_outbuf = resp.qp_state;\r
345         }\r
346 \r
347 out:\r
348         HCA_EXIT(HCA_DBG_QP);\r
349         return status;\r
350 }\r
351 \r
352 ib_api_status_t\r
353 mlnx_destroy_qp (\r
354         IN              const   ib_qp_handle_t                          h_qp,\r
355         IN              const   uint64_t                                        timewait )\r
356 {\r
357         ib_api_status_t         status;\r
358         int err;\r
359         struct ib_qp *p_ib_qp = (struct ib_qp *)h_qp;\r
360 \r
361         UNUSED_PARAM( timewait );\r
362 \r
363         HCA_ENTER( HCA_DBG_QP);\r
364 \r
365         HCA_PRINT(TRACE_LEVEL_INFORMATION       ,HCA_DBG_SHIM  ,\r
366                 ("qpnum %#x, pcs %p\n", p_ib_qp->qp_num, PsGetCurrentProcess()) );\r
367 \r
368         err = ib_destroy_qp( p_ib_qp );\r
369         if (err) {\r
370                 HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_QP,\r
371                         ("ibv_destroy_qp failed (%d)\n", err));\r
372                 status = errno_to_iberr(err);\r
373                 goto err_destroy_qp;\r
374         }\r
375 \r
376         status = IB_SUCCESS;\r
377 \r
378 err_destroy_qp:\r
379         if (status != IB_SUCCESS)\r
380                 HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_QP,\r
381                         ("completes with ERROR status %x\n", status));\r
382         HCA_EXIT(HCA_DBG_QP);\r
383         return status;\r
384 }\r
385 \r
386 void\r
387 mlnx_qp_if(\r
388         IN      OUT                     ci_interface_t                          *p_interface )\r
389 {\r
390         p_interface->create_qp = mlnx_create_qp;\r
391         p_interface->create_spl_qp = mlnx_create_spl_qp;\r
392         p_interface->modify_qp = mlnx_modify_qp;\r
393         p_interface->ndi_modify_qp = mlnx_ndi_modify_qp;\r
394         p_interface->query_qp = mlnx_query_qp;\r
395         p_interface->destroy_qp = mlnx_destroy_qp;\r
396 }\r
397 \r