1219820Sjeff/*
2219820Sjeff * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
3219820Sjeff * Copyright (c) 2006, 2007 Cisco Systems, Inc.  All rights reserved.
4219820Sjeff *
5219820Sjeff * This software is available to you under a choice of one of two
6219820Sjeff * licenses.  You may choose to be licensed under the terms of the GNU
7219820Sjeff * General Public License (GPL) Version 2, available from the file
8219820Sjeff * COPYING in the main directory of this source tree, or the
9219820Sjeff * OpenIB.org BSD license below:
10219820Sjeff *
11219820Sjeff *     Redistribution and use in source and binary forms, with or
12219820Sjeff *     without modification, are permitted provided that the following
13219820Sjeff *     conditions are met:
14219820Sjeff *
15219820Sjeff *      - Redistributions of source code must retain the above
16219820Sjeff *        copyright notice, this list of conditions and the following
17219820Sjeff *        disclaimer.
18219820Sjeff *
19219820Sjeff *      - Redistributions in binary form must reproduce the above
20219820Sjeff *        copyright notice, this list of conditions and the following
21219820Sjeff *        disclaimer in the documentation and/or other materials
22219820Sjeff *        provided with the distribution.
23219820Sjeff *
24219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31219820Sjeff * SOFTWARE.
32219820Sjeff */
33219820Sjeff
34219820Sjeff#if HAVE_CONFIG_H
35219820Sjeff#  include <config.h>
36219820Sjeff#endif /* HAVE_CONFIG_H */
37219820Sjeff
38219820Sjeff#include <stdio.h>
39219820Sjeff#include <netinet/in.h>
40219820Sjeff#include <sys/types.h>
41219820Sjeff#include <sys/stat.h>
42219820Sjeff#include <fcntl.h>
43219820Sjeff#include <unistd.h>
44219820Sjeff#include <stdlib.h>
45219820Sjeff#include <alloca.h>
46219820Sjeff#include <errno.h>
47219820Sjeff
48219820Sjeff#include <infiniband/arch.h>
49219820Sjeff
50219820Sjeff#include "ibverbs.h"
51219820Sjeff
52219820Sjeffstatic pthread_mutex_t device_list_lock = PTHREAD_MUTEX_INITIALIZER;
53219820Sjeffstatic int num_devices;
54219820Sjeffstatic struct ibv_device **device_list;
55219820Sjeff
56219820Sjeffstruct ibv_device **__ibv_get_device_list(int *num)
57219820Sjeff{
58219820Sjeff	struct ibv_device **l = 0;
59219820Sjeff	int i;
60219820Sjeff
61219820Sjeff	if (num)
62219820Sjeff		*num = 0;
63219820Sjeff
64219820Sjeff	pthread_mutex_lock(&device_list_lock);
65219820Sjeff
66219820Sjeff	if (!num_devices)
67219820Sjeff		num_devices = ibverbs_init(&device_list);
68219820Sjeff
69219820Sjeff	if (num_devices < 0) {
70219820Sjeff		errno = -num_devices;
71219820Sjeff		goto out;
72219820Sjeff	}
73219820Sjeff
74219820Sjeff	l = calloc(num_devices + 1, sizeof (struct ibv_device *));
75219820Sjeff	if (!l) {
76219820Sjeff		errno = ENOMEM;
77219820Sjeff		goto out;
78219820Sjeff	}
79219820Sjeff
80219820Sjeff	for (i = 0; i < num_devices; ++i)
81219820Sjeff		l[i] = device_list[i];
82219820Sjeff	if (num)
83219820Sjeff		*num = num_devices;
84219820Sjeff
85219820Sjeffout:
86219820Sjeff	pthread_mutex_unlock(&device_list_lock);
87219820Sjeff	return l;
88219820Sjeff}
89219820Sjeffdefault_symver(__ibv_get_device_list, ibv_get_device_list);
90219820Sjeff
91219820Sjeffvoid __ibv_free_device_list(struct ibv_device **list)
92219820Sjeff{
93219820Sjeff	free(list);
94219820Sjeff}
95219820Sjeffdefault_symver(__ibv_free_device_list, ibv_free_device_list);
96219820Sjeff
97219820Sjeffconst char *__ibv_get_device_name(struct ibv_device *device)
98219820Sjeff{
99219820Sjeff	return device->name;
100219820Sjeff}
101219820Sjeffdefault_symver(__ibv_get_device_name, ibv_get_device_name);
102219820Sjeff
103219820Sjeffuint64_t __ibv_get_device_guid(struct ibv_device *device)
104219820Sjeff{
105219820Sjeff	char attr[24];
106219820Sjeff	uint64_t guid = 0;
107219820Sjeff	uint16_t parts[4];
108219820Sjeff	int i;
109219820Sjeff
110219820Sjeff	if (ibv_read_sysfs_file(device->ibdev_path, "node_guid",
111219820Sjeff				attr, sizeof attr) < 0)
112219820Sjeff		return 0;
113219820Sjeff
114219820Sjeff	if (sscanf(attr, "%hx:%hx:%hx:%hx",
115219820Sjeff		   parts, parts + 1, parts + 2, parts + 3) != 4)
116219820Sjeff		return 0;
117219820Sjeff
118219820Sjeff	for (i = 0; i < 4; ++i)
119219820Sjeff		guid = (guid << 16) | parts[i];
120219820Sjeff
121219820Sjeff	return htonll(guid);
122219820Sjeff}
123219820Sjeffdefault_symver(__ibv_get_device_guid, ibv_get_device_guid);
124219820Sjeff
125219820Sjeffstruct ibv_context *__ibv_open_device(struct ibv_device *device)
126219820Sjeff{
127219820Sjeff	char *devpath;
128219820Sjeff	int cmd_fd;
129219820Sjeff	struct ibv_context *context;
130219820Sjeff
131219820Sjeff	if (asprintf(&devpath, "/dev/%s", device->dev_name) < 0)
132219820Sjeff		return NULL;
133219820Sjeff
134219820Sjeff	/*
135219820Sjeff	 * We'll only be doing writes, but we need O_RDWR in case the
136219820Sjeff	 * provider needs to mmap() the file.
137219820Sjeff	 */
138219820Sjeff	cmd_fd = open(devpath, O_RDWR);
139219820Sjeff	free(devpath);
140219820Sjeff
141219820Sjeff	if (cmd_fd < 0)
142219820Sjeff		return NULL;
143219820Sjeff
144219820Sjeff	context = device->ops.alloc_context(device, cmd_fd);
145219820Sjeff	if (!context)
146219820Sjeff		goto err;
147219820Sjeff
148219820Sjeff	context->device = device;
149219820Sjeff	context->cmd_fd = cmd_fd;
150219820Sjeff	pthread_mutex_init(&context->mutex, NULL);
151219820Sjeff
152219820Sjeff	return context;
153219820Sjeff
154219820Sjefferr:
155219820Sjeff	close(cmd_fd);
156219820Sjeff
157219820Sjeff	return NULL;
158219820Sjeff}
159219820Sjeffdefault_symver(__ibv_open_device, ibv_open_device);
160219820Sjeff
161219820Sjeffint __ibv_close_device(struct ibv_context *context)
162219820Sjeff{
163219820Sjeff	int async_fd = context->async_fd;
164219820Sjeff	int cmd_fd   = context->cmd_fd;
165219820Sjeff	int cq_fd    = -1;
166219820Sjeff
167219820Sjeff	if (abi_ver <= 2) {
168219820Sjeff		struct ibv_abi_compat_v2 *t = context->abi_compat;
169219820Sjeff		cq_fd = t->channel.fd;
170219820Sjeff		free(context->abi_compat);
171219820Sjeff	}
172219820Sjeff
173219820Sjeff	context->device->ops.free_context(context);
174219820Sjeff
175219820Sjeff	close(async_fd);
176219820Sjeff	close(cmd_fd);
177219820Sjeff	if (abi_ver <= 2)
178219820Sjeff		close(cq_fd);
179219820Sjeff
180219820Sjeff	return 0;
181219820Sjeff}
182219820Sjeffdefault_symver(__ibv_close_device, ibv_close_device);
183219820Sjeff
184219820Sjeffint __ibv_get_async_event(struct ibv_context *context,
185219820Sjeff			  struct ibv_async_event *event)
186219820Sjeff{
187219820Sjeff	struct ibv_kern_async_event ev;
188219820Sjeff
189219820Sjeff	if (read(context->async_fd, &ev, sizeof ev) != sizeof ev)
190219820Sjeff		return -1;
191219820Sjeff
192219820Sjeff	event->event_type = ev.event_type;
193219820Sjeff
194219820Sjeff	if (event->event_type & IBV_XRC_QP_EVENT_FLAG) {
195219820Sjeff		event->element.xrc_qp_num = ev.element;
196219820Sjeff	} else
197219820Sjeff		switch (event->event_type) {
198219820Sjeff		case IBV_EVENT_CQ_ERR:
199219820Sjeff			event->element.cq = (void *) (uintptr_t) ev.element;
200219820Sjeff			break;
201219820Sjeff
202219820Sjeff		case IBV_EVENT_QP_FATAL:
203219820Sjeff		case IBV_EVENT_QP_REQ_ERR:
204219820Sjeff		case IBV_EVENT_QP_ACCESS_ERR:
205219820Sjeff		case IBV_EVENT_COMM_EST:
206219820Sjeff		case IBV_EVENT_SQ_DRAINED:
207219820Sjeff		case IBV_EVENT_PATH_MIG:
208219820Sjeff		case IBV_EVENT_PATH_MIG_ERR:
209219820Sjeff		case IBV_EVENT_QP_LAST_WQE_REACHED:
210219820Sjeff			event->element.qp = (void *) (uintptr_t) ev.element;
211219820Sjeff			break;
212219820Sjeff
213219820Sjeff		case IBV_EVENT_SRQ_ERR:
214219820Sjeff		case IBV_EVENT_SRQ_LIMIT_REACHED:
215219820Sjeff			event->element.srq = (void *) (uintptr_t) ev.element;
216219820Sjeff			break;
217219820Sjeff		default:
218219820Sjeff			event->element.port_num = ev.element;
219219820Sjeff			break;
220219820Sjeff		}
221219820Sjeff
222219820Sjeff	if (context->ops.async_event)
223219820Sjeff		context->ops.async_event(event);
224219820Sjeff
225219820Sjeff	return 0;
226219820Sjeff}
227219820Sjeffdefault_symver(__ibv_get_async_event, ibv_get_async_event);
228219820Sjeff
229219820Sjeffvoid __ibv_ack_async_event(struct ibv_async_event *event)
230219820Sjeff{
231219820Sjeff	switch (event->event_type) {
232219820Sjeff	case IBV_EVENT_CQ_ERR:
233219820Sjeff	{
234219820Sjeff		struct ibv_cq *cq = event->element.cq;
235219820Sjeff
236219820Sjeff		pthread_mutex_lock(&cq->mutex);
237219820Sjeff		++cq->async_events_completed;
238219820Sjeff		pthread_cond_signal(&cq->cond);
239219820Sjeff		pthread_mutex_unlock(&cq->mutex);
240219820Sjeff
241219820Sjeff		return;
242219820Sjeff	}
243219820Sjeff
244219820Sjeff	case IBV_EVENT_QP_FATAL:
245219820Sjeff	case IBV_EVENT_QP_REQ_ERR:
246219820Sjeff	case IBV_EVENT_QP_ACCESS_ERR:
247219820Sjeff	case IBV_EVENT_COMM_EST:
248219820Sjeff	case IBV_EVENT_SQ_DRAINED:
249219820Sjeff	case IBV_EVENT_PATH_MIG:
250219820Sjeff	case IBV_EVENT_PATH_MIG_ERR:
251219820Sjeff	case IBV_EVENT_QP_LAST_WQE_REACHED:
252219820Sjeff	{
253219820Sjeff		struct ibv_qp *qp = event->element.qp;
254219820Sjeff
255219820Sjeff		pthread_mutex_lock(&qp->mutex);
256219820Sjeff		++qp->events_completed;
257219820Sjeff		pthread_cond_signal(&qp->cond);
258219820Sjeff		pthread_mutex_unlock(&qp->mutex);
259219820Sjeff
260219820Sjeff		return;
261219820Sjeff	}
262219820Sjeff
263219820Sjeff	case IBV_EVENT_SRQ_ERR:
264219820Sjeff	case IBV_EVENT_SRQ_LIMIT_REACHED:
265219820Sjeff	{
266219820Sjeff		struct ibv_srq *srq = event->element.srq;
267219820Sjeff
268219820Sjeff		pthread_mutex_lock(&srq->mutex);
269219820Sjeff		++srq->events_completed;
270219820Sjeff		pthread_cond_signal(&srq->cond);
271219820Sjeff		pthread_mutex_unlock(&srq->mutex);
272219820Sjeff
273219820Sjeff		return;
274219820Sjeff	}
275219820Sjeff
276219820Sjeff	default:
277219820Sjeff		return;
278219820Sjeff	}
279219820Sjeff}
280219820Sjeffdefault_symver(__ibv_ack_async_event, ibv_ack_async_event);
281