1/*
2 * Copyright (c) 2005-2009 Intel Corporation.  All rights reserved.
3 *
4 * This software is available to you under the OpenIB.org BSD license
5 * below:
6 *
7 *     Redistribution and use in source and binary forms, with or
8 *     without modification, are permitted provided that the following
9 *     conditions are met:
10 *
11 *      - Redistributions of source code must retain the above
12 *        copyright notice, this list of conditions and the following
13 *        disclaimer.
14 *
15 *      - Redistributions in binary form must reproduce the above
16 *        copyright notice, this list of conditions and the following
17 *        disclaimer in the documentation and/or other materials
18 *        provided with the distribution.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV
23 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
24 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
25 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
26 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 * SOFTWARE.
28 */
29
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33#include <errno.h>
34#include <getopt.h>
35#include <netdb.h>
36#include <rdma/rdma_cma.h>
37#include <rdma/rdma_verbs.h>
38
39static const char *port = "7471";
40
41static struct rdma_cm_id *listen_id, *id;
42static struct ibv_mr *mr, *send_mr;
43static int send_flags;
44static uint8_t send_msg[16];
45static uint8_t recv_msg[16];
46
47static int run(void)
48{
49	struct rdma_addrinfo hints, *res;
50	struct ibv_qp_init_attr init_attr;
51	struct ibv_qp_attr qp_attr;
52	struct ibv_wc wc;
53	int ret;
54
55	memset(&hints, 0, sizeof hints);
56	hints.ai_flags = RAI_PASSIVE;
57	hints.ai_port_space = RDMA_PS_TCP;
58	ret = rdma_getaddrinfo(NULL, port, &hints, &res);
59	if (ret) {
60		printf("rdma_getaddrinfo: %s\n", gai_strerror(ret));
61		return ret;
62	}
63
64	memset(&init_attr, 0, sizeof init_attr);
65	init_attr.cap.max_send_wr = init_attr.cap.max_recv_wr = 1;
66	init_attr.cap.max_send_sge = init_attr.cap.max_recv_sge = 1;
67	init_attr.cap.max_inline_data = 16;
68	init_attr.sq_sig_all = 1;
69	ret = rdma_create_ep(&listen_id, res, NULL, &init_attr);
70	if (ret) {
71		perror("rdma_create_ep");
72		goto out_free_addrinfo;
73	}
74
75	ret = rdma_listen(listen_id, 0);
76	if (ret) {
77		perror("rdma_listen");
78		goto out_destroy_listen_ep;
79	}
80
81	ret = rdma_get_request(listen_id, &id);
82	if (ret) {
83		perror("rdma_get_request");
84		goto out_destroy_listen_ep;
85	}
86
87	memset(&qp_attr, 0, sizeof qp_attr);
88	memset(&init_attr, 0, sizeof init_attr);
89	ret = ibv_query_qp(id->qp, &qp_attr, IBV_QP_CAP,
90			   &init_attr);
91	if (ret) {
92		perror("ibv_query_qp");
93		goto out_destroy_accept_ep;
94	}
95	if (init_attr.cap.max_inline_data >= 16)
96		send_flags = IBV_SEND_INLINE;
97	else
98		printf("rdma_server: device doesn't support IBV_SEND_INLINE, "
99		       "using sge sends\n");
100
101	mr = rdma_reg_msgs(id, recv_msg, 16);
102	if (!mr) {
103		ret = -1;
104		perror("rdma_reg_msgs for recv_msg");
105		goto out_destroy_accept_ep;
106	}
107	if ((send_flags & IBV_SEND_INLINE) == 0) {
108		send_mr = rdma_reg_msgs(id, send_msg, 16);
109		if (!send_mr) {
110			ret = -1;
111			perror("rdma_reg_msgs for send_msg");
112			goto out_dereg_recv;
113		}
114	}
115
116	ret = rdma_post_recv(id, NULL, recv_msg, 16, mr);
117	if (ret) {
118		perror("rdma_post_recv");
119		goto out_dereg_send;
120	}
121
122	ret = rdma_accept(id, NULL);
123	if (ret) {
124		perror("rdma_accept");
125		goto out_dereg_send;
126	}
127
128	while ((ret = rdma_get_recv_comp(id, &wc)) == 0);
129	if (ret < 0) {
130		perror("rdma_get_recv_comp");
131		goto out_disconnect;
132	}
133
134	ret = rdma_post_send(id, NULL, send_msg, 16, send_mr, send_flags);
135	if (ret) {
136		perror("rdma_post_send");
137		goto out_disconnect;
138	}
139
140	while ((ret = rdma_get_send_comp(id, &wc)) == 0);
141	if (ret < 0)
142		perror("rdma_get_send_comp");
143	else
144		ret = 0;
145
146out_disconnect:
147	rdma_disconnect(id);
148out_dereg_send:
149	if ((send_flags & IBV_SEND_INLINE) == 0)
150		rdma_dereg_mr(send_mr);
151out_dereg_recv:
152	rdma_dereg_mr(mr);
153out_destroy_accept_ep:
154	rdma_destroy_ep(id);
155out_destroy_listen_ep:
156	rdma_destroy_ep(listen_id);
157out_free_addrinfo:
158	rdma_freeaddrinfo(res);
159	return ret;
160}
161
162int main(int argc, char **argv)
163{
164	int op, ret;
165
166	while ((op = getopt(argc, argv, "p:")) != -1) {
167		switch (op) {
168		case 'p':
169			port = optarg;
170			break;
171		default:
172			printf("usage: %s\n", argv[0]);
173			printf("\t[-p port_number]\n");
174			exit(1);
175		}
176	}
177
178	printf("rdma_server: start\n");
179	ret = run();
180	printf("rdma_server: end %d\n", ret);
181	return ret;
182}
183