blob: ac58e5b21df8b768942ce4fb54f687f6d9e89b70 [file] [log] [blame]
/*
* Copyright (C) 2008-2013 Emulex. All rights reserved.
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/mman.h>
#include <pthread.h>
#include "ocrdma_main.h"
#include "ocrdma_abi.h"
#include <ccan/list.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
static void ocrdma_free_context(struct ibv_context *ibctx);
#define PCI_VENDOR_ID_EMULEX 0x10DF
#define PCI_DEVICE_ID_EMULEX_GEN1 0xe220
#define PCI_DEVICE_ID_EMULEX_GEN2 0x720
#define PCI_DEVICE_ID_EMULEX_GEN2_VF 0x728
#define UCNA(v, d) \
VERBS_PCI_MATCH(PCI_VENDOR_ID_##v, PCI_DEVICE_ID_EMULEX_##d, NULL)
static const struct verbs_match_ent ucna_table[] = {
VERBS_DRIVER_ID(RDMA_DRIVER_OCRDMA),
UCNA(EMULEX, GEN1),
UCNA(EMULEX, GEN2),
UCNA(EMULEX, GEN2_VF),
{}
};
static const struct verbs_context_ops ocrdma_ctx_ops = {
.query_device_ex = ocrdma_query_device,
.query_port = ocrdma_query_port,
.alloc_pd = ocrdma_alloc_pd,
.dealloc_pd = ocrdma_free_pd,
.reg_mr = ocrdma_reg_mr,
.dereg_mr = ocrdma_dereg_mr,
.create_cq = ocrdma_create_cq,
.poll_cq = ocrdma_poll_cq,
.req_notify_cq = ocrdma_arm_cq,
.resize_cq = ocrdma_resize_cq,
.destroy_cq = ocrdma_destroy_cq,
.create_qp = ocrdma_create_qp,
.query_qp = ocrdma_query_qp,
.modify_qp = ocrdma_modify_qp,
.destroy_qp = ocrdma_destroy_qp,
.post_send = ocrdma_post_send,
.post_recv = ocrdma_post_recv,
.create_ah = ocrdma_create_ah,
.destroy_ah = ocrdma_destroy_ah,
.create_srq = ocrdma_create_srq,
.modify_srq = ocrdma_modify_srq,
.query_srq = ocrdma_query_srq,
.destroy_srq = ocrdma_destroy_srq,
.post_srq_recv = ocrdma_post_srq_recv,
.attach_mcast = ocrdma_attach_mcast,
.detach_mcast = ocrdma_detach_mcast,
.free_context = ocrdma_free_context,
};
static void ocrdma_uninit_device(struct verbs_device *verbs_device)
{
struct ocrdma_device *dev = get_ocrdma_dev(&verbs_device->device);
free(dev);
}
/*
* ocrdma_alloc_context
*/
static struct verbs_context *ocrdma_alloc_context(struct ibv_device *ibdev,
int cmd_fd,
void *private_data)
{
struct ocrdma_devctx *ctx;
struct uocrdma_get_context cmd;
struct uocrdma_get_context_resp resp = {};
ctx = verbs_init_and_alloc_context(ibdev, cmd_fd, ctx, ibv_ctx,
RDMA_DRIVER_OCRDMA);
if (!ctx)
return NULL;
if (ibv_cmd_get_context(&ctx->ibv_ctx,
(struct ibv_get_context *)&cmd, sizeof cmd,
&resp.ibv_resp, sizeof(resp)))
goto cmd_err;
verbs_set_ops(&ctx->ibv_ctx, &ocrdma_ctx_ops);
get_ocrdma_dev(ibdev)->id = resp.dev_id;
get_ocrdma_dev(ibdev)->max_inline_data = resp.max_inline_data;
get_ocrdma_dev(ibdev)->wqe_size = resp.wqe_size;
get_ocrdma_dev(ibdev)->rqe_size = resp.rqe_size;
memcpy(get_ocrdma_dev(ibdev)->fw_ver, resp.fw_ver, sizeof(resp.fw_ver));
get_ocrdma_dev(ibdev)->dpp_wqe_size = resp.dpp_wqe_size;
ctx->ah_tbl =
mmap(NULL, resp.ah_tbl_len, PROT_READ | PROT_WRITE, MAP_SHARED,
cmd_fd, resp.ah_tbl_page);
if (ctx->ah_tbl == MAP_FAILED)
goto cmd_err;
ctx->ah_tbl_len = resp.ah_tbl_len;
ocrdma_init_ahid_tbl(ctx);
return &ctx->ibv_ctx;
cmd_err:
ocrdma_err("%s: Failed to allocate context for device.\n", __func__);
verbs_uninit_context(&ctx->ibv_ctx);
free(ctx);
return NULL;
}
/*
* ocrdma_free_context
*/
static void ocrdma_free_context(struct ibv_context *ibctx)
{
struct ocrdma_devctx *ctx = get_ocrdma_ctx(ibctx);
if (ctx->ah_tbl)
munmap((void *)ctx->ah_tbl, ctx->ah_tbl_len);
verbs_uninit_context(&ctx->ibv_ctx);
free(ctx);
}
static struct verbs_device *
ocrdma_device_alloc(struct verbs_sysfs_dev *sysfs_dev)
{
struct ocrdma_device *dev;
dev = calloc(1, sizeof(*dev));
if (!dev)
return NULL;
dev->qp_tbl = malloc(OCRDMA_MAX_QP * sizeof(struct ocrdma_qp *));
if (!dev->qp_tbl)
goto qp_err;
bzero(dev->qp_tbl, OCRDMA_MAX_QP * sizeof(struct ocrdma_qp *));
pthread_mutex_init(&dev->dev_lock, NULL);
pthread_spin_init(&dev->flush_q_lock, PTHREAD_PROCESS_PRIVATE);
return &dev->ibv_dev;
qp_err:
free(dev);
return NULL;
}
static const struct verbs_device_ops ocrdma_dev_ops = {
.name = "ocrdma",
.match_min_abi_version = OCRDMA_ABI_VERSION,
.match_max_abi_version = OCRDMA_ABI_VERSION,
.match_table = ucna_table,
.alloc_device = ocrdma_device_alloc,
.uninit_device = ocrdma_uninit_device,
.alloc_context = ocrdma_alloc_context,
};
PROVIDER_DRIVER(ocrdma, ocrdma_dev_ops);