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