2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A */
2N/A
2N/A/*
2N/A *
2N/A * MODULE: dapl_srq.c
2N/A *
2N/A * PURPOSE: Shared Receive Queue
2N/A * Description: Interfaces in this file are completely described in
2N/A * the DAPL 1.2 API, Chapter 6, section 5
2N/A *
2N/A */
2N/A
2N/A#include "dapl.h"
2N/A#include "dapl_adapter_util.h"
2N/A#include "dapl_ia_util.h"
2N/A#include "dapl_srq_util.h"
2N/A#include "dapl_cookie.h"
2N/A
2N/A/*
2N/A * dapl_srq_create
2N/A *
2N/A * uDAPL: User Direct Access Program Library Version 1.2, 6.5.1
2N/A *
2N/A * creates an instance of a Shared Receive Queue (SRQ) that is provided
2N/A * to the Consumer as srq_handle.
2N/A *
2N/A * Input:
2N/A * ia_handle
2N/A * pz_handle
2N/A * srq_attr
2N/A *
2N/A * Output:
2N/A * srq_handle
2N/A *
2N/A * Returns:
2N/A * DAT_SUCCESS
2N/A * DAT_INSUFFICIENT_RESOURCES
2N/A * DAT_INVALID_HANDLE
2N/A * DAT_INVALID_PARAMETER
2N/A * DAT_MODEL_NOT_SUPPORTED
2N/A */
2N/A
2N/ADAT_RETURN
2N/Adapl_srq_create(
2N/A IN DAT_IA_HANDLE ia_handle,
2N/A IN DAT_PZ_HANDLE pz_handle,
2N/A IN DAT_SRQ_ATTR *srq_attr,
2N/A OUT DAT_SRQ_HANDLE *srq_handle)
2N/A{
2N/A DAPL_IA *ia_ptr;
2N/A DAPL_SRQ *srq_ptr;
2N/A DAT_SRQ_ATTR srq_attr_limit;
2N/A DAT_RETURN dat_status;
2N/A
2N/A ia_ptr = (DAPL_IA *)ia_handle;
2N/A dat_status = DAT_SUCCESS;
2N/A /*
2N/A * Verify parameters
2N/A */
2N/A if (DAPL_BAD_HANDLE(ia_ptr, DAPL_MAGIC_IA)) {
2N/A dat_status = DAT_ERROR(DAT_INVALID_HANDLE,
2N/A DAT_INVALID_HANDLE_IA);
2N/A goto bail;
2N/A }
2N/A
2N/A if ((pz_handle == NULL) || DAPL_BAD_HANDLE(pz_handle, DAPL_MAGIC_PZ)) {
2N/A dat_status = DAT_ERROR(DAT_INVALID_HANDLE,
2N/A DAT_INVALID_HANDLE_PZ);
2N/A goto bail;
2N/A }
2N/A
2N/A if ((srq_attr == NULL) || ((uintptr_t)srq_attr & 3)) {
2N/A dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3);
2N/A goto bail;
2N/A }
2N/A
2N/A if (srq_handle == NULL) {
2N/A dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG4);
2N/A goto bail;
2N/A }
2N/A
2N/A if (srq_attr->max_recv_dtos == 0 || srq_attr->max_recv_iov == 0 ||
2N/A srq_attr->low_watermark != DAT_SRQ_LW_DEFAULT) {
2N/A dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3);
2N/A goto bail;
2N/A }
2N/A
2N/A /* Verify the attributes against the transport */
2N/A (void) dapl_os_memzero(&srq_attr_limit, sizeof (DAT_SRQ_ATTR));
2N/A dat_status = dapls_ib_query_hca(ia_ptr->hca_ptr, NULL, NULL, NULL,
2N/A &srq_attr_limit);
2N/A if (dat_status != DAT_SUCCESS) {
2N/A goto bail;
2N/A }
2N/A if (srq_attr->max_recv_dtos > srq_attr_limit.max_recv_dtos ||
2N/A srq_attr->max_recv_iov > srq_attr_limit.max_recv_iov) {
2N/A dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3);
2N/A goto bail;
2N/A }
2N/A
2N/A /* Allocate SRQ */
2N/A srq_ptr = dapl_srq_alloc(ia_ptr, srq_attr);
2N/A if (srq_ptr == NULL) {
2N/A dat_status = DAT_ERROR(DAT_INSUFFICIENT_RESOURCES,
2N/A DAT_RESOURCE_MEMORY);
2N/A goto bail;
2N/A }
2N/A
2N/A /* Take a reference on the PZ handle */
2N/A dapl_os_atomic_inc(&((DAPL_PZ *)pz_handle)->pz_ref_count);
2N/A
2N/A /*
2N/A * Fill in the SRQ
2N/A */
2N/A srq_ptr->param.ia_handle = ia_handle;
2N/A srq_ptr->param.srq_state = DAT_SRQ_STATE_OPERATIONAL;
2N/A srq_ptr->param.pz_handle = pz_handle;
2N/A srq_ptr->param.max_recv_dtos = srq_attr->max_recv_dtos;
2N/A srq_ptr->param.max_recv_iov = srq_attr->max_recv_iov;
2N/A srq_ptr->param.low_watermark = DAT_SRQ_LW_DEFAULT;
2N/A
2N/A srq_ptr->param.available_dto_count = DAT_VALUE_UNKNOWN;
2N/A srq_ptr->param.outstanding_dto_count = 0;
2N/A
2N/A dat_status = dapls_ib_srq_alloc(ia_ptr, srq_ptr);
2N/A if (dat_status != DAT_SUCCESS) {
2N/A dapl_os_atomic_dec(&((DAPL_PZ *)pz_handle)->pz_ref_count);
2N/A dapl_srq_dealloc(srq_ptr);
2N/A goto bail;
2N/A }
2N/A /* Link it onto the IA */
2N/A dapl_ia_link_srq(ia_ptr, srq_ptr);
2N/A
2N/A *srq_handle = srq_ptr;
2N/Abail:
2N/A return (dat_status);
2N/A}
2N/A
2N/A/*
2N/A * dapl_srq_free
2N/A *
2N/A * uDAPL: User Direct Access Program Library Version 1.2, 6.5.5
2N/A *
2N/A * destroys an instance of the SRQ. The SRQ cannot be destroyed if it is
2N/A * in use by an EP.
2N/A *
2N/A * Input:
2N/A * srq_handle
2N/A *
2N/A * Output:
2N/A * none
2N/A *
2N/A * Returns:
2N/A * DAT_SUCCESS
2N/A * DAT_INVALID_HANDLE
2N/A * DAT_INVALID_STATE
2N/A */
2N/A
2N/ADAT_RETURN
2N/Adapl_srq_free(
2N/A IN DAT_SRQ_HANDLE srq_handle)
2N/A{
2N/A DAPL_SRQ *srq_ptr;
2N/A DAPL_IA *ia_ptr;
2N/A DAT_SRQ_PARAM *param;
2N/A DAT_RETURN dat_status = DAT_SUCCESS;
2N/A
2N/A if (DAPL_BAD_HANDLE(srq_handle, DAPL_MAGIC_SRQ)) {
2N/A dat_status = DAT_ERROR(DAT_INVALID_HANDLE,
2N/A DAT_INVALID_HANDLE_SRQ);
2N/A goto bail;
2N/A }
2N/A
2N/A srq_ptr = (DAPL_SRQ *)srq_handle;
2N/A param = &srq_ptr->param;
2N/A if (0 != srq_ptr->srq_ref_count) {
2N/A dapl_dbg_log(DAPL_DBG_TYPE_EP,
2N/A "dapl_srq_free: Free SRQ: %p, refcnt %d\n",
2N/A srq_ptr, srq_ptr->srq_ref_count);
2N/A dat_status = DAT_ERROR(DAT_INVALID_HANDLE,
2N/A DAT_INVALID_STATE_SRQ_IN_USE);
2N/A goto bail;
2N/A }
2N/A
2N/A ia_ptr = srq_ptr->header.owner_ia;
2N/A param->srq_state = DAT_SRQ_STATE_ERROR;
2N/A
2N/A dapls_ib_srq_free(ia_ptr, srq_ptr);
2N/A
2N/A /* Remove link from the IA */
2N/A dapl_ia_unlink_srq(ia_ptr, srq_ptr);
2N/A
2N/A dapl_os_assert(param->pz_handle != NULL);
2N/A dapl_os_atomic_dec(&((DAPL_PZ *)param->pz_handle)->pz_ref_count);
2N/A param->pz_handle = NULL;
2N/A
2N/A dapl_srq_dealloc(srq_ptr);
2N/A
2N/Abail:
2N/A return (dat_status);
2N/A}
2N/A
2N/A/*
2N/A * dapl_srq_post_recv
2N/A *
2N/A * uDAPL: User Direct Access Program Library Version 1.2, 6.5.8
2N/A *
2N/A * posts the receive buffer that can be used for the incoming message into
2N/A * the local_iov by any connected EP that uses SRQ.
2N/A *
2N/A * Input:
2N/A * srq_handle
2N/A * num_segments
2N/A * local_iov
2N/A * user_cookie
2N/A *
2N/A * Output:
2N/A * none
2N/A *
2N/A * Returns:
2N/A * DAT_SUCCESS
2N/A * DAT_INVALID_HANDLE
2N/A * DAT_INSUFFICIENT_RESOURCES
2N/A * DAT_INVALID_PARAMETER
2N/A * DAT_PROTECTION_VIOLATION
2N/A * DAT_PRIVILEGES_VIOLATION
2N/A */
2N/A
2N/ADAT_RETURN
2N/Adapl_srq_post_recv(
2N/A IN DAT_SRQ_HANDLE srq_handle,
2N/A IN DAT_COUNT num_segments,
2N/A IN DAT_LMR_TRIPLET *local_iov,
2N/A IN DAT_DTO_COOKIE user_cookie)
2N/A{
2N/A DAPL_SRQ *srq_ptr;
2N/A DAPL_COOKIE *cookie;
2N/A DAT_RETURN dat_status;
2N/A
2N/A dapl_dbg_log(DAPL_DBG_TYPE_API,
2N/A "dapl_srq_post_recv (%p, %d, %p, %P)\n",
2N/A srq_handle,
2N/A num_segments,
2N/A local_iov,
2N/A user_cookie.as_64);
2N/A
2N/A if (DAPL_BAD_HANDLE(srq_handle, DAPL_MAGIC_SRQ)) {
2N/A dat_status = DAT_ERROR(DAT_INVALID_HANDLE,
2N/A DAT_INVALID_HANDLE_SRQ);
2N/A goto bail;
2N/A }
2N/A
2N/A srq_ptr = (DAPL_SRQ *) srq_handle;
2N/A
2N/A /*
2N/A * Synchronization ok since this buffer is only used for receive
2N/A * requests, which aren't allowed to race with each other.
2N/A */
2N/A dat_status = dapls_dto_cookie_alloc(&srq_ptr->recv_buffer,
2N/A DAPL_DTO_TYPE_RECV,
2N/A user_cookie,
2N/A &cookie);
2N/A if (DAT_SUCCESS != dat_status) {
2N/A goto bail;
2N/A }
2N/A
2N/A /*
2N/A * Invoke provider specific routine to post DTO
2N/A */
2N/A dat_status = dapls_ib_post_srq(srq_ptr, cookie, num_segments,
2N/A local_iov);
2N/A
2N/A if (dat_status != DAT_SUCCESS) {
2N/A dapls_cookie_dealloc(&srq_ptr->recv_buffer, cookie);
2N/A } else {
2N/A dapl_os_atomic_inc(&srq_ptr->recv_count);
2N/A }
2N/A
2N/Abail:
2N/A dapl_dbg_log(DAPL_DBG_TYPE_RTN,
2N/A "dapl_srq_post_recv () returns 0x%x\n", dat_status);
2N/A
2N/A return (dat_status);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * dapl_srq_query
2N/A *
2N/A * uDAPL: User Direct Access Program Library Version 1.2, 6.5.6
2N/A *
2N/A * provides to the Consumer SRQ parameters. The Consumer passes in a pointer
2N/A * to the Consumer-allocated structures for SRQ parameters that the Provider
2N/A * fills.
2N/A *
2N/A * Input:
2N/A * srq_handle
2N/A * srq_param_mask
2N/A *
2N/A * Output:
2N/A * srq_param
2N/A *
2N/A * Returns:
2N/A * DAT_SUCCESS
2N/A * DAT_INVALID_HANDLE
2N/A * DAT_INVALID_PARAMETER
2N/A */
2N/A
2N/ADAT_RETURN
2N/Adapl_srq_query(
2N/A IN DAT_SRQ_HANDLE srq_handle,
2N/A IN DAT_SRQ_PARAM_MASK srq_param_mask,
2N/A OUT DAT_SRQ_PARAM *srq_param)
2N/A{
2N/A DAPL_SRQ *srq_ptr;
2N/A DAT_RETURN dat_status;
2N/A
2N/A dat_status = DAT_SUCCESS;
2N/A
2N/A if (srq_param_mask & ~DAT_SRQ_FIELD_ALL) {
2N/A dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG2);
2N/A goto bail;
2N/A }
2N/A
2N/A if (NULL == srq_param) {
2N/A dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3);
2N/A goto bail;
2N/A }
2N/A
2N/A
2N/A if (DAPL_BAD_HANDLE(srq_handle, DAPL_MAGIC_SRQ)) {
2N/A dat_status = DAT_ERROR(DAT_INVALID_HANDLE, 0);
2N/A goto bail;
2N/A }
2N/A
2N/A srq_ptr = (DAPL_SRQ *)srq_handle;
2N/A /* Do a struct copy */
2N/A *srq_param = srq_ptr->param;
2N/A /* update the outstanding dto count */
2N/A srq_param->outstanding_dto_count = srq_ptr->recv_count;
2N/A
2N/Abail:
2N/A return (dat_status);
2N/A}
2N/A
2N/A/*
2N/A * dapl_srq_set_lw
2N/A *
2N/A * uDAPL: User Direct Access Program Library Version 1.2, 6.5.4
2N/A *
2N/A * sets the low watermark value for SRQ and arms SRQ for generating an
2N/A * asynchronous event for low watermark. An asynchronous event will be
2N/A * generated when the number of buffers on SRQ is below the low watermark
2N/A * for the first time. This may happen during this call or when an
2N/A * associated EP takes a buffer from the SRQ.
2N/A *
2N/A * Input:
2N/A * srq_handle
2N/A * low_watermark
2N/A *
2N/A * Output:
2N/A * none
2N/A *
2N/A * Returns:
2N/A * DAT_SUCCESS
2N/A * DAT_INVALID_HANDLE
2N/A * DAT_INVALID_PARAMETER
2N/A * DAT_MODEL_NOT_SUPPORTED
2N/A */
2N/A
2N/A/* ARGSUSED */
2N/ADAT_RETURN
2N/Adapl_srq_set_lw(
2N/A IN DAT_SRQ_HANDLE srq_handle,
2N/A IN DAT_COUNT low_watermark)
2N/A{
2N/A return (DAT_MODEL_NOT_SUPPORTED);
2N/A}
2N/A
2N/A/*
2N/A * dapl_srq_resize
2N/A *
2N/A * uDAPL: User Direct Access Program Library Version 1.2, 6.5.7
2N/A *
2N/A * modifies the size of the queue of SRQ. Resizing of SRQ shall not cause
2N/A * any incoming messages on any of the EPs that use the SRQ to be lost.
2N/A *
2N/A * Input:
2N/A * srq_handle
2N/A * srq_max_recv_dto
2N/A *
2N/A * Output:
2N/A * none
2N/A *
2N/A * Returns:
2N/A * DAT_SUCCESS
2N/A * DAT_INVALID_HANDLE
2N/A * DAT_INVALID_PARAMETER
2N/A * DAT_INSUFFICIENT_RESOURCES
2N/A * DAT_INVALID_STATE
2N/A */
2N/A
2N/A/* ARGSUSED */
2N/ADAT_RETURN
2N/Adapl_srq_resize(
2N/A IN DAT_SRQ_HANDLE srq_handle,
2N/A IN DAT_COUNT srq_max_recv_dtos)
2N/A{
2N/A DAPL_SRQ *srq_ptr;
2N/A DAT_SRQ_ATTR srq_attr_limit;
2N/A DAPL_COOKIE_BUFFER new_cb;
2N/A DAT_RETURN dat_status;
2N/A
2N/A
2N/A srq_ptr = (DAPL_SRQ *)srq_handle;
2N/A dat_status = DAT_SUCCESS;
2N/A
2N/A if (DAPL_BAD_HANDLE(srq_handle, DAPL_MAGIC_SRQ)) {
2N/A return (DAT_ERROR(DAT_INVALID_HANDLE, DAT_HANDLE_TYPE_SRQ));
2N/A }
2N/A
2N/A /* can't shrink below the number of outstanding recvs */
2N/A if (srq_max_recv_dtos < srq_ptr->recv_count) {
2N/A return (DAT_ERROR(DAT_INVALID_STATE, 0));
2N/A }
2N/A
2N/A /*
2N/A * shrinking SRQs is not supported on tavor return success without
2N/A * any modification.
2N/A */
2N/A if (srq_max_recv_dtos <= srq_ptr->param.max_recv_dtos) {
2N/A return (DAT_SUCCESS);
2N/A }
2N/A
2N/A /* Verify the attributes against the transport */
2N/A (void) dapl_os_memzero(&srq_attr_limit, sizeof (DAT_SRQ_ATTR));
2N/A dat_status = dapls_ib_query_hca(srq_ptr->header.owner_ia->hca_ptr,
2N/A NULL, NULL, NULL, &srq_attr_limit);
2N/A if (dat_status != DAT_SUCCESS) {
2N/A return (dat_status);
2N/A }
2N/A
2N/A if (srq_max_recv_dtos > srq_attr_limit.max_recv_dtos) {
2N/A dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG2);
2N/A return (dat_status);
2N/A }
2N/A
2N/A dat_status = dapls_cb_resize(&srq_ptr->recv_buffer, srq_max_recv_dtos,
2N/A &new_cb);
2N/A if (dat_status != DAT_SUCCESS) {
2N/A return (dat_status);
2N/A }
2N/A
2N/A dat_status = dapls_ib_srq_resize(srq_ptr, srq_max_recv_dtos);
2N/A if (dat_status != DAT_SUCCESS) {
2N/A goto bail;
2N/A }
2N/A
2N/A dapls_cb_free(&srq_ptr->recv_buffer);
2N/A srq_ptr->recv_buffer = new_cb; /* struct copy */
2N/A srq_ptr->param.max_recv_dtos = srq_max_recv_dtos;
2N/A
2N/A return (DAT_SUCCESS);
2N/Abail:
2N/A dapls_cb_free(&new_cb);
2N/A
2N/A return (dat_status);
2N/A}