Blame opasadb/lib/path/opasadb_path.c

Packit Service 3470d1
/* BEGIN_ICS_COPYRIGHT2 ****************************************
Packit Service 3470d1
Packit Service 3470d1
Copyright (c) 2015-2017, Intel Corporation
Packit Service 3470d1
Packit Service 3470d1
Redistribution and use in source and binary forms, with or without
Packit Service 3470d1
modification, are permitted provided that the following conditions are met:
Packit Service 3470d1
Packit Service 3470d1
    * Redistributions of source code must retain the above copyright notice,
Packit Service 3470d1
      this list of conditions and the following disclaimer.
Packit Service 3470d1
    * Redistributions in binary form must reproduce the above copyright
Packit Service 3470d1
      notice, this list of conditions and the following disclaimer in the
Packit Service 3470d1
      documentation and/or other materials provided with the distribution.
Packit Service 3470d1
    * Neither the name of Intel Corporation nor the names of its contributors
Packit Service 3470d1
      may be used to endorse or promote products derived from this software
Packit Service 3470d1
      without specific prior written permission.
Packit Service 3470d1
Packit Service 3470d1
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
Packit Service 3470d1
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
Packit Service 3470d1
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
Packit Service 3470d1
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
Packit Service 3470d1
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
Packit Service 3470d1
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
Packit Service 3470d1
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
Packit Service 3470d1
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
Packit Service 3470d1
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
Packit Service 3470d1
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit Service 3470d1
Packit Service 3470d1
** END_ICS_COPYRIGHT2   ****************************************/
Packit Service 3470d1
Packit Service 3470d1
/* [ICS VERSION STRING: unknown] */
Packit Service 3470d1
#include <ctype.h>
Packit Service 3470d1
#include <stdio.h>
Packit Service 3470d1
#include <stdlib.h>
Packit Service 3470d1
#include <string.h>
Packit Service 3470d1
#include <unistd.h>
Packit Service 3470d1
#include <sys/types.h>
Packit Service 3470d1
#include <sys/socket.h>
Packit Service 3470d1
#include <arpa/inet.h>
Packit Service 3470d1
#include <fcntl.h>
Packit Service 3470d1
#include <sys/errno.h>
Packit Service 3470d1
#include <linux/types.h>
Packit Service 3470d1
#include <verbs.h>
Packit Service 3470d1
#include "opasadb_debug.h"
Packit Service 3470d1
#include "opasadb_path.h"
Packit Service 3470d1
Packit Service 3470d1
/*
Packit Service 3470d1
 * IbAccess headers don't play well with OFED headers, and OFED doesn't
Packit Service 3470d1
 * export the path mask. I have to duplicate these defines here.
Packit Service 3470d1
 */
Packit Service 3470d1
#define IB_PATH_RECORD_COMP_SERVICEID                   0x00000003
Packit Service 3470d1
#define IB_PATH_RECORD_COMP_DGID                        0x00000004
Packit Service 3470d1
#define IB_PATH_RECORD_COMP_SGID                        0x00000008
Packit Service 3470d1
#define IB_PATH_RECORD_COMP_DLID                        0x00000010
Packit Service 3470d1
#define IB_PATH_RECORD_COMP_SLID                        0x00000020
Packit Service 3470d1
#define IB_PATH_RECORD_COMP_RAWTRAFFIC                  0x00000040
Packit Service 3470d1
    /* reserved field                                   0x00000080 */
Packit Service 3470d1
#define IB_PATH_RECORD_COMP_FLOWLABEL                   0x00000100
Packit Service 3470d1
#define IB_PATH_RECORD_COMP_HOPLIMIT                    0x00000200
Packit Service 3470d1
#define IB_PATH_RECORD_COMP_TCLASS                      0x00000400
Packit Service 3470d1
#define IB_PATH_RECORD_COMP_REVERSIBLE                  0x00000800
Packit Service 3470d1
#define IB_PATH_RECORD_COMP_NUMBPATH                    0x00001000
Packit Service 3470d1
#define IB_PATH_RECORD_COMP_PKEY                        0x00002000
Packit Service 3470d1
#define IB_PATH_RECORD_COMP_QOS_CLASS                   0x00004000
Packit Service 3470d1
#define IB_PATH_RECORD_COMP_SL                          0x00008000
Packit Service 3470d1
#define IB_PATH_RECORD_COMP_MTUSELECTOR                 0x00010000
Packit Service 3470d1
#define IB_PATH_RECORD_COMP_MTU                         0x00020000
Packit Service 3470d1
#define IB_PATH_RECORD_COMP_RATESELECTOR                0x00040000
Packit Service 3470d1
#define IB_PATH_RECORD_COMP_RATE                        0x00080000
Packit Service 3470d1
#define IB_PATH_RECORD_COMP_PKTLIFESELECTOR             0x00100000
Packit Service 3470d1
#define IB_PATH_RECORD_COMP_PKTLIFE                     0x00200000
Packit Service 3470d1
#define IB_PATH_RECORD_COMP_PREFERENCE                  0x00400000
Packit Service 3470d1
    /* reserved field                                   0x00800000 */
