new file mode 100644
@@ -0,0 +1,104 @@
+/*
+ * InfiniBand Transport Layer
+ *
+ * Copyright (c) 2014 - 2017 ProfitBricks GmbH. All rights reserved.
+ * Authors: Fabian Holler < mail@fholler.de>
+ * Jack Wang <jinpu.wang@profitbricks.com>
+ * Kleber Souza <kleber.souza@profitbricks.com>
+ * Danil Kipnis <danil.kipnis@profitbricks.com>
+ * Roman Pen <roman.penyaev@profitbricks.com>
+ * Milind Dumbare <Milind.dumbare@gmail.com>
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * 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 MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <rdma/ibtrs.h>
+
+u64 timediff_cur_ms(u64 cur_ms)
+{
+ struct timespec cur = CURRENT_TIME;
+ struct timespec ts = ns_to_timespec(cur_ms * NSEC_PER_MSEC);
+
+ if (timespec_compare(&cur, &ts) < 0)
+ return timespec_to_ms(&ts) - timespec_to_ms(&cur);
+ else
+ return timespec_to_ms(&cur) - timespec_to_ms(&ts);
+}
+
+/*
+ * ibtrs_malloc() - allocate kernel or virtual memory
+ * @size: size to be allocated
+ *
+ * The pointer returned must be freed with kvfree()
+ */
+void *ibtrs_malloc(size_t size)
+{
+ void *p;
+
+ p = kmalloc(size, (GFP_KERNEL | __GFP_REPEAT));
+ if (p)
+ return p;
+
+ /* try allocating virtual memory */
+ p = vmalloc(size);
+ if (p)
+ return p;
+
+ return NULL;
+}
+
+/*
+ * ibtrs_zalloc() - allocate kernel or virtual memory
+ * @size: size to be allocated
+ *
+ * The pointer returned must be freed with kvfree()
+ */
+void *ibtrs_zalloc(size_t size)
+{
+ void *p;
+
+ p = kzalloc(size, GFP_KERNEL);
+ if (p)
+ return p;
+
+ /* try allocating virtual memory */
+ p = vzalloc(size);
+ if (p)
+ return p;
+
+ return NULL;
+}
new file mode 100644
@@ -0,0 +1,112 @@
+/*
+ * InfiniBand Transport Layer
+ *
+ * Copyright (c) 2014 - 2017 ProfitBricks GmbH. All rights reserved.
+ * Authors: Fabian Holler < mail@fholler.de>
+ * Jack Wang <jinpu.wang@profitbricks.com>
+ * Kleber Souza <kleber.souza@profitbricks.com>
+ * Danil Kipnis <danil.kipnis@profitbricks.com>
+ * Roman Pen <roman.penyaev@profitbricks.com>
+ * Milind Dumbare <Milind.dumbare@gmail.com>
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * 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 MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ *
+ */
+
+#include <rdma/ibtrs.h>
+#include <rdma/ibtrs_log.h>
+
+inline void ibtrs_heartbeat_set_send_ts(struct ibtrs_heartbeat *h)
+{
+ struct timespec ts = CURRENT_TIME;
+
+ atomic64_set(&h->send_ts_ms, timespec_to_ms(&ts));
+}
+
+inline void ibtrs_set_last_heartbeat(struct ibtrs_heartbeat *h)
+{
+ struct timespec ts = CURRENT_TIME;
+
+ atomic64_set(&h->recv_ts_ms, timespec_to_ms(&ts));
+}
+
+inline u64 ibtrs_heartbeat_send_ts_diff_ms(const struct ibtrs_heartbeat *h)
+{
+ return timediff_cur_ms(atomic64_read(&h->send_ts_ms));
+}
+
+inline u64 ibtrs_recv_ts_ms_diff_ms(const struct ibtrs_heartbeat *h)
+{
+ return timediff_cur_ms(atomic64_read(&h->recv_ts_ms));
+}
+
+void ibtrs_set_heartbeat_timeout(struct ibtrs_heartbeat *h, u32 timeout_ms)
+{
+ h->timeout_ms = timeout_ms;
+ h->warn_timeout_ms = (timeout_ms >> 1) + (timeout_ms >> 2);
+}
+
+void ibtrs_heartbeat_warn(const struct ibtrs_heartbeat *h)
+{
+ u64 diff = ibtrs_recv_ts_ms_diff_ms(h);
+
+ DEB("last heartbeat message from %s was received %lu, %llums"
+ " ago\n", ibtrs_prefix(h), atomic64_read(&h->recv_ts_ms), diff);
+
+ if (diff >= h->warn_timeout_ms)
+ WRN(h, "Last Heartbeat message received %llums ago,"
+ " timeout: %ums\n", diff, h->timeout_ms);
+}
+
+bool ibtrs_heartbeat_timeout_is_expired(const struct ibtrs_heartbeat *h)
+{
+ u64 diff;
+
+ if (h->timeout_ms == 0)
+ return false;
+
+ diff = ibtrs_recv_ts_ms_diff_ms(h);
+
+ DEB("last heartbeat message from %s received %lu, %llums ago\n",
+ ibtrs_prefix(h), atomic64_read(&h->recv_ts_ms), diff);
+
+ if (diff >= h->timeout_ms) {
+ ERR(h, "Heartbeat timeout expired, no heartbeat received "
+ "for %llums, timeout: %ums\n", diff,
+ h->timeout_ms);
+ return true;
+ }
+
+ return false;
+}
new file mode 100644
@@ -0,0 +1,248 @@
+/*
+ * InfiniBand Transport Layer
+ *
+ * Copyright (c) 2014 - 2017 ProfitBricks GmbH. All rights reserved.
+ * Authors: Fabian Holler < mail@fholler.de>
+ * Jack Wang <jinpu.wang@profitbricks.com>
+ * Kleber Souza <kleber.souza@profitbricks.com>
+ * Danil Kipnis <danil.kipnis@profitbricks.com>
+ * Roman Pen <roman.penyaev@profitbricks.com>
+ * Milind Dumbare <Milind.dumbare@gmail.com>
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * 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 MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ *
+ */
+
+#include <linux/errno.h>
+#include <linux/printk.h>
+#include <rdma/ibtrs.h>
+#include <rdma/ibtrs_log.h>
+
+static int
+ibtrs_validate_msg_sess_open_resp(const struct ibtrs_msg_sess_open_resp *msg)
+{
+ static const int min_bufs = 1;
+
+ if (unlikely(msg->hdr.tsize !=
+ IBTRS_MSG_SESS_OPEN_RESP_LEN(msg->cnt))) {
+ ERR_NP("Session open resp msg received with unexpected length"
+ " %dB instead of %luB\n", msg->hdr.tsize,
+ IBTRS_MSG_SESS_OPEN_RESP_LEN(msg->cnt));
+
+ return -EINVAL;
+ }
+
+ if (msg->max_inflight_msg < min_bufs) {
+ ERR_NP("Sess Open msg received with invalid max_inflight_msg %d"
+ " expected >= %d\n", msg->max_inflight_msg, min_bufs);
+ return -EINVAL;
+ }
+
+ if (unlikely(msg->cnt != msg->max_inflight_msg)) {
+ ERR_NP("Session open msg received with invalid cnt %d"
+ " expected %d (queue_depth)\n", msg->cnt,
+ msg->max_inflight_msg);
+ return -EINVAL;
+ }
+
+ if (msg->ver != IBTRS_VERSION) {
+ WRN_NP("Sess open resp version mismatch: client version %d,"
+ " server version: %d\n", IBTRS_VERSION, msg->ver);
+ }
+
+ return 0;
+}
+
+static int
+ibtrs_validate_msg_user(const struct ibtrs_msg_user *msg)
+{
+ /* keep as place holder */
+ return 0;
+}
+
+static int
+ibtrs_validate_msg_rdma_write(const struct ibtrs_msg_rdma_write *msg,
+ u16 queue_depth)
+{
+ if (unlikely(msg->hdr.tsize <= sizeof(*msg))) {
+ ERR_NP("RDMA-Write msg received with invalid length %d"
+ " expected > %lu\n", msg->hdr.tsize, sizeof(*msg));
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int
+ibtrs_validate_msg_req_rdma_write(const struct ibtrs_msg_req_rdma_write *msg,
+ u16 queue_depth)
+{
+ if (unlikely(msg->hdr.tsize <= sizeof(*msg))) {
+ ERR_NP("Request-RDMA-Write msg request received with invalid"
+ " length %d expected > %lu\n", msg->hdr.tsize,
+ sizeof(*msg));
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int
+ibtrs_validate_msg_con_open(const struct ibtrs_msg_con_open *msg)
+{
+ if (unlikely(msg->hdr.tsize != sizeof(*msg))) {
+ ERR_NP("Con Open msg received with invalid length: %d"
+ " expected %lu\n", msg->hdr.tsize, sizeof(*msg));
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int
+ibtrs_validate_msg_sess_open(const struct ibtrs_msg_sess_open *msg)
+{
+ if (msg->hdr.tsize != sizeof(*msg)) {
+ ERR_NP("Sess open msg received with invalid length: %d"
+ " expected %lu\n", msg->hdr.tsize, sizeof(*msg));
+ return -EPROTONOSUPPORT;
+ }
+
+ if (msg->ver != IBTRS_VERSION) {
+ WRN_NP("Sess open msg version mismatch: client version %d,"
+ " server version: %d\n", msg->ver, IBTRS_VERSION);
+ }
+
+ return 0;
+}
+
+static int ibtrs_validate_msg_sess_info(const struct ibtrs_msg_sess_info *msg)
+{
+ if (msg->hdr.tsize != sizeof(*msg)) {
+ ERR_NP("Error message received with invalid length: %d,"
+ " expected %lu\n", msg->hdr.tsize, sizeof(*msg));
+ return -EPROTONOSUPPORT;
+ }
+
+ return 0;
+}
+
+static int ibtrs_validate_msg_error(const struct ibtrs_msg_error *msg)
+{
+ if (msg->hdr.tsize != sizeof(*msg)) {
+ ERR_NP("Error message received with invalid length: %d,"
+ " expected %lu\n", msg->hdr.tsize, sizeof(*msg));
+ return -EPROTONOSUPPORT;
+ }
+
+ return 0;
+}
+
+int ibtrs_validate_message(u16 queue_depth, const void *data)
+{
+ const struct ibtrs_msg_hdr *hdr = data;
+
+ switch (hdr->type) {
+ case IBTRS_MSG_RDMA_WRITE: {
+ const struct ibtrs_msg_rdma_write *msg = data;
+
+ return ibtrs_validate_msg_rdma_write(msg, queue_depth);
+ }
+ case IBTRS_MSG_REQ_RDMA_WRITE: {
+ const struct ibtrs_msg_req_rdma_write *req = data;
+
+ return ibtrs_validate_msg_req_rdma_write(req, queue_depth);
+ }
+ case IBTRS_MSG_SESS_OPEN_RESP: {
+ const struct ibtrs_msg_sess_open_resp *msg = data;
+
+ return ibtrs_validate_msg_sess_open_resp(msg);
+ }
+ case IBTRS_MSG_SESS_INFO: {
+ const struct ibtrs_msg_sess_info *msg = data;
+
+ return ibtrs_validate_msg_sess_info(msg);
+ }
+ case IBTRS_MSG_USER: {
+ const struct ibtrs_msg_user *msg = data;
+
+ return ibtrs_validate_msg_user(msg);
+ }
+ case IBTRS_MSG_CON_OPEN: {
+ const struct ibtrs_msg_con_open *msg = data;
+
+ return ibtrs_validate_msg_con_open(msg);
+ }
+ case IBTRS_MSG_SESS_OPEN: {
+ const struct ibtrs_msg_sess_open *msg = data;
+
+ return ibtrs_validate_msg_sess_open(msg);
+ }
+ case IBTRS_MSG_ERROR: {
+ const struct ibtrs_msg_error *msg = data;
+
+ return ibtrs_validate_msg_error(msg);
+ }
+ default:
+ ERR_NP("Received IBTRS message with unknown type\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+void fill_ibtrs_msg_sess_open(struct ibtrs_msg_sess_open *msg, u8 con_cnt,
+ const uuid_le *uuid)
+{
+ msg->hdr.type = IBTRS_MSG_SESS_OPEN;
+ msg->hdr.tsize = sizeof(*msg);
+ msg->ver = IBTRS_VERSION;
+ msg->con_cnt = con_cnt;
+
+ memcpy(msg->uuid, uuid->b, IBTRS_UUID_SIZE);
+}
+
+void fill_ibtrs_msg_con_open(struct ibtrs_msg_con_open *msg,
+ const uuid_le *uuid)
+{
+ msg->hdr.type = IBTRS_MSG_CON_OPEN;
+ msg->hdr.tsize = sizeof(*msg);
+ memcpy(msg->uuid, uuid->b, IBTRS_UUID_SIZE);
+}
+
+void fill_ibtrs_msg_sess_info(struct ibtrs_msg_sess_info *msg,
+ const char *hostname) {
+ msg->hdr.type = IBTRS_MSG_SESS_INFO;
+ msg->hdr.tsize = sizeof(*msg);
+ memcpy(msg->hostname, hostname, sizeof(msg->hostname));
+}
new file mode 100644
@@ -0,0 +1,412 @@
+/*
+ * InfiniBand Transport Layer
+ *
+ * Copyright (c) 2014 - 2017 ProfitBricks GmbH. All rights reserved.
+ * Authors: Fabian Holler < mail@fholler.de>
+ * Jack Wang <jinpu.wang@profitbricks.com>
+ * Kleber Souza <kleber.souza@profitbricks.com>
+ * Danil Kipnis <danil.kipnis@profitbricks.com>
+ * Roman Pen <roman.penyaev@profitbricks.com>
+ * Milind Dumbare <Milind.dumbare@gmail.com>
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * 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 MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ *
+ */
+
+#include <rdma/ibtrs.h>
+#include <rdma/ibtrs_log.h>
+#include <rdma/ib.h>
+
+int ibtrs_write_empty_imm(struct ib_qp *qp, u32 imm_data,
+ enum ib_send_flags flags)
+{
+ struct ib_send_wr wr, *bad_wr;
+
+ memset(&wr, 0, sizeof(wr));
+ wr.send_flags = flags;
+ wr.opcode = IB_WR_RDMA_WRITE_WITH_IMM;
+ wr.ex.imm_data = cpu_to_be32(imm_data);
+
+ return ib_post_send(qp, &wr, &bad_wr);
+}
+
+int ibtrs_post_send(struct ib_qp *qp, struct ib_mr *mr, struct ibtrs_iu *iu,
+ u32 size)
+{
+ struct ib_sge list;
+ struct ib_send_wr wr, *bad_wr;
+
+ if ((WARN_ON(size == 0)))
+ return -EINVAL;
+
+ list.addr = iu->dma_addr;
+ list.length = size;
+ list.lkey = mr->lkey;
+
+ memset(&wr, 0, sizeof(wr));
+ wr.next = NULL;
+ wr.wr_id = (uintptr_t)iu;
+ wr.sg_list = &list;
+ wr.num_sge = 1;
+ wr.opcode = IB_WR_SEND;
+ wr.send_flags = IB_SEND_SIGNALED;
+
+ return ib_post_send(qp, &wr, &bad_wr);
+}
+
+static int post_rdma_write(struct ib_qp *qp, struct ib_sge *sge, size_t num_sge,
+ u32 rkey, u64 rdma_addr, u64 wr_id, u32 imm_data,
+ enum ib_wr_opcode opcode, enum ib_send_flags flags)
+{
+ struct ib_send_wr *bad_wr;
+ struct ib_rdma_wr wr;
+ int i;
+
+ wr.wr.next = NULL;
+ wr.wr.wr_id = wr_id;
+ wr.wr.sg_list = sge;
+ wr.wr.num_sge = num_sge;
+ wr.rkey = rkey;
+ wr.remote_addr = rdma_addr;
+ wr.wr.opcode = opcode;
+ wr.wr.ex.imm_data = cpu_to_be32(imm_data);
+ wr.wr.send_flags = flags;
+
+ /* if one of the sges has 0 size,, the operation will fail with an
+ * length error
+ */
+ for (i = 0; i < num_sge; i++)
+ if (WARN_ON(sge[i].length == 0))
+ return -EINVAL;
+
+ return ib_post_send(qp, &wr.wr, &bad_wr);
+}
+
+inline int ib_post_rdma_write(struct ib_qp *qp, struct ib_sge *sge,
+ unsigned int num_sge, u32 rkey, u64 rdma_addr,
+ u64 wr_id)
+{
+ return post_rdma_write(qp, sge, num_sge, rkey, rdma_addr, wr_id,
+ 0, IB_WR_RDMA_WRITE, 0);
+}
+
+inline int ib_post_rdma_write_imm(struct ib_qp *qp, struct ib_sge *sge,
+ unsigned int num_sge, u32 rkey, u64 rdma_addr,
+ u64 wr_id, u32 imm_data,
+ enum ib_send_flags flags)
+{
+ return post_rdma_write(qp, sge, num_sge, rkey, rdma_addr, wr_id,
+ imm_data, IB_WR_RDMA_WRITE_WITH_IMM, flags);
+}
+
+int ib_get_max_wr_queue_size(struct ib_device *dev)
+{
+ struct ib_device_attr *attr = &dev->attrs;
+
+ return attr->max_qp_wr;
+}
+
+static const char *ib_event_str(enum ib_event_type ev)
+{
+ switch (ev) {
+ case IB_EVENT_CQ_ERR:
+ return "IB_EVENT_CQ_ERR";
+ case IB_EVENT_QP_FATAL:
+ return "IB_EVENT_QP_FATAIL";
+ case IB_EVENT_QP_REQ_ERR:
+ return "IB_EVENT_QP_REQ_ERR";
+ case IB_EVENT_QP_ACCESS_ERR:
+ return "IB_EVENT_QP_ACCESS_ERR";
+ case IB_EVENT_COMM_EST:
+ return "IB_EVENT_COMM_EST";
+ case IB_EVENT_SQ_DRAINED:
+ return "IB_EVENT_SQ_DRAINED";
+ case IB_EVENT_PATH_MIG:
+ return "IB_EVENT_PATH_MIG";
+ case IB_EVENT_PATH_MIG_ERR:
+ return "IB_EVENT_PATH_MIG_ERR";
+ case IB_EVENT_DEVICE_FATAL:
+ return "IB_EVENT_DEVICE_FATAL";
+ case IB_EVENT_PORT_ACTIVE:
+ return "IB_EVENT_PORT_ACTIVE";
+ case IB_EVENT_PORT_ERR:
+ return "IB_EVENT_PORT_ERR";
+ case IB_EVENT_LID_CHANGE:
+ return "IB_EVENT_LID_CHANGE";
+ case IB_EVENT_PKEY_CHANGE:
+ return "IB_EVENT_PKEY_CHANGE";
+ case IB_EVENT_SM_CHANGE:
+ return "IB_EVENT_SM_CHANGE";
+ case IB_EVENT_SRQ_ERR:
+ return "IB_EVENT_SRQ_ERR";
+ case IB_EVENT_SRQ_LIMIT_REACHED:
+ return "IB_EVENT_SRQ_LIMIT_REACHED";
+ case IB_EVENT_QP_LAST_WQE_REACHED:
+ return "IB_EVENT_QP_LAST_WQE_REACHED";
+ case IB_EVENT_CLIENT_REREGISTER:
+ return "IB_EVENT_CLIENT_REREGISTER";
+ case IB_EVENT_GID_CHANGE:
+ return "IB_EVENT_GID_CHANGE";
+ default:
+ return "Unknown IB event";
+ }
+};
+
+static void ib_event_handler(struct ib_event_handler *h, struct ib_event *ev)
+{
+ switch (ev->event) {
+ case IB_EVENT_DEVICE_FATAL:
+ case IB_EVENT_PORT_ERR:
+ WRN_NP("Received IB event %s (%d) on device %s port %d\n",
+ ib_event_str(ev->event), ev->event,
+ ev->device->name, ev->element.port_num);
+ break;
+ default:
+ INFO_NP("Received IB event %s (%d) on device %s port %d\n",
+ ib_event_str(ev->event), ev->event,
+ ev->device->name, ev->element.port_num);
+ break;
+ }
+}
+
+static void qp_event_handler(struct ib_event *ev, void *ctx)
+{
+ struct ib_con *con = ctx;
+
+ switch (ev->event) {
+ case IB_EVENT_COMM_EST:
+ INFO(con, "QP event %s (%d) received\n",
+ ib_event_str(ev->event), ev->event);
+ rdma_notify(con->cm_id, IB_EVENT_COMM_EST);
+ break;
+ default:
+ INFO(con, "Unhandled QP event %s (%d) received\n",
+ ib_event_str(ev->event), ev->event);
+ break;
+ }
+}
+
+static void cq_event_handler(struct ib_event *ev, void *ctx)
+{
+ INFO_NP("CQ event %s (%d)\n", ib_event_str(ev->event), ev->event);
+}
+
+int ib_session_init(struct ib_device *dev, struct ib_session *s)
+{
+ int err;
+
+ s->pd = ib_alloc_pd(dev, IB_PD_UNSAFE_GLOBAL_RKEY);
+ if (IS_ERR(s->pd)) {
+ ERR_NP("Allocating protection domain failed, errno: %ld\n",
+ PTR_ERR(s->pd));
+ return PTR_ERR(s->pd);
+ }
+ s->mr = s->pd->__internal_mr;
+ INIT_IB_EVENT_HANDLER(&s->event_handler, dev, ib_event_handler);
+ err = ib_register_event_handler(&s->event_handler);
+ if (err) {
+ ERR_NP("Registering IB event handler failed, errno: %d\n",
+ err);
+ goto err;
+ }
+
+ return 0;
+
+err:
+ ib_dealloc_pd(s->pd);
+ s->pd = NULL;
+ s->mr = NULL;
+
+ return err;
+}
+
+static int init_cq(struct ib_con *con, struct rdma_cm_id *cm_id,
+ ib_comp_handler comp_handler, void *ctx, int cq_vector,
+ u16 cq_size)
+{
+ struct ib_cq_init_attr cq_attr = {};
+
+ cq_attr.cqe = cq_size * 2 + 1;
+ cq_attr.comp_vector = cq_vector;
+
+ con->cq = ib_create_cq(cm_id->device, comp_handler, cq_event_handler,
+ ctx, &cq_attr);/*1 for beacon*/
+ if (IS_ERR(con->cq)) {
+ ERR(con, "Creating completion queue failed, errno: %ld\n",
+ PTR_ERR(con->cq));
+ return PTR_ERR(con->cq);
+ }
+
+ return 0;
+}
+
+inline int ibtrs_request_cq_notifications(struct ib_con *con)
+{
+ return ib_req_notify_cq(con->cq, IB_CQ_NEXT_COMP |
+ IB_CQ_REPORT_MISSED_EVENTS);
+}
+
+void ib_con_destroy(struct ib_con *con)
+{
+ int err;
+
+ err = ib_destroy_qp(con->qp);
+ if (err)
+ ERR(con, "Destroying QP failed, errno: %d\n",
+ err);
+
+ err = ib_destroy_cq(con->cq);
+ if (err)
+ ERR(con, "Destroying CQ failed, errno: %d\n",
+ err);
+}
+
+static int create_qp(struct ib_con *con, struct rdma_cm_id *cm_id,
+ struct ib_pd *pd, u16 wr_queue_size, u32 max_send_sge)
+{
+ struct ib_qp_init_attr init_attr = {NULL};
+ int ret;
+
+ init_attr.cap.max_send_wr = wr_queue_size + 1;/*1 more for beacon*/
+ init_attr.cap.max_recv_wr = wr_queue_size;
+ init_attr.cap.max_recv_sge = 2;
+ init_attr.event_handler = qp_event_handler;
+ init_attr.qp_context = con;
+ init_attr.cap.max_send_sge = max_send_sge;
+
+ init_attr.qp_type = IB_QPT_RC;
+ init_attr.send_cq = con->cq;
+ init_attr.recv_cq = con->cq;
+ init_attr.sq_sig_type = IB_SIGNAL_REQ_WR;
+
+ ret = rdma_create_qp(cm_id, pd, &init_attr);
+ if (ret) {
+ ERR(con, "Creating QP failed, errno: %d\n", ret);
+ return ret;
+ }
+
+ con->qp = cm_id->qp;
+ return ret;
+}
+
+int post_beacon(struct ib_con *con)
+{
+ struct ib_send_wr *bad_wr;
+
+ return ib_post_send(con->qp, &con->beacon, &bad_wr);
+}
+
+int ib_con_init(struct ib_con *con, struct rdma_cm_id *cm_id,
+ u32 max_send_sge,
+ ib_comp_handler comp_handler, void *ctx, int cq_vector,
+ u16 cq_size, u16 wr_queue_size, struct ib_session *session)
+{
+ int err, ret;
+
+ err = init_cq(con, cm_id, comp_handler, ctx,
+ cq_vector, cq_size);
+ if (err)
+ return err;
+
+ err = create_qp(con, cm_id, session->pd, wr_queue_size, max_send_sge);
+ if (err) {
+ ret = ib_destroy_cq(con->cq);
+ if (ret)
+ ERR(con, "Destroying CQ failed, errno: %d\n",
+ ret);
+ return err;
+ }
+ con->beacon.wr_id = (uintptr_t)&con->beacon;
+ con->beacon.opcode = IB_WR_SEND;
+ con->cm_id = cm_id;
+
+ return 0;
+}
+
+void ib_session_destroy(struct ib_session *session)
+{
+ if (session->pd) {
+ ib_dealloc_pd(session->pd);
+ session->pd = NULL;
+ }
+
+ ib_unregister_event_handler(&session->event_handler);
+}
+
+int ibtrs_addr_to_str(const struct sockaddr_storage *addr, char *buf,
+ size_t len)
+{
+ switch (addr->ss_family) {
+ case AF_IB:
+ return scnprintf(buf, len, "gid:%pI6",
+ &((struct sockaddr_ib *)
+ addr)->sib_addr.sib_raw);
+ case AF_INET:
+ return scnprintf(buf, len, "ip:%pI4",
+ &((struct sockaddr_in *)addr)->sin_addr);
+ case AF_INET6:
+ /* workaround for ip4 client addr being set to INET6 family.
+ * This should fix it:
+ * yotamke@mellanox.com: [PATCH for-next] RDMA/CMA: Mark
+ * IPv4 addresses correctly when the listener is IPv6]
+ * http://permalink.gmane.org/gmane.linux.drivers.rdma/22395
+ *
+ * The first byte of ip6 address can't be 0. If it is, assume
+ * structure addr actually contains ip4 address.
+ */
+ if (!((struct sockaddr_in6 *)addr)->sin6_addr.s6_addr[0]) {
+ return scnprintf(buf, len, "ip:%pI4",
+ &((struct sockaddr_in *)
+ addr)->sin_addr);
+ }
+ /* end of workaround*/
+ return scnprintf(buf, len, "ip:%pI6c",
+ &((struct sockaddr_in6 *)addr)->sin6_addr);
+ default:
+ ERR_NP("Invalid address family\n");
+ return -EINVAL;
+ }
+}
+EXPORT_SYMBOL(ibtrs_addr_to_str);
+
+int ibtrs_heartbeat_timeout_validate(int timeout)
+{
+ if (timeout && timeout < MIN_HEARTBEAT_TIMEOUT_MS) {
+ WRN_NP("Heartbeat timeout: %d is invalid, must be 0 "
+ "or >= %d ms\n", timeout, MIN_HEARTBEAT_TIMEOUT_MS);
+ return -EINVAL;
+ }
+
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,113 @@
+/*
+ * InfiniBand Transport Layer
+ *
+ * Copyright (c) 2014 - 2017 ProfitBricks GmbH. All rights reserved.
+ * Authors: Fabian Holler < mail@fholler.de>
+ * Jack Wang <jinpu.wang@profitbricks.com>
+ * Kleber Souza <kleber.souza@profitbricks.com>
+ * Danil Kipnis <danil.kipnis@profitbricks.com>
+ * Roman Pen <roman.penyaev@profitbricks.com>
+ * Milind Dumbare <Milind.dumbare@gmail.com>
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * 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 MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ *
+ */
+
+#include <linux/slab.h>
+#include <rdma/ibtrs.h>
+
+/*
+ * Return an IU to the free pool
+ */
+inline void ibtrs_iu_put(struct list_head *head, struct ibtrs_iu *iu)
+{
+ list_add(&iu->list, head);
+}
+
+/*
+ * Get an IU from the free pool, need lock to protect list
+ */
+struct ibtrs_iu *ibtrs_iu_get(struct list_head *head)
+{
+ struct ibtrs_iu *iu;
+
+ if (list_empty(head))
+ return NULL;
+
+ iu = list_first_entry(head, struct ibtrs_iu, list);
+ list_del(&iu->list);
+ return iu;
+}
+
+struct ibtrs_iu *ibtrs_iu_alloc(u32 tag, size_t size, gfp_t gfp_mask,
+ struct ib_device *dma_dev,
+ enum dma_data_direction direction, bool is_msg)
+{
+ struct ibtrs_iu *iu;
+
+ iu = kmalloc(sizeof(*iu), gfp_mask);
+ if (!iu)
+ return NULL;
+
+ iu->buf = kzalloc(size, gfp_mask);
+ if (!iu->buf)
+ goto err1;
+
+ iu->dma_addr = ib_dma_map_single(dma_dev, iu->buf, size, direction);
+ if (ib_dma_mapping_error(dma_dev, iu->dma_addr))
+ goto err2;
+
+ iu->size = size;
+ iu->direction = direction;
+ iu->tag = tag;
+ iu->is_msg = is_msg;
+ return iu;
+
+err2:
+ kfree(iu->buf);
+err1:
+ kfree(iu);
+ return NULL;
+}
+
+void ibtrs_iu_free(struct ibtrs_iu *iu, enum dma_data_direction dir,
+ struct ib_device *ib_dev)
+{
+ if (WARN_ON(!iu))
+ return;
+
+ ib_dma_unmap_single(ib_dev, iu->dma_addr, iu->size, dir);
+ kfree(iu->buf);
+ kfree(iu);
+}