Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / drivers / infiniband / hw / usnic / usnic_ib_qp_grp.c
1 /*
2  * Copyright (c) 2013, Cisco Systems, Inc. All rights reserved.
3  *
4  * This program is free software; you may redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; version 2 of the License.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
9  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
10  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
11  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
12  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
13  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
15  * SOFTWARE.
16  *
17  */
18 #include <linux/bug.h>
19 #include <linux/errno.h>
20 #include <linux/module.h>
21 #include <linux/spinlock.h>
22
23 #include "usnic_log.h"
24 #include "usnic_vnic.h"
25 #include "usnic_fwd.h"
26 #include "usnic_uiom.h"
27 #include "usnic_debugfs.h"
28 #include "usnic_ib_qp_grp.h"
29 #include "usnic_ib_sysfs.h"
30 #include "usnic_transport.h"
31
32 #define DFLT_RQ_IDX     0
33
34 const char *usnic_ib_qp_grp_state_to_string(enum ib_qp_state state)
35 {
36         switch (state) {
37         case IB_QPS_RESET:
38                 return "Rst";
39         case IB_QPS_INIT:
40                 return "Init";
41         case IB_QPS_RTR:
42                 return "RTR";
43         case IB_QPS_RTS:
44                 return "RTS";
45         case IB_QPS_SQD:
46                 return "SQD";
47         case IB_QPS_SQE:
48                 return "SQE";
49         case IB_QPS_ERR:
50                 return "ERR";
51         default:
52                 return "UNKOWN STATE";
53
54         }
55 }
56
57 int usnic_ib_qp_grp_dump_hdr(char *buf, int buf_sz)
58 {
59         return scnprintf(buf, buf_sz, "|QPN\t|State\t|PID\t|VF Idx\t|Fil ID");
60 }
61
62 int usnic_ib_qp_grp_dump_rows(void *obj, char *buf, int buf_sz)
63 {
64         struct usnic_ib_qp_grp *qp_grp = obj;
65         struct usnic_ib_qp_grp_flow *default_flow;
66         if (obj) {
67                 default_flow = list_first_entry(&qp_grp->flows_lst,
68                                         struct usnic_ib_qp_grp_flow, link);
69                 return scnprintf(buf, buf_sz, "|%d\t|%s\t|%d\t|%hu\t|%d",
70                                         qp_grp->ibqp.qp_num,
71                                         usnic_ib_qp_grp_state_to_string(
72                                                         qp_grp->state),
73                                         qp_grp->owner_pid,
74                                         usnic_vnic_get_index(qp_grp->vf->vnic),
75                                         default_flow->flow->flow_id);
76         } else {
77                 return scnprintf(buf, buf_sz, "|N/A\t|N/A\t|N/A\t|N/A\t|N/A");
78         }
79 }
80
81 static struct usnic_vnic_res_chunk *
82 get_qp_res_chunk(struct usnic_ib_qp_grp *qp_grp)
83 {
84         lockdep_assert_held(&qp_grp->lock);
85         /*
86          * The QP res chunk, used to derive qp indices,
87          * are just indices of the RQs
88          */
89         return usnic_ib_qp_grp_get_chunk(qp_grp, USNIC_VNIC_RES_TYPE_RQ);
90 }
91
92 static int enable_qp_grp(struct usnic_ib_qp_grp *qp_grp)
93 {
94
95         int status;
96         int i, vnic_idx;
97         struct usnic_vnic_res_chunk *res_chunk;
98         struct usnic_vnic_res *res;
99
100         lockdep_assert_held(&qp_grp->lock);
101
102         vnic_idx = usnic_vnic_get_index(qp_grp->vf->vnic);
103
104         res_chunk = get_qp_res_chunk(qp_grp);
105         if (IS_ERR_OR_NULL(res_chunk)) {
106                 usnic_err("Unable to get qp res with err %ld\n",
107                                 PTR_ERR(res_chunk));
108                 return res_chunk ? PTR_ERR(res_chunk) : -ENOMEM;
109         }
110
111         for (i = 0; i < res_chunk->cnt; i++) {
112                 res = res_chunk->res[i];
113                 status = usnic_fwd_enable_qp(qp_grp->ufdev, vnic_idx,
114                                                 res->vnic_idx);
115                 if (status) {
116                         usnic_err("Failed to enable qp %d of %s:%d\n with err %d\n",
117                                         res->vnic_idx, qp_grp->ufdev->name,
118                                         vnic_idx, status);
119                         goto out_err;
120                 }
121         }
122
123         return 0;
124
125 out_err:
126         for (i--; i >= 0; i--) {
127                 res = res_chunk->res[i];
128                 usnic_fwd_disable_qp(qp_grp->ufdev, vnic_idx,
129                                         res->vnic_idx);
130         }
131
132         return status;
133 }
134
135 static int disable_qp_grp(struct usnic_ib_qp_grp *qp_grp)
136 {
137         int i, vnic_idx;
138         struct usnic_vnic_res_chunk *res_chunk;
139         struct usnic_vnic_res *res;
140         int status = 0;
141
142         lockdep_assert_held(&qp_grp->lock);
143         vnic_idx = usnic_vnic_get_index(qp_grp->vf->vnic);
144
145         res_chunk = get_qp_res_chunk(qp_grp);
146         if (IS_ERR_OR_NULL(res_chunk)) {
147                 usnic_err("Unable to get qp res with err %ld\n",
148                         PTR_ERR(res_chunk));
149                 return res_chunk ? PTR_ERR(res_chunk) : -ENOMEM;
150         }
151
152         for (i = 0; i < res_chunk->cnt; i++) {
153                 res = res_chunk->res[i];
154                 status = usnic_fwd_disable_qp(qp_grp->ufdev, vnic_idx,
155                                                 res->vnic_idx);
156                 if (status) {
157                         usnic_err("Failed to disable rq %d of %s:%d\n with err %d\n",
158                                         res->vnic_idx,
159                                         qp_grp->ufdev->name,
160                                         vnic_idx, status);
161                 }
162         }
163
164         return status;
165
166 }
167
168 static int init_filter_action(struct usnic_ib_qp_grp *qp_grp,
169                                 struct usnic_filter_action *uaction)
170 {
171         struct usnic_vnic_res_chunk *res_chunk;
172
173         res_chunk = usnic_ib_qp_grp_get_chunk(qp_grp, USNIC_VNIC_RES_TYPE_RQ);
174         if (IS_ERR_OR_NULL(res_chunk)) {
175                 usnic_err("Unable to get %s with err %ld\n",
176                         usnic_vnic_res_type_to_str(USNIC_VNIC_RES_TYPE_RQ),
177                         PTR_ERR(res_chunk));
178                 return res_chunk ? PTR_ERR(res_chunk) : -ENOMEM;
179         }
180
181         uaction->vnic_idx = usnic_vnic_get_index(qp_grp->vf->vnic);
182         uaction->action.type = FILTER_ACTION_RQ_STEERING;
183         uaction->action.u.rq_idx = res_chunk->res[DFLT_RQ_IDX]->vnic_idx;
184
185         return 0;
186 }
187
188 static struct usnic_ib_qp_grp_flow*
189 create_roce_custom_flow(struct usnic_ib_qp_grp *qp_grp,
190                         struct usnic_transport_spec *trans_spec)
191 {
192         uint16_t port_num;
193         int err;
194         struct filter filter;
195         struct usnic_filter_action uaction;
196         struct usnic_ib_qp_grp_flow *qp_flow;
197         struct usnic_fwd_flow *flow;
198         enum usnic_transport_type trans_type;
199
200         trans_type = trans_spec->trans_type;
201         port_num = trans_spec->usnic_roce.port_num;
202
203         /* Reserve Port */
204         port_num = usnic_transport_rsrv_port(trans_type, port_num);
205         if (port_num == 0)
206                 return ERR_PTR(-EINVAL);
207
208         /* Create Flow */
209         usnic_fwd_init_usnic_filter(&filter, port_num);
210         err = init_filter_action(qp_grp, &uaction);
211         if (err)
212                 goto out_unreserve_port;
213
214         flow = usnic_fwd_alloc_flow(qp_grp->ufdev, &filter, &uaction);
215         if (IS_ERR_OR_NULL(flow)) {
216                 usnic_err("Unable to alloc flow failed with err %ld\n",
217                                 PTR_ERR(flow));
218                 err = flow ? PTR_ERR(flow) : -EFAULT;
219                 goto out_unreserve_port;
220         }
221
222         /* Create Flow Handle */
223         qp_flow = kzalloc(sizeof(*qp_flow), GFP_ATOMIC);
224         if (IS_ERR_OR_NULL(qp_flow)) {
225                 err = qp_flow ? PTR_ERR(qp_flow) : -ENOMEM;
226                 goto out_dealloc_flow;
227         }
228         qp_flow->flow = flow;
229         qp_flow->trans_type = trans_type;
230         qp_flow->usnic_roce.port_num = port_num;
231         qp_flow->qp_grp = qp_grp;
232         return qp_flow;
233
234 out_dealloc_flow:
235         usnic_fwd_dealloc_flow(flow);
236 out_unreserve_port:
237         usnic_transport_unrsrv_port(trans_type, port_num);
238         return ERR_PTR(err);
239 }
240
241 static void release_roce_custom_flow(struct usnic_ib_qp_grp_flow *qp_flow)
242 {
243         usnic_fwd_dealloc_flow(qp_flow->flow);
244         usnic_transport_unrsrv_port(qp_flow->trans_type,
245                                         qp_flow->usnic_roce.port_num);
246         kfree(qp_flow);
247 }
248
249 static struct usnic_ib_qp_grp_flow*
250 create_udp_flow(struct usnic_ib_qp_grp *qp_grp,
251                 struct usnic_transport_spec *trans_spec)
252 {
253         struct socket *sock;
254         int sock_fd;
255         int err;
256         struct filter filter;
257         struct usnic_filter_action uaction;
258         struct usnic_ib_qp_grp_flow *qp_flow;
259         struct usnic_fwd_flow *flow;
260         enum usnic_transport_type trans_type;
261         uint32_t addr;
262         uint16_t port_num;
263         int proto;
264
265         trans_type = trans_spec->trans_type;
266         sock_fd = trans_spec->udp.sock_fd;
267
268         /* Get and check socket */
269         sock = usnic_transport_get_socket(sock_fd);
270         if (IS_ERR_OR_NULL(sock))
271                 return ERR_CAST(sock);
272
273         err = usnic_transport_sock_get_addr(sock, &proto, &addr, &port_num);
274         if (err)
275                 goto out_put_sock;
276
277         if (proto != IPPROTO_UDP) {
278                 usnic_err("Protocol for fd %d is not UDP", sock_fd);
279                 err = -EPERM;
280                 goto out_put_sock;
281         }
282
283         /* Create flow */
284         usnic_fwd_init_udp_filter(&filter, addr, port_num);
285         err = init_filter_action(qp_grp, &uaction);
286         if (err)
287                 goto out_put_sock;
288
289         flow = usnic_fwd_alloc_flow(qp_grp->ufdev, &filter, &uaction);
290         if (IS_ERR_OR_NULL(flow)) {
291                 usnic_err("Unable to alloc flow failed with err %ld\n",
292                                 PTR_ERR(flow));
293                 err = flow ? PTR_ERR(flow) : -EFAULT;
294                 goto out_put_sock;
295         }
296
297         /* Create qp_flow */
298         qp_flow = kzalloc(sizeof(*qp_flow), GFP_ATOMIC);
299         if (IS_ERR_OR_NULL(qp_flow)) {
300                 err = qp_flow ? PTR_ERR(qp_flow) : -ENOMEM;
301                 goto out_dealloc_flow;
302         }
303         qp_flow->flow = flow;
304         qp_flow->trans_type = trans_type;
305         qp_flow->udp.sock = sock;
306         qp_flow->qp_grp = qp_grp;
307         return qp_flow;
308
309 out_dealloc_flow:
310         usnic_fwd_dealloc_flow(flow);
311 out_put_sock:
312         usnic_transport_put_socket(sock);
313         return ERR_PTR(err);
314 }
315
316 static void release_udp_flow(struct usnic_ib_qp_grp_flow *qp_flow)
317 {
318         usnic_fwd_dealloc_flow(qp_flow->flow);
319         usnic_transport_put_socket(qp_flow->udp.sock);
320         kfree(qp_flow);
321 }
322
323 static struct usnic_ib_qp_grp_flow*
324 create_and_add_flow(struct usnic_ib_qp_grp *qp_grp,
325                         struct usnic_transport_spec *trans_spec)
326 {
327         struct usnic_ib_qp_grp_flow *qp_flow;
328         enum usnic_transport_type trans_type;
329
330         trans_type = trans_spec->trans_type;
331         switch (trans_type) {
332         case USNIC_TRANSPORT_ROCE_CUSTOM:
333                 qp_flow = create_roce_custom_flow(qp_grp, trans_spec);
334                 break;
335         case USNIC_TRANSPORT_IPV4_UDP:
336                 qp_flow = create_udp_flow(qp_grp, trans_spec);
337                 break;
338         default:
339                 usnic_err("Unsupported transport %u\n",
340                                 trans_spec->trans_type);
341                 return ERR_PTR(-EINVAL);
342         }
343
344         if (!IS_ERR_OR_NULL(qp_flow)) {
345                 list_add_tail(&qp_flow->link, &qp_grp->flows_lst);
346                 usnic_debugfs_flow_add(qp_flow);
347         }
348
349
350         return qp_flow;
351 }
352
353 static void release_and_remove_flow(struct usnic_ib_qp_grp_flow *qp_flow)
354 {
355         usnic_debugfs_flow_remove(qp_flow);
356         list_del(&qp_flow->link);
357
358         switch (qp_flow->trans_type) {
359         case USNIC_TRANSPORT_ROCE_CUSTOM:
360                 release_roce_custom_flow(qp_flow);
361                 break;
362         case USNIC_TRANSPORT_IPV4_UDP:
363                 release_udp_flow(qp_flow);
364                 break;
365         default:
366                 WARN(1, "Unsupported transport %u\n",
367                                 qp_flow->trans_type);
368                 break;
369         }
370 }
371
372 static void release_and_remove_all_flows(struct usnic_ib_qp_grp *qp_grp)
373 {
374         struct usnic_ib_qp_grp_flow *qp_flow, *tmp;
375         list_for_each_entry_safe(qp_flow, tmp, &qp_grp->flows_lst, link)
376                 release_and_remove_flow(qp_flow);
377 }
378
379 int usnic_ib_qp_grp_modify(struct usnic_ib_qp_grp *qp_grp,
380                                 enum ib_qp_state new_state,
381                                 void *data)
382 {
383         int status = 0;
384         int vnic_idx;
385         struct ib_event ib_event;
386         enum ib_qp_state old_state;
387         struct usnic_transport_spec *trans_spec;
388         struct usnic_ib_qp_grp_flow *qp_flow;
389
390         old_state = qp_grp->state;
391         vnic_idx = usnic_vnic_get_index(qp_grp->vf->vnic);
392         trans_spec = (struct usnic_transport_spec *) data;
393
394         spin_lock(&qp_grp->lock);
395         switch (new_state) {
396         case IB_QPS_RESET:
397                 switch (old_state) {
398                 case IB_QPS_RESET:
399                         /* NO-OP */
400                         break;
401                 case IB_QPS_INIT:
402                         release_and_remove_all_flows(qp_grp);
403                         status = 0;
404                         break;
405                 case IB_QPS_RTR:
406                 case IB_QPS_RTS:
407                 case IB_QPS_ERR:
408                         status = disable_qp_grp(qp_grp);
409                         release_and_remove_all_flows(qp_grp);
410                         break;
411                 default:
412                         status = -EINVAL;
413                 }
414                 break;
415         case IB_QPS_INIT:
416                 switch (old_state) {
417                 case IB_QPS_RESET:
418                         if (trans_spec) {
419                                 qp_flow = create_and_add_flow(qp_grp,
420                                                                 trans_spec);
421                                 if (IS_ERR_OR_NULL(qp_flow)) {
422                                         status = qp_flow ? PTR_ERR(qp_flow) : -EFAULT;
423                                         break;
424                                 }
425                         } else {
426                                 /*
427                                  * Optional to specify filters.
428                                  */
429                                 status = 0;
430                         }
431                         break;
432                 case IB_QPS_INIT:
433                         if (trans_spec) {
434                                 qp_flow = create_and_add_flow(qp_grp,
435                                                                 trans_spec);
436                                 if (IS_ERR_OR_NULL(qp_flow)) {
437                                         status = qp_flow ? PTR_ERR(qp_flow) : -EFAULT;
438                                         break;
439                                 }
440                         } else {
441                                 /*
442                                  * Doesn't make sense to go into INIT state
443                                  * from INIT state w/o adding filters.
444                                  */
445                                 status = -EINVAL;
446                         }
447                         break;
448                 case IB_QPS_RTR:
449                         status = disable_qp_grp(qp_grp);
450                         break;
451                 case IB_QPS_RTS:
452                         status = disable_qp_grp(qp_grp);
453                         break;
454                 default:
455                         status = -EINVAL;
456                 }
457                 break;
458         case IB_QPS_RTR:
459                 switch (old_state) {
460                 case IB_QPS_INIT:
461                         status = enable_qp_grp(qp_grp);
462                         break;
463                 default:
464                         status = -EINVAL;
465                 }
466                 break;
467         case IB_QPS_RTS:
468                 switch (old_state) {
469                 case IB_QPS_RTR:
470                         /* NO-OP FOR NOW */
471                         break;
472                 default:
473                         status = -EINVAL;
474                 }
475                 break;
476         case IB_QPS_ERR:
477                 ib_event.device = &qp_grp->vf->pf->ib_dev;
478                 ib_event.element.qp = &qp_grp->ibqp;
479                 ib_event.event = IB_EVENT_QP_FATAL;
480
481                 switch (old_state) {
482                 case IB_QPS_RESET:
483                         qp_grp->ibqp.event_handler(&ib_event,
484                                         qp_grp->ibqp.qp_context);
485                         break;
486                 case IB_QPS_INIT:
487                         release_and_remove_all_flows(qp_grp);
488                         qp_grp->ibqp.event_handler(&ib_event,
489                                         qp_grp->ibqp.qp_context);
490                         break;
491                 case IB_QPS_RTR:
492                 case IB_QPS_RTS:
493                         status = disable_qp_grp(qp_grp);
494                         release_and_remove_all_flows(qp_grp);
495                         qp_grp->ibqp.event_handler(&ib_event,
496                                         qp_grp->ibqp.qp_context);
497                         break;
498                 default:
499                         status = -EINVAL;
500                 }
501                 break;
502         default:
503                 status = -EINVAL;
504         }
505         spin_unlock(&qp_grp->lock);
506
507         if (!status) {
508                 qp_grp->state = new_state;
509                 usnic_info("Transistioned %u from %s to %s",
510                 qp_grp->grp_id,
511                 usnic_ib_qp_grp_state_to_string(old_state),
512                 usnic_ib_qp_grp_state_to_string(new_state));
513         } else {
514                 usnic_err("Failed to transition %u from %s to %s",
515                 qp_grp->grp_id,
516                 usnic_ib_qp_grp_state_to_string(old_state),
517                 usnic_ib_qp_grp_state_to_string(new_state));
518         }
519
520         return status;
521 }
522
523 static struct usnic_vnic_res_chunk**
524 alloc_res_chunk_list(struct usnic_vnic *vnic,
525                         struct usnic_vnic_res_spec *res_spec, void *owner_obj)
526 {
527         enum usnic_vnic_res_type res_type;
528         struct usnic_vnic_res_chunk **res_chunk_list;
529         int err, i, res_cnt, res_lst_sz;
530
531         for (res_lst_sz = 0;
532                 res_spec->resources[res_lst_sz].type != USNIC_VNIC_RES_TYPE_EOL;
533                 res_lst_sz++) {
534                 /* Do Nothing */
535         }
536
537         res_chunk_list = kzalloc(sizeof(*res_chunk_list)*(res_lst_sz+1),
538                                         GFP_ATOMIC);
539         if (!res_chunk_list)
540                 return ERR_PTR(-ENOMEM);
541
542         for (i = 0; res_spec->resources[i].type != USNIC_VNIC_RES_TYPE_EOL;
543                 i++) {
544                 res_type = res_spec->resources[i].type;
545                 res_cnt = res_spec->resources[i].cnt;
546
547                 res_chunk_list[i] = usnic_vnic_get_resources(vnic, res_type,
548                                         res_cnt, owner_obj);
549                 if (IS_ERR_OR_NULL(res_chunk_list[i])) {
550                         err = res_chunk_list[i] ?
551                                         PTR_ERR(res_chunk_list[i]) : -ENOMEM;
552                         usnic_err("Failed to get %s from %s with err %d\n",
553                                 usnic_vnic_res_type_to_str(res_type),
554                                 usnic_vnic_pci_name(vnic),
555                                 err);
556                         goto out_free_res;
557                 }
558         }
559
560         return res_chunk_list;
561
562 out_free_res:
563         for (i--; i > 0; i--)
564                 usnic_vnic_put_resources(res_chunk_list[i]);
565         kfree(res_chunk_list);
566         return ERR_PTR(err);
567 }
568
569 static void free_qp_grp_res(struct usnic_vnic_res_chunk **res_chunk_list)
570 {
571         int i;
572         for (i = 0; res_chunk_list[i]; i++)
573                 usnic_vnic_put_resources(res_chunk_list[i]);
574         kfree(res_chunk_list);
575 }
576
577 static int qp_grp_and_vf_bind(struct usnic_ib_vf *vf,
578                                 struct usnic_ib_pd *pd,
579                                 struct usnic_ib_qp_grp *qp_grp)
580 {
581         int err;
582         struct pci_dev *pdev;
583
584         lockdep_assert_held(&vf->lock);
585
586         pdev = usnic_vnic_get_pdev(vf->vnic);
587         if (vf->qp_grp_ref_cnt == 0) {
588                 err = usnic_uiom_attach_dev_to_pd(pd->umem_pd, &pdev->dev);
589                 if (err) {
590                         usnic_err("Failed to attach %s to domain\n",
591                                         pci_name(pdev));
592                         return err;
593                 }
594                 vf->pd = pd;
595         }
596         vf->qp_grp_ref_cnt++;
597
598         WARN_ON(vf->pd != pd);
599         qp_grp->vf = vf;
600
601         return 0;
602 }
603
604 static void qp_grp_and_vf_unbind(struct usnic_ib_qp_grp *qp_grp)
605 {
606         struct pci_dev *pdev;
607         struct usnic_ib_pd *pd;
608
609         lockdep_assert_held(&qp_grp->vf->lock);
610
611         pd = qp_grp->vf->pd;
612         pdev = usnic_vnic_get_pdev(qp_grp->vf->vnic);
613         if (--qp_grp->vf->qp_grp_ref_cnt == 0) {
614                 qp_grp->vf->pd = NULL;
615                 usnic_uiom_detach_dev_from_pd(pd->umem_pd, &pdev->dev);
616         }
617         qp_grp->vf = NULL;
618 }
619
620 static void log_spec(struct usnic_vnic_res_spec *res_spec)
621 {
622         char buf[512];
623         usnic_vnic_spec_dump(buf, sizeof(buf), res_spec);
624         usnic_dbg("%s\n", buf);
625 }
626
627 static int qp_grp_id_from_flow(struct usnic_ib_qp_grp_flow *qp_flow,
628                                 uint32_t *id)
629 {
630         enum usnic_transport_type trans_type = qp_flow->trans_type;
631         int err;
632         uint16_t port_num = 0;
633
634         switch (trans_type) {
635         case USNIC_TRANSPORT_ROCE_CUSTOM:
636                 *id = qp_flow->usnic_roce.port_num;
637                 break;
638         case USNIC_TRANSPORT_IPV4_UDP:
639                 err = usnic_transport_sock_get_addr(qp_flow->udp.sock,
640                                                         NULL, NULL,
641                                                         &port_num);
642                 if (err)
643                         return err;
644                 /*
645                  * Copy port_num to stack first and then to *id,
646                  * so that the short to int cast works for little
647                  * and big endian systems.
648                  */
649                 *id = port_num;
650                 break;
651         default:
652                 usnic_err("Unsupported transport %u\n", trans_type);
653                 return -EINVAL;
654         }
655
656         return 0;
657 }
658
659 struct usnic_ib_qp_grp *
660 usnic_ib_qp_grp_create(struct usnic_fwd_dev *ufdev, struct usnic_ib_vf *vf,
661                         struct usnic_ib_pd *pd,
662                         struct usnic_vnic_res_spec *res_spec,
663                         struct usnic_transport_spec *transport_spec)
664 {
665         struct usnic_ib_qp_grp *qp_grp;
666         int err;
667         enum usnic_transport_type transport = transport_spec->trans_type;
668         struct usnic_ib_qp_grp_flow *qp_flow;
669
670         lockdep_assert_held(&vf->lock);
671
672         err = usnic_vnic_res_spec_satisfied(&min_transport_spec[transport],
673                                                 res_spec);
674         if (err) {
675                 usnic_err("Spec does not meet miniumum req for transport %d\n",
676                                 transport);
677                 log_spec(res_spec);
678                 return ERR_PTR(err);
679         }
680
681         qp_grp = kzalloc(sizeof(*qp_grp), GFP_ATOMIC);
682         if (!qp_grp) {
683                 usnic_err("Unable to alloc qp_grp - Out of memory\n");
684                 return NULL;
685         }
686
687         qp_grp->res_chunk_list = alloc_res_chunk_list(vf->vnic, res_spec,
688                                                         qp_grp);
689         if (IS_ERR_OR_NULL(qp_grp->res_chunk_list)) {
690                 err = qp_grp->res_chunk_list ?
691                                 PTR_ERR(qp_grp->res_chunk_list) : -ENOMEM;
692                 usnic_err("Unable to alloc res for %d with err %d\n",
693                                 qp_grp->grp_id, err);
694                 goto out_free_qp_grp;
695         }
696
697         err = qp_grp_and_vf_bind(vf, pd, qp_grp);
698         if (err)
699                 goto out_free_res;
700
701         INIT_LIST_HEAD(&qp_grp->flows_lst);
702         spin_lock_init(&qp_grp->lock);
703         qp_grp->ufdev = ufdev;
704         qp_grp->state = IB_QPS_RESET;
705         qp_grp->owner_pid = current->pid;
706
707         qp_flow = create_and_add_flow(qp_grp, transport_spec);
708         if (IS_ERR_OR_NULL(qp_flow)) {
709                 usnic_err("Unable to create and add flow with err %ld\n",
710                                 PTR_ERR(qp_flow));
711                 err = qp_flow ? PTR_ERR(qp_flow) : -EFAULT;
712                 goto out_qp_grp_vf_unbind;
713         }
714
715         err = qp_grp_id_from_flow(qp_flow, &qp_grp->grp_id);
716         if (err)
717                 goto out_release_flow;
718         qp_grp->ibqp.qp_num = qp_grp->grp_id;
719
720         usnic_ib_sysfs_qpn_add(qp_grp);
721
722         return qp_grp;
723
724 out_release_flow:
725         release_and_remove_flow(qp_flow);
726 out_qp_grp_vf_unbind:
727         qp_grp_and_vf_unbind(qp_grp);
728 out_free_res:
729         free_qp_grp_res(qp_grp->res_chunk_list);
730 out_free_qp_grp:
731         kfree(qp_grp);
732
733         return ERR_PTR(err);
734 }
735
736 void usnic_ib_qp_grp_destroy(struct usnic_ib_qp_grp *qp_grp)
737 {
738
739         WARN_ON(qp_grp->state != IB_QPS_RESET);
740         lockdep_assert_held(&qp_grp->vf->lock);
741
742         release_and_remove_all_flows(qp_grp);
743         usnic_ib_sysfs_qpn_remove(qp_grp);
744         qp_grp_and_vf_unbind(qp_grp);
745         free_qp_grp_res(qp_grp->res_chunk_list);
746         kfree(qp_grp);
747 }
748
749 struct usnic_vnic_res_chunk*
750 usnic_ib_qp_grp_get_chunk(struct usnic_ib_qp_grp *qp_grp,
751                                 enum usnic_vnic_res_type res_type)
752 {
753         int i;
754
755         for (i = 0; qp_grp->res_chunk_list[i]; i++) {
756                 if (qp_grp->res_chunk_list[i]->type == res_type)
757                         return qp_grp->res_chunk_list[i];
758         }
759
760         return ERR_PTR(-EINVAL);
761 }