Packit Service 3470d1
#define IB_PATH_RECORD_COMP_ALL                         0x007fff7f
Packit Service 3470d1
Packit Service 3470d1
/*
Packit Service 3470d1
 * IbAccess headers don't play well with OFED headers. Because of this,
Packit Service 3470d1
 * I have to put modified prototypes here.
Packit Service 3470d1
 */
Packit Service 3470d1
int op_ppath_find_path(void *reader,
Packit Service 3470d1
					   const char *hfi_name,
Packit Service 3470d1
					   __u16 port,
Packit Service 3470d1
					   __u64 mask,
Packit Service 3470d1
					   op_path_rec_t *query,
Packit Service 3470d1
					   op_path_rec_t *result);
Packit Service 3470d1
Packit Service 3470d1
void op_ppath_close_reader(void *r);
Packit Service 3470d1
void *op_ppath_allocate_reader(void);
Packit Service 3470d1
int op_ppath_create_reader(void *reader);
Packit Service 3470d1
Packit Service 3470d1
struct op_path_context {
Packit Service 3470d1
	void  	*reader;
Packit Service 3470d1
Packit Service 3470d1
	struct 	ibv_context *ibv_context;		
Packit Service 3470d1
	struct 	ibv_device_attr device_attr;	
Packit Service 3470d1
    struct 	ibv_port_attr port_attr; 		
Packit Service 3470d1
Packit Service 3470d1
	__u16	port_num;
Packit Service 3470d1
	__u16	*pkey_table;
Packit Service 3470d1
};
Packit Service 3470d1
Packit Service 3470d1
static uint64_t build_comp_mask(op_path_rec_t path)
Packit Service 3470d1
{
Packit Service 3470d1
	uint64_t mask = 0;
Packit Service 3470d1
Packit Service 3470d1
	if (path.service_id) 
Packit Service 3470d1
		mask |= IB_PATH_RECORD_COMP_SERVICEID;
Packit Service 3470d1
Packit Service 3470d1
	if (path.dgid.unicast.interface_id | path.dgid.unicast.prefix) 
Packit Service 3470d1
		mask |= IB_PATH_RECORD_COMP_DGID;
Packit Service 3470d1
	if (path.sgid.unicast.interface_id | path.sgid.unicast.prefix) 
Packit Service 3470d1
		mask |= IB_PATH_RECORD_COMP_SGID;
Packit Service 3470d1
	if (path.dlid) 
Packit Service 3470d1
		mask |= IB_PATH_RECORD_COMP_DLID;
Packit Service 3470d1
	if (path.slid) 
Packit Service 3470d1
		mask |= IB_PATH_RECORD_COMP_SLID;
Packit Service 3470d1
	if (ntohl(path.hop_flow_raw) & 0x80000000) 
Packit Service 3470d1
		mask |= IB_PATH_RECORD_COMP_RAWTRAFFIC;
Packit Service 3470d1
	if (ntohl(path.hop_flow_raw) & 0x0FFFFF00)
Packit Service 3470d1
		mask |= IB_PATH_RECORD_COMP_FLOWLABEL;
Packit Service 3470d1
	if (ntohl(path.hop_flow_raw) & 0x000000FF)
Packit Service 3470d1
		mask |= IB_PATH_RECORD_COMP_HOPLIMIT;
Packit Service 3470d1
	if (path.tclass) 
Packit Service 3470d1
		mask |= IB_PATH_RECORD_COMP_TCLASS;
Packit Service 3470d1
	if (path.num_path & 0xFF) mask |= IB_PATH_RECORD_COMP_REVERSIBLE;
Packit Service 3470d1
	if (path.num_path & 0x7F) mask |= IB_PATH_RECORD_COMP_NUMBPATH;
Packit Service 3470d1
	if (path.pkey) mask |= IB_PATH_RECORD_COMP_PKEY;
Packit Service 3470d1
	if (ntohs(path.qos_class_sl) & 0x0FFF) 
Packit Service 3470d1
		mask |= IB_PATH_RECORD_COMP_QOS_CLASS;
Packit Service 3470d1
	if (ntohs(path.qos_class_sl) & 0xF000) 
Packit Service 3470d1
		mask |= IB_PATH_RECORD_COMP_SL;
Packit Service 3470d1
	if (path.mtu & 0xC0) 
Packit Service 3470d1
		mask |= IB_PATH_RECORD_COMP_MTUSELECTOR;
Packit Service 3470d1
	if (path.mtu & 0x3F) 
Packit Service 3470d1
		mask |= IB_PATH_RECORD_COMP_MTU;
Packit Service 3470d1
	if (path.rate & 0xC0) 
Packit Service 3470d1
		mask |= IB_PATH_RECORD_COMP_RATESELECTOR;
Packit Service 3470d1
	if (path.rate & 0x3F) 
Packit Service 3470d1
		mask |= IB_PATH_RECORD_COMP_RATE;
Packit Service 3470d1
	if (path.pkt_life & 0xC0) 
Packit Service 3470d1
		mask |= IB_PATH_RECORD_COMP_PKTLIFESELECTOR;
Packit Service 3470d1
	if (path.pkt_life & 0x3F) 
Packit Service 3470d1
		mask |= IB_PATH_RECORD_COMP_PKTLIFE;
Packit Service 3470d1
	if (path.preference) 
Packit Service 3470d1
		mask |= IB_PATH_RECORD_COMP_PREFERENCE;
Packit Service 3470d1
Packit Service 3470d1
	return mask;
Packit Service 3470d1
};
Packit Service 3470d1
Packit Service 3470d1
static struct ibv_device	**dev_list = NULL;
Packit Service 3470d1
static int num_devices = 0;
Packit Service 3470d1
Packit Service 3470d1
/*
Packit Service 3470d1
 * Convenience function. Given the name of an HFI,
Packit Service 3470d1
 * returns the ibv_device structure associated with it.
Packit Service 3470d1
 * Returns NULL if the HFI could not be found.
Packit Service 3470d1
 *
Packit Service 3470d1
 * HFI can be identified by name ("mthfi0") or by number
Packit Service 3470d1
 * "1", "2", et cetera.
Packit Service 3470d1
 *
Packit Service 3470d1
 * OPENS THE HFI! Use ibv_close_device() to release it.
Packit Service 3470d1
 */ 
