1c0894b3eSJack Wang // SPDX-License-Identifier: GPL-2.0-or-later 2c0894b3eSJack Wang /* 3c0894b3eSJack Wang * RDMA Transport Layer 4c0894b3eSJack Wang * 5c0894b3eSJack Wang * Copyright (c) 2014 - 2018 ProfitBricks GmbH. All rights reserved. 6c0894b3eSJack Wang * Copyright (c) 2018 - 2019 1&1 IONOS Cloud GmbH. All rights reserved. 7c0894b3eSJack Wang * Copyright (c) 2019 - 2020 1&1 IONOS SE. All rights reserved. 8c0894b3eSJack Wang */ 9c0894b3eSJack Wang #undef pr_fmt 10c0894b3eSJack Wang #define pr_fmt(fmt) KBUILD_MODNAME " L" __stringify(__LINE__) ": " fmt 11c0894b3eSJack Wang 12c0894b3eSJack Wang #include <linux/module.h> 13c0894b3eSJack Wang #include <linux/inet.h> 14c0894b3eSJack Wang 15c0894b3eSJack Wang #include "rtrs-pri.h" 16c0894b3eSJack Wang #include "rtrs-log.h" 17c0894b3eSJack Wang 18c0894b3eSJack Wang MODULE_DESCRIPTION("RDMA Transport Core"); 19c0894b3eSJack Wang MODULE_LICENSE("GPL"); 20c0894b3eSJack Wang 21354462ebSGuoqing Jiang struct rtrs_iu *rtrs_iu_alloc(u32 iu_num, size_t size, gfp_t gfp_mask, 22c0894b3eSJack Wang struct ib_device *dma_dev, 23c0894b3eSJack Wang enum dma_data_direction dir, 24c0894b3eSJack Wang void (*done)(struct ib_cq *cq, struct ib_wc *wc)) 25c0894b3eSJack Wang { 26c0894b3eSJack Wang struct rtrs_iu *ius, *iu; 27c0894b3eSJack Wang int i; 28c0894b3eSJack Wang 29354462ebSGuoqing Jiang ius = kcalloc(iu_num, sizeof(*ius), gfp_mask); 30c0894b3eSJack Wang if (!ius) 31c0894b3eSJack Wang return NULL; 32354462ebSGuoqing Jiang for (i = 0; i < iu_num; i++) { 33c0894b3eSJack Wang iu = &ius[i]; 348bd372acSGioh Kim iu->direction = dir; 35c0894b3eSJack Wang iu->buf = kzalloc(size, gfp_mask); 36c0894b3eSJack Wang if (!iu->buf) 37c0894b3eSJack Wang goto err; 38c0894b3eSJack Wang 39c0894b3eSJack Wang iu->dma_addr = ib_dma_map_single(dma_dev, iu->buf, size, dir); 40c0894b3eSJack Wang if (ib_dma_mapping_error(dma_dev, iu->dma_addr)) 41c0894b3eSJack Wang goto err; 42c0894b3eSJack Wang 43c0894b3eSJack Wang iu->cqe.done = done; 44c0894b3eSJack Wang iu->size = size; 45c0894b3eSJack Wang } 46c0894b3eSJack Wang return ius; 47c0894b3eSJack Wang err: 488bd372acSGioh Kim rtrs_iu_free(ius, dma_dev, i); 49c0894b3eSJack Wang return NULL; 50c0894b3eSJack Wang } 51c0894b3eSJack Wang EXPORT_SYMBOL_GPL(rtrs_iu_alloc); 52c0894b3eSJack Wang 53354462ebSGuoqing Jiang void rtrs_iu_free(struct rtrs_iu *ius, struct ib_device *ibdev, u32 queue_num) 54c0894b3eSJack Wang { 55c0894b3eSJack Wang struct rtrs_iu *iu; 56c0894b3eSJack Wang int i; 57c0894b3eSJack Wang 58c0894b3eSJack Wang if (!ius) 59c0894b3eSJack Wang return; 60c0894b3eSJack Wang 61354462ebSGuoqing Jiang for (i = 0; i < queue_num; i++) { 62c0894b3eSJack Wang iu = &ius[i]; 638bd372acSGioh Kim ib_dma_unmap_single(ibdev, iu->dma_addr, iu->size, iu->direction); 64c0894b3eSJack Wang kfree(iu->buf); 65c0894b3eSJack Wang } 66c0894b3eSJack Wang kfree(ius); 67c0894b3eSJack Wang } 68c0894b3eSJack Wang EXPORT_SYMBOL_GPL(rtrs_iu_free); 69c0894b3eSJack Wang 70c0894b3eSJack Wang int rtrs_iu_post_recv(struct rtrs_con *con, struct rtrs_iu *iu) 71c0894b3eSJack Wang { 72c0894b3eSJack Wang struct rtrs_sess *sess = con->sess; 73c0894b3eSJack Wang struct ib_recv_wr wr; 74c0894b3eSJack Wang struct ib_sge list; 75c0894b3eSJack Wang 76c0894b3eSJack Wang list.addr = iu->dma_addr; 77c0894b3eSJack Wang list.length = iu->size; 78c0894b3eSJack Wang list.lkey = sess->dev->ib_pd->local_dma_lkey; 79c0894b3eSJack Wang 80c0894b3eSJack Wang if (list.length == 0) { 81c0894b3eSJack Wang rtrs_wrn(con->sess, 82c0894b3eSJack Wang "Posting receive work request failed, sg list is empty\n"); 83c0894b3eSJack Wang return -EINVAL; 84c0894b3eSJack Wang } 85c0894b3eSJack Wang wr = (struct ib_recv_wr) { 86c0894b3eSJack Wang .wr_cqe = &iu->cqe, 87c0894b3eSJack Wang .sg_list = &list, 88c0894b3eSJack Wang .num_sge = 1, 89c0894b3eSJack Wang }; 90c0894b3eSJack Wang 91c0894b3eSJack Wang return ib_post_recv(con->qp, &wr, NULL); 92c0894b3eSJack Wang } 93c0894b3eSJack Wang EXPORT_SYMBOL_GPL(rtrs_iu_post_recv); 94c0894b3eSJack Wang 95c0894b3eSJack Wang int rtrs_post_recv_empty(struct rtrs_con *con, struct ib_cqe *cqe) 96c0894b3eSJack Wang { 97c0894b3eSJack Wang struct ib_recv_wr wr; 98c0894b3eSJack Wang 99c0894b3eSJack Wang wr = (struct ib_recv_wr) { 100c0894b3eSJack Wang .wr_cqe = cqe, 101c0894b3eSJack Wang }; 102c0894b3eSJack Wang 103c0894b3eSJack Wang return ib_post_recv(con->qp, &wr, NULL); 104c0894b3eSJack Wang } 105c0894b3eSJack Wang EXPORT_SYMBOL_GPL(rtrs_post_recv_empty); 106c0894b3eSJack Wang 107e6ab8cf5SGuoqing Jiang static int rtrs_post_send(struct ib_qp *qp, struct ib_send_wr *head, 108*630e438fSJack Wang struct ib_send_wr *wr, struct ib_send_wr *tail) 109e6ab8cf5SGuoqing Jiang { 110e6ab8cf5SGuoqing Jiang if (head) { 111*630e438fSJack Wang struct ib_send_wr *next = head; 112e6ab8cf5SGuoqing Jiang 113*630e438fSJack Wang while (next->next) 114*630e438fSJack Wang next = next->next; 115*630e438fSJack Wang next->next = wr; 116e6ab8cf5SGuoqing Jiang } else { 117e6ab8cf5SGuoqing Jiang head = wr; 118e6ab8cf5SGuoqing Jiang } 119e6ab8cf5SGuoqing Jiang 120*630e438fSJack Wang if (tail) 121*630e438fSJack Wang wr->next = tail; 122*630e438fSJack Wang 123e6ab8cf5SGuoqing Jiang return ib_post_send(qp, head, NULL); 124e6ab8cf5SGuoqing Jiang } 125e6ab8cf5SGuoqing Jiang 126c0894b3eSJack Wang int rtrs_iu_post_send(struct rtrs_con *con, struct rtrs_iu *iu, size_t size, 127c0894b3eSJack Wang struct ib_send_wr *head) 128c0894b3eSJack Wang { 129c0894b3eSJack Wang struct rtrs_sess *sess = con->sess; 130c0894b3eSJack Wang struct ib_send_wr wr; 131c0894b3eSJack Wang struct ib_sge list; 132c0894b3eSJack Wang 133c0894b3eSJack Wang if (WARN_ON(size == 0)) 134c0894b3eSJack Wang return -EINVAL; 135c0894b3eSJack Wang 136c0894b3eSJack Wang list.addr = iu->dma_addr; 137c0894b3eSJack Wang list.length = size; 138c0894b3eSJack Wang list.lkey = sess->dev->ib_pd->local_dma_lkey; 139c0894b3eSJack Wang 140c0894b3eSJack Wang wr = (struct ib_send_wr) { 141c0894b3eSJack Wang .wr_cqe = &iu->cqe, 142c0894b3eSJack Wang .sg_list = &list, 143c0894b3eSJack Wang .num_sge = 1, 144c0894b3eSJack Wang .opcode = IB_WR_SEND, 145c0894b3eSJack Wang .send_flags = IB_SEND_SIGNALED, 146c0894b3eSJack Wang }; 147c0894b3eSJack Wang 148*630e438fSJack Wang return rtrs_post_send(con->qp, head, &wr, NULL); 149c0894b3eSJack Wang } 150c0894b3eSJack Wang EXPORT_SYMBOL_GPL(rtrs_iu_post_send); 151c0894b3eSJack Wang 152c0894b3eSJack Wang int rtrs_iu_post_rdma_write_imm(struct rtrs_con *con, struct rtrs_iu *iu, 153c0894b3eSJack Wang struct ib_sge *sge, unsigned int num_sge, 154c0894b3eSJack Wang u32 rkey, u64 rdma_addr, u32 imm_data, 155c0894b3eSJack Wang enum ib_send_flags flags, 156*630e438fSJack Wang struct ib_send_wr *head, 157*630e438fSJack Wang struct ib_send_wr *tail) 158c0894b3eSJack Wang { 159c0894b3eSJack Wang struct ib_rdma_wr wr; 160c0894b3eSJack Wang int i; 161c0894b3eSJack Wang 162c0894b3eSJack Wang wr = (struct ib_rdma_wr) { 163c0894b3eSJack Wang .wr.wr_cqe = &iu->cqe, 164c0894b3eSJack Wang .wr.sg_list = sge, 165c0894b3eSJack Wang .wr.num_sge = num_sge, 166c0894b3eSJack Wang .rkey = rkey, 167c0894b3eSJack Wang .remote_addr = rdma_addr, 168c0894b3eSJack Wang .wr.opcode = IB_WR_RDMA_WRITE_WITH_IMM, 169c0894b3eSJack Wang .wr.ex.imm_data = cpu_to_be32(imm_data), 170c0894b3eSJack Wang .wr.send_flags = flags, 171c0894b3eSJack Wang }; 172c0894b3eSJack Wang 173c0894b3eSJack Wang /* 174c0894b3eSJack Wang * If one of the sges has 0 size, the operation will fail with a 175c0894b3eSJack Wang * length error 176c0894b3eSJack Wang */ 177c0894b3eSJack Wang for (i = 0; i < num_sge; i++) 178c0894b3eSJack Wang if (WARN_ON(sge[i].length == 0)) 179c0894b3eSJack Wang return -EINVAL; 180c0894b3eSJack Wang 181*630e438fSJack Wang return rtrs_post_send(con->qp, head, &wr.wr, tail); 182c0894b3eSJack Wang } 183c0894b3eSJack Wang EXPORT_SYMBOL_GPL(rtrs_iu_post_rdma_write_imm); 184c0894b3eSJack Wang 185c0894b3eSJack Wang int rtrs_post_rdma_write_imm_empty(struct rtrs_con *con, struct ib_cqe *cqe, 186c0894b3eSJack Wang u32 imm_data, enum ib_send_flags flags, 187c0894b3eSJack Wang struct ib_send_wr *head) 188c0894b3eSJack Wang { 1897fbc3c37SJack Wang struct ib_rdma_wr wr; 190c0894b3eSJack Wang 1917fbc3c37SJack Wang wr = (struct ib_rdma_wr) { 1927fbc3c37SJack Wang .wr.wr_cqe = cqe, 1937fbc3c37SJack Wang .wr.send_flags = flags, 1947fbc3c37SJack Wang .wr.opcode = IB_WR_RDMA_WRITE_WITH_IMM, 1957fbc3c37SJack Wang .wr.ex.imm_data = cpu_to_be32(imm_data), 196c0894b3eSJack Wang }; 197c0894b3eSJack Wang 198*630e438fSJack Wang return rtrs_post_send(con->qp, head, &wr.wr, NULL); 199c0894b3eSJack Wang } 200c0894b3eSJack Wang EXPORT_SYMBOL_GPL(rtrs_post_rdma_write_imm_empty); 201c0894b3eSJack Wang 202c0894b3eSJack Wang static void qp_event_handler(struct ib_event *ev, void *ctx) 203c0894b3eSJack Wang { 204c0894b3eSJack Wang struct rtrs_con *con = ctx; 205c0894b3eSJack Wang 206c0894b3eSJack Wang switch (ev->event) { 207c0894b3eSJack Wang case IB_EVENT_COMM_EST: 208c0894b3eSJack Wang rtrs_info(con->sess, "QP event %s (%d) received\n", 209c0894b3eSJack Wang ib_event_msg(ev->event), ev->event); 210c0894b3eSJack Wang rdma_notify(con->cm_id, IB_EVENT_COMM_EST); 211c0894b3eSJack Wang break; 212c0894b3eSJack Wang default: 213c0894b3eSJack Wang rtrs_info(con->sess, "Unhandled QP event %s (%d) received\n", 214c0894b3eSJack Wang ib_event_msg(ev->event), ev->event); 215c0894b3eSJack Wang break; 216c0894b3eSJack Wang } 217c0894b3eSJack Wang } 218c0894b3eSJack Wang 219354462ebSGuoqing Jiang static int create_cq(struct rtrs_con *con, int cq_vector, int nr_cqe, 220c0894b3eSJack Wang enum ib_poll_context poll_ctx) 221c0894b3eSJack Wang { 222c0894b3eSJack Wang struct rdma_cm_id *cm_id = con->cm_id; 223c0894b3eSJack Wang struct ib_cq *cq; 224c0894b3eSJack Wang 225354462ebSGuoqing Jiang cq = ib_cq_pool_get(cm_id->device, nr_cqe, cq_vector, poll_ctx); 226c0894b3eSJack Wang if (IS_ERR(cq)) { 227c0894b3eSJack Wang rtrs_err(con->sess, "Creating completion queue failed, errno: %ld\n", 228c0894b3eSJack Wang PTR_ERR(cq)); 229c0894b3eSJack Wang return PTR_ERR(cq); 230c0894b3eSJack Wang } 231c0894b3eSJack Wang con->cq = cq; 232354462ebSGuoqing Jiang con->nr_cqe = nr_cqe; 233c0894b3eSJack Wang 234c0894b3eSJack Wang return 0; 235c0894b3eSJack Wang } 236c0894b3eSJack Wang 237c0894b3eSJack Wang static int create_qp(struct rtrs_con *con, struct ib_pd *pd, 2387490fd1fSJack Wang u32 max_send_wr, u32 max_recv_wr, u32 max_sge) 239c0894b3eSJack Wang { 240c0894b3eSJack Wang struct ib_qp_init_attr init_attr = {NULL}; 241c0894b3eSJack Wang struct rdma_cm_id *cm_id = con->cm_id; 242c0894b3eSJack Wang int ret; 243c0894b3eSJack Wang 2447490fd1fSJack Wang init_attr.cap.max_send_wr = max_send_wr; 2457490fd1fSJack Wang init_attr.cap.max_recv_wr = max_recv_wr; 246c0894b3eSJack Wang init_attr.cap.max_recv_sge = 1; 247c0894b3eSJack Wang init_attr.event_handler = qp_event_handler; 248c0894b3eSJack Wang init_attr.qp_context = con; 249c0894b3eSJack Wang init_attr.cap.max_send_sge = max_sge; 250c0894b3eSJack Wang 251c0894b3eSJack Wang init_attr.qp_type = IB_QPT_RC; 252c0894b3eSJack Wang init_attr.send_cq = con->cq; 253c0894b3eSJack Wang init_attr.recv_cq = con->cq; 254c0894b3eSJack Wang init_attr.sq_sig_type = IB_SIGNAL_REQ_WR; 255c0894b3eSJack Wang 256c0894b3eSJack Wang ret = rdma_create_qp(cm_id, pd, &init_attr); 257c0894b3eSJack Wang if (ret) { 258c0894b3eSJack Wang rtrs_err(con->sess, "Creating QP failed, err: %d\n", ret); 259c0894b3eSJack Wang return ret; 260c0894b3eSJack Wang } 261c0894b3eSJack Wang con->qp = cm_id->qp; 262c0894b3eSJack Wang 263c0894b3eSJack Wang return ret; 264c0894b3eSJack Wang } 265c0894b3eSJack Wang 266c0894b3eSJack Wang int rtrs_cq_qp_create(struct rtrs_sess *sess, struct rtrs_con *con, 267354462ebSGuoqing Jiang u32 max_send_sge, int cq_vector, int nr_cqe, 2687490fd1fSJack Wang u32 max_send_wr, u32 max_recv_wr, 2697490fd1fSJack Wang enum ib_poll_context poll_ctx) 270c0894b3eSJack Wang { 271c0894b3eSJack Wang int err; 272c0894b3eSJack Wang 273354462ebSGuoqing Jiang err = create_cq(con, cq_vector, nr_cqe, poll_ctx); 274c0894b3eSJack Wang if (err) 275c0894b3eSJack Wang return err; 276c0894b3eSJack Wang 2777490fd1fSJack Wang err = create_qp(con, sess->dev->ib_pd, max_send_wr, max_recv_wr, 2787490fd1fSJack Wang max_send_sge); 279c0894b3eSJack Wang if (err) { 280354462ebSGuoqing Jiang ib_cq_pool_put(con->cq, con->nr_cqe); 281c0894b3eSJack Wang con->cq = NULL; 282c0894b3eSJack Wang return err; 283c0894b3eSJack Wang } 284c0894b3eSJack Wang con->sess = sess; 285c0894b3eSJack Wang 286c0894b3eSJack Wang return 0; 287c0894b3eSJack Wang } 288c0894b3eSJack Wang EXPORT_SYMBOL_GPL(rtrs_cq_qp_create); 289c0894b3eSJack Wang 290c0894b3eSJack Wang void rtrs_cq_qp_destroy(struct rtrs_con *con) 291c0894b3eSJack Wang { 292c0894b3eSJack Wang if (con->qp) { 293c0894b3eSJack Wang rdma_destroy_qp(con->cm_id); 294c0894b3eSJack Wang con->qp = NULL; 295c0894b3eSJack Wang } 296c0894b3eSJack Wang if (con->cq) { 297354462ebSGuoqing Jiang ib_cq_pool_put(con->cq, con->nr_cqe); 298c0894b3eSJack Wang con->cq = NULL; 299c0894b3eSJack Wang } 300c0894b3eSJack Wang } 301c0894b3eSJack Wang EXPORT_SYMBOL_GPL(rtrs_cq_qp_destroy); 302c0894b3eSJack Wang 303c0894b3eSJack Wang static void schedule_hb(struct rtrs_sess *sess) 304c0894b3eSJack Wang { 305c0894b3eSJack Wang queue_delayed_work(sess->hb_wq, &sess->hb_dwork, 306c0894b3eSJack Wang msecs_to_jiffies(sess->hb_interval_ms)); 307c0894b3eSJack Wang } 308c0894b3eSJack Wang 309c0894b3eSJack Wang void rtrs_send_hb_ack(struct rtrs_sess *sess) 310c0894b3eSJack Wang { 311c0894b3eSJack Wang struct rtrs_con *usr_con = sess->con[0]; 312c0894b3eSJack Wang u32 imm; 313c0894b3eSJack Wang int err; 314c0894b3eSJack Wang 315c0894b3eSJack Wang imm = rtrs_to_imm(RTRS_HB_ACK_IMM, 0); 316c0894b3eSJack Wang err = rtrs_post_rdma_write_imm_empty(usr_con, sess->hb_cqe, imm, 317b38041d5SJack Wang 0, NULL); 318c0894b3eSJack Wang if (err) { 319c0894b3eSJack Wang sess->hb_err_handler(usr_con); 320c0894b3eSJack Wang return; 321c0894b3eSJack Wang } 322c0894b3eSJack Wang } 323c0894b3eSJack Wang EXPORT_SYMBOL_GPL(rtrs_send_hb_ack); 324c0894b3eSJack Wang 325c0894b3eSJack Wang static void hb_work(struct work_struct *work) 326c0894b3eSJack Wang { 327c0894b3eSJack Wang struct rtrs_con *usr_con; 328c0894b3eSJack Wang struct rtrs_sess *sess; 329c0894b3eSJack Wang u32 imm; 330c0894b3eSJack Wang int err; 331c0894b3eSJack Wang 332c0894b3eSJack Wang sess = container_of(to_delayed_work(work), typeof(*sess), hb_dwork); 333c0894b3eSJack Wang usr_con = sess->con[0]; 334c0894b3eSJack Wang 335c0894b3eSJack Wang if (sess->hb_missed_cnt > sess->hb_missed_max) { 336c0894b3eSJack Wang sess->hb_err_handler(usr_con); 337c0894b3eSJack Wang return; 338c0894b3eSJack Wang } 339c0894b3eSJack Wang if (sess->hb_missed_cnt++) { 340c0894b3eSJack Wang /* Reschedule work without sending hb */ 341c0894b3eSJack Wang schedule_hb(sess); 342c0894b3eSJack Wang return; 343c0894b3eSJack Wang } 344dc3b66a0SGioh Kim 345dc3b66a0SGioh Kim sess->hb_last_sent = ktime_get(); 346dc3b66a0SGioh Kim 347c0894b3eSJack Wang imm = rtrs_to_imm(RTRS_HB_MSG_IMM, 0); 348c0894b3eSJack Wang err = rtrs_post_rdma_write_imm_empty(usr_con, sess->hb_cqe, imm, 349b38041d5SJack Wang 0, NULL); 350c0894b3eSJack Wang if (err) { 351c0894b3eSJack Wang sess->hb_err_handler(usr_con); 352c0894b3eSJack Wang return; 353c0894b3eSJack Wang } 354c0894b3eSJack Wang 355c0894b3eSJack Wang schedule_hb(sess); 356c0894b3eSJack Wang } 357c0894b3eSJack Wang 358c0894b3eSJack Wang void rtrs_init_hb(struct rtrs_sess *sess, struct ib_cqe *cqe, 359c0894b3eSJack Wang unsigned int interval_ms, unsigned int missed_max, 360c0894b3eSJack Wang void (*err_handler)(struct rtrs_con *con), 361c0894b3eSJack Wang struct workqueue_struct *wq) 362c0894b3eSJack Wang { 363c0894b3eSJack Wang sess->hb_cqe = cqe; 364c0894b3eSJack Wang sess->hb_interval_ms = interval_ms; 365c0894b3eSJack Wang sess->hb_err_handler = err_handler; 366c0894b3eSJack Wang sess->hb_wq = wq; 367c0894b3eSJack Wang sess->hb_missed_max = missed_max; 368c0894b3eSJack Wang sess->hb_missed_cnt = 0; 369c0894b3eSJack Wang INIT_DELAYED_WORK(&sess->hb_dwork, hb_work); 370c0894b3eSJack Wang } 371c0894b3eSJack Wang EXPORT_SYMBOL_GPL(rtrs_init_hb); 372c0894b3eSJack Wang 373c0894b3eSJack Wang void rtrs_start_hb(struct rtrs_sess *sess) 374c0894b3eSJack Wang { 375c0894b3eSJack Wang schedule_hb(sess); 376c0894b3eSJack Wang } 377c0894b3eSJack Wang EXPORT_SYMBOL_GPL(rtrs_start_hb); 378c0894b3eSJack Wang 379c0894b3eSJack Wang void rtrs_stop_hb(struct rtrs_sess *sess) 380c0894b3eSJack Wang { 381c0894b3eSJack Wang cancel_delayed_work_sync(&sess->hb_dwork); 382c0894b3eSJack Wang sess->hb_missed_cnt = 0; 383c0894b3eSJack Wang } 384c0894b3eSJack Wang EXPORT_SYMBOL_GPL(rtrs_stop_hb); 385c0894b3eSJack Wang 386c0894b3eSJack Wang static int rtrs_str_gid_to_sockaddr(const char *addr, size_t len, 387c0894b3eSJack Wang short port, struct sockaddr_storage *dst) 388c0894b3eSJack Wang { 389c0894b3eSJack Wang struct sockaddr_ib *dst_ib = (struct sockaddr_ib *)dst; 390c0894b3eSJack Wang int ret; 391c0894b3eSJack Wang 392c0894b3eSJack Wang /* 393c0894b3eSJack Wang * We can use some of the IPv6 functions since GID is a valid 394c0894b3eSJack Wang * IPv6 address format 395c0894b3eSJack Wang */ 396c0894b3eSJack Wang ret = in6_pton(addr, len, dst_ib->sib_addr.sib_raw, '\0', NULL); 397c0894b3eSJack Wang if (ret == 0) 398c0894b3eSJack Wang return -EINVAL; 399c0894b3eSJack Wang 400c0894b3eSJack Wang dst_ib->sib_family = AF_IB; 401c0894b3eSJack Wang /* 402c0894b3eSJack Wang * Use the same TCP server port number as the IB service ID 403c0894b3eSJack Wang * on the IB port space range 404c0894b3eSJack Wang */ 405c0894b3eSJack Wang dst_ib->sib_sid = cpu_to_be64(RDMA_IB_IP_PS_IB | port); 406c0894b3eSJack Wang dst_ib->sib_sid_mask = cpu_to_be64(0xffffffffffffffffULL); 407c0894b3eSJack Wang dst_ib->sib_pkey = cpu_to_be16(0xffff); 408c0894b3eSJack Wang 409c0894b3eSJack Wang return 0; 410c0894b3eSJack Wang } 411c0894b3eSJack Wang 412c0894b3eSJack Wang /** 413c0894b3eSJack Wang * rtrs_str_to_sockaddr() - Convert rtrs address string to sockaddr 414c0894b3eSJack Wang * @addr: String representation of an addr (IPv4, IPv6 or IB GID): 415c0894b3eSJack Wang * - "ip:192.168.1.1" 416c0894b3eSJack Wang * - "ip:fe80::200:5aee:feaa:20a2" 417c0894b3eSJack Wang * - "gid:fe80::200:5aee:feaa:20a2" 418c0894b3eSJack Wang * @len: String address length 419c0894b3eSJack Wang * @port: Destination port 420c0894b3eSJack Wang * @dst: Destination sockaddr structure 421c0894b3eSJack Wang * 422c0894b3eSJack Wang * Returns 0 if conversion successful. Non-zero on error. 423c0894b3eSJack Wang */ 424c0894b3eSJack Wang static int rtrs_str_to_sockaddr(const char *addr, size_t len, 425c0894b3eSJack Wang u16 port, struct sockaddr_storage *dst) 426c0894b3eSJack Wang { 427c0894b3eSJack Wang if (strncmp(addr, "gid:", 4) == 0) { 428c0894b3eSJack Wang return rtrs_str_gid_to_sockaddr(addr + 4, len - 4, port, dst); 429c0894b3eSJack Wang } else if (strncmp(addr, "ip:", 3) == 0) { 430c0894b3eSJack Wang char port_str[8]; 431c0894b3eSJack Wang char *cpy; 432c0894b3eSJack Wang int err; 433c0894b3eSJack Wang 434c0894b3eSJack Wang snprintf(port_str, sizeof(port_str), "%u", port); 435c0894b3eSJack Wang cpy = kstrndup(addr + 3, len - 3, GFP_KERNEL); 436c0894b3eSJack Wang err = cpy ? inet_pton_with_scope(&init_net, AF_UNSPEC, 437c0894b3eSJack Wang cpy, port_str, dst) : -ENOMEM; 438c0894b3eSJack Wang kfree(cpy); 439c0894b3eSJack Wang 440c0894b3eSJack Wang return err; 441c0894b3eSJack Wang } 442c0894b3eSJack Wang return -EPROTONOSUPPORT; 443c0894b3eSJack Wang } 444c0894b3eSJack Wang 445c0894b3eSJack Wang /** 446c0894b3eSJack Wang * sockaddr_to_str() - convert sockaddr to a string. 447c0894b3eSJack Wang * @addr: the sockadddr structure to be converted. 448c0894b3eSJack Wang * @buf: string containing socket addr. 449c0894b3eSJack Wang * @len: string length. 450c0894b3eSJack Wang * 451c0894b3eSJack Wang * The return value is the number of characters written into buf not 452c0894b3eSJack Wang * including the trailing '\0'. If len is == 0 the function returns 0.. 453c0894b3eSJack Wang */ 454c0894b3eSJack Wang int sockaddr_to_str(const struct sockaddr *addr, char *buf, size_t len) 455c0894b3eSJack Wang { 456c0894b3eSJack Wang 457c0894b3eSJack Wang switch (addr->sa_family) { 458c0894b3eSJack Wang case AF_IB: 459c0894b3eSJack Wang return scnprintf(buf, len, "gid:%pI6", 460c0894b3eSJack Wang &((struct sockaddr_ib *)addr)->sib_addr.sib_raw); 461c0894b3eSJack Wang case AF_INET: 462c0894b3eSJack Wang return scnprintf(buf, len, "ip:%pI4", 463c0894b3eSJack Wang &((struct sockaddr_in *)addr)->sin_addr); 464c0894b3eSJack Wang case AF_INET6: 465c0894b3eSJack Wang return scnprintf(buf, len, "ip:%pI6c", 466c0894b3eSJack Wang &((struct sockaddr_in6 *)addr)->sin6_addr); 467c0894b3eSJack Wang } 468c0894b3eSJack Wang return scnprintf(buf, len, "<invalid address family>"); 469c0894b3eSJack Wang } 470c0894b3eSJack Wang EXPORT_SYMBOL(sockaddr_to_str); 471c0894b3eSJack Wang 472c0894b3eSJack Wang /** 4738e86499eSGioh Kim * rtrs_addr_to_str() - convert rtrs_addr to a string "src@dst" 4748e86499eSGioh Kim * @addr: the rtrs_addr structure to be converted 4758e86499eSGioh Kim * @buf: string containing source and destination addr of a path 4768e86499eSGioh Kim * separated by '@' I.e. "ip:1.1.1.1@ip:1.1.1.2" 4778e86499eSGioh Kim * "ip:1.1.1.1@ip:1.1.1.2". 4788e86499eSGioh Kim * @len: string length 4798e86499eSGioh Kim * 4808e86499eSGioh Kim * The return value is the number of characters written into buf not 4818e86499eSGioh Kim * including the trailing '\0'. 4828e86499eSGioh Kim */ 4838e86499eSGioh Kim int rtrs_addr_to_str(const struct rtrs_addr *addr, char *buf, size_t len) 4848e86499eSGioh Kim { 4858e86499eSGioh Kim int cnt; 4868e86499eSGioh Kim 4878e86499eSGioh Kim cnt = sockaddr_to_str((struct sockaddr *)addr->src, 4888e86499eSGioh Kim buf, len); 4898e86499eSGioh Kim cnt += scnprintf(buf + cnt, len - cnt, "@"); 4908e86499eSGioh Kim sockaddr_to_str((struct sockaddr *)addr->dst, 4918e86499eSGioh Kim buf + cnt, len - cnt); 4928e86499eSGioh Kim return cnt; 4938e86499eSGioh Kim } 4948e86499eSGioh Kim EXPORT_SYMBOL(rtrs_addr_to_str); 4958e86499eSGioh Kim 4968e86499eSGioh Kim /** 497c0894b3eSJack Wang * rtrs_addr_to_sockaddr() - convert path string "src,dst" or "src@dst" 498c0894b3eSJack Wang * to sockaddreses 499c0894b3eSJack Wang * @str: string containing source and destination addr of a path 500c0894b3eSJack Wang * separated by ',' or '@' I.e. "ip:1.1.1.1,ip:1.1.1.2" or 501c0894b3eSJack Wang * "ip:1.1.1.1@ip:1.1.1.2". If str contains only one address it's 502c0894b3eSJack Wang * considered to be destination. 503c0894b3eSJack Wang * @len: string length 504c0894b3eSJack Wang * @port: Destination port number. 505c0894b3eSJack Wang * @addr: will be set to the source/destination address or to NULL 506c0894b3eSJack Wang * if str doesn't contain any source address. 507c0894b3eSJack Wang * 508c0894b3eSJack Wang * Returns zero if conversion successful. Non-zero otherwise. 509c0894b3eSJack Wang */ 510c0894b3eSJack Wang int rtrs_addr_to_sockaddr(const char *str, size_t len, u16 port, 511c0894b3eSJack Wang struct rtrs_addr *addr) 512c0894b3eSJack Wang { 513c0894b3eSJack Wang const char *d; 514c0894b3eSJack Wang 515c0894b3eSJack Wang d = strchr(str, ','); 516c0894b3eSJack Wang if (!d) 517c0894b3eSJack Wang d = strchr(str, '@'); 518c0894b3eSJack Wang if (d) { 519c0894b3eSJack Wang if (rtrs_str_to_sockaddr(str, d - str, 0, addr->src)) 520c0894b3eSJack Wang return -EINVAL; 521c0894b3eSJack Wang d += 1; 522c0894b3eSJack Wang len -= d - str; 523c0894b3eSJack Wang str = d; 524c0894b3eSJack Wang 525c0894b3eSJack Wang } else { 526c0894b3eSJack Wang addr->src = NULL; 527c0894b3eSJack Wang } 528c0894b3eSJack Wang return rtrs_str_to_sockaddr(str, len, port, addr->dst); 529c0894b3eSJack Wang } 530c0894b3eSJack Wang EXPORT_SYMBOL(rtrs_addr_to_sockaddr); 531c0894b3eSJack Wang 532c0894b3eSJack Wang void rtrs_rdma_dev_pd_init(enum ib_pd_flags pd_flags, 533c0894b3eSJack Wang struct rtrs_rdma_dev_pd *pool) 534c0894b3eSJack Wang { 535c0894b3eSJack Wang WARN_ON(pool->ops && (!pool->ops->alloc ^ !pool->ops->free)); 536c0894b3eSJack Wang INIT_LIST_HEAD(&pool->list); 537c0894b3eSJack Wang mutex_init(&pool->mutex); 538c0894b3eSJack Wang pool->pd_flags = pd_flags; 539c0894b3eSJack Wang } 540c0894b3eSJack Wang EXPORT_SYMBOL(rtrs_rdma_dev_pd_init); 541c0894b3eSJack Wang 542c0894b3eSJack Wang void rtrs_rdma_dev_pd_deinit(struct rtrs_rdma_dev_pd *pool) 543c0894b3eSJack Wang { 544c0894b3eSJack Wang mutex_destroy(&pool->mutex); 545c0894b3eSJack Wang WARN_ON(!list_empty(&pool->list)); 546c0894b3eSJack Wang } 547c0894b3eSJack Wang EXPORT_SYMBOL(rtrs_rdma_dev_pd_deinit); 548c0894b3eSJack Wang 549c0894b3eSJack Wang static void dev_free(struct kref *ref) 550c0894b3eSJack Wang { 551c0894b3eSJack Wang struct rtrs_rdma_dev_pd *pool; 552c0894b3eSJack Wang struct rtrs_ib_dev *dev; 553c0894b3eSJack Wang 554c0894b3eSJack Wang dev = container_of(ref, typeof(*dev), ref); 555c0894b3eSJack Wang pool = dev->pool; 556c0894b3eSJack Wang 557c0894b3eSJack Wang mutex_lock(&pool->mutex); 558c0894b3eSJack Wang list_del(&dev->entry); 559c0894b3eSJack Wang mutex_unlock(&pool->mutex); 560c0894b3eSJack Wang 561c0894b3eSJack Wang if (pool->ops && pool->ops->deinit) 562c0894b3eSJack Wang pool->ops->deinit(dev); 563c0894b3eSJack Wang 564c0894b3eSJack Wang ib_dealloc_pd(dev->ib_pd); 565c0894b3eSJack Wang 566c0894b3eSJack Wang if (pool->ops && pool->ops->free) 567c0894b3eSJack Wang pool->ops->free(dev); 568c0894b3eSJack Wang else 569c0894b3eSJack Wang kfree(dev); 570c0894b3eSJack Wang } 571c0894b3eSJack Wang 572c0894b3eSJack Wang int rtrs_ib_dev_put(struct rtrs_ib_dev *dev) 573c0894b3eSJack Wang { 574c0894b3eSJack Wang return kref_put(&dev->ref, dev_free); 575c0894b3eSJack Wang } 576c0894b3eSJack Wang EXPORT_SYMBOL(rtrs_ib_dev_put); 577c0894b3eSJack Wang 578c0894b3eSJack Wang static int rtrs_ib_dev_get(struct rtrs_ib_dev *dev) 579c0894b3eSJack Wang { 580c0894b3eSJack Wang return kref_get_unless_zero(&dev->ref); 581c0894b3eSJack Wang } 582c0894b3eSJack Wang 583c0894b3eSJack Wang struct rtrs_ib_dev * 584c0894b3eSJack Wang rtrs_ib_dev_find_or_add(struct ib_device *ib_dev, 585c0894b3eSJack Wang struct rtrs_rdma_dev_pd *pool) 586c0894b3eSJack Wang { 587c0894b3eSJack Wang struct rtrs_ib_dev *dev; 588c0894b3eSJack Wang 589c0894b3eSJack Wang mutex_lock(&pool->mutex); 590c0894b3eSJack Wang list_for_each_entry(dev, &pool->list, entry) { 591c0894b3eSJack Wang if (dev->ib_dev->node_guid == ib_dev->node_guid && 592c0894b3eSJack Wang rtrs_ib_dev_get(dev)) 593c0894b3eSJack Wang goto out_unlock; 594c0894b3eSJack Wang } 595c0894b3eSJack Wang mutex_unlock(&pool->mutex); 596c0894b3eSJack Wang if (pool->ops && pool->ops->alloc) 597c0894b3eSJack Wang dev = pool->ops->alloc(); 598c0894b3eSJack Wang else 599c0894b3eSJack Wang dev = kzalloc(sizeof(*dev), GFP_KERNEL); 600c0894b3eSJack Wang if (IS_ERR_OR_NULL(dev)) 601c0894b3eSJack Wang goto out_err; 602c0894b3eSJack Wang 603c0894b3eSJack Wang kref_init(&dev->ref); 604c0894b3eSJack Wang dev->pool = pool; 605c0894b3eSJack Wang dev->ib_dev = ib_dev; 606c0894b3eSJack Wang dev->ib_pd = ib_alloc_pd(ib_dev, pool->pd_flags); 607c0894b3eSJack Wang if (IS_ERR(dev->ib_pd)) 608c0894b3eSJack Wang goto out_free_dev; 609c0894b3eSJack Wang 610c0894b3eSJack Wang if (pool->ops && pool->ops->init && pool->ops->init(dev)) 611c0894b3eSJack Wang goto out_free_pd; 612c0894b3eSJack Wang 613c0894b3eSJack Wang mutex_lock(&pool->mutex); 614c0894b3eSJack Wang list_add(&dev->entry, &pool->list); 615c0894b3eSJack Wang out_unlock: 616c0894b3eSJack Wang mutex_unlock(&pool->mutex); 617c0894b3eSJack Wang return dev; 618c0894b3eSJack Wang 619c0894b3eSJack Wang out_free_pd: 620c0894b3eSJack Wang ib_dealloc_pd(dev->ib_pd); 621c0894b3eSJack Wang out_free_dev: 622c0894b3eSJack Wang if (pool->ops && pool->ops->free) 623c0894b3eSJack Wang pool->ops->free(dev); 624c0894b3eSJack Wang else 625c0894b3eSJack Wang kfree(dev); 626c0894b3eSJack Wang out_err: 627c0894b3eSJack Wang return NULL; 628c0894b3eSJack Wang } 629c0894b3eSJack Wang EXPORT_SYMBOL(rtrs_ib_dev_find_or_add); 630