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