Packit Service 3470d1
struct ibv_context *
Packit Service 3470d1
op_path_find_hfi(const char *name, 
Packit Service 3470d1
			    struct ibv_device **device)
Packit Service 3470d1
{
Packit Service 3470d1
	struct ibv_device	*ibv_dev = NULL;
Packit Service 3470d1
	struct ibv_context	*context = NULL;
Packit Service 3470d1
	int i;
Packit Service 3470d1
Packit Service 3470d1
	if (!dev_list) {
Packit Service 3470d1
		dev_list = ibv_get_device_list(&num_devices);
Packit Service 3470d1
	}
Packit Service 3470d1
	if (!dev_list) {
Packit Service 3470d1
		errno = EFAULT;
Packit Service 3470d1
		return NULL;
Packit Service 3470d1
	}
Packit Service 3470d1
	if (name == NULL || name[0]=='\0') {
Packit Service 3470d1
		i=0;
Packit Service 3470d1
	} else if (isdigit(name[0])) {
Packit Service 3470d1
		i = strtoul(name,NULL,0) - 1;
Packit Service 3470d1
		if (i < 0 || i >= num_devices){
Packit Service 3470d1
			errno = EFAULT;
Packit Service 3470d1
                        return NULL;
Packit Service 3470d1
		}
Packit Service 3470d1
	} else {
Packit Service 3470d1
		for (i=0; i < num_devices; i++) {
Packit Service 3470d1
			if (!strcmp(ibv_get_device_name(dev_list[i]), name))
Packit Service 3470d1
				break;
Packit Service 3470d1
		}
Packit Service 3470d1
		if (i >= num_devices) {
Packit Service 3470d1
			errno = EFAULT;
Packit Service 3470d1
			return NULL;
Packit Service 3470d1
		}
Packit Service 3470d1
	}
Packit Service 3470d1
	ibv_dev = dev_list[i];
Packit Service 3470d1
Packit Service 3470d1
	/*
Packit Service 3470d1
	 * Opens the verbs interface to the HFI.
Packit Service 3470d1
	 * Note that this will increment the usage counter for that
Packit Service 3470d1
	 * HFI. This needs to be done before we release the device list.
Packit Service 3470d1
	 */
Packit Service 3470d1
	if(ibv_dev) {
Packit Service 3470d1
		context = ibv_open_device(ibv_dev);
Packit Service 3470d1
		if (!context) {
Packit Service 3470d1
			errno = EFAULT;
Packit Service 3470d1
			*device = NULL;
Packit Service 3470d1
		} else {
Packit Service 3470d1
			*device = ibv_dev;
Packit Service 3470d1
		}
Packit Service 3470d1
	} else {
Packit Service 3470d1
		*device = NULL;
Packit Service 3470d1
		errno = ENODEV;
Packit Service 3470d1
	}
Packit Service 3470d1
Packit Service 3470d1
	return context;
Packit Service 3470d1
}
Packit Service 3470d1
Packit Service 3470d1
/*
Packit Service 3470d1
 * Opens the interface to the opp module.
Packit Service 3470d1
 * Must be called before any use of the path functions.
Packit Service 3470d1
 *
Packit Service 3470d1
 * device		The verbs context for the HFI.
Packit Service 3470d1
 *				Can be acquired via op_path_find_hfi.
Packit Service 3470d1
 *
Packit Service 3470d1
 * port_num		The port to use for sending queries.
Packit Service 3470d1
 *
Packit Service 3470d1
 * This information is used for querying pkeys and 
Packit Service 3470d1
 * calculating timeouts.
Packit Service 3470d1
 *
Packit Service 3470d1
 * Returns a pointer to the op_path context on success, or returns NULL 
Packit Service 3470d1
 * and sets errno if the device could not be opened.
Packit Service 3470d1
 */
