linux/drivers/infiniband/hw/usnic/usnic_ib_qp_grp.c
<<
>>
Prefs
   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
  48const 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
  71int 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
  76int 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
  95static struct usnic_vnic_res_chunk *
  96get_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
 106static 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
 139out_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
 149static 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
 182static 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
 202static struct usnic_ib_qp_grp_flow*
 203create_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
 246out_dealloc_flow:
 247        usnic_fwd_dealloc_flow(flow);
 248out_unreserve_port:
 249        usnic_transport_unrsrv_port(trans_type, port_num);
 250        return ERR_PTR(err);
 251}
 252
 253static 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
 261static struct usnic_ib_qp_grp_flow*
 262create_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
 319out_dealloc_flow:
 320        usnic_fwd_dealloc_flow(flow);
 321out_put_sock:
 322        usnic_transport_put_socket(sock);
 323        return ERR_PTR(err);
 324}
 325
 326static 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
 333static struct usnic_ib_qp_grp_flow*
 334create_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
 363static 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
 382static 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
 389int 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
 531static struct usnic_vnic_res_chunk**
 532alloc_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
 570out_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
 577static 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
 585static 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
 612static 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
 628static 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
 635static 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
 667int 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
 722out_release_flow:
 723        release_and_remove_flow(qp_flow);
 724out_qp_grp_vf_unbind:
 725        qp_grp_and_vf_unbind(qp_grp);
 726out_free_res:
 727        free_qp_grp_res(qp_grp->res_chunk_list);
 728        return err;
 729}
 730
 731void 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
 743struct usnic_vnic_res_chunk*
 744usnic_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}
 756