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 21c0894b3eSJack Wang struct rtrs_iu *rtrs_iu_alloc(u32 queue_size, 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 29c0894b3eSJack Wang ius = kcalloc(queue_size, sizeof(*ius), gfp_mask); 30c0894b3eSJack Wang if (!ius) 31c0894b3eSJack Wang return NULL; 32c0894b3eSJack Wang for (i = 0; i < queue_size; 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 538bd372acSGioh Kim void rtrs_iu_free(struct rtrs_iu *ius, struct ib_device *ibdev, u32 queue_size) 54c0894b3eSJack Wang { 55c0894b3eSJack Wang struct rtrs_iu *iu; 56c0894b3eSJack Wang int i; 57c0894b3eSJack Wang 58c0894b3eSJack Wang if (!ius) 59c0894b3eSJack Wang return; 60c0894b3eSJack Wang 61c0894b3eSJack Wang for (i = 0; i < queue_size; 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, 108e6ab8cf5SGuoqing Jiang struct ib_send_wr *wr) 109e6ab8cf5SGuoqing Jiang { 110e6ab8cf5SGuoqing Jiang if (head) { 111e6ab8cf5SGuoqing Jiang struct ib_send_wr *tail = head; 112e6ab8cf5SGuoqing Jiang 113e6ab8cf5SGuoqing Jiang while (tail->next) 114e6ab8cf5SGuoqing Jiang tail = tail->next; 115e6ab8cf5SGuoqing Jiang tail->next = wr; 116e6ab8cf5SGuoqing Jiang } else { 117e6ab8cf5SGuoqing Jiang head = wr; 118e6ab8cf5SGuoqing Jiang } 119e6ab8cf5SGuoqing Jiang 120e6ab8cf5SGuoqing Jiang return ib_post_send(qp, head, NULL); 121e6ab8cf5SGuoqing Jiang } 122e6ab8cf5SGuoqing Jiang 123c0894b3eSJack Wang int rtrs_iu_post_send(struct rtrs_con *con, struct rtrs_iu *iu, size_t size, 124c0894b3eSJack Wang struct ib_send_wr *head) 125c0894b3eSJack Wang { 126c0894b3eSJack Wang struct rtrs_sess *sess = con->sess; 127c0894b3eSJack Wang struct ib_send_wr wr; 128c0894b3eSJack Wang struct ib_sge list; 129c0894b3eSJack Wang 130c0894b3eSJack Wang if (WARN_ON(size == 0)) 131c0894b3eSJack Wang return -EINVAL; 132c0894b3eSJack Wang 133c0894b3eSJack Wang list.addr = iu->dma_addr; 134c0894b3eSJack Wang list.length = size; 135c0894b3eSJack Wang list.lkey = sess->dev->ib_pd->local_dma_lkey; 136c0894b3eSJack Wang 137c0894b3eSJack Wang wr = (struct ib_send_wr) { 138c0894b3eSJack Wang .wr_cqe = &iu->cqe, 139c0894b3eSJack Wang .sg_list = &list, 140c0894b3eSJack Wang .num_sge = 1, 141c0894b3eSJack Wang .opcode = IB_WR_SEND, 142c0894b3eSJack Wang .send_flags = IB_SEND_SIGNALED, 143c0894b3eSJack Wang }; 144c0894b3eSJack Wang 145e6ab8cf5SGuoqing Jiang return rtrs_post_send(con->qp, head, &wr); 146c0894b3eSJack Wang } 147c0894b3eSJack Wang EXPORT_SYMBOL_GPL(rtrs_iu_post_send); 148c0894b3eSJack Wang 149c0894b3eSJack Wang int rtrs_iu_post_rdma_write_imm(struct rtrs_con *con, struct rtrs_iu *iu, 150c0894b3eSJack Wang struct ib_sge *sge, unsigned int num_sge, 151c0894b3eSJack Wang u32 rkey, u64 rdma_addr, u32 imm_data, 152c0894b3eSJack Wang enum ib_send_flags flags, 153c0894b3eSJack Wang struct ib_send_wr *head) 154c0894b3eSJack Wang { 155c0894b3eSJack Wang struct ib_rdma_wr wr; 156c0894b3eSJack Wang int i; 157c0894b3eSJack Wang 158c0894b3eSJack Wang wr = (struct ib_rdma_wr) { 159c0894b3eSJack Wang .wr.wr_cqe = &iu->cqe, 160c0894b3eSJack Wang .wr.sg_list = sge, 161c0894b3eSJack Wang .wr.num_sge = num_sge, 162c0894b3eSJack Wang .rkey = rkey, 163c0894b3eSJack Wang .remote_addr = rdma_addr, 164c0894b3eSJack Wang .wr.opcode = IB_WR_RDMA_WRITE_WITH_IMM, 165c0894b3eSJack Wang .wr.ex.imm_data = cpu_to_be32(imm_data), 166c0894b3eSJack Wang .wr.send_flags = flags, 167c0894b3eSJack Wang }; 168c0894b3eSJack Wang 169c0894b3eSJack Wang /* 170c0894b3eSJack Wang * If one of the sges has 0 size, the operation will fail with a 171c0894b3eSJack Wang * length error 172c0894b3eSJack Wang */ 173c0894b3eSJack Wang for (i = 0; i < num_sge; i++) 174c0894b3eSJack Wang if (WARN_ON(sge[i].length == 0)) 175c0894b3eSJack Wang return -EINVAL; 176c0894b3eSJack Wang 177e6ab8cf5SGuoqing Jiang return rtrs_post_send(con->qp, head, &wr.wr); 178c0894b3eSJack Wang } 179c0894b3eSJack Wang EXPORT_SYMBOL_GPL(rtrs_iu_post_rdma_write_imm); 180c0894b3eSJack Wang 181c0894b3eSJack Wang int rtrs_post_rdma_write_imm_empty(struct rtrs_con *con, struct ib_cqe *cqe, 182c0894b3eSJack Wang u32 imm_data, enum ib_send_flags flags, 183c0894b3eSJack Wang struct ib_send_wr *head) 184c0894b3eSJack Wang { 185c0894b3eSJack Wang struct ib_send_wr wr; 186c0894b3eSJack Wang 187c0894b3eSJack Wang wr = (struct ib_send_wr) { 188c0894b3eSJack Wang .wr_cqe = cqe, 189c0894b3eSJack Wang .send_flags = flags, 190c0894b3eSJack Wang .opcode = IB_WR_RDMA_WRITE_WITH_IMM, 191c0894b3eSJack Wang .ex.imm_data = cpu_to_be32(imm_data), 192c0894b3eSJack Wang }; 193c0894b3eSJack Wang 194e6ab8cf5SGuoqing Jiang return rtrs_post_send(con->qp, head, &wr); 195c0894b3eSJack Wang } 196c0894b3eSJack Wang EXPORT_SYMBOL_GPL(rtrs_post_rdma_write_imm_empty); 197c0894b3eSJack Wang 198c0894b3eSJack Wang static void qp_event_handler(struct ib_event *ev, void *ctx) 199c0894b3eSJack Wang { 200c0894b3eSJack Wang struct rtrs_con *con = ctx; 201c0894b3eSJack Wang 202c0894b3eSJack Wang switch (ev->event) { 203c0894b3eSJack Wang case IB_EVENT_COMM_EST: 204c0894b3eSJack Wang rtrs_info(con->sess, "QP event %s (%d) received\n", 205c0894b3eSJack Wang ib_event_msg(ev->event), ev->event); 206c0894b3eSJack Wang rdma_notify(con->cm_id, IB_EVENT_COMM_EST); 207c0894b3eSJack Wang break; 208c0894b3eSJack Wang default: 209c0894b3eSJack Wang rtrs_info(con->sess, "Unhandled QP event %s (%d) received\n", 210c0894b3eSJack Wang ib_event_msg(ev->event), ev->event); 211c0894b3eSJack Wang break; 212c0894b3eSJack Wang } 213c0894b3eSJack Wang } 214c0894b3eSJack Wang 215c0894b3eSJack Wang static int create_cq(struct rtrs_con *con, int cq_vector, u16 cq_size, 216c0894b3eSJack Wang enum ib_poll_context poll_ctx) 217c0894b3eSJack Wang { 218c0894b3eSJack Wang struct rdma_cm_id *cm_id = con->cm_id; 219c0894b3eSJack Wang struct ib_cq *cq; 220c0894b3eSJack Wang 221c0894b3eSJack Wang cq = ib_alloc_cq(cm_id->device, con, cq_size, 222c0894b3eSJack Wang cq_vector, poll_ctx); 223c0894b3eSJack Wang if (IS_ERR(cq)) { 224c0894b3eSJack Wang rtrs_err(con->sess, "Creating completion queue failed, errno: %ld\n", 225c0894b3eSJack Wang PTR_ERR(cq)); 226c0894b3eSJack Wang return PTR_ERR(cq); 227c0894b3eSJack Wang } 228c0894b3eSJack Wang con->cq = cq; 229c0894b3eSJack Wang 230c0894b3eSJack Wang return 0; 231c0894b3eSJack Wang } 232c0894b3eSJack Wang 233c0894b3eSJack Wang static int create_qp(struct rtrs_con *con, struct ib_pd *pd, 2347490fd1fSJack Wang u32 max_send_wr, u32 max_recv_wr, u32 max_sge) 235c0894b3eSJack Wang { 236c0894b3eSJack Wang struct ib_qp_init_attr init_attr = {NULL}; 237c0894b3eSJack Wang struct rdma_cm_id *cm_id = con->cm_id; 238c0894b3eSJack Wang int ret; 239c0894b3eSJack Wang 2407490fd1fSJack Wang init_attr.cap.max_send_wr = max_send_wr; 2417490fd1fSJack Wang init_attr.cap.max_recv_wr = max_recv_wr; 242c0894b3eSJack Wang init_attr.cap.max_recv_sge = 1; 243c0894b3eSJack Wang init_attr.event_handler = qp_event_handler; 244c0894b3eSJack Wang init_attr.qp_context = con; 245c0894b3eSJack Wang init_attr.cap.max_send_sge = max_sge; 246c0894b3eSJack Wang 247c0894b3eSJack Wang init_attr.qp_type = IB_QPT_RC; 248c0894b3eSJack Wang init_attr.send_cq = con->cq; 249c0894b3eSJack Wang init_attr.recv_cq = con->cq; 250c0894b3eSJack Wang init_attr.sq_sig_type = IB_SIGNAL_REQ_WR; 251c0894b3eSJack Wang 252c0894b3eSJack Wang ret = rdma_create_qp(cm_id, pd, &init_attr); 253c0894b3eSJack Wang if (ret) { 254c0894b3eSJack Wang rtrs_err(con->sess, "Creating QP failed, err: %d\n", ret); 255c0894b3eSJack Wang return ret; 256c0894b3eSJack Wang } 257c0894b3eSJack Wang con->qp = cm_id->qp; 258c0894b3eSJack Wang 259c0894b3eSJack Wang return ret; 260c0894b3eSJack Wang } 261c0894b3eSJack Wang 262c0894b3eSJack Wang int rtrs_cq_qp_create(struct rtrs_sess *sess, struct rtrs_con *con, 2637490fd1fSJack Wang u32 max_send_sge, int cq_vector, int cq_size, 2647490fd1fSJack Wang u32 max_send_wr, u32 max_recv_wr, 2657490fd1fSJack Wang enum ib_poll_context poll_ctx) 266c0894b3eSJack Wang { 267c0894b3eSJack Wang int err; 268c0894b3eSJack Wang 269c0894b3eSJack Wang err = create_cq(con, cq_vector, cq_size, poll_ctx); 270c0894b3eSJack Wang if (err) 271c0894b3eSJack Wang return err; 272c0894b3eSJack Wang 2737490fd1fSJack Wang err = create_qp(con, sess->dev->ib_pd, max_send_wr, max_recv_wr, 2747490fd1fSJack Wang max_send_sge); 275c0894b3eSJack Wang if (err) { 276c0894b3eSJack Wang ib_free_cq(con->cq); 277c0894b3eSJack Wang con->cq = NULL; 278c0894b3eSJack Wang return err; 279c0894b3eSJack Wang } 280c0894b3eSJack Wang con->sess = sess; 281c0894b3eSJack Wang 282c0894b3eSJack Wang return 0; 283c0894b3eSJack Wang } 284c0894b3eSJack Wang EXPORT_SYMBOL_GPL(rtrs_cq_qp_create); 285c0894b3eSJack Wang 286c0894b3eSJack Wang void rtrs_cq_qp_destroy(struct rtrs_con *con) 287c0894b3eSJack Wang { 288c0894b3eSJack Wang if (con->qp) { 289c0894b3eSJack Wang rdma_destroy_qp(con->cm_id); 290c0894b3eSJack Wang con->qp = NULL; 291c0894b3eSJack Wang } 292c0894b3eSJack Wang if (con->cq) { 293c0894b3eSJack Wang ib_free_cq(con->cq); 294c0894b3eSJack Wang con->cq = NULL; 295c0894b3eSJack Wang } 296c0894b3eSJack Wang } 297c0894b3eSJack Wang EXPORT_SYMBOL_GPL(rtrs_cq_qp_destroy); 298c0894b3eSJack Wang 299c0894b3eSJack Wang static void schedule_hb(struct rtrs_sess *sess) 300c0894b3eSJack Wang { 301c0894b3eSJack Wang queue_delayed_work(sess->hb_wq, &sess->hb_dwork, 302c0894b3eSJack Wang msecs_to_jiffies(sess->hb_interval_ms)); 303c0894b3eSJack Wang } 304c0894b3eSJack Wang 305c0894b3eSJack Wang void rtrs_send_hb_ack(struct rtrs_sess *sess) 306c0894b3eSJack Wang { 307c0894b3eSJack Wang struct rtrs_con *usr_con = sess->con[0]; 308c0894b3eSJack Wang u32 imm; 309c0894b3eSJack Wang int err; 310c0894b3eSJack Wang 311c0894b3eSJack Wang imm = rtrs_to_imm(RTRS_HB_ACK_IMM, 0); 312c0894b3eSJack Wang err = rtrs_post_rdma_write_imm_empty(usr_con, sess->hb_cqe, imm, 313*b38041d5SJack Wang 0, NULL); 314c0894b3eSJack Wang if (err) { 315c0894b3eSJack Wang sess->hb_err_handler(usr_con); 316c0894b3eSJack Wang return; 317c0894b3eSJack Wang } 318c0894b3eSJack Wang } 319c0894b3eSJack Wang EXPORT_SYMBOL_GPL(rtrs_send_hb_ack); 320c0894b3eSJack Wang 321c0894b3eSJack Wang static void hb_work(struct work_struct *work) 322c0894b3eSJack Wang { 323c0894b3eSJack Wang struct rtrs_con *usr_con; 324c0894b3eSJack Wang struct rtrs_sess *sess; 325c0894b3eSJack Wang u32 imm; 326c0894b3eSJack Wang int err; 327c0894b3eSJack Wang 328c0894b3eSJack Wang sess = container_of(to_delayed_work(work), typeof(*sess), hb_dwork); 329c0894b3eSJack Wang usr_con = sess->con[0]; 330c0894b3eSJack Wang 331c0894b3eSJack Wang if (sess->hb_missed_cnt > sess->hb_missed_max) { 332c0894b3eSJack Wang sess->hb_err_handler(usr_con); 333c0894b3eSJack Wang return; 334c0894b3eSJack Wang } 335c0894b3eSJack Wang if (sess->hb_missed_cnt++) { 336c0894b3eSJack Wang /* Reschedule work without sending hb */ 337c0894b3eSJack Wang schedule_hb(sess); 338c0894b3eSJack Wang return; 339c0894b3eSJack Wang } 340c0894b3eSJack Wang imm = rtrs_to_imm(RTRS_HB_MSG_IMM, 0); 341c0894b3eSJack Wang err = rtrs_post_rdma_write_imm_empty(usr_con, sess->hb_cqe, imm, 342*b38041d5SJack Wang 0, NULL); 343c0894b3eSJack Wang if (err) { 344c0894b3eSJack Wang sess->hb_err_handler(usr_con); 345c0894b3eSJack Wang return; 346c0894b3eSJack Wang } 347c0894b3eSJack Wang 348c0894b3eSJack Wang schedule_hb(sess); 349c0894b3eSJack Wang } 350c0894b3eSJack Wang 351c0894b3eSJack Wang void rtrs_init_hb(struct rtrs_sess *sess, struct ib_cqe *cqe, 352c0894b3eSJack Wang unsigned int interval_ms, unsigned int missed_max, 353c0894b3eSJack Wang void (*err_handler)(struct rtrs_con *con), 354c0894b3eSJack Wang struct workqueue_struct *wq) 355c0894b3eSJack Wang { 356c0894b3eSJack Wang sess->hb_cqe = cqe; 357c0894b3eSJack Wang sess->hb_interval_ms = interval_ms; 358c0894b3eSJack Wang sess->hb_err_handler = err_handler; 359c0894b3eSJack Wang sess->hb_wq = wq; 360c0894b3eSJack Wang sess->hb_missed_max = missed_max; 361c0894b3eSJack Wang sess->hb_missed_cnt = 0; 362c0894b3eSJack Wang INIT_DELAYED_WORK(&sess->hb_dwork, hb_work); 363c0894b3eSJack Wang } 364c0894b3eSJack Wang EXPORT_SYMBOL_GPL(rtrs_init_hb); 365c0894b3eSJack Wang 366c0894b3eSJack Wang void rtrs_start_hb(struct rtrs_sess *sess) 367c0894b3eSJack Wang { 368c0894b3eSJack Wang schedule_hb(sess); 369c0894b3eSJack Wang } 370c0894b3eSJack Wang EXPORT_SYMBOL_GPL(rtrs_start_hb); 371c0894b3eSJack Wang 372c0894b3eSJack Wang void rtrs_stop_hb(struct rtrs_sess *sess) 373c0894b3eSJack Wang { 374c0894b3eSJack Wang cancel_delayed_work_sync(&sess->hb_dwork); 375c0894b3eSJack Wang sess->hb_missed_cnt = 0; 376c0894b3eSJack Wang sess->hb_missed_max = 0; 377c0894b3eSJack Wang } 378c0894b3eSJack Wang EXPORT_SYMBOL_GPL(rtrs_stop_hb); 379c0894b3eSJack Wang 380c0894b3eSJack Wang static int rtrs_str_gid_to_sockaddr(const char *addr, size_t len, 381c0894b3eSJack Wang short port, struct sockaddr_storage *dst) 382c0894b3eSJack Wang { 383c0894b3eSJack Wang struct sockaddr_ib *dst_ib = (struct sockaddr_ib *)dst; 384c0894b3eSJack Wang int ret; 385c0894b3eSJack Wang 386c0894b3eSJack Wang /* 387c0894b3eSJack Wang * We can use some of the IPv6 functions since GID is a valid 388c0894b3eSJack Wang * IPv6 address format 389c0894b3eSJack Wang */ 390c0894b3eSJack Wang ret = in6_pton(addr, len, dst_ib->sib_addr.sib_raw, '\0', NULL); 391c0894b3eSJack Wang if (ret == 0) 392c0894b3eSJack Wang return -EINVAL; 393c0894b3eSJack Wang 394c0894b3eSJack Wang dst_ib->sib_family = AF_IB; 395c0894b3eSJack Wang /* 396c0894b3eSJack Wang * Use the same TCP server port number as the IB service ID 397c0894b3eSJack Wang * on the IB port space range 398c0894b3eSJack Wang */ 399c0894b3eSJack Wang dst_ib->sib_sid = cpu_to_be64(RDMA_IB_IP_PS_IB | port); 400c0894b3eSJack Wang dst_ib->sib_sid_mask = cpu_to_be64(0xffffffffffffffffULL); 401c0894b3eSJack Wang dst_ib->sib_pkey = cpu_to_be16(0xffff); 402c0894b3eSJack Wang 403c0894b3eSJack Wang return 0; 404c0894b3eSJack Wang } 405c0894b3eSJack Wang 406c0894b3eSJack Wang /** 407c0894b3eSJack Wang * rtrs_str_to_sockaddr() - Convert rtrs address string to sockaddr 408c0894b3eSJack Wang * @addr: String representation of an addr (IPv4, IPv6 or IB GID): 409c0894b3eSJack Wang * - "ip:192.168.1.1" 410c0894b3eSJack Wang * - "ip:fe80::200:5aee:feaa:20a2" 411c0894b3eSJack Wang * - "gid:fe80::200:5aee:feaa:20a2" 412c0894b3eSJack Wang * @len: String address length 413c0894b3eSJack Wang * @port: Destination port 414c0894b3eSJack Wang * @dst: Destination sockaddr structure 415c0894b3eSJack Wang * 416c0894b3eSJack Wang * Returns 0 if conversion successful. Non-zero on error. 417c0894b3eSJack Wang */ 418c0894b3eSJack Wang static int rtrs_str_to_sockaddr(const char *addr, size_t len, 419c0894b3eSJack Wang u16 port, struct sockaddr_storage *dst) 420c0894b3eSJack Wang { 421c0894b3eSJack Wang if (strncmp(addr, "gid:", 4) == 0) { 422c0894b3eSJack Wang return rtrs_str_gid_to_sockaddr(addr + 4, len - 4, port, dst); 423c0894b3eSJack Wang } else if (strncmp(addr, "ip:", 3) == 0) { 424c0894b3eSJack Wang char port_str[8]; 425c0894b3eSJack Wang char *cpy; 426c0894b3eSJack Wang int err; 427c0894b3eSJack Wang 428c0894b3eSJack Wang snprintf(port_str, sizeof(port_str), "%u", port); 429c0894b3eSJack Wang cpy = kstrndup(addr + 3, len - 3, GFP_KERNEL); 430c0894b3eSJack Wang err = cpy ? inet_pton_with_scope(&init_net, AF_UNSPEC, 431c0894b3eSJack Wang cpy, port_str, dst) : -ENOMEM; 432c0894b3eSJack Wang kfree(cpy); 433c0894b3eSJack Wang 434c0894b3eSJack Wang return err; 435c0894b3eSJack Wang } 436c0894b3eSJack Wang return -EPROTONOSUPPORT; 437c0894b3eSJack Wang } 438c0894b3eSJack Wang 439c0894b3eSJack Wang /** 440c0894b3eSJack Wang * sockaddr_to_str() - convert sockaddr to a string. 441c0894b3eSJack Wang * @addr: the sockadddr structure to be converted. 442c0894b3eSJack Wang * @buf: string containing socket addr. 443c0894b3eSJack Wang * @len: string length. 444c0894b3eSJack Wang * 445c0894b3eSJack Wang * The return value is the number of characters written into buf not 446c0894b3eSJack Wang * including the trailing '\0'. If len is == 0 the function returns 0.. 447c0894b3eSJack Wang */ 448c0894b3eSJack Wang int sockaddr_to_str(const struct sockaddr *addr, char *buf, size_t len) 449c0894b3eSJack Wang { 450c0894b3eSJack Wang 451c0894b3eSJack Wang switch (addr->sa_family) { 452c0894b3eSJack Wang case AF_IB: 453c0894b3eSJack Wang return scnprintf(buf, len, "gid:%pI6", 454c0894b3eSJack Wang &((struct sockaddr_ib *)addr)->sib_addr.sib_raw); 455c0894b3eSJack Wang case AF_INET: 456c0894b3eSJack Wang return scnprintf(buf, len, "ip:%pI4", 457c0894b3eSJack Wang &((struct sockaddr_in *)addr)->sin_addr); 458c0894b3eSJack Wang case AF_INET6: 459c0894b3eSJack Wang return scnprintf(buf, len, "ip:%pI6c", 460c0894b3eSJack Wang &((struct sockaddr_in6 *)addr)->sin6_addr); 461c0894b3eSJack Wang } 462c0894b3eSJack Wang return scnprintf(buf, len, "<invalid address family>"); 463c0894b3eSJack Wang } 464c0894b3eSJack Wang EXPORT_SYMBOL(sockaddr_to_str); 465c0894b3eSJack Wang 466c0894b3eSJack Wang /** 467c0894b3eSJack Wang * rtrs_addr_to_sockaddr() - convert path string "src,dst" or "src@dst" 468c0894b3eSJack Wang * to sockaddreses 469c0894b3eSJack Wang * @str: string containing source and destination addr of a path 470c0894b3eSJack Wang * separated by ',' or '@' I.e. "ip:1.1.1.1,ip:1.1.1.2" or 471c0894b3eSJack Wang * "ip:1.1.1.1@ip:1.1.1.2". If str contains only one address it's 472c0894b3eSJack Wang * considered to be destination. 473c0894b3eSJack Wang * @len: string length 474c0894b3eSJack Wang * @port: Destination port number. 475c0894b3eSJack Wang * @addr: will be set to the source/destination address or to NULL 476c0894b3eSJack Wang * if str doesn't contain any source address. 477c0894b3eSJack Wang * 478c0894b3eSJack Wang * Returns zero if conversion successful. Non-zero otherwise. 479c0894b3eSJack Wang */ 480c0894b3eSJack Wang int rtrs_addr_to_sockaddr(const char *str, size_t len, u16 port, 481c0894b3eSJack Wang struct rtrs_addr *addr) 482c0894b3eSJack Wang { 483c0894b3eSJack Wang const char *d; 484c0894b3eSJack Wang 485c0894b3eSJack Wang d = strchr(str, ','); 486c0894b3eSJack Wang if (!d) 487c0894b3eSJack Wang d = strchr(str, '@'); 488c0894b3eSJack Wang if (d) { 489c0894b3eSJack Wang if (rtrs_str_to_sockaddr(str, d - str, 0, addr->src)) 490c0894b3eSJack Wang return -EINVAL; 491c0894b3eSJack Wang d += 1; 492c0894b3eSJack Wang len -= d - str; 493c0894b3eSJack Wang str = d; 494c0894b3eSJack Wang 495c0894b3eSJack Wang } else { 496c0894b3eSJack Wang addr->src = NULL; 497c0894b3eSJack Wang } 498c0894b3eSJack Wang return rtrs_str_to_sockaddr(str, len, port, addr->dst); 499c0894b3eSJack Wang } 500c0894b3eSJack Wang EXPORT_SYMBOL(rtrs_addr_to_sockaddr); 501c0894b3eSJack Wang 502c0894b3eSJack Wang void rtrs_rdma_dev_pd_init(enum ib_pd_flags pd_flags, 503c0894b3eSJack Wang struct rtrs_rdma_dev_pd *pool) 504c0894b3eSJack Wang { 505c0894b3eSJack Wang WARN_ON(pool->ops && (!pool->ops->alloc ^ !pool->ops->free)); 506c0894b3eSJack Wang INIT_LIST_HEAD(&pool->list); 507c0894b3eSJack Wang mutex_init(&pool->mutex); 508c0894b3eSJack Wang pool->pd_flags = pd_flags; 509c0894b3eSJack Wang } 510c0894b3eSJack Wang EXPORT_SYMBOL(rtrs_rdma_dev_pd_init); 511c0894b3eSJack Wang 512c0894b3eSJack Wang void rtrs_rdma_dev_pd_deinit(struct rtrs_rdma_dev_pd *pool) 513c0894b3eSJack Wang { 514c0894b3eSJack Wang mutex_destroy(&pool->mutex); 515c0894b3eSJack Wang WARN_ON(!list_empty(&pool->list)); 516c0894b3eSJack Wang } 517c0894b3eSJack Wang EXPORT_SYMBOL(rtrs_rdma_dev_pd_deinit); 518c0894b3eSJack Wang 519c0894b3eSJack Wang static void dev_free(struct kref *ref) 520c0894b3eSJack Wang { 521c0894b3eSJack Wang struct rtrs_rdma_dev_pd *pool; 522c0894b3eSJack Wang struct rtrs_ib_dev *dev; 523c0894b3eSJack Wang 524c0894b3eSJack Wang dev = container_of(ref, typeof(*dev), ref); 525c0894b3eSJack Wang pool = dev->pool; 526c0894b3eSJack Wang 527c0894b3eSJack Wang mutex_lock(&pool->mutex); 528c0894b3eSJack Wang list_del(&dev->entry); 529c0894b3eSJack Wang mutex_unlock(&pool->mutex); 530c0894b3eSJack Wang 531c0894b3eSJack Wang if (pool->ops && pool->ops->deinit) 532c0894b3eSJack Wang pool->ops->deinit(dev); 533c0894b3eSJack Wang 534c0894b3eSJack Wang ib_dealloc_pd(dev->ib_pd); 535c0894b3eSJack Wang 536c0894b3eSJack Wang if (pool->ops && pool->ops->free) 537c0894b3eSJack Wang pool->ops->free(dev); 538c0894b3eSJack Wang else 539c0894b3eSJack Wang kfree(dev); 540c0894b3eSJack Wang } 541c0894b3eSJack Wang 542c0894b3eSJack Wang int rtrs_ib_dev_put(struct rtrs_ib_dev *dev) 543c0894b3eSJack Wang { 544c0894b3eSJack Wang return kref_put(&dev->ref, dev_free); 545c0894b3eSJack Wang } 546c0894b3eSJack Wang EXPORT_SYMBOL(rtrs_ib_dev_put); 547c0894b3eSJack Wang 548c0894b3eSJack Wang static int rtrs_ib_dev_get(struct rtrs_ib_dev *dev) 549c0894b3eSJack Wang { 550c0894b3eSJack Wang return kref_get_unless_zero(&dev->ref); 551c0894b3eSJack Wang } 552c0894b3eSJack Wang 553c0894b3eSJack Wang struct rtrs_ib_dev * 554c0894b3eSJack Wang rtrs_ib_dev_find_or_add(struct ib_device *ib_dev, 555c0894b3eSJack Wang struct rtrs_rdma_dev_pd *pool) 556c0894b3eSJack Wang { 557c0894b3eSJack Wang struct rtrs_ib_dev *dev; 558c0894b3eSJack Wang 559c0894b3eSJack Wang mutex_lock(&pool->mutex); 560c0894b3eSJack Wang list_for_each_entry(dev, &pool->list, entry) { 561c0894b3eSJack Wang if (dev->ib_dev->node_guid == ib_dev->node_guid && 562c0894b3eSJack Wang rtrs_ib_dev_get(dev)) 563c0894b3eSJack Wang goto out_unlock; 564c0894b3eSJack Wang } 565c0894b3eSJack Wang mutex_unlock(&pool->mutex); 566c0894b3eSJack Wang if (pool->ops && pool->ops->alloc) 567c0894b3eSJack Wang dev = pool->ops->alloc(); 568c0894b3eSJack Wang else 569c0894b3eSJack Wang dev = kzalloc(sizeof(*dev), GFP_KERNEL); 570c0894b3eSJack Wang if (IS_ERR_OR_NULL(dev)) 571c0894b3eSJack Wang goto out_err; 572c0894b3eSJack Wang 573c0894b3eSJack Wang kref_init(&dev->ref); 574c0894b3eSJack Wang dev->pool = pool; 575c0894b3eSJack Wang dev->ib_dev = ib_dev; 576c0894b3eSJack Wang dev->ib_pd = ib_alloc_pd(ib_dev, pool->pd_flags); 577c0894b3eSJack Wang if (IS_ERR(dev->ib_pd)) 578c0894b3eSJack Wang goto out_free_dev; 579c0894b3eSJack Wang 580c0894b3eSJack Wang if (pool->ops && pool->ops->init && pool->ops->init(dev)) 581c0894b3eSJack Wang goto out_free_pd; 582c0894b3eSJack Wang 583c0894b3eSJack Wang mutex_lock(&pool->mutex); 584c0894b3eSJack Wang list_add(&dev->entry, &pool->list); 585c0894b3eSJack Wang out_unlock: 586c0894b3eSJack Wang mutex_unlock(&pool->mutex); 587c0894b3eSJack Wang return dev; 588c0894b3eSJack Wang 589c0894b3eSJack Wang out_free_pd: 590c0894b3eSJack Wang ib_dealloc_pd(dev->ib_pd); 591c0894b3eSJack Wang out_free_dev: 592c0894b3eSJack Wang if (pool->ops && pool->ops->free) 593c0894b3eSJack Wang pool->ops->free(dev); 594c0894b3eSJack Wang else 595c0894b3eSJack Wang kfree(dev); 596c0894b3eSJack Wang out_err: 597c0894b3eSJack Wang return NULL; 598c0894b3eSJack Wang } 599c0894b3eSJack Wang EXPORT_SYMBOL(rtrs_ib_dev_find_or_add); 600