Packit Service 3470d1
void *
Packit Service 3470d1
op_path_open(struct ibv_device *device, int p)
Packit Service 3470d1
{
Packit Service 3470d1
	int         i, err;
Packit Service 3470d1
	struct op_path_context *context;
Packit Service 3470d1
Packit Service 3470d1
Packit Service 3470d1
	if (!device) {
Packit Service 3470d1
		errno=ENXIO;
Packit Service 3470d1
		return NULL;
Packit Service 3470d1
	}
Packit Service 3470d1
Packit Service 3470d1
	context = malloc(sizeof(struct op_path_context));
Packit Service 3470d1
	if (!context) {
Packit Service 3470d1
		errno=ENOMEM;
Packit Service 3470d1
		return NULL;
Packit Service 3470d1
	}
Packit Service 3470d1
	memset(context,0,sizeof(struct op_path_context));
Packit Service 3470d1
Packit Service 3470d1
	context->ibv_context = ibv_open_device(device);
Packit Service 3470d1
	if (!context->ibv_context) {
Packit Service 3470d1
		errno=ENODEV;
Packit Service 3470d1
		goto open_device_failed;
Packit Service 3470d1
	}
Packit Service 3470d1
Packit Service 3470d1
	context->port_num = p;
Packit Service 3470d1
Packit Service 3470d1
	context->reader = op_ppath_allocate_reader();
Packit Service 3470d1
	if (!context->reader) {
Packit Service 3470d1
		errno=ENOMEM;
Packit Service 3470d1
		goto alloc_reader_failed;
Packit Service 3470d1
	}
Packit Service 3470d1
Packit Service 3470d1
	err = op_ppath_create_reader(context->reader);
Packit Service 3470d1
	if (err) {
Packit Service 3470d1
		errno=err;
Packit Service 3470d1
		goto create_reader_failed;
Packit Service 3470d1
	}
Packit Service 3470d1
Packit Service 3470d1
	if ((err=ibv_query_device(context->ibv_context,
Packit Service 3470d1
                         &(context->device_attr)))) {
Packit Service 3470d1
		errno=EFAULT;
Packit Service 3470d1
		goto query_attr_failed;
Packit Service 3470d1
	}
Packit Service 3470d1
Packit Service 3470d1
	if ((err=ibv_query_port(context->ibv_context,
Packit Service 3470d1
                       context->port_num,
Packit Service 3470d1
                       &(context->port_attr)))) {
Packit Service 3470d1
		errno=EFAULT;
Packit Service 3470d1
		goto query_attr_failed;
Packit Service 3470d1
	}
Packit Service 3470d1
Packit Service 3470d1
	context->pkey_table = malloc(context->device_attr.max_pkeys* sizeof(int));     
Packit Service 3470d1
	if (!context->pkey_table) {
Packit Service 3470d1
		errno= ENOMEM;
Packit Service 3470d1
		goto query_attr_failed;
Packit Service 3470d1
	}
Packit Service 3470d1
	memset(context->pkey_table,0,context->device_attr.max_pkeys* sizeof(int));
Packit Service 3470d1
Packit Service 3470d1
	for (i = 0, err = 0; !err && i<context->device_attr.max_pkeys; i++) {
Packit Service 3470d1
		err = ibv_query_pkey(context->ibv_context, context->port_num, i,
Packit Service 3470d1
                             &(context->pkey_table[i]));
Packit Service 3470d1
		if (err) {
Packit Service 3470d1
			errno=EFAULT;
Packit Service 3470d1
			goto query_pkey_failed;
Packit Service 3470d1
		}
Packit Service 3470d1
	}
Packit Service 3470d1
Packit Service 3470d1
	return context;
Packit Service 3470d1
Packit Service 3470d1
query_pkey_failed:
Packit Service 3470d1
	free(context->pkey_table);
Packit Service 3470d1
query_attr_failed:
Packit Service 3470d1
	op_ppath_close_reader(context->reader);
Packit Service 3470d1
create_reader_failed:
Packit Service 3470d1
	free(context->reader);
Packit Service 3470d1
alloc_reader_failed:
Packit Service 3470d1
	ibv_close_device(context->ibv_context);
Packit Service 3470d1
open_device_failed:
Packit Service 3470d1
	free(context);
Packit Service 3470d1
	return NULL;
Packit Service 3470d1
}
Packit Service 3470d1
Packit Service 3470d1
/*
Packit Service 3470d1
 * Closes the interface to the opp module.
Packit Service 3470d1
 * No path functions will work after calling this function.
Packit Service 3470d1
 */
