|
Packit |
857059 |
/* BEGIN_ICS_COPYRIGHT5 ****************************************
|
|
Packit |
857059 |
|
|
Packit Service |
3f7ca0 |
Copyright (c) 2015-2020, Intel Corporation
|
|
Packit |
857059 |
|
|
Packit |
857059 |
Redistribution and use in source and binary forms, with or without
|
|
Packit |
857059 |
modification, are permitted provided that the following conditions are met:
|
|
Packit |
857059 |
|
|
Packit |
857059 |
* Redistributions of source code must retain the above copyright notice,
|
|
Packit |
857059 |
this list of conditions and the following disclaimer.
|
|
Packit |
857059 |
* Redistributions in binary form must reproduce the above copyright
|
|
Packit |
857059 |
notice, this list of conditions and the following disclaimer in the
|
|
Packit |
857059 |
documentation and/or other materials provided with the distribution.
|
|
Packit |
857059 |
* Neither the name of Intel Corporation nor the names of its contributors
|
|
Packit |
857059 |
may be used to endorse or promote products derived from this software
|
|
Packit |
857059 |
without specific prior written permission.
|
|
Packit |
857059 |
|
|
Packit |
857059 |
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
Packit |
857059 |
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
Packit |
857059 |
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
Packit |
857059 |
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
|
Packit |
857059 |
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
Packit |
857059 |
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
Packit |
857059 |
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
Packit |
857059 |
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
Packit |
857059 |
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
Packit |
857059 |
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
Packit |
857059 |
|
|
Packit |
857059 |
* ** END_ICS_COPYRIGHT5 ****************************************/
|
|
Packit |
857059 |
/* [ICS VERSION STRING: unknown] */
|
|
Packit |
857059 |
|
|
Packit |
857059 |
/*
|
|
Packit |
857059 |
* OFED "User SA" support.
|
|
Packit |
857059 |
*
|
|
Packit |
857059 |
* This module provides userspace access to the "User SA" components, which
|
|
Packit |
857059 |
* exposes SA Notice multiplexing functionality to userspace.
|
|
Packit |
857059 |
*
|
|
Packit |
857059 |
* Note that this implementation follows the opamgt model using the omgt_port
|
|
Packit |
857059 |
* object to track the connection. It creates the kernel channel on
|
|
Packit |
857059 |
* initialization and holds it open. Explicit deregistration and shutdown is
|
|
Packit |
857059 |
* not required, as libibsa and the kernel will automatically clear
|
|
Packit |
857059 |
* registrations when a channel is closed.
|
|
Packit |
857059 |
*/
|
|
Packit |
857059 |
|
|
Packit |
857059 |
#include <string.h>
|
|
Packit |
857059 |
#include <unistd.h>
|
|
Packit |
857059 |
#include <sys/types.h>
|
|
Packit |
857059 |
#include <sys/stat.h>
|
|
Packit |
857059 |
#include <fcntl.h>
|
|
Packit |
857059 |
#include <semaphore.h>
|
|
Packit |
857059 |
#include <infiniband/umad_types.h>
|
|
Packit |
857059 |
#include <infiniband/umad_sa.h>
|
|
Packit |
857059 |
#include <poll.h>
|
|
Packit |
857059 |
#include <sys/uio.h>
|
|
Packit |
857059 |
|
|
Packit |
857059 |
#define OPAMGT_PRIVATE 1
|
|
Packit |
857059 |
|
|
Packit |
857059 |
#include "ib_utils_openib.h"
|
|
Packit |
857059 |
#include "ib_notice_net.h"
|
|
Packit |
857059 |
#include "iba/public/ibyteswap.h"
|
|
Packit |
857059 |
#include "iba/stl_sa_types.h"
|
|
Packit |
857059 |
#include "iba/stl_mad_priv.h"
|
|
Packit |
857059 |
|
|
Packit |
857059 |
#define OMGT_SA_MAX_REGISTRANTS 10
|
|
Packit |
857059 |
|
|
Packit |
857059 |
#define OMGT_SA_DEVICE_NAME_LEN_MAX 32
|
|
Packit |
857059 |
|
|
Packit |
857059 |
#define OMGT_SA_DEFAULT_LOCK_TIMEOUT 5 // seconds
|
|
Packit |
857059 |
|
|
Packit |
857059 |
#ifndef container_of
|
|
Packit |
857059 |
#define container_of(ptr, type, field) \
|
|
Packit |
857059 |
((type *) ((void *) ptr - offsetof(type, field)))
|
|
Packit |
857059 |
#endif
|
|
Packit |
857059 |
|
|
Packit |
857059 |
struct ibv_sa_event {
|
|
Packit |
857059 |
void *context;
|
|
Packit |
857059 |
int status;
|
|
Packit |
857059 |
int attr_count;
|
|
Packit |
857059 |
int attr_size;
|
|
Packit |
857059 |
int attr_offset;
|
|
Packit |
857059 |
uint16_t attr_id;
|
|
Packit |
857059 |
void *attr;
|
|
Packit |
857059 |
};
|
|
Packit |
857059 |
struct omgt_sa_event {
|
|
Packit |
857059 |
struct ibv_sa_event event;
|
|
Packit |
857059 |
struct ibv_sa_event_channel *channel;
|
|
Packit |
857059 |
void *data;
|
|
Packit |
857059 |
};
|
|
Packit |
857059 |
|
|
Packit |
857059 |
int omgt_lock_sem(SEMAPHORE* const pSema)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
struct timespec ts;
|
|
Packit |
857059 |
clock_gettime(CLOCK_REALTIME, &ts);
|
|
Packit |
857059 |
ts.tv_sec += OMGT_SA_DEFAULT_LOCK_TIMEOUT;
|
|
Packit |
857059 |
int ret;
|
|
Packit |
857059 |
while ((ret = sem_timedwait(pSema, &ts)) && errno == EINTR) continue;
|
|
Packit |
857059 |
return ret ? errno : 0;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
void omgt_unlock_sem(SEMAPHORE * const pSema)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
sem_post(pSema);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
/**
|
|
Packit |
857059 |
* port->lock must be held
|
|
Packit |
857059 |
*/
|
|
Packit |
857059 |
static int reg_sa_msg_mr(struct omgt_port *port, struct omgt_sa_msg *msg,
|
|
Packit |
857059 |
enum ibv_wr_opcode opcode,
|
|
Packit |
857059 |
uint32_t rem_qpn, uint32_t rem_qkey)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
msg->mr = ibv_reg_mr(port->sa_qp_pd, msg->data, sizeof(msg->data),
|
|
Packit |
857059 |
IBV_ACCESS_LOCAL_WRITE);
|
|
Packit |
857059 |
if (!msg->mr) {
|
|
Packit |
857059 |
OMGT_OUTPUT_ERROR(port, "Notice: sa msg register memory region failed\n");
|
|
Packit |
857059 |
return (-EIO);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
msg->sge.addr = (uint64_t)msg->data;
|
|
Packit |
857059 |
msg->sge.length = sizeof(msg->data);
|
|
Packit |
857059 |
msg->sge.lkey = msg->mr->lkey;
|
|
Packit |
857059 |
msg->in_q = 0;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if (opcode == IBV_WR_SEND) {
|
|
Packit |
857059 |
msg->wr.send.wr_id = (uint64_t)msg;
|
|
Packit |
857059 |
msg->wr.send.next = NULL;
|
|
Packit |
857059 |
msg->wr.send.sg_list = &msg->sge;
|
|
Packit |
857059 |
msg->wr.send.num_sge = 1;
|
|
Packit |
857059 |
msg->wr.send.opcode = IBV_WR_SEND;
|
|
Packit |
857059 |
msg->wr.send.send_flags = IBV_SEND_SIGNALED;
|
|
Packit |
857059 |
msg->wr.send.wr.ud.ah = port->sa_ah;
|
|
Packit |
857059 |
msg->wr.send.wr.ud.remote_qpn = rem_qpn;
|
|
Packit |
857059 |
msg->wr.send.wr.ud.remote_qkey = rem_qkey;
|
|
Packit |
857059 |
} else {
|
|
Packit |
857059 |
msg->wr.recv.wr_id = (uint64_t)msg;
|
|
Packit |
857059 |
msg->wr.recv.next = NULL;
|
|
Packit |
857059 |
msg->wr.recv.sg_list = &msg->sge;
|
|
Packit |
857059 |
msg->wr.recv.num_sge = 1;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
return (0);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
/**
|
|
Packit |
857059 |
* port->lock must be held
|
|
Packit |
857059 |
*/
|
|
Packit |
857059 |
static struct omgt_sa_msg * alloc_send_sa_msg(struct omgt_port *port)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
struct omgt_sa_msg *msg;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if (!port->sa_ah) {
|
|
Packit |
857059 |
struct ibv_ah_attr attr;
|
|
Packit |
857059 |
int err = 0;
|
|
Packit |
857059 |
memset(&attr, 0, sizeof(attr));
|
|
Packit |
857059 |
|
|
Packit |
857059 |
attr.dlid = (uint16_t)port->umad_port_cache.sm_lid;
|
|
Packit |
857059 |
if (omgt_is_ext_lid(port->umad_port_cache.base_lid) ||
|
|
Packit |
857059 |
omgt_is_ext_lid(port->umad_port_cache.sm_lid)) {
|
|
Packit |
857059 |
attr.is_global = 1;
|
|
Packit |
857059 |
attr.grh.hop_limit = 1;
|
|
Packit |
857059 |
attr.grh.sgid_index = 0;
|
|
Packit |
857059 |
attr.grh.dgid.global.subnet_prefix =
|
|
Packit |
857059 |
port->umad_port_cache.gid_prefix;
|
|
Packit |
857059 |
/* Not too sure why ntoh64 is required */
|
|
Packit |
857059 |
attr.grh.dgid.global.interface_id =
|
|
Packit |
857059 |
ntoh64(omgt_create_gid(port->umad_port_cache.sm_lid));
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if ((err = omgt_lock_sem(&port->umad_port_cache_lock)) != 0) {
|
|
Packit |
857059 |
OMGT_OUTPUT_ERROR(port, "failed to acquire lock (err: %d)\n", err);
|
|
Packit |
857059 |
return (NULL);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
attr.sl = port->umad_port_cache.sm_sl;
|
|
Packit |
857059 |
omgt_unlock_sem(&port->umad_port_cache_lock);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
attr.port_num = port->hfi_port_num;
|
|
Packit |
857059 |
port->sa_ah = ibv_create_ah(port->sa_qp_pd, &attr);
|
|
Packit |
857059 |
if (!port->sa_ah) {
|
|
Packit |
857059 |
OMGT_OUTPUT_ERROR(port, "failed to create SA AH (err: %d)\n", errno);
|
|
Packit |
857059 |
return (NULL);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
msg = calloc(1, sizeof(*msg));
|
|
Packit |
857059 |
if (!msg)
|
|
Packit |
857059 |
return (NULL);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if (reg_sa_msg_mr(port, msg, IBV_WR_SEND, 1, UMAD_QKEY)) {
|
|
Packit |
857059 |
free(msg);
|
|
Packit |
857059 |
return (NULL);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
msg->prev = msg;
|
|
Packit |
857059 |
msg->next = msg;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
return (msg);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
/**
|
|
Packit |
857059 |
* port->lock must be held
|
|
Packit |
857059 |
*/
|
|
Packit |
857059 |
static void free_sa_msg(struct omgt_sa_msg *msg)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
if (msg->mr)
|
|
Packit |
857059 |
ibv_dereg_mr(msg->mr);
|
|
Packit |
857059 |
free(msg);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
|
|
Packit |
857059 |
/**
|
|
Packit |
857059 |
* Adds a registration to the list.
|
|
Packit |
857059 |
* NOTE: Caller must hold the lock.
|
|
Packit |
857059 |
*
|
|
Packit |
857059 |
* @param port port opened by omgt_open_port_
|
|
Packit |
857059 |
* @param reg Pointer to the registration structure.
|
|
Packit |
857059 |
*
|
|
Packit |
857059 |
* @return none
|
|
Packit |
857059 |
*/
|
|
Packit |
857059 |
void omgt_sa_add_reg_unsafe(struct omgt_port *port, omgt_sa_registration_t *reg)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
reg->next = port->regs_list;
|
|
Packit |
857059 |
port->regs_list = reg;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
static void set_sa_msg_tid(struct omgt_port *port, struct umad_sa_packet *sa_pkt)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
port->next_tid++;
|
|
Packit |
857059 |
if (port->next_tid == 0)
|
|
Packit |
857059 |
port->next_tid++;
|
|
Packit |
857059 |
sa_pkt->mad_hdr.tid = hton64((uint64_t)port->next_tid);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
static void set_sa_common_stl_inform_info(struct omgt_port *port, struct umad_sa_packet *sa_pkt)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
STL_INFORM_INFO *informinfo;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
sa_pkt->mad_hdr.base_version = STL_BASE_VERSION;
|
|
Packit |
857059 |
sa_pkt->mad_hdr.mgmt_class = MCLASS_SUBN_ADM;
|
|
Packit |
857059 |
sa_pkt->mad_hdr.class_version = STL_SA_CLASS_VERSION;
|
|
Packit |
857059 |
sa_pkt->mad_hdr.method = MMTHD_SET;
|
|
Packit |
857059 |
sa_pkt->mad_hdr.attr_id = hton16(STL_MCLASS_ATTRIB_ID_INFORM_INFO);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
sa_pkt->rmpp_hdr.rmpp_version = UMAD_RMPP_VERSION;
|
|
Packit |
857059 |
sa_pkt->rmpp_hdr.rmpp_type = 0;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
informinfo = (STL_INFORM_INFO *)sa_pkt->data;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
informinfo->LIDRangeBegin = UINT32_MAX;
|
|
Packit |
857059 |
informinfo->IsGeneric = 1;
|
|
Packit |
857059 |
informinfo->Type = UINT16_MAX;
|
|
Packit |
857059 |
informinfo->u.Generic.u2.s.ProducerType = 0xFFFFFF;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
static void set_sa_common_stl_response_notice(struct omgt_port *port, struct umad_sa_packet *sa_pkt)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
STL_NOTICE *notice;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
sa_pkt->mad_hdr.base_version = STL_BASE_VERSION;
|
|
Packit |
857059 |
sa_pkt->mad_hdr.mgmt_class = MCLASS_SUBN_ADM;
|
|
Packit |
857059 |
sa_pkt->mad_hdr.class_version = STL_SA_CLASS_VERSION;
|
|
Packit |
857059 |
sa_pkt->mad_hdr.method = MMTHD_REPORT_RESP;
|
|
Packit |
857059 |
sa_pkt->mad_hdr.attr_id = hton16(STL_MCLASS_ATTRIB_ID_NOTICE);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
sa_pkt->rmpp_hdr.rmpp_version = UMAD_RMPP_VERSION;
|
|
Packit |
857059 |
sa_pkt->rmpp_hdr.rmpp_type = 0;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
notice = (STL_NOTICE *)sa_pkt->data;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// if the Type is set to 0x7f (empty) all other fields are unused
|
|
Packit |
857059 |
notice->Attributes.Generic.u.AsReg32 = 0;
|
|
Packit |
857059 |
notice->Attributes.Generic.u.s.Type = 0x7f;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
static void post_send_sa_msg(struct omgt_port *port,
|
|
Packit |
857059 |
struct omgt_sa_msg *msg,
|
|
Packit |
857059 |
enum omgt_reg_retry_state resend)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
int rc;
|
|
Packit |
857059 |
struct ibv_send_wr *bad_wr = NULL;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if (msg->in_q) {
|
|
Packit |
857059 |
OMGT_OUTPUT_ERROR(port, "msg (%p) is already in the send Q!!!\n", msg);
|
|
Packit |
857059 |
return;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if (!msg->retries) {
|
|
Packit |
857059 |
OMGT_OUTPUT_ERROR(port, "msg (%p) has timed out!!!\n", msg);
|
|
Packit |
857059 |
return;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if (port->outstanding_sends_cnt >= port->num_userspace_send_buf) {
|
|
Packit |
857059 |
OMGT_OUTPUT_ERROR(port, "no send buffers\n");
|
|
Packit |
857059 |
return;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if (OMGT_RRS_SEND_RETRY == resend) {
|
|
Packit |
857059 |
msg->retries--;
|
|
Packit |
857059 |
if (!msg->retries) {
|
|
Packit |
857059 |
OMGT_DBGPRINT(port, "Timeout sending SA msg.\n");
|
|
Packit |
857059 |
return;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
set_sa_msg_tid(port, (struct umad_sa_packet *)msg->data);
|
|
Packit |
857059 |
if ((rc = ibv_post_send(port->sa_qp, &(msg->wr.send), &bad_wr)) == 0) {
|
|
Packit |
857059 |
port->outstanding_sends_cnt++;
|
|
Packit |
857059 |
msg->in_q = 1;
|
|
Packit |
857059 |
} else {
|
|
Packit |
857059 |
OMGT_OUTPUT_ERROR(port, "Notice: post send WR failed: %s: Aborting send.\n",
|
|
Packit |
857059 |
strerror(rc));
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
static int omgt_post_notice_recvs(struct omgt_port *port)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
int i = 0;
|
|
Packit |
857059 |
int post_count = 0;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
/* post recv msgs */
|
|
Packit |
857059 |
for (i = 0; i < port->num_userspace_recv_buf; i++) {
|
|
Packit |
857059 |
if (reg_sa_msg_mr(port, &port->recv_bufs[i], 0, 0, 0))
|
|
Packit |
857059 |
goto init_error;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
for (i = 0; i < port->num_userspace_recv_buf; i++) {
|
|
Packit |
857059 |
if (ibv_post_recv(port->sa_qp, &port->recv_bufs[i].wr.recv, NULL)) {
|
|
Packit |
857059 |
port->recv_bufs[i].in_q = 0;
|
|
Packit |
857059 |
} else {
|
|
Packit |
857059 |
post_count++;
|
|
Packit |
857059 |
port->recv_bufs[i].in_q = 1;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
if (!post_count)
|
|
Packit |
857059 |
goto init_error;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
return (0);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
init_error:
|
|
Packit |
857059 |
for (/* */; i >= 0; i--) {
|
|
Packit |
857059 |
ibv_dereg_mr(port->recv_bufs[i].mr);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
return (-EIO);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
static struct omgt_sa_msg *
|
|
Packit |
857059 |
find_req_by_tid(struct omgt_port *port, uint32_t tid)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
struct omgt_sa_msg *rc = NULL;
|
|
Packit |
857059 |
struct omgt_sa_msg *msg;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
OMGT_DBGPRINT(port, "find req tid 0x%x\n", tid);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
LIST_FOR_EACH(&port->pending_reg_msg_head, msg) {
|
|
Packit |
857059 |
struct umad_sa_packet *sa_pkt = (struct umad_sa_packet *)msg->data;
|
|
Packit |
857059 |
uint32_t mtid = ntoh64(sa_pkt->mad_hdr.tid) & 0xffffffff;
|
|
Packit |
857059 |
OMGT_DBGPRINT(port, "found tid 0x%x\n", mtid);
|
|
Packit |
857059 |
if (mtid == tid) {
|
|
Packit |
857059 |
rc = msg;
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
return rc;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
static void process_sa_get_resp(struct omgt_port *port, struct umad_sa_packet *sa_pkt)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
struct omgt_sa_msg *req;
|
|
Packit |
857059 |
STL_INFORM_INFO *informinfo = (STL_INFORM_INFO *)sa_pkt->data;
|
|
Packit |
857059 |
uint16_t trap_num = ntoh16(informinfo->u.Generic.TrapNumber);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
omgt_lock_sem(&port->lock);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
/* find the registration for this response */
|
|
Packit |
857059 |
req = find_req_by_tid(port, ntoh64(sa_pkt->mad_hdr.tid) & 0xffffffff);
|
|
Packit |
857059 |
if (req) {
|
|
Packit |
857059 |
if (informinfo->Subscribe == 1) {
|
|
Packit |
857059 |
OMGT_DBGPRINT(port, "registration complete for trap %d; req %p\n", trap_num, req);
|
|
Packit |
857059 |
} else {
|
|
Packit |
857059 |
OMGT_DBGPRINT(port, "UN-registration complete for trap %d; req %p\n", trap_num, req);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
/* Check if the registration has been freed */
|
|
Packit |
857059 |
if (req->reg)
|
|
Packit |
857059 |
req->reg->reg_msg = NULL;
|
|
Packit |
857059 |
LIST_DEL(req);
|
|
Packit |
857059 |
free_sa_msg(req);
|
|
Packit |
857059 |
} else {
|
|
Packit |
857059 |
OMGT_OUTPUT_ERROR(port, "Unknown get response; 'trap num' %d\n", trap_num);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
omgt_unlock_sem(&port->lock);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
/* Recv'ed messages will a GRH on them or at least space (40 bytes) */
|
|
Packit |
857059 |
/* for a GRH which we need to remove. */
|
|
Packit |
857059 |
static struct umad_sa_packet *
|
|
Packit |
857059 |
sa_pkt_from_recv_msg(struct omgt_sa_msg *msg)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
return (struct umad_sa_packet *)&msg->data[sizeof(struct ibv_grh)];
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
static void process_sa_report(struct omgt_port *port, struct umad_sa_packet *sa_pkt)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
struct omgt_sa_msg *response_msg = NULL;
|
|
Packit |
857059 |
struct umad_sa_packet *response_pkt = NULL;
|
|
Packit |
857059 |
struct ibv_send_wr *bad_wr = NULL;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
STL_NOTICE *notice = (STL_NOTICE *)sa_pkt->data;
|
|
Packit |
857059 |
STL_TRAP_GID *notice_gid = (STL_TRAP_GID *)¬ice->Data[0];
|
|
Packit |
857059 |
struct omgt_thread_msg thread_msg;
|
|
Packit |
857059 |
struct iovec iov[2];
|
|
Packit |
857059 |
size_t write_count, write_size;
|
|
Packit |
857059 |
uint16_t trap_num = ntoh16(notice->Attributes.Generic.TrapNumber);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// create and send ReportResp to trap notify
|
|
Packit |
857059 |
if (omgt_lock_sem(&port->lock)) {
|
|
Packit |
857059 |
OMGT_OUTPUT_ERROR(port, "failed to acquire lock (status: %d)\n", FTIMEOUT);
|
|
Packit |
857059 |
return;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
response_msg = alloc_send_sa_msg(port);
|
|
Packit |
857059 |
if (response_msg)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
STL_NOTICE *notice_resp;
|
|
Packit |
857059 |
int rc;
|
|
Packit |
857059 |
memset(response_msg->data, 0, sizeof(response_msg->data));
|
|
Packit |
857059 |
response_pkt = (struct umad_sa_packet *)response_msg->data;
|
|
Packit |
857059 |
set_sa_common_stl_response_notice(port, response_pkt);
|
|
Packit |
857059 |
notice_resp = (STL_NOTICE *)response_pkt->data;
|
|
Packit |
857059 |
BSWAP_STL_NOTICE(notice_resp);
|
|
Packit |
857059 |
response_pkt->mad_hdr.tid = sa_pkt->mad_hdr.tid;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if ((rc = ibv_post_send(port->sa_qp, &(response_msg->wr.send), &bad_wr)) != 0) {
|
|
Packit |
857059 |
OMGT_OUTPUT_ERROR(port, "Notice: post send WR failed: %s: Aborting send.\n",
|
|
Packit |
857059 |
strerror(rc));
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
free_sa_msg(response_msg);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
omgt_unlock_sem(&port->lock);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
thread_msg.size = sizeof *notice;
|
|
Packit |
857059 |
thread_msg.evt = OMGT_TH_EVT_TRAP_MSG;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
iov[0].iov_base = &thread_msg;
|
|
Packit |
857059 |
iov[0].iov_len = sizeof thread_msg;
|
|
Packit |
857059 |
iov[1].iov_base = notice;
|
|
Packit |
857059 |
iov[1].iov_len = sizeof *notice;
|
|
Packit |
857059 |
write_size = iov[0].iov_len + iov[1].iov_len;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if ( write_size !=
|
|
Packit |
857059 |
(write_count = writev(port->umad_port_sv[1], iov, 2)) )
|
|
Packit |
857059 |
OMGT_OUTPUT_ERROR(port, "bad write count %d\n", (int)write_count);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
OMGT_DBGPRINT(port, "process_sa_report: msg queued - trap %d gid %02x%02x%02x%02x%02x%02x%02x%02x\n",
|
|
Packit |
857059 |
trap_num, notice_gid->Gid.Raw[8], notice_gid->Gid.Raw[9], notice_gid->Gid.Raw[10], notice_gid->Gid.Raw[11],
|
|
Packit |
857059 |
notice_gid->Gid.Raw[12], notice_gid->Gid.Raw[13], notice_gid->Gid.Raw[14], notice_gid->Gid.Raw[15]);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
static void process_sa_rcv_msg(struct omgt_port *port, struct omgt_sa_msg *msg)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
struct umad_sa_packet *sa_pkt = sa_pkt_from_recv_msg(msg);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
switch (sa_pkt->mad_hdr.method) {
|
|
Packit |
857059 |
case UMAD_METHOD_GET_RESP:
|
|
Packit |
857059 |
process_sa_get_resp(port, sa_pkt);
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
case UMAD_METHOD_REPORT:
|
|
Packit |
857059 |
process_sa_report(port, sa_pkt);
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
default:
|
|
Packit |
857059 |
OMGT_OUTPUT_ERROR(port, "unknown 'message' received : method 0x%x\n", sa_pkt->mad_hdr.method);
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
int repost_pending_registrations(struct omgt_port *port)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
int new_timeout_ms = -1;
|
|
Packit |
857059 |
struct omgt_sa_msg *msg;
|
|
Packit |
857059 |
struct omgt_sa_msg *del_msg;
|
|
Packit |
857059 |
struct omgt_thread_msg thread_msg;
|
|
Packit |
857059 |
omgt_sa_registration_t *reg;
|
|
Packit |
857059 |
struct iovec iov[2];
|
|
Packit |
857059 |
size_t write_size, write_count;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
omgt_lock_sem(&port->lock);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
LIST_FOR_EACH(&port->pending_reg_msg_head, msg) {
|
|
Packit |
857059 |
if (msg->retries) {
|
|
Packit |
857059 |
new_timeout_ms = NOTICE_REG_TIMEOUT_MS;
|
|
Packit |
857059 |
post_send_sa_msg(port, msg, OMGT_RRS_SEND_RETRY);
|
|
Packit |
857059 |
} else {
|
|
Packit |
857059 |
/*
|
|
Packit |
857059 |
* When the registration is unregistered (in
|
|
Packit |
857059 |
* userspace_unregister()), msg->reg is NULL and we could not
|
|
Packit |
857059 |
* send the timeout event anymore (the caller is not waiting
|
|
Packit |
857059 |
* for notification anymore).
|
|
Packit |
857059 |
*/
|
|
Packit |
857059 |
if (msg->reg) {
|
|
Packit |
857059 |
reg = msg->reg;
|
|
Packit |
857059 |
thread_msg.size = sizeof *reg;
|
|
Packit |
857059 |
thread_msg.evt = OMGT_TH_EVT_TRAP_REG_ERR_TIMEOUT;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
iov[0].iov_base = &thread_msg;
|
|
Packit |
857059 |
iov[0].iov_len = sizeof thread_msg;
|
|
Packit |
857059 |
iov[1].iov_base = reg;
|
|
Packit |
857059 |
iov[1].iov_len = sizeof *reg;
|
|
Packit |
857059 |
write_size = iov[0].iov_len + iov[1].iov_len;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
write_count = writev(port->umad_port_sv[1], iov, 2);
|
|
Packit |
857059 |
if ( write_size != write_count)
|
|
Packit |
857059 |
OMGT_OUTPUT_ERROR(port, "bad write count %d\n",
|
|
Packit |
857059 |
(int)write_count);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// detach the msg to be deleted from the list first
|
|
Packit |
857059 |
del_msg = msg;
|
|
Packit |
857059 |
msg = msg->prev;
|
|
Packit |
857059 |
if (del_msg->reg) {
|
|
Packit |
857059 |
OMGT_DBGPRINT(port, "registration timeout on trap %d : req %p\n",
|
|
Packit |
857059 |
del_msg->reg->trap_num, del_msg->reg);
|
|
Packit |
857059 |
} else {
|
|
Packit |
857059 |
OMGT_DBGPRINT(port, "registration timeout on trap: No information available.\n");
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
if (del_msg->reg)
|
|
Packit |
857059 |
del_msg->reg->reg_msg = NULL;
|
|
Packit |
857059 |
LIST_DEL(del_msg);
|
|
Packit |
857059 |
free_sa_msg(del_msg);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
omgt_unlock_sem(&port->lock);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
return new_timeout_ms;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
/* This function is only called after all registrations have been
|
|
Packit |
857059 |
freed and the port thread has terminated. It is called to free
|
|
Packit |
857059 |
all pending registration/unregistration messages */
|
|
Packit |
857059 |
void omgt_sa_remove_all_pending_reg_msgs(struct omgt_port *port)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
struct omgt_sa_msg *msg;
|
|
Packit |
857059 |
struct omgt_sa_msg *del_msg;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
omgt_lock_sem(&port->lock);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
LIST_FOR_EACH(&port->pending_reg_msg_head, msg) {
|
|
Packit |
857059 |
/* detach the msg to be deleted from the list first */
|
|
Packit |
857059 |
del_msg = msg;
|
|
Packit |
857059 |
msg = msg->prev;
|
|
Packit |
857059 |
LIST_DEL(del_msg);
|
|
Packit |
857059 |
free_sa_msg(del_msg);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
omgt_unlock_sem(&port->lock);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
static void process_wc(struct omgt_port *port, struct ibv_wc *wc)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
struct omgt_sa_msg *msg = (struct omgt_sa_msg *)wc->wr_id;
|
|
Packit |
857059 |
int i;
|
|
Packit |
857059 |
if (wc->opcode == IBV_WC_SEND) {
|
|
Packit |
857059 |
OMGT_DBGPRINT(port, "Notice Send Completion %p : %s\n",
|
|
Packit |
857059 |
msg,
|
|
Packit |
857059 |
ibv_wc_status_str(wc->status));
|
|
Packit |
857059 |
|
|
Packit |
857059 |
omgt_lock_sem(&port->lock);
|
|
Packit |
857059 |
port->outstanding_sends_cnt--;
|
|
Packit |
857059 |
msg->in_q = 0;
|
|
Packit |
857059 |
omgt_unlock_sem(&port->lock);
|
|
Packit |
857059 |
if (wc->status != IBV_WC_SUCCESS) {
|
|
Packit |
857059 |
/* Thread will handle reposting */
|
|
Packit |
857059 |
OMGT_OUTPUT_ERROR(port, "Notice Send Completion not success : %s... ",
|
|
Packit |
857059 |
ibv_wc_status_str(wc->status));
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
} else if (wc->opcode == IBV_WC_RECV) {
|
|
Packit |
857059 |
OMGT_DBGPRINT(port, "Notice Recv Completion %p flags %d: %s\n", msg, wc->wc_flags, ibv_wc_status_str(wc->status));
|
|
Packit |
857059 |
process_sa_rcv_msg(port, msg);
|
|
Packit |
857059 |
if (ibv_post_recv(port->sa_qp, &msg->wr.recv, NULL)) {
|
|
Packit |
857059 |
OMGT_OUTPUT_ERROR(port, "Failed to repost recv buffer - mark as unqueued\n");
|
|
Packit |
857059 |
msg->in_q = 0;
|
|
Packit |
857059 |
} else {
|
|
Packit |
857059 |
msg->in_q = 1;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// If any receive buffers failed to repost cycle through the list here
|
|
Packit |
857059 |
// and retry the post to keep the buffer queue full.
|
|
Packit |
857059 |
for (i = 0; i < port->num_userspace_recv_buf; i++)
|
|
Packit |
857059 |
if (!port->recv_bufs[i].in_q)
|
|
Packit |
857059 |
if (0 == ibv_post_recv(port->sa_qp, &port->recv_bufs[i].wr.recv, NULL)) {
|
|
Packit |
857059 |
port->recv_bufs[i].in_q = 1;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
} else {
|
|
Packit |
857059 |
OMGT_OUTPUT_ERROR(port, "Unknown work completion event: 0x%x\n", wc->opcode);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
void handle_sa_ud_qp(struct omgt_port *port)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
struct ibv_wc wc;
|
|
Packit |
857059 |
struct ibv_cq *ev_cq = port->sa_qp_cq;
|
|
Packit |
857059 |
struct omgt_port *ev_port;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if (ibv_get_cq_event(port->sa_qp_comp_channel, &ev_cq, (void **)&ev_port))
|
|
Packit |
857059 |
goto request_notify;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
ibv_ack_cq_events(ev_cq, 1);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if (port != ev_port || ev_cq != port->sa_qp_cq) {
|
|
Packit |
857059 |
OMGT_OUTPUT_ERROR(port, "ibv_get_cq_event failed to get event for our notice/CQ\n");
|
|
Packit |
857059 |
goto request_notify;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
while (ibv_poll_cq(port->sa_qp_cq, 1, &wc) > 0) {
|
|
Packit |
857059 |
process_wc(port, &wc);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
request_notify:
|
|
Packit |
857059 |
if (ibv_req_notify_cq(port->sa_qp_cq, 0))
|
|
Packit |
857059 |
OMGT_OUTPUT_ERROR(port, "ibv_req_notify_cq failed\n");
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
int start_ud_cq_monitor(struct omgt_port *port)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
int rc;
|
|
Packit |
857059 |
struct omgt_thread_msg msg = {0};
|
|
Packit |
857059 |
|
|
Packit |
857059 |
msg.size = sizeof(msg);
|
|
Packit |
857059 |
msg.evt = OMGT_TH_EVT_UD_MONITOR_ON;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
rc = write(port->umad_port_sv[0], &msg, sizeof(msg));
|
|
Packit |
857059 |
if (rc <= 0) {
|
|
Packit |
857059 |
OMGT_OUTPUT_ERROR(port, "Failed to start CQ Monitoring...\n");
|
|
Packit |
857059 |
return 1;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
return 0;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
int stop_ud_cq_monitor(struct omgt_port *port)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
int rc;
|
|
Packit |
857059 |
struct omgt_thread_msg msg = {0};
|
|
Packit |
857059 |
|
|
Packit |
857059 |
msg.size = sizeof(msg);
|
|
Packit |
857059 |
msg.evt = OMGT_TH_EVT_UD_MONITOR_OFF;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
rc = write(port->umad_port_sv[0], &msg, sizeof(msg));
|
|
Packit |
857059 |
if (rc <= 0) {
|
|
Packit |
857059 |
OMGT_OUTPUT_ERROR(port, "Failed to stop CQ Monitoring...\n");
|
|
Packit |
857059 |
return 1;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
return 0;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
int create_sa_qp(struct omgt_port *port)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
int i;
|
|
Packit |
857059 |
int flags, rc;
|
|
Packit |
857059 |
int buf_cnt;
|
|
Packit |
857059 |
struct ibv_qp_init_attr init_attr = {0};
|
|
Packit |
857059 |
struct ibv_qp_attr attr = {0};
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if (port->sa_qp) {
|
|
Packit |
857059 |
return 0;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
port->sa_qp_comp_channel = ibv_create_comp_channel(port->verbs_ctx);
|
|
Packit |
857059 |
if (!port->sa_qp_comp_channel) {
|
|
Packit |
857059 |
OMGT_OUTPUT_ERROR(port, "Notice: create comp_channel failed\n");
|
|
Packit |
857059 |
return -EIO;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
flags = fcntl(port->sa_qp_comp_channel->fd, F_GETFL);
|
|
Packit |
857059 |
rc = fcntl(port->sa_qp_comp_channel->fd, F_SETFL, flags | O_NONBLOCK);
|
|
Packit |
857059 |
if (rc < 0) {
|
|
Packit |
857059 |
OMGT_OUTPUT_ERROR(port, "Notice: create QP failed\n");
|
|
Packit |
857059 |
goto cq_fail;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
port->recv_bufs = calloc(port->num_userspace_recv_buf,
|
|
Packit |
857059 |
sizeof *port->recv_bufs);
|
|
Packit |
857059 |
if (!port->recv_bufs){
|
|
Packit |
857059 |
OMGT_OUTPUT_ERROR(port, "Notice: recv message buffer allocation failed\n");
|
|
Packit |
857059 |
goto cq_fail;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
buf_cnt = port->num_userspace_recv_buf + port->num_userspace_send_buf + 10;
|
|
Packit |
857059 |
port->sa_qp_cq = ibv_create_cq(port->verbs_ctx, buf_cnt, (void *)port,
|
|
Packit |
857059 |
port->sa_qp_comp_channel, 0);
|
|
Packit |
857059 |
if (!port->sa_qp_cq) {
|
|
Packit |
857059 |
OMGT_OUTPUT_ERROR(port, "Notice: create QP failed\n");
|
|
Packit |
857059 |
goto buf_fail;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if (ibv_req_notify_cq(port->sa_qp_cq, 0)) {
|
|
Packit Service |
3f7ca0 |
OMGT_OUTPUT_ERROR(port, "Notice: req_notify_cq: failed\n");
|
|
Packit |
857059 |
goto pd_fail;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
port->sa_qp_pd = ibv_alloc_pd(port->verbs_ctx);
|
|
Packit |
857059 |
if (!port->sa_qp_pd) {
|
|
Packit |
857059 |
OMGT_OUTPUT_ERROR(port, "Notice: Alloc PD failed\n");
|
|
Packit |
857059 |
goto pd_fail;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
memset(&init_attr, 0, sizeof(init_attr));
|
|
Packit |
857059 |
init_attr.qp_context = (void *)port;
|
|
Packit |
857059 |
init_attr.send_cq = port->sa_qp_cq;
|
|
Packit |
857059 |
init_attr.recv_cq = port->sa_qp_cq;
|
|
Packit |
857059 |
init_attr.cap.max_send_wr = port->num_userspace_send_buf +1;
|
|
Packit |
857059 |
init_attr.cap.max_recv_wr = port->num_userspace_recv_buf +1;
|
|
Packit |
857059 |
init_attr.cap.max_send_sge = 1;
|
|
Packit |
857059 |
init_attr.cap.max_recv_sge = 1;
|
|
Packit |
857059 |
init_attr.qp_type = IBV_QPT_UD;
|
|
Packit |
857059 |
init_attr.sq_sig_all = 1;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
port->sa_qp = ibv_create_qp(port->sa_qp_pd, &init_attr);
|
|
Packit |
857059 |
if (!port->sa_qp) {
|
|
Packit |
857059 |
OMGT_OUTPUT_ERROR(port, "Notice: create QP failed\n");
|
|
Packit |
857059 |
goto qp_fail;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
attr.qp_state = IBV_QPS_INIT;
|
|
Packit |
857059 |
attr.port_num = port->hfi_port_num;
|
|
Packit |
857059 |
attr.qkey = UMAD_QKEY;
|
|
Packit |
857059 |
if ( 0xffff == (attr.pkey_index = omgt_find_pkey(port, 0xffff)) )
|
|
Packit |
857059 |
attr.pkey_index = omgt_find_pkey(port, 0x7fff);
|
|
Packit |
857059 |
if (ibv_modify_qp(port->sa_qp, &attr, IBV_QP_STATE | IBV_QP_PKEY_INDEX |
|
|
Packit |
857059 |
IBV_QP_PORT | IBV_QP_QKEY)) {
|
|
Packit |
857059 |
OMGT_OUTPUT_ERROR(port, "Notice: failed to modify QP to init\n");
|
|
Packit |
857059 |
goto destroy_qp;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
attr.qp_state = IBV_QPS_RTR;
|
|
Packit |
857059 |
if (ibv_modify_qp(port->sa_qp, &attr, IBV_QP_STATE)) {
|
|
Packit |
857059 |
OMGT_OUTPUT_ERROR(port, "Notice: failed to modify QP to rtr\n");
|
|
Packit |
857059 |
goto destroy_qp;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
attr.qp_state = IBV_QPS_RTS;
|
|
Packit |
857059 |
attr.sq_psn = 0;
|
|
Packit |
857059 |
if (ibv_modify_qp(port->sa_qp, &attr, IBV_QP_STATE | IBV_QP_SQ_PSN)) {
|
|
Packit |
857059 |
OMGT_OUTPUT_ERROR(port, "Notice: failed to modify QP to rts\n");
|
|
Packit |
857059 |
goto destroy_qp;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if (omgt_post_notice_recvs(port)) {
|
|
Packit |
857059 |
OMGT_OUTPUT_ERROR(port, "Notice: post recv buffers failed\n");
|
|
Packit |
857059 |
goto destroy_qp;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if (start_ud_cq_monitor(port))
|
|
Packit |
857059 |
goto unreg_recv;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
return (0);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
unreg_recv:
|
|
Packit |
857059 |
OMGT_DBGPRINT(port, "create_sa_qp: unreg_recv\n");
|
|
Packit |
857059 |
for (i = 0; i<port->num_userspace_recv_buf; i++)
|
|
Packit |
857059 |
ibv_dereg_mr(port->recv_bufs[i].mr);
|
|
Packit |
857059 |
destroy_qp:
|
|
Packit |
857059 |
OMGT_DBGPRINT(port, "create_sa_qp: destroy_qp\n");
|
|
Packit |
857059 |
ibv_destroy_qp(port->sa_qp);
|
|
Packit |
857059 |
port->sa_qp = NULL;
|
|
Packit |
857059 |
qp_fail:
|
|
Packit |
857059 |
OMGT_DBGPRINT(port, "create_sa_qp: qp_fail\n");
|
|
Packit |
857059 |
ibv_dealloc_pd(port->sa_qp_pd);
|
|
Packit |
857059 |
pd_fail:
|
|
Packit |
857059 |
OMGT_DBGPRINT(port, "create_sa_qp: pd_fail\n");
|
|
Packit |
857059 |
ibv_destroy_cq(port->sa_qp_cq);
|
|
Packit |
857059 |
buf_fail:
|
|
Packit |
857059 |
OMGT_DBGPRINT(port, "create_sa_qp: buf_fail\n");
|
|
Packit |
857059 |
free(port->recv_bufs);
|
|
Packit |
857059 |
cq_fail:
|
|
Packit |
857059 |
OMGT_DBGPRINT(port, "create_sa_qp: cq_fail\n");
|
|
Packit |
857059 |
ibv_destroy_comp_channel(port->sa_qp_comp_channel);
|
|
Packit |
857059 |
return (-EIO);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
static int start_outstanding_req_timer(struct omgt_port *port)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
int rc;
|
|
Packit |
857059 |
struct omgt_thread_msg msg = {0};
|
|
Packit |
857059 |
|
|
Packit |
857059 |
msg.size = sizeof(msg);
|
|
Packit |
857059 |
msg.evt = OMGT_TH_EVT_START_OUTSTANDING_REQ_TIME;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
rc = write(port->umad_port_sv[0], &msg, sizeof(msg));
|
|
Packit |
857059 |
if (rc <= 0) {
|
|
Packit |
857059 |
OMGT_OUTPUT_ERROR(port, "Failed to start outstanding request timer...\n");
|
|
Packit |
857059 |
return 1;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
return 0;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
/**
|
|
Packit |
857059 |
* port->lock must be held
|
|
Packit |
857059 |
*/
|
|
Packit |
857059 |
int userspace_register(struct omgt_port *port, uint16_t trap_num, omgt_sa_registration_t *reg)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
struct omgt_sa_msg *sa_msg;
|
|
Packit |
857059 |
struct umad_sa_packet *sa_pkt;
|
|
Packit |
857059 |
STL_INFORM_INFO *informinfo;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
sa_msg = alloc_send_sa_msg(port);
|
|
Packit |
857059 |
if (!sa_msg)
|
|
Packit |
857059 |
return (-EIO);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
memset(sa_msg->data, 0, sizeof(sa_msg->data));
|
|
Packit |
857059 |
sa_pkt = (struct umad_sa_packet *)sa_msg->data;
|
|
Packit |
857059 |
set_sa_common_stl_inform_info(port, sa_pkt);
|
|
Packit |
857059 |
informinfo = (STL_INFORM_INFO *)sa_pkt->data;
|
|
Packit |
857059 |
informinfo->Subscribe = 1;
|
|
Packit |
857059 |
informinfo->u.Generic.TrapNumber = trap_num;
|
|
Packit |
857059 |
informinfo->u.Generic.u1.s.RespTimeValue = 19;
|
|
Packit |
857059 |
BSWAP_STL_INFORM_INFO(informinfo);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
LIST_ADD(&port->pending_reg_msg_head, sa_msg);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
reg->reg_msg = sa_msg;
|
|
Packit |
857059 |
sa_msg->reg = reg;
|
|
Packit |
857059 |
sa_msg->retries = NOTICE_REG_RETRY_COUNT;
|
|
Packit |
857059 |
sa_msg->status = 0;
|
|
Packit |
857059 |
post_send_sa_msg(port, sa_msg, OMGT_RRS_SEND_INITIAL);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
OMGT_DBGPRINT(port, "starting timer to register %d\n", trap_num);
|
|
Packit |
857059 |
start_outstanding_req_timer(port);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
return (0);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
/**
|
|
Packit |
857059 |
* port->lock must be held
|
|
Packit |
857059 |
*/
|
|
Packit |
857059 |
static int userspace_unregister(struct omgt_port *port, omgt_sa_registration_t *reg)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
struct omgt_sa_msg *sa_msg;
|
|
Packit |
857059 |
struct umad_sa_packet *sa_pkt;
|
|
Packit |
857059 |
STL_INFORM_INFO *informinfo;
|
|
Packit |
857059 |
uint16_t trap_num;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if (reg->reg_msg) {
|
|
Packit |
857059 |
LIST_DEL(reg->reg_msg);
|
|
Packit |
857059 |
/* Registration never completed just free the oustanding mad */
|
|
Packit |
857059 |
free_sa_msg(reg->reg_msg);
|
|
Packit |
857059 |
return 0;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
sa_msg = alloc_send_sa_msg(port);
|
|
Packit |
857059 |
if (!sa_msg) {
|
|
Packit |
857059 |
OMGT_OUTPUT_ERROR(port, "Notice: failed to allocate SA message\n");
|
|
Packit |
857059 |
return (-EIO);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
trap_num = reg->trap_num;
|
|
Packit |
857059 |
memset(sa_msg->data, 0, sizeof(sa_msg->data));
|
|
Packit |
857059 |
sa_pkt = (struct umad_sa_packet *)sa_msg->data;
|
|
Packit |
857059 |
set_sa_common_stl_inform_info(port, sa_pkt);
|
|
Packit |
857059 |
informinfo = (STL_INFORM_INFO *)sa_pkt->data;
|
|
Packit |
857059 |
informinfo->Subscribe = 0;
|
|
Packit |
857059 |
informinfo->u.Generic.TrapNumber = trap_num;
|
|
Packit |
857059 |
informinfo->u.Generic.u1.s.RespTimeValue = 19;
|
|
Packit |
857059 |
informinfo->u.Generic.u1.s.QPNumber = port->sa_qp->qp_num;
|
|
Packit |
857059 |
BSWAP_STL_INFORM_INFO(informinfo);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
LIST_ADD(&port->pending_reg_msg_head, sa_msg);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
/* By the time the response comes back, the variable "reg" is already
|
|
Packit |
857059 |
freed by omgt_sa_remove_gre_by_trap (the caller), and we should not
|
|
Packit |
857059 |
set it here to avoid segfault in process_sa_gret_resp() */
|
|
Packit |
857059 |
sa_msg->reg = NULL;
|
|
Packit |
857059 |
sa_msg->retries = NOTICE_REG_RETRY_COUNT;
|
|
Packit |
857059 |
sa_msg->status = 0;
|
|
Packit |
857059 |
post_send_sa_msg(port, sa_msg, OMGT_RRS_SEND_INITIAL);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
OMGT_DBGPRINT(port, "starting timer to un-register %d\n", trap_num);
|
|
Packit |
857059 |
start_outstanding_req_timer(port);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
return 0;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
/**
|
|
Packit |
857059 |
* Removes a registration based on its trap number.
|
|
Packit |
857059 |
* NOTE: Caller must hold the lock.
|
|
Packit |
857059 |
*
|
|
Packit |
857059 |
* @param port port opened by omgt_open_port_*
|
|
Packit |
857059 |
* @param trap_num The trap number to search for
|
|
Packit |
857059 |
*
|
|
Packit |
857059 |
* @return 0 if success, else error code
|
|
Packit |
857059 |
*/
|
|
Packit |
857059 |
FSTATUS omgt_sa_remove_reg_by_trap_unsafe(struct omgt_port *port, uint16_t trap_num)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
omgt_sa_registration_t *curr = port->regs_list, *prev = NULL;
|
|
Packit |
857059 |
while (curr != NULL) {
|
|
Packit |
857059 |
if (curr->trap_num == trap_num) {
|
|
Packit |
857059 |
if (prev != NULL)
|
|
Packit |
857059 |
prev->next = curr->next;
|
|
Packit |
857059 |
else
|
|
Packit |
857059 |
port->regs_list = curr->next;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
userspace_unregister(port, curr);
|
|
Packit |
857059 |
free(curr);
|
|
Packit |
857059 |
return FSUCCESS;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
prev = curr;
|
|
Packit |
857059 |
curr = curr->next;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
return FERROR;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
/**
|
|
Packit |
857059 |
* Clear all registrations from the port.
|
|
Packit |
857059 |
*/
|
|
Packit |
857059 |
void omgt_sa_clear_regs_unsafe(struct omgt_port *port)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
FSTATUS status = FTIMEOUT;
|
|
Packit |
857059 |
if (omgt_lock_sem(&port->lock)) {
|
|
Packit |
857059 |
OMGT_OUTPUT_ERROR(port, "failed to acquire lock (status: %d)\n", status);
|
|
Packit |
857059 |
return;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
while (port->regs_list != NULL) {
|
|
Packit |
857059 |
/* The called function takes care of adjusting the head pointer
|
|
Packit |
857059 |
and freeing the entry*/
|
|
Packit |
857059 |
omgt_sa_remove_reg_by_trap_unsafe(port, port->regs_list->trap_num);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
omgt_unlock_sem(&port->lock);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
/**
|
|
Packit |
857059 |
* Re-register all current registrations for the port.
|
|
Packit |
857059 |
*/
|
|
Packit |
857059 |
int reregister_traps(struct omgt_port *port)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
int ret;
|
|
Packit |
857059 |
int status = -1;
|
|
Packit |
857059 |
if (omgt_lock_sem(&port->lock)) {
|
|
Packit |
857059 |
OMGT_OUTPUT_ERROR(port, "failed to acquire lock (status: %d)\n", status);
|
|
Packit |
857059 |
return status;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
omgt_sa_registration_t *curr = port->regs_list;
|
|
Packit |
857059 |
while (curr != NULL) {
|
|
Packit |
857059 |
if ((ret = userspace_register(port, curr->trap_num, curr)) != 0) {
|
|
Packit |
857059 |
OMGT_OUTPUT_ERROR(port, "omgt_sa_reregister_trap_regs: failed to register for trap (%u) (status: %d)\n",
|
|
Packit |
857059 |
curr->trap_num, ret);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
curr = curr->next;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
omgt_unlock_sem(&port->lock);
|
|
Packit |
857059 |
return 0;
|
|
Packit |
857059 |
}
|