#include <sys/time.h>
#include <strings.h>
#include "dapl_evd_util.h"
#include "dapl_ia_util.h"
#include "dapl_cno_util.h"
#include "dapl_ring_buffer_util.h"
#include "dapl_adapter_util.h"
#include "dapl_tavor_ibtf_impl.h"
#include "dapl_cookie.h"
#include "dapl.h"
#ifdef DAPL_DBG
static void
dapli_evd_eh_print_cqe(
IN ib_work_completion_t cqe);
#endif
static DAT_BOOLEAN
dapli_evd_cqe_to_event(
IN DAPL_EVD *evd_ptr,
IN ib_work_completion_t *cqe_ptr,
IN DAT_BOOLEAN process_premature_events,
OUT DAT_EVENT *event_ptr);
static DAT_RETURN
dapli_evd_event_alloc(
IN DAPL_EVD *evd_ptr,
IN DAPL_CNO *cno_ptr,
IN DAT_COUNT qlen);
DAT_RETURN
dapls_evd_internal_create(
DAPL_IA *ia_ptr,
DAPL_CNO *cno_ptr,
DAT_COUNT min_qlen,
DAT_EVD_FLAGS evd_flags,
DAPL_EVD **evd_ptr_ptr)
{
DAPL_EVD *evd_ptr;
DAT_COUNT cq_len;
DAT_RETURN dat_status;
dat_status = DAT_SUCCESS;
*evd_ptr_ptr = NULL;
cq_len = min_qlen;
evd_ptr = dapls_evd_alloc(ia_ptr,
cno_ptr,
evd_flags,
min_qlen);
if (!evd_ptr) {
dat_status = DAT_ERROR(DAT_INSUFFICIENT_RESOURCES,
DAT_RESOURCE_MEMORY);
goto bail;
}
evd_ptr->evd_producer_locking_needed =
((evd_flags & ~ (DAT_EVD_DTO_FLAG|DAT_EVD_RMR_BIND_FLAG)) != 0);
evd_ptr->evd_state = DAPL_EVD_STATE_OPEN;
dat_status = dapls_ib_cq_alloc(ia_ptr,
evd_ptr, cno_ptr, &cq_len);
if (dat_status != DAT_SUCCESS) {
goto bail;
}
#if 0
dat_status = dapls_ib_setup_async_callback(
ia_ptr,
DAPL_ASYNC_CQ_COMPLETION,
(unsigned int *) evd_ptr->ib_cq_handle,
(ib_async_handler_t)dapl_evd_dto_callback,
evd_ptr);
if (dat_status != DAT_SUCCESS) {
goto bail;
}
#endif
dat_status = dapli_evd_event_alloc(evd_ptr, cno_ptr, cq_len);
if (dat_status != DAT_SUCCESS) {
goto bail;
}
dapl_os_assert(dat_status == DAT_SUCCESS);
dapl_ia_link_evd(ia_ptr, evd_ptr);
*evd_ptr_ptr = evd_ptr;
bail:
if (dat_status != DAT_SUCCESS) {
if (evd_ptr) {
(void) dapls_evd_dealloc(evd_ptr);
}
}
return (dat_status);
}
DAPL_EVD *
dapls_evd_alloc(
IN DAPL_IA *ia_ptr,
IN DAPL_CNO *cno_ptr,
IN DAT_EVD_FLAGS evd_flags,
IN DAT_COUNT qlen)
{
DAPL_EVD *evd_ptr;
evd_ptr = NULL;
evd_ptr = (DAPL_EVD *)dapl_os_alloc(sizeof (DAPL_EVD));
if (!evd_ptr) {
goto bail;
}
(void) dapl_os_memzero(evd_ptr, sizeof (DAPL_EVD));
evd_ptr->header.provider = ia_ptr->header.provider;
evd_ptr->header.magic = DAPL_MAGIC_EVD;
evd_ptr->header.handle_type = DAT_HANDLE_TYPE_EVD;
evd_ptr->header.owner_ia = ia_ptr;
evd_ptr->header.user_context.as_64 = 0;
evd_ptr->header.user_context.as_ptr = NULL;
dapl_llist_init_entry(&evd_ptr->header.ia_list_entry);
dapl_os_lock_init(&evd_ptr->header.lock);
evd_ptr->evd_state = DAPL_EVD_STATE_INITIAL;
evd_ptr->evd_flags = evd_flags;
evd_ptr->evd_enabled = DAT_TRUE;
evd_ptr->evd_waitable = DAT_TRUE;
evd_ptr->evd_producer_locking_needed = 1;
evd_ptr->ib_cq_handle = IB_INVALID_HANDLE;
evd_ptr->evd_ref_count = 0;
evd_ptr->catastrophic_overflow = DAT_FALSE;
evd_ptr->qlen = qlen;
dapl_llist_init_entry(&evd_ptr->cno_list_entry);
evd_ptr->completion_type = DAPL_EVD_STATE_THRESHOLD;
(void) dapl_os_wait_object_init(&evd_ptr->wait_object);
bail:
return (evd_ptr);
}
DAT_RETURN
dapli_evd_event_alloc(
IN DAPL_EVD *evd_ptr,
IN DAPL_CNO *cno_ptr,
IN DAT_COUNT qlen)
{
DAT_EVENT *event_ptr;
DAT_COUNT i;
DAT_RETURN dat_status;
dat_status = DAT_SUCCESS;
event_ptr = NULL;
event_ptr = (DAT_EVENT *) dapl_os_alloc(qlen * sizeof (DAT_EVENT));
if (!event_ptr) {
goto bail;
}
evd_ptr->events = event_ptr;
evd_ptr->qlen = qlen;
dat_status = dapls_rbuf_alloc(&evd_ptr->free_event_queue, qlen);
if (dat_status != DAT_SUCCESS) {
goto bail;
}
dat_status = dapls_rbuf_alloc(&evd_ptr->pending_event_queue, qlen);
if (dat_status != DAT_SUCCESS) {
goto bail;
}
for (i = 0; i < qlen; i++) {
dat_status = dapls_rbuf_add(&evd_ptr->free_event_queue,
(void *)event_ptr);
dapl_os_assert(dat_status == DAT_SUCCESS);
event_ptr++;
}
evd_ptr->cq_notified = DAT_FALSE;
evd_ptr->cq_notified_when = 0;
evd_ptr->cno_active_count = 0;
if (cno_ptr != NULL) {
dapl_os_lock(&cno_ptr->header.lock);
dapl_llist_add_head(&cno_ptr->evd_list_head,
&evd_ptr->cno_list_entry, evd_ptr);
dapl_os_atomic_inc(&cno_ptr->cno_ref_count);
dapl_os_unlock(&cno_ptr->header.lock);
}
evd_ptr->cno_ptr = cno_ptr;
evd_ptr->threshold = 0;
bail:
return (dat_status);
}
DAT_RETURN
dapls_evd_dealloc(
IN DAPL_EVD *evd_ptr)
{
DAT_RETURN dat_status;
DAPL_IA *ia_ptr;
dat_status = DAT_SUCCESS;
dapl_os_assert(evd_ptr->header.magic == DAPL_MAGIC_EVD);
dapl_os_assert(evd_ptr->evd_ref_count == 0);
if (evd_ptr->ib_cq_handle != IB_INVALID_HANDLE) {
ia_ptr = evd_ptr->header.owner_ia;
dat_status = dapls_ib_cq_free(ia_ptr, evd_ptr);
if (dat_status != DAT_SUCCESS) {
goto bail;
}
}
evd_ptr->header.magic = DAPL_MAGIC_INVALID;
if (evd_ptr->cno_ptr != NULL) {
dapl_os_lock(&evd_ptr->cno_ptr->header.lock);
(void) dapl_llist_remove_entry(&evd_ptr->cno_ptr->evd_list_head,
&evd_ptr->cno_list_entry);
dapl_os_atomic_dec(&evd_ptr->cno_ptr->cno_ref_count);
dapl_os_unlock(&evd_ptr->cno_ptr->header.lock);
}
dapls_rbuf_destroy(&evd_ptr->free_event_queue);
dapls_rbuf_destroy(&evd_ptr->pending_event_queue);
if (evd_ptr->events) {
dapl_os_free(evd_ptr->events,
evd_ptr->qlen * sizeof (DAT_EVENT));
}
(void) dapl_os_wait_object_destroy(&evd_ptr->wait_object);
dapl_os_free(evd_ptr, sizeof (DAPL_EVD));
bail:
return (dat_status);
}
#ifdef DAPL_DBG
void
dapli_evd_eh_print_cqe(IN ib_work_completion_t cqe)
{
static char *optable[] = {
"",
"OP_SEND",
"OP_RDMA_READ",
"OP_RDMA_WRITE",
"OP_COMP_AND_SWAP",
"OP_FETCH_AND_ADD",
"OP_BIND_MW",
"OP_RECEIVE",
"OP_RECEIVE_RDMAWI",
0
};
DAPL_COOKIE *dto_cookie;
dto_cookie = (DAPL_COOKIE *) (uintptr_t)DAPL_GET_CQE_WRID(&cqe);
dapl_dbg_log(DAPL_DBG_TYPE_CALLBACK,
"\t >>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<\n");
dapl_dbg_log(DAPL_DBG_TYPE_CALLBACK,
"\t dapl_evd_dto_callback : CQE \n");
dapl_dbg_log(DAPL_DBG_TYPE_CALLBACK,
"\t\t work_req_id 0x%llx\n", DAPL_GET_CQE_WRID(&cqe));
dapl_dbg_log(DAPL_DBG_TYPE_CALLBACK,
"\t\t op_type: %s\n", optable[DAPL_GET_CQE_OPTYPE(&cqe)]);
if ((DAPL_GET_CQE_OPTYPE(&cqe) == OP_SEND) ||
(DAPL_GET_CQE_OPTYPE(&cqe) == OP_RDMA_WRITE)) {
dapl_dbg_log(DAPL_DBG_TYPE_CALLBACK,
"\t\t bytes_num %d\n", dto_cookie->val.dto.size);
} else {
dapl_dbg_log(DAPL_DBG_TYPE_CALLBACK,
"\t\t bytes_num %d\n", DAPL_GET_CQE_BYTESNUM(&cqe));
}
dapl_dbg_log(DAPL_DBG_TYPE_CALLBACK,
"\t\t status %d\n", DAPL_GET_CQE_STATUS(&cqe));
dapl_dbg_log(DAPL_DBG_TYPE_CALLBACK,
"\t >>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<\n");
}
#endif
static DAT_EVENT *
dapli_evd_get_event(
DAPL_EVD *evd_ptr)
{
DAT_EVENT *event;
if (evd_ptr->evd_producer_locking_needed) {
dapl_os_lock(&evd_ptr->header.lock);
}
event = (DAT_EVENT *)dapls_rbuf_remove(&evd_ptr->free_event_queue);
if (!event && evd_ptr->evd_producer_locking_needed) {
dapl_os_unlock(&evd_ptr->header.lock);
}
return (event);
}
static void
dapli_evd_post_event(
IN DAPL_EVD *evd_ptr,
IN const DAT_EVENT *event_ptr)
{
DAT_RETURN dat_status;
DAPL_CNO *cno_to_trigger = NULL;
dapl_dbg_log(DAPL_DBG_TYPE_EVD,
"dapli_evd_post_event: Called with event # %x\n",
event_ptr->event_number);
dat_status = dapls_rbuf_add(&evd_ptr->pending_event_queue,
(void *)event_ptr);
dapl_os_assert(dat_status == DAT_SUCCESS);
dapl_os_assert(evd_ptr->evd_state == DAPL_EVD_STATE_WAITED ||
evd_ptr->evd_state == DAPL_EVD_STATE_OPEN);
if (evd_ptr->evd_state == DAPL_EVD_STATE_OPEN) {
if (evd_ptr->evd_enabled) {
cno_to_trigger = evd_ptr->cno_ptr;
}
if (evd_ptr->evd_producer_locking_needed) {
dapl_os_unlock(&evd_ptr->header.lock);
}
} else {
if (event_ptr->event_number == DAT_SOFTWARE_EVENT) {
if (!evd_ptr->evd_producer_locking_needed) {
dapl_os_lock(&evd_ptr->header.lock);
}
if (evd_ptr->evd_state == DAPL_EVD_STATE_WAITED) {
dapl_os_unlock(&evd_ptr->header.lock);
(void) dapls_ib_event_wakeup(evd_ptr);
} else {
dapl_os_unlock(&evd_ptr->header.lock);
}
} else {
if (evd_ptr->evd_producer_locking_needed) {
dapl_os_unlock(&evd_ptr->header.lock);
}
}
}
if (cno_to_trigger != NULL) {
dapl_cno_trigger(cno_to_trigger, evd_ptr);
}
}
static void
dapli_evd_post_event_nosignal(
IN DAPL_EVD *evd_ptr,
IN const DAT_EVENT *event_ptr)
{
DAT_RETURN dat_status;
dapl_dbg_log(DAPL_DBG_TYPE_EVD,
"dapli_evd_post_event: Called with event # %x\n",
event_ptr->event_number);
dat_status = dapls_rbuf_add(&evd_ptr->pending_event_queue,
(void *)event_ptr);
dapl_os_assert(dat_status == DAT_SUCCESS);
dapl_os_assert(evd_ptr->evd_state == DAPL_EVD_STATE_WAITED ||
evd_ptr->evd_state == DAPL_EVD_STATE_OPEN);
if (evd_ptr->evd_producer_locking_needed) {
dapl_os_unlock(&evd_ptr->header.lock);
}
}
static void
dapli_evd_format_overflow_event(
IN DAPL_EVD *evd_ptr,
OUT DAT_EVENT *event_ptr)
{
DAPL_IA *ia_ptr;
ia_ptr = evd_ptr->header.owner_ia;
event_ptr->evd_handle = (DAT_EVD_HANDLE)evd_ptr;
event_ptr->event_number = DAT_ASYNC_ERROR_EVD_OVERFLOW;
event_ptr->event_data.asynch_error_event_data.dat_handle =
(DAT_HANDLE)ia_ptr;
}
static void
dapli_evd_post_overflow_event(
IN DAPL_EVD *async_evd_ptr,
IN DAPL_EVD *overflow_evd_ptr)
{
DAT_EVENT *overflow_event;
if (async_evd_ptr == overflow_evd_ptr) {
async_evd_ptr->catastrophic_overflow = DAT_TRUE;
async_evd_ptr->evd_state = DAPL_EVD_STATE_DEAD;
return;
}
overflow_event = dapli_evd_get_event(overflow_evd_ptr);
if (!overflow_event) {
overflow_evd_ptr->catastrophic_overflow = DAT_TRUE;
overflow_evd_ptr->evd_state = DAPL_EVD_STATE_DEAD;
return;
}
dapli_evd_format_overflow_event(overflow_evd_ptr, overflow_event);
dapli_evd_post_event(overflow_evd_ptr, overflow_event);
}
static DAT_EVENT *
dapli_evd_get_and_init_event(
IN DAPL_EVD *evd_ptr,
IN DAT_EVENT_NUMBER event_number)
{
DAT_EVENT *event_ptr;
event_ptr = dapli_evd_get_event(evd_ptr);
if (NULL == event_ptr) {
dapli_evd_post_overflow_event(
evd_ptr->header.owner_ia->async_error_evd, evd_ptr);
} else {
event_ptr->evd_handle = (DAT_EVD_HANDLE) evd_ptr;
event_ptr->event_number = event_number;
}
return (event_ptr);
}
DAT_RETURN
dapls_evd_post_cr_arrival_event(
IN DAPL_EVD *evd_ptr,
IN DAT_EVENT_NUMBER event_number,
IN DAT_SP_HANDLE sp_handle,
DAT_IA_ADDRESS_PTR ia_address_ptr,
DAT_CONN_QUAL conn_qual,
DAT_CR_HANDLE cr_handle)
{
DAT_EVENT *event_ptr;
event_ptr = dapli_evd_get_and_init_event(evd_ptr, event_number);
if (!event_ptr) {
return (DAT_INSUFFICIENT_RESOURCES | DAT_RESOURCE_MEMORY);
}
event_ptr->event_data.cr_arrival_event_data.sp_handle = sp_handle;
event_ptr->event_data.cr_arrival_event_data.local_ia_address_ptr
= ia_address_ptr;
event_ptr->event_data.cr_arrival_event_data.conn_qual = conn_qual;
event_ptr->event_data.cr_arrival_event_data.cr_handle = cr_handle;
dapli_evd_post_event(evd_ptr, event_ptr);
return (DAT_SUCCESS);
}
DAT_RETURN
dapls_evd_post_connection_event(
IN DAPL_EVD *evd_ptr,
IN DAT_EVENT_NUMBER event_number,
IN DAT_EP_HANDLE ep_handle,
IN DAT_COUNT private_data_size,
IN DAT_PVOID private_data)
{
DAT_EVENT *event_ptr;
event_ptr = dapli_evd_get_and_init_event(evd_ptr, event_number);
if (!event_ptr) {
return (DAT_INSUFFICIENT_RESOURCES | DAT_RESOURCE_MEMORY);
}
event_ptr->event_data.connect_event_data.ep_handle = ep_handle;
event_ptr->event_data.connect_event_data.private_data_size
= private_data_size;
event_ptr->event_data.connect_event_data.private_data = private_data;
dapli_evd_post_event(evd_ptr, event_ptr);
return (DAT_SUCCESS);
}
DAT_RETURN
dapls_evd_post_async_error_event(
IN DAPL_EVD *evd_ptr,
IN DAT_EVENT_NUMBER event_number,
IN DAT_IA_HANDLE ia_handle)
{
DAT_EVENT *event_ptr;
event_ptr = dapli_evd_get_and_init_event(evd_ptr, event_number);
if (!event_ptr) {
return (DAT_INSUFFICIENT_RESOURCES | DAT_RESOURCE_MEMORY);
}
event_ptr->event_data.asynch_error_event_data.dat_handle = ia_handle;
dapli_evd_post_event(evd_ptr, event_ptr);
return (DAT_SUCCESS);
}
DAT_RETURN
dapls_evd_post_software_event(
IN DAPL_EVD *evd_ptr,
IN DAT_EVENT_NUMBER event_number,
IN DAT_PVOID pointer)
{
DAT_EVENT *event_ptr;
event_ptr = dapli_evd_get_and_init_event(evd_ptr, event_number);
if (!event_ptr) {
return (DAT_QUEUE_FULL);
}
event_ptr->event_data.software_event_data.pointer = pointer;
dapli_evd_post_event(evd_ptr, event_ptr);
return (DAT_SUCCESS);
}
void
dapls_evd_post_premature_events(IN DAPL_EP *ep_ptr)
{
DAPL_EVD *evd_ptr;
DAT_EVENT *event;
ib_work_completion_t *cqe;
uint32_t qpn;
int prm_idx;
int nevents;
int i;
dapls_ib_poll_premature_events(ep_ptr, &cqe, &nevents);
evd_ptr = ep_ptr->param.recv_evd_handle;
qpn = ep_ptr->qpn;
i = 0;
prm_idx = 0;
while (i < nevents) {
dapl_os_assert(!ep_ptr->srq_attached ||
(prm_idx <= ((DAPL_SRQ *)ep_ptr->param.srq_handle)->
param.max_recv_dtos));
if (ep_ptr->srq_attached &&
(!DAPL_CQE_IS_VALID(&cqe[prm_idx]) ||
(DAPL_GET_CQE_QPN(&cqe[prm_idx]) != qpn))) {
prm_idx++;
continue;
}
dapl_dbg_log(DAPL_DBG_TYPE_DTO_COMP_ERR,
" Premature DTO processing\n");
#ifdef DAPL_DBG
dapli_evd_eh_print_cqe(cqe[i]);
#endif
event = dapli_evd_get_and_init_event(evd_ptr,
DAT_DTO_COMPLETION_EVENT);
if (event == NULL) {
return;
}
(void) dapli_evd_cqe_to_event(evd_ptr, &cqe[i], DAT_TRUE,
event);
dapli_evd_post_event_nosignal(evd_ptr, event);
if (ep_ptr->srq_attached) {
dapls_ib_free_premature_events(ep_ptr, prm_idx);
prm_idx++;
}
i++;
}
}
static DAT_BOOLEAN
dapli_evd_cqe_to_event(
IN DAPL_EVD *evd_ptr,
IN ib_work_completion_t *cqe_ptr,
IN DAT_BOOLEAN process_premature_events,
OUT DAT_EVENT *event_ptr)
{
DAPL_EP *ep_ptr;
DAPL_SRQ *srq_ptr;
DAPL_COOKIE *cookie;
DAT_EP_STATE ep_state;
ib_qp_handle_t qp;
ib_uint32_t ib_status;
ib_uint32_t ibtype;
int srq_enabled;
int dto_error = 0;
ib_status = DAPL_GET_CQE_STATUS(cqe_ptr);
cookie = (DAPL_COOKIE *)((uintptr_t)DAPL_GET_CQE_WRID(cqe_ptr));
dapl_os_assert((NULL != cookie));
if (cookie->queue_type == DAPL_COOKIE_QUEUE_EP) {
srq_enabled = 0;
ep_ptr = cookie->queue.ep;
} else {
srq_enabled = 1;
srq_ptr = cookie->queue.srq;
dapl_os_assert(NULL != srq_ptr);
dapl_os_assert(srq_ptr->header.magic == DAPL_MAGIC_SRQ);
ib_status = DAPL_GET_CQE_STATUS(cqe_ptr);
ep_ptr = dapls_ib_srq_lookup_ep(srq_ptr, cqe_ptr);
}
dapl_os_assert((NULL != ep_ptr));
dapl_os_assert((ep_ptr->header.magic == DAPL_MAGIC_EP) ||
(ep_ptr->header.magic == DAPL_MAGIC_EP_EXIT));
event_ptr->evd_handle = (DAT_EVD_HANDLE) evd_ptr;
if (!process_premature_events &&
(cookie->type == DAPL_COOKIE_TYPE_DTO) &&
(ib_status == IB_COMP_ST_SUCCESS)) {
ep_state = ep_ptr->param.ep_state;
qp = ep_ptr->qp_handle;
if ((ep_state == DAT_EP_STATE_ACTIVE_CONNECTION_PENDING) ||
(ep_state == DAT_EP_STATE_COMPLETION_PENDING) ||
(qp->qp_num_premature_events > 0)) {
dapls_ib_store_premature_events(qp, cqe_ptr);
return (DAT_FALSE);
}
}
switch (cookie->type) {
case DAPL_COOKIE_TYPE_DTO:
{
DAPL_COOKIE_BUFFER *buffer;
if (DAPL_DTO_TYPE_RECV == cookie->val.dto.type) {
if (srq_enabled) {
dapl_os_atomic_dec(&srq_ptr->recv_count);
buffer = &srq_ptr->recv_buffer;
} else {
dapl_os_atomic_dec(&ep_ptr->recv_count);
buffer = &ep_ptr->recv_buffer;
}
} else {
dapl_os_atomic_dec(&ep_ptr->req_count);
buffer = &ep_ptr->req_buffer;
}
event_ptr->event_number = DAT_DTO_COMPLETION_EVENT;
event_ptr->event_data.dto_completion_event_data.ep_handle =
ep_ptr;
event_ptr->event_data.dto_completion_event_data.user_cookie =
cookie->val.dto.cookie;
switch (ib_status) {
case IB_COMP_ST_SUCCESS:
{
ibtype = DAPL_GET_CQE_OPTYPE(cqe_ptr);
event_ptr->event_data.dto_completion_event_data.status =
DAT_DTO_SUCCESS;
dapl_os_assert((ibtype == OP_SEND &&
cookie->val.dto.type == DAPL_DTO_TYPE_SEND) ||
(ibtype == OP_RECEIVE &&
cookie->val.dto.type == DAPL_DTO_TYPE_RECV) ||
(ibtype == OP_RDMA_WRITE &&
cookie->val.dto.type ==
DAPL_DTO_TYPE_RDMA_WRITE) ||
(ibtype == OP_RDMA_READ &&
cookie->val.dto.type ==
DAPL_DTO_TYPE_RDMA_READ));
break;
}
case IB_COMP_ST_LOCAL_LEN_ERR:
{
event_ptr->event_data.dto_completion_event_data.status =
DAT_DTO_ERR_LOCAL_LENGTH;
break;
}
case IB_COMP_ST_LOCAL_PROTECT_ERR:
{
event_ptr->event_data.dto_completion_event_data.status =
DAT_DTO_ERR_LOCAL_PROTECTION;
break;
}
case IB_COMP_ST_WR_FLUSHED_ERR:
{
event_ptr->event_data.dto_completion_event_data.status =
DAT_DTO_ERR_FLUSHED;
break;
}
case IB_COMP_ST_BAD_RESPONSE_ERR:
{
event_ptr->event_data.dto_completion_event_data.status =
DAT_DTO_ERR_BAD_RESPONSE;
break;
}
case IB_COMP_ST_REM_REQ_ERR:
case IB_COMP_ST_REM_OP_ERR:
{
event_ptr->event_data.dto_completion_event_data.status =
DAT_DTO_ERR_REMOTE_RESPONDER;
break;
}
case IB_COMP_ST_REM_ACC_ERR:
{
event_ptr->event_data.dto_completion_event_data.status =
DAT_DTO_ERR_REMOTE_ACCESS;
break;
}
case IB_COMP_ST_TRANSP_COUNTER:
{
event_ptr->event_data.dto_completion_event_data.status =
DAT_DTO_ERR_TRANSPORT;
break;
}
case IB_COMP_ST_RNR_COUNTER:
{
event_ptr->event_data.dto_completion_event_data.status =
DAT_DTO_ERR_RECEIVER_NOT_READY;
break;
}
case IB_COMP_ST_MW_BIND_ERR:
{
event_ptr->event_data.dto_completion_event_data.status =
DAT_RMR_OPERATION_FAILED;
break;
}
case IB_COMP_ST_LOCAL_OP_ERR:
{
event_ptr->event_data.dto_completion_event_data.status =
DAT_DTO_ERR_LOCAL_EP;
break;
}
default:
{
dapl_dbg_log(DAPL_DBG_TYPE_DTO_COMP_ERR,
" DTO completion ERROR: %d: op %#x\n",
DAPL_GET_CQE_STATUS(cqe_ptr),
DAPL_GET_CQE_OPTYPE(cqe_ptr));
event_ptr->event_data.dto_completion_event_data.status =
DAT_DTO_FAILURE;
break;
}
}
if ((event_ptr->event_data.dto_completion_event_data.status !=
DAT_DTO_SUCCESS) &&
(event_ptr->event_data.dto_completion_event_data.status !=
DAT_RMR_OPERATION_FAILED)) {
dto_error = 1;
dapl_dbg_log(DAPL_DBG_TYPE_DTO_COMP_ERR,
" DTO completion ERROR: %d: op %#x\n",
DAPL_GET_CQE_STATUS(cqe_ptr),
DAPL_GET_CQE_OPTYPE(cqe_ptr));
}
if (cookie->val.dto.type == DAPL_DTO_TYPE_SEND ||
cookie->val.dto.type == DAPL_DTO_TYPE_RDMA_WRITE) {
event_ptr->event_data.dto_completion_event_data.
transfered_length = cookie->val.dto.size;
} else {
event_ptr->event_data.dto_completion_event_data.
transfered_length = DAPL_GET_CQE_BYTESNUM(cqe_ptr);
}
dapls_cookie_dealloc(buffer, cookie);
break;
}
case DAPL_COOKIE_TYPE_RMR:
{
dapl_os_atomic_dec(&ep_ptr->req_count);
event_ptr->event_number = DAT_RMR_BIND_COMPLETION_EVENT;
event_ptr->event_data.rmr_completion_event_data.rmr_handle =
cookie->val.rmr.rmr;
event_ptr->event_data.rmr_completion_event_data.user_cookie =
cookie->val.rmr.cookie;
if (ib_status == IB_COMP_ST_SUCCESS) {
ibtype = DAPL_GET_CQE_OPTYPE(cqe_ptr);
event_ptr->event_data.rmr_completion_event_data.status =
DAT_RMR_BIND_SUCCESS;
dapl_os_assert(ibtype == OP_BIND_MW);
} else {
event_ptr->event_data.rmr_completion_event_data.status =
DAT_RMR_BIND_FAILURE;
dto_error = 1;
}
dapls_cookie_dealloc(&ep_ptr->req_buffer, cookie);
break;
}
default:
{
dapl_os_assert(!"Invalid Operation type");
break;
}
}
if ((dto_error) && (ep_ptr->param.ep_state == DAT_EP_STATE_CONNECTED)) {
ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED;
dapls_ib_disconnect_clean(ep_ptr, DAT_TRUE, IB_CME_CONNECTED);
}
if (process_premature_events && (ep_ptr->param.ep_state ==
DAT_EP_STATE_DISCONNECTED) && (ib_status == IB_COMP_ST_SUCCESS)) {
dapl_os_assert(ibtype == OP_RECEIVE &&
cookie->val.dto.type == DAPL_DTO_TYPE_RECV);
event_ptr->event_data.dto_completion_event_data.status =
DAT_DTO_ERR_FLUSHED;
}
return (DAT_TRUE);
}
void
dapls_evd_copy_cq(
DAPL_EVD *evd_ptr,
int *nevents)
{
ib_work_completion_t cqe[MAX_CQES_PER_POLL];
DAT_RETURN dat_status;
ib_cq_handle_t cq_handle;
DAT_EVENT *event;
uint_t num_cqes_polled = 0;
int cqe_events;
int i;
cq_handle = evd_ptr->ib_cq_handle;
*nevents = 0;
if (cq_handle == IB_INVALID_HANDLE) {
return;
}
dat_status = DAPL_POLL(evd_ptr)(cq_handle,
cqe, MAX_CQES_PER_POLL, &num_cqes_polled);
if (dat_status == DAT_SUCCESS) {
dapl_dbg_log(DAPL_DBG_TYPE_EVD, "dapls_evd_copy_cq: %u\n",
num_cqes_polled);
cqe_events = 0;
for (i = 0; i < num_cqes_polled; i++) {
#ifdef DAPL_DBG
dapli_evd_eh_print_cqe(cqe[i]);
#endif
event = dapli_evd_get_and_init_event(
evd_ptr, DAT_DTO_COMPLETION_EVENT);
if (event == NULL) {
return;
}
if (dapli_evd_cqe_to_event(evd_ptr, &cqe[i], DAT_FALSE,
event)) {
dapli_evd_post_event_nosignal(evd_ptr, event);
cqe_events++;
} else {
dapl_dbg_log(DAPL_DBG_TYPE_EVD,
"dapls_evd_copy_cq: premature event\n");
dat_status = dapls_rbuf_add(&evd_ptr->
free_event_queue, (void *)event);
dapl_os_assert(dat_status == DAT_SUCCESS);
if (evd_ptr->evd_producer_locking_needed) {
dapl_os_unlock(&evd_ptr->header.lock);
}
}
}
*nevents = cqe_events;
} else if (DAT_GET_TYPE(dat_status) != DAT_QUEUE_EMPTY) {
dapl_dbg_log(DAPL_DBG_TYPE_ERR,
"dapls_evd_copy_cq: dapls_ib_completion_poll "
"returned 0x%x\n", dat_status);
dapl_os_assert(!"Bad return from dapls_ib_completion_poll");
}
}
DAT_RETURN
dapls_evd_copy_events(DAPL_EVD *evd_ptr, DAT_TIMEOUT timeout)
{
dapl_ib_event_t evp_arr[NUM_EVENTS_PER_POLL];
dapl_ib_event_t *evpp_start;
dapl_ib_event_t *evpp;
DAPL_IA *ia_ptr;
DAT_RETURN dat_status;
int waited;
uint64_t curr_time;
uint64_t final_time;
uint64_t time_left;
int events_needed = 0;
int nevents = 0;
int num_cqe = 0;
int num_ke = 0;
int i;
if (evd_ptr->evd_flags & (DAT_EVD_CONNECTION_FLAG |
DAT_EVD_CR_FLAG | DAT_EVD_ASYNC_FLAG)) {
if (evd_ptr->threshold <= NUM_EVENTS_PER_POLL) {
evpp = evp_arr;
} else {
evpp = (dapl_ib_event_t *)dapl_os_alloc(
evd_ptr->threshold * sizeof (dapl_ib_event_t));
if (evpp == NULL) {
return (DAT_INSUFFICIENT_RESOURCES);
}
}
evpp_start = evpp;
if (evd_ptr->threshold == 0 && timeout == 0)
evd_ptr->threshold = 1;
} else {
evpp = NULL;
evpp_start = NULL;
}
ia_ptr = evd_ptr->header.owner_ia;
waited = 0;
dat_status = DAT_SUCCESS;
if (timeout == 0) {
final_time = 0;
time_left = 0;
} else if (timeout == DAT_TIMEOUT_INFINITE) {
#define DAPL_ONE_YEAR_IN_USEC ((365 * 24 * 3600) * 1000000LL)
curr_time = gethrtime();
time_left = DAPL_ONE_YEAR_IN_USEC;
final_time = curr_time + DAPL_ONE_YEAR_IN_USEC * 1000;
} else {
curr_time = gethrtime();
final_time = curr_time + (uint64_t)(timeout&0x7fffffff)*1000;
time_left = (final_time - curr_time)/1000;
}
do {
if (evd_ptr->evd_flags & (DAT_EVD_DTO_FLAG |
DAT_EVD_RMR_BIND_FLAG)) {
nevents = 0;
dapls_evd_copy_cq(evd_ptr, &nevents);
num_cqe += nevents;
dapl_dbg_log(DAPL_DBG_TYPE_EVD,
"dapls_evd_copy_event: copy_cq num_cqe(%d)\n",
num_cqe);
}
events_needed = evd_ptr->threshold - num_ke -
dapls_rbuf_count(&evd_ptr->pending_event_queue);
if (events_needed < 0) {
break;
} else if (events_needed == 0) {
if (evd_ptr->threshold == 0)
dat_status = DAT_ERROR(DAT_QUEUE_EMPTY, 0);
break;
} else {
if (num_cqe)
break;
}
if (waited > 0) {
dapl_dbg_log(DAPL_DBG_TYPE_EVD,
"dapls_evd_copy_event: waited[%d]\n", waited);
if (dat_status != DAT_SUCCESS)
break;
curr_time = gethrtime();
if (curr_time >= final_time)
break;
time_left = (final_time - curr_time)/1000;
}
if (evd_ptr->evd_flags & (DAT_EVD_DTO_FLAG |
DAT_EVD_RMR_BIND_FLAG)) {
if (events_needed == 1) {
dat_status = dapls_set_cq_notify(ia_ptr,
evd_ptr);
if (dat_status != DAT_SUCCESS) {
dapl_dbg_log(DAPL_DBG_TYPE_EVD,
"dapls_evd_copy_event:"
" set_cq_notify(%d)\n", dat_status);
return (dat_status);
}
} else if (events_needed > 1) {
dat_status = dapls_set_cq_notify(ia_ptr,
evd_ptr);
if (dat_status != DAT_SUCCESS) {
dapl_dbg_log(DAPL_DBG_TYPE_EVD,
"dapls_evd_copy_event:"
" set_cqN_notify:%d\n", dat_status);
return (dat_status);
}
}
}
nevents = 0;
if (evpp_start) {
dat_status = dapls_ib_event_poll(evd_ptr, time_left,
(evd_ptr->threshold - (num_cqe + num_ke)), evpp,
&nevents);
dapl_dbg_log(DAPL_DBG_TYPE_EVD,
"dapls_evd_copy_event: poll returned 0x%x(%d)\n",
dat_status, nevents);
num_ke += nevents;
evpp += nevents;
} else {
dat_status = dapls_ib_event_poll(evd_ptr, time_left,
0, NULL, &nevents);
dapl_dbg_log(DAPL_DBG_TYPE_EVD,
"dapls_evd_copy_event: poll(cq_notification) "
"returned 0x%x\n", dat_status);
if (DAT_GET_TYPE(dat_status) == DAT_INTERRUPTED_CALL)
return (dat_status);
}
waited++;
} while (dapls_rbuf_count(&evd_ptr->pending_event_queue) + num_ke <
evd_ptr->threshold);
for (i = 0; i < num_ke; i++) {
switch (evpp_start[i].ibe_ev_family) {
case DAPL_CR_EVENTS:
case DAPL_PASSIVE_CONNECTION_EVENTS:
dapl_dbg_log(DAPL_DBG_TYPE_EVD,
"dapls_evd_copy_event: Passive side Event %d\n",
evpp_start[i].ibe_ce.ibce_event);
dapls_cr_callback((ib_cm_handle_t)
evpp_start[i].ibe_ce.ibce_psep_cookie,
evpp_start[i].ibe_ce.ibce_event,
evpp_start[i].ibe_ce.ibce_priv_data_ptr, (void *)
(uintptr_t)evpp_start[i].ibe_ce.ibce_cookie);
break;
case DAPL_ACTIVE_CONNECTION_EVENTS:
dapl_dbg_log(DAPL_DBG_TYPE_EVD,
"dapls_evd_copy_event: Active Conn Event %d\n",
evpp_start[i].ibe_ce.ibce_event);
dapl_evd_connection_callback((ib_cm_handle_t)
IB_INVALID_HANDLE,
evpp_start[i].ibe_ce.ibce_event,
evpp_start[i].ibe_ce.ibce_priv_data_ptr, (void *)
(uintptr_t)evpp_start[i].ibe_ce.ibce_cookie);
break;
case DAPL_ASYNC_EVENTS:
dapl_dbg_log(DAPL_DBG_TYPE_EVD,
"dapls_evd_copy_event: Async Event %d\n",
evpp_start[i].ibe_async.ibae_type);
dapls_ib_async_callback(evd_ptr,
ia_ptr->hca_ptr->ib_hca_handle,
&(evpp_start[i].ibe_async), ia_ptr);
break;
default:
dapl_dbg_log(DAPL_DBG_TYPE_ERR,
"dapls_evd_copy_event: dapls_ib_event_poll %d "
"returned 0x%x\n", i, evpp_start[i].ibe_ev_family);
dapl_os_assert(!"Bad return from dapls_ib_event_poll");
break;
}
}
return (dat_status);
}
DAT_RETURN
dapls_evd_cq_poll_to_event(IN DAPL_EVD *evd_ptr, OUT DAT_EVENT *event)
{
DAT_RETURN dat_status;
ib_work_completion_t cur_cqe;
dat_status = DAPL_POLL1(evd_ptr)(evd_ptr->ib_cq_handle, &cur_cqe);
if (dat_status == DAT_SUCCESS) {
#ifdef DAPL_DBG
dapli_evd_eh_print_cqe(cur_cqe);
#endif
(void) dapli_evd_cqe_to_event(evd_ptr, &cur_cqe, DAT_FALSE,
event);
}
return (dat_status);
}