Packit Service 3470d1
void 
Packit Service 3470d1
op_path_close(void *uc)
Packit Service 3470d1
{
Packit Service 3470d1
	struct op_path_context *context = (struct op_path_context *)uc;
Packit Service 3470d1
Packit Service 3470d1
	
Packit Service 3470d1
	op_ppath_close_reader(context->reader);
Packit Service 3470d1
	
Packit Service 3470d1
	/*
Packit Service 3470d1
	 * Close the HFI and release the memory being used.
Packit Service 3470d1
	 */
Packit Service 3470d1
	ibv_close_device(context->ibv_context);
Packit Service 3470d1
Packit Service 3470d1
	/*
Packit Service 3470d1
     * Releases the memory used by the list - and decrements the usage
Packit Service 3470d1
     * counters on the HFIs. Note that this is important; all the HFIs
Packit Service 3470d1
     * in the device list are flagged as being used from the time
Packit Service 3470d1
     * the list is acquired until it is freed.
Packit Service 3470d1
     */
Packit Service 3470d1
    if (dev_list) {
Packit Service 3470d1
		ibv_free_device_list(dev_list);
Packit Service 3470d1
		dev_list = NULL;
Packit Service 3470d1
		num_devices = 0;
Packit Service 3470d1
	}
Packit Service 3470d1
	
Packit Service 3470d1
	free(context);
Packit Service 3470d1
}
Packit Service 3470d1
Packit Service 3470d1
/*
Packit Service 3470d1
 * Retrieves an IB Path Record given a particular query.
Packit Service 3470d1
 *
Packit Service 3470d1
 * context		Pointer to the HFI and port to query on.
Packit Service 3470d1
 *
Packit Service 3470d1
 * query		The path record to use for asking the query.
Packit Service 3470d1
 *				All fields should be zero'ed out except for
Packit Service 3470d1
 *				those being used to query! For example,
Packit Service 3470d1
 *				a simple query might specify the source lid,
Packit Service 3470d1
 *				the destination lid and a pkey. All fields should
Packit Service 3470d1
 *				be in network byte order.
Packit Service 3470d1
 * 
Packit Service 3470d1
 * response		The path record where the completed path will
Packit Service 3470d1
 *				be written. All fields are in network byte order.
Packit Service 3470d1
 *
Packit Service 3470d1
 * RETURN VAL:	This function will return a 0 on success,
Packit Service 3470d1
 *				or non-zero on error.
Packit Service 3470d1
 */
