dapl_tavor_ibtf_qp.c revision 1ed53a3f65abecaadc1b967e341970ad0f6b2aeb
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include "dapl.h"
#include "dapl_adapter_util.h"
#include "dapl_evd_util.h"
#include "dapl_cr_util.h"
#include "dapl_lmr_util.h"
#include "dapl_rmr_util.h"
#include "dapl_cookie.h"
#include "dapl_tavor_ibtf_impl.h"
#include "dapl_hash.h"
/* Function prototypes */
extern void dapls_tavor_srq_wrid_free(ib_srq_handle_t);
/*
* dapli_get_dto_cq
*
* Obtain the cq_handle for a DTO EVD. If the EVD is NULL, use the
* null_ib_cq_handle. If it hasn't been created yet, create it now in
* the HCA structure. It will be cleaned up in dapls_ib_cqd_destroy().
*
* This is strictly internal to IB. DAPL allows a NULL DTO EVD handle,
* but IB does not. So we create a CQ under the hood and make sure
* an error is generated if the user every tries to post, by
*
* Returns
* A valid CQ handle
*/
static ib_cq_handle_t
{
int ia_fd;
int retval;
if (evd_ptr != DAT_HANDLE_NULL) {
} else {
dapl_os_alloc(sizeof (struct dapls_ib_cq_handle));
"dapli_get_dto_cq: cq malloc failed\n");
return (IB_INVALID_HANDLE);
}
/*
* create a fake a CQ, we don't bother to mmap this CQ
* since nobody know about it to reap events from it.
*/
/* call into driver to allocate cq */
if (retval != 0) {
"dapli_get_dto_cq: DAPL_EVD_CREATE failed\n");
sizeof (struct dapls_ib_cq_handle));
return (IB_INVALID_HANDLE);
}
(void) dapl_os_memzero(cq_handle,
sizeof (struct dapls_ib_cq_handle));
"dapli_get_dto_cq: cq 0x%p created, hkey 0x%016llx\n",
/* save this dummy CQ handle into the hca */
}
return (cq_handle);
}
/*
* dapl_ib_qp_alloc
*
* Alloc a QP
*
* Input:
* *ep_ptr pointer to EP INFO
* ib_hca_handle provider HCA handle
* ib_pd_handle provider protection domain handle
* cq_recv provider recv CQ handle
* cq_send provider send CQ handle
*
* Output:
* none
*
* Returns:
* DAT_SUCCESS
* DAT_INSUFFICIENT_RESOURCES
*
*/
{
uint32_t i;
int ia_fd;
int hca_fd;
int retval;
/* check parameters */
"qp_alloc: hca_handle == NULL\n");
return (DAT_INVALID_PARAMETER);
}
/* fill in args for ep_create */
sizeof (struct dapls_ib_qp_handle));
"qp_alloc: os_alloc failed\n");
return (DAT_ERROR(DAT_INSUFFICIENT_RESOURCES,
}
sizeof (ib_work_completion_t);
if (premev_size != 0) {
"qp_alloc:alloc premature_events failed\n");
return (DAT_ERROR(DAT_INSUFFICIENT_RESOURCES,
}
}
qp_p->qp_num_premature_events = 0;
ep_args.ep_srq_hkey = 0;
ep_args.ep_srq_attached = 0;
} else {
premev_size = 0;
/* premature events for EPs with SRQ sit on the SRQ */
qp_p->qp_num_premature_events = 0;
}
/*
* there are cases when ep_ptr is a dummy container ep, and the orig
* ep pointer is passed in ep_ctx_ptr. eg - dapl_ep_modify does this.
* ep_cookie should be the actual ep pointer, not the dummy container
* ep since the kernel returns this via events and the CM callback
* routines
*/
"qp_alloc: ep_ptr 0x%p, pz 0x%p (0x%llx), rcv_evd 0x%p (0x%llx)\n"
" snd_evd 0x%p (0x%llx), conn_evd 0x%p (0x%llx)\n"
" srq_hdl 0x%p (0x%llx)\n"
" sq_sz %d, rq_sz %d, sq_sgl_sz %d, rq_sgl_sz %d\n",
/* The next line is only needed for backward compatibility */
"qp_alloc: ep_create failed errno %d, retval %d\n",
if (premev_size != 0) {
}
}
/* In the case of Arbel or Hermon */
mqp->mqp_mapoffset);
"qp_alloc: mmap failed(%d)\n", errno);
if (retval != 0) {
"qp_alloc: EP_FREE err:%d\n", errno);
}
if (premev_size != 0) {
}
return (dapls_convert_error(errno, 0));
}
"qp_alloc: created, qp_sq_buf %p, qp_rq_buf %p\n",
"qp_alloc: created, sq numwqe %x wqesz %x, rq numwqe %x wqesz %x\n",
"qp_alloc: created, qp_sq_desc_addr %x, qp_rq_desc_addr %x\n",
"qp_alloc: created, ep_ptr 0x%p, ep_hkey 0x%016llx\n\n",
/*
* Calculate the number of bits in max_rmrs - this is indirectly
* the max number of entried in the MPT table (defaults to 512K
* but is configurable). This value is used while creating new
* rkeys in bind processing (see dapl_tavor_hw.c).
* Stash this value in the qp handle, don't want to do this math
* for every bind
*/
;
/* update the qp handle in the ep ptr */
/*
* ibt_alloc_rc_channel transitions the qp state to INIT.
* hence we directly transition from UNATTACHED to INIT
*/
/* insert ep into the SRQ's ep_table */
if (dat_status != DAT_SUCCESS) {
"qp_alloc: srq_add_ep failed ep_ptr 0x%p, 0x%x\n",
ep_ptr, dat_status);
return (DAT_INVALID_PARAMETER);
}
} else {
qp_p->qp_srq_enabled = 0;
}
return (DAT_ERROR(DAT_INSUFFICIENT_RESOURCES,
}
return (DAT_SUCCESS);
}
/*
* dapls_ib_qp_free
*
* Free a QP
*
* Input:
* *ep_ptr pointer to EP INFO
* ib_hca_handle provider HCA handle
*
* Output:
* none
*
* Returns:
* none
*
*/
{
int retval;
"qp_free: munmap failed(%d)\n", errno);
}
if (retval != 0) {
"qp_free: ioctl errno = %d, retval = %d\n",
}
"qp_free: freed, ep_ptr 0x%p, ep_hkey 0x%016llx\n",
} else {
if (qp_p->qp_premature_events) {
sizeof (ib_work_completion_t));
}
}
}
return (DAT_SUCCESS);
}
/*
* dapl_ib_qp_modify
*
* Set the QP to the parameters specified in an EP_PARAM
*
* We can't be sure what state the QP is in so we first obtain the state
* from the driver. The EP_PARAM structure that is provided has been
* sanitized such that only non-zero values are valid.
*
* Input:
* ib_hca_handle HCA handle
* qp_handle QP handle
* ep_attr Sanitized EP Params
*
* Output:
* none
*
* Returns:
* DAT_SUCCESS
* DAT_INSUFFICIENT_RESOURCES
* DAT_INVALID_PARAMETER
*
*/
{
int ia_fd;
int retval;
"qp_modify: qp_handle == NULL\n");
return (DAT_INVALID_PARAMETER);
}
"qp_modify: hca_handle == NULL\n");
return (DAT_INVALID_PARAMETER);
}
/*
* NOTE: ep_attr->max_mtu_size indicates the maximum message
* size, which is always 2GB for IB. Nothing to do with the IB
* implementation, nothing to set up.
*/
if (ep_attr->max_rdma_size > 0) {
return (DAT_ERROR(DAT_INVALID_PARAMETER, 0));
}
}
/*
* The following parameters are dealt by creating a new qp
* in dapl_ep_modify.
* - max_recv_dtos
* - max_request_dtos
* - max_recv_iov
* - max_request_iov
*/
if (ep_attr->max_rdma_read_in > 0) {
epm_needed = B_TRUE;
}
if (ep_attr->max_rdma_read_out > 0) {
epm_needed = B_TRUE;
}
if (!epm_needed) {
"qp_modify: ep_hkey = %016llx nothing to do\n",
return (DAT_SUCCESS);
}
if (retval != 0) {
"qp_modify: ioctl failed errno %d, retval %d\n",
}
return (DAT_SUCCESS);
}
/*
* Allocate the srq data structure as well as the kernel resource
* corresponding to it.
*/
{
uint32_t i;
int ia_fd;
int hca_fd;
int retval;
/* check parameters */
"srq_alloc: hca_handle == NULL\n");
}
/* fill in args for srq_create */
"srq_alloc: os_alloc failed\n");
return (DAT_ERROR(DAT_INSUFFICIENT_RESOURCES,
}
"srq_alloc: srq_ptr 0x%p, pz 0x%p (0x%llx), srq_sz %d"
" srq_sgl %d\n",
/* The next line is only needed for backward compatibility */
"srq_alloc: srq_create failed errno %d, retval %d\n",
}
/* In the case of Arbel or Hermon */
"srq_alloc: mmap failed(%d)\n", errno);
if (retval != 0) {
"srq_alloc: SRQ_FREE err:%d\n", errno);
}
return (dapls_convert_error(errno, 0));
}
/* since 0 is a valid index, -1 indicates invalid value */
/*
* update the srq handle in the srq ptr, this is needed since from
* here on cleanup is done by calling dapls_ib_srq_free()
*/
"srq_alloc: os_alloc premature_events failed\n");
return (DAT_ERROR(DAT_INSUFFICIENT_RESOURCES,
}
"srq_alloc: os_alloc freepr_events failed\n");
return (DAT_ERROR(DAT_INSUFFICIENT_RESOURCES,
}
ibsrq_p->srq_freepr_head = 0;
ibsrq_p->srq_freepr_tail = 0;
/* initialize the free list of premature events */
for (i = 0; i < ibsrq_p->srq_freepr_num_events; i++) {
ibsrq_p->srq_freepr_events[i] = i;
/*
* wc_res_hash field is used to mark entries in the premature
* events list
*/
}
"srq_alloc: created, srq_ptr 0x%p, srq_hkey 0x%016llx\n",
"srq_alloc: wridlist alloc failed\n");
return (DAT_ERROR(DAT_INSUFFICIENT_RESOURCES,
}
/* allocate a hash table to to store EPs */
if (retval != DAT_SUCCESS) {
"create failed %d\n", retval);
return (retval);
}
return (DAT_SUCCESS);
}
/*
* SRQ Free routine
*/
void
{
int retval;
if (srq_handle == IB_INVALID_HANDLE) {
return; /* nothing to do */
}
"srq_free: munmap failed(%d)\n", errno);
}
if (retval != 0) {
}
"srq_free: freed, srq_ptr 0x%p, srq_hkey 0x%016llx\n",
if (srq_handle->srq_ep_table) {
}
if (srq_handle->srq_wridlist) {
}
if (srq_handle->srq_freepr_events) {
}
if (srq_handle->srq_premature_events) {
}
}
/*
* Adds EP to a hashtable in SRQ
*/
static DAT_RETURN
{
}
/*
* Removes an EP from the hashtable in SRQ
*/
static void
{
if (retval != DAT_SUCCESS) {
}
}
/*
* Lookup an EP from the hashtable in SRQ
*/
DAPL_EP *
{
if (retval != DAT_SUCCESS) {
}
return (epp);
}
/*
* dapl_ib_srq_resize
*
* Resize an SRQ
*
* Input:
* srq_ptr pointer to SRQ struct
* srqlen new length of the SRQ
* Output:
* none
*
* Returns:
* DAT_SUCCESS
* DAT_INVALID_HANDLE
* DAT_INTERNAL_ERROR
* DAT_INSUFFICIENT_RESOURCES
*
*/
{
/* attempt to resize back to the current size */
if (DAT_SUCCESS != dat_status) {
/*
* XXX this is catastrophic need to post an event
* to the async evd
*/
return (DAT_INTERNAL_ERROR);
}
}
return (dat_status);
}
/*
* dapli_ib_srq_resize_internal
*
* An internal routine to resize a SRQ.
*
* Input:
* srq_ptr pointer to SRQ struct
* srqlen new length of the srq
* Output:
* none
*
* Returns:
* DAT_SUCCESS
* DAT_INVALID_HANDLE
* DAT_INSUFFICIENT_RESOURCES
*
*/
static DAT_RETURN
{
int ia_fd;
int hca_fd;
int idx, i;
int retval;
"dapls_ib_srq_resize: srq 0x%p srq_hdl 0x%p "
"srq_hkey 0x%016llx srqlen %d\n",
/*
* Since SRQs are created in powers of 2 its possible that the
* previously allocated SRQ has sufficient entries. If the current
* SRQ is big enough and it is mapped we are done.
*/
return (DAT_SUCCESS);
}
/* unmap the SRQ before resizing it */
srq_handle->srq_map_len) < 0)) {
"srq_resize: munmap(%p:0x%llx) failed(%d)\n",
}
/* srq_addr is unmapped and no longer valid */
/* The next line is only needed for backward compatibility */
"dapls_ib_srq_resize: srq 0x%p, err: %s\n",
return (DAT_ERROR(DAT_INVALID_HANDLE,
} else { /* Need to retry resize with a smaller qlen */
return (DAT_ERROR(DAT_INSUFFICIENT_RESOURCES,
}
}
/* In the case of Arbel or Hermon */
if (msrq->msrq_rdbr_mapoffset != 0 ||
msrq->msrq_rdbr_maplen != 0)
"srq_resize: mmap failed(%d)\n", errno);
/* Need to retry resize with a smaller qlen */
return (DAT_ERROR(DAT_INSUFFICIENT_RESOURCES,
}
sizeof (ib_work_completion_t);
sizeof (ib_work_completion_t);
if (new_freepr_events == NULL) {
goto bail;
}
if (new_premature_events == NULL) {
goto bail;
}
goto bail;
}
idx = 0;
/* copy valid premature events */
for (i = 0; i < srq_handle->srq_wq_numwqe; i++) {
if (!DAPL_CQE_IS_VALID(&old_premature_events[i])) {
continue;
}
&old_premature_events[i], sizeof (ib_work_completion_t));
idx++;
}
/* Initialize free events lists */
new_freepr_events[i] = idx + i;
}
srq_handle->srq_freepr_head = 0;
/* a full freepr list has tail at 0 */
if (idx == 0) {
srq_handle->srq_freepr_tail = 0;
} else {
}
if (old_freepr_events) {
}
if (old_premature_events) {
}
/*
* update the srq fields,
* note: the srq_wq_lastwqeindex doesn't change since the old
* work queue is copied as a whole into the new work queue.
*/
return (DAT_SUCCESS);
bail:
if (new_freepr_events) {
}
if (new_premature_events) {
}
}