Blame opamgt/src/ib_notice.c

Packit 857059
/* BEGIN_ICS_COPYRIGHT5 ****************************************
Packit 857059
Packit 857059
Copyright (c) 2015-2017, 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 *)&notice->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 857059
        OMGT_OUTPUT_ERROR(port, "Notice: req_notifiy_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
}