Packit Service 3470d1
int 
Packit Service 3470d1
op_path_get_path_by_rec(void *uc,
Packit Service 3470d1
					   op_path_rec_t *query, 
Packit Service 3470d1
					   op_path_rec_t *response)
Packit Service 3470d1
{
Packit Service 3470d1
	uint64_t mask = build_comp_mask(*query);
Packit Service 3470d1
	struct op_path_context *context = (struct op_path_context *)uc;
Packit Service 3470d1
Packit Service 3470d1
	return op_ppath_find_path(context->reader,
Packit Service 3470d1
							  ibv_get_device_name(context->ibv_context->device),
Packit Service 3470d1
							  context->port_num,
Packit Service 3470d1
							  mask,
Packit Service 3470d1
					  		  query,
Packit Service 3470d1
							  response);
Packit Service 3470d1
}
Packit Service 3470d1
Packit Service 3470d1
/*
Packit Service 3470d1
 * Retrieves an IB Path Record to a given destination.
Packit Service 3470d1
 *
Packit Service 3470d1
 * op_path_context  A handle to the interface to query over.
Packit Service 3470d1
 *
Packit Service 3470d1
 * hfi_context  A handle to the HFI that will be used for
Packit Service 3470d1
 *              this path. 
Packit Service 3470d1
 *
Packit Service 3470d1
 * port         The local port number that will be used 
Packit Service 3470d1
 *              for this path. (not the lid.)
Packit Service 3470d1
 *
Packit Service 3470d1
 * dgid         The destination GID.
Packit Service 3470d1
 *
Packit Service 3470d1
 * pkey         The desired pkey. This should be zero to
Packit Service 3470d1
 *              accept the default.
Packit Service 3470d1
 *
Packit Service 3470d1
 * response     The path record where the completed path will
Packit Service 3470d1
 *              be written. All fields are in network byte order.
Packit Service 3470d1
 *
Packit Service 3470d1
 * RETURN VAL:  This function will return a value of 0 on success,
Packit Service 3470d1
 *              or non-zero on error.
Packit Service 3470d1
 */
Packit Service 3470d1
int 
Packit Service 3470d1
op_path_get_path_to_dgid(void *uc,
Packit Service 3470d1
						uint16_t pkey,
Packit Service 3470d1
						union ibv_gid dgid,
Packit Service 3470d1
						op_path_rec_t *response)
Packit Service 3470d1
{
Packit Service 3470d1
Packit Service 3470d1
	op_path_rec_t query;
Packit Service 3470d1
	struct op_path_context *context = (struct op_path_context *)uc;
Packit Service 3470d1
		
Packit Service 3470d1
	memset(&query,0,sizeof(query));
Packit Service 3470d1
Packit Service 3470d1
	query.dgid.unicast.prefix = dgid.global.subnet_prefix;
Packit Service 3470d1
	query.dgid.unicast.interface_id = dgid.global.interface_id;
Packit Service 3470d1
	query.pkey = pkey;
Packit Service 3470d1
	query.slid = ntohs(context->port_attr.lid);
Packit Service 3470d1
Packit Service 3470d1
	return op_path_get_path_by_rec(uc,&query,response);
Packit Service 3470d1
}
Packit Service 3470d1
Packit Service 3470d1
Packit Service 3470d1
/*
Packit Service 3470d1
 * Converts a pkey to a pkey index, which is needed by the queue pairs.
Packit Service 3470d1
 * Returns 0 on succes, non zero on error.
Packit Service 3470d1
 */
Packit Service 3470d1
int op_path_find_pkey(void *uc, uint16_t pkey, uint16_t *pkey_index)
Packit Service 3470d1
{
Packit Service 3470d1
	int i;
Packit Service 3470d1
	struct op_path_context *context = (struct op_path_context *)uc;
Packit Service 3470d1
Packit Service 3470d1
	for (i = 0; i< context->device_attr.max_pkeys; i++) {
Packit Service 3470d1
		if (pkey == context->pkey_table[i]) {
Packit Service 3470d1
			*pkey_index = (uint16_t) i;
Packit Service 3470d1
			return 0;
Packit Service 3470d1
		}
Packit Service 3470d1
	}
Packit Service 3470d1
Packit Service 3470d1
	return EINVAL;
Packit Service 3470d1
}
Packit Service 3470d1
Packit Service 3470d1
/*
Packit Service 3470d1
 * Given an HFI and a path record's packet lifetime attribute, 
Packit Service 3470d1
 * compute the packet lifetime for a queue pair.
Packit Service 3470d1
 */
