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