Packit Service 3470d1
uint8_t op_path_compute_timeout(struct ibv_context *hfi_context, 
Packit Service 3470d1
								uint8_t pkt_life)
Packit Service 3470d1
{
Packit Service 3470d1
	uint8_t result;
Packit Service 3470d1
	struct ibv_device_attr device_attr;
Packit Service 3470d1
Packit Service 3470d1
	pkt_life &= 0x1f;
Packit Service 3470d1
Packit Service 3470d1
	if (ibv_query_device(hfi_context, &device_attr))
Packit Service 3470d1
		return 0;
Packit Service 3470d1
Packit Service 3470d1
	/* Adding 1 has the effect of doubling the timeout. */
Packit Service 3470d1
	/* We do this because we're looking for a round-trip figure. */
Packit Service 3470d1
	result = pkt_life + 1; 
Packit Service 3470d1
Packit Service 3470d1
	/* If the HFI's local delay is larger than the time out so far, */
Packit Service 3470d1
	/* replace the result with the local delay, doubled. */
Packit Service 3470d1
	if (pkt_life < device_attr.local_ca_ack_delay) {
Packit Service 3470d1
		result = device_attr.local_ca_ack_delay + 1;
Packit Service 3470d1
	}  else {
Packit Service 3470d1
		/* The local delay is smaller than the packet life time, */
Packit Service 3470d1
		/* so we'll simply double the timeout value again. */
Packit Service 3470d1
		result += 1;
Packit Service 3470d1
	}
Packit Service 3470d1
Packit Service 3470d1
	if (result > 0x1f) result = 0x1f;
Packit Service 3470d1
Packit Service 3470d1
	return result;
Packit Service 3470d1
}
Packit Service 3470d1
Packit Service 3470d1
/*
Packit Service 3470d1
 * Fills out a qp_attr structure and its mask based on the contents
Packit Service 3470d1
 * of a path record and an optional alternate path.
Packit Service 3470d1
 *
Packit Service 3470d1
 * alt_path	can be null. In that case, no alternate path will be 
Packit Service 3470d1
 * set.
Packit Service 3470d1
 *
Packit Service 3470d1
 * Returns a mask listing the attributes that have been set. Returns 0 
Packit Service 3470d1
 * on error and sets errno.
Packit Service 3470d1
 */
Packit Service 3470d1
unsigned op_path_qp_attr(struct ibv_qp_attr *qp_attr,
Packit Service 3470d1
						void *uc,
Packit Service 3470d1
						op_path_rec_t *primary_path,
Packit Service 3470d1
						void *alt_uc,
Packit Service 3470d1
						op_path_rec_t *alt_path)
Packit Service 3470d1
Packit Service 3470d1
{
Packit Service 3470d1
	struct op_path_context *context = uc;
Packit Service 3470d1
	uint16_t pkey_index = 0;
Packit Service 3470d1
Packit Service 3470d1
	struct op_path_context *alt_context = alt_uc;
Packit Service 3470d1
	uint16_t alt_pkey_index = 0;
Packit Service 3470d1
Packit Service 3470d1
	unsigned mask = 0;
Packit Service 3470d1
	struct ibv_ah_attr *ah_attr = &qp_attr->ah_attr;
Packit Service 3470d1
Packit Service 3470d1
	if (op_path_find_pkey(context,primary_path->pkey, &pkey_index)) {
Packit Service 3470d1
		errno = EINVAL;
Packit Service 3470d1
		return 0;
Packit Service 3470d1
	}
Packit Service 3470d1
Packit Service 3470d1
	qp_attr->path_mtu				= OP_PATH_REC_MTU(primary_path);
Packit Service 3470d1
	mask							|= IBV_QP_PATH_MTU;
Packit Service 3470d1
	qp_attr->pkey_index				= pkey_index;
Packit Service 3470d1
	mask							|= IBV_QP_PKEY_INDEX;
Packit Service 3470d1
Packit Service 3470d1
	ah_attr->dlid					= ntohs(primary_path->dlid);
Packit Service 3470d1
	ah_attr->sl						= OP_PATH_REC_SL(primary_path);
Packit Service 3470d1
	ah_attr->src_path_bits			= ntohs(primary_path->slid) & ((1<<context->port_attr.lmc) - 1); 
Packit Service 3470d1
	ah_attr->static_rate			= primary_path->rate & 0x3f;
Packit Service 3470d1
	ah_attr->port_num				= context->port_num;
Packit Service 3470d1
	ah_attr->is_global				= (OP_PATH_REC_HOP_LIMIT(primary_path)>0)?1:0;
Packit Service 3470d1
	if (ah_attr->is_global) {
Packit Service 3470d1
		ah_attr->grh.dgid.global.subnet_prefix = primary_path->dgid.unicast.prefix;
Packit Service 3470d1
		ah_attr->grh.dgid.global.interface_id = primary_path->dgid.unicast.interface_id;
Packit Service 3470d1
		ah_attr->grh.flow_label		= OP_PATH_REC_FLOW_LBL(primary_path);
Packit Service 3470d1
		ah_attr->grh.sgid_index		= 0; // BUGBUG - One day this will be wrong.
Packit Service 3470d1
		ah_attr->grh.hop_limit		= OP_PATH_REC_HOP_LIMIT(primary_path);
Packit Service 3470d1
		ah_attr->grh.traffic_class	= primary_path->tclass;
Packit Service 3470d1
	}
Packit Service 3470d1
	mask                            |= IBV_QP_AV;
Packit Service 3470d1
Packit Service 3470d1
	if (alt_path && alt_context) {
Packit Service 3470d1
		struct ibv_ah_attr *alt_ah_attr = &qp_attr->alt_ah_attr;
Packit Service 3470d1
Packit Service 3470d1
		if (op_path_find_pkey(alt_context,alt_path->pkey, &alt_pkey_index))
Packit Service 3470d1
			return 0;
Packit Service 3470d1
		
Packit Service 3470d1
		qp_attr->path_mig_state 	= IBV_MIG_ARMED;
Packit Service 3470d1
		mask 						|= IBV_QP_PATH_MIG_STATE;
Packit Service 3470d1
		qp_attr->alt_pkey_index		= alt_pkey_index;
Packit Service 3470d1
		mask 						|= IBV_QP_ALT_PATH;
Packit Service 3470d1
Packit Service 3470d1
		alt_ah_attr->dlid			= ntohs(alt_path->dlid);
Packit Service 3470d1
		alt_ah_attr->sl				= OP_PATH_REC_SL(alt_path);
Packit Service 3470d1
		alt_ah_attr->src_path_bits	= ntohs(alt_path->slid) & ((1<<alt_context->port_attr.lmc) - 1);
Packit Service 3470d1
		alt_ah_attr->static_rate	= alt_path->rate & 0x3f;
Packit Service 3470d1
		alt_ah_attr->port_num		= alt_context->port_num;
Packit Service 3470d1
		alt_ah_attr->is_global		= (OP_PATH_REC_HOP_LIMIT(alt_path)>0)?1:0;
Packit Service 3470d1
		if (alt_ah_attr->is_global) {
Packit Service 3470d1
			alt_ah_attr->grh.dgid.global.subnet_prefix = alt_path->dgid.unicast.prefix;
Packit Service 3470d1
			alt_ah_attr->grh.dgid.global.interface_id = alt_path->dgid.unicast.interface_id;
Packit Service 3470d1
			alt_ah_attr->grh.flow_label	= OP_PATH_REC_FLOW_LBL(alt_path);
Packit Service 3470d1
			alt_ah_attr->grh.sgid_index	= 0; // BUGBUG - One day this will be wrong.
Packit Service 3470d1
			alt_ah_attr->grh.hop_limit	= OP_PATH_REC_HOP_LIMIT(alt_path);
Packit Service 3470d1
			alt_ah_attr->grh.traffic_class	= alt_path->tclass;
Packit Service 3470d1
		}
Packit Service 3470d1
	}
Packit Service 3470d1
Packit Service 3470d1
	return mask;
Packit Service 3470d1
}
Packit Service 3470d1
Packit Service 3470d1
unsigned op_path_check_version(void)
Packit Service 3470d1
{
Packit Service 3470d1
	return OPA_SA_DB_PATH_API_VERSION;
Packit Service 3470d1
}