/*
* 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 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Copyright (c) 2005 SilverStorm Technologies, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
/*
* Sun elects to include this software in Sun product
* under the OpenIB BSD license.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This file contains CM related work:
*
* Service registration/deregistration
* Path lookup
* CM connection callbacks
* CM active and passive connection establishment
* Connection failover
*/
/*
* Handle an incoming CM REQ
*/
/* ARGSUSED */
static ibt_cm_status_t
{
int ret;
/*
* CM private data brings IP information
* Private data received is a stream of bytes and may not be properly
* aligned. So, bcopy the data onto the stack before accessing it.
*/
sizeof (rds_cm_private_data_t));
/* extract the CM IP info */
&ipcm_info);
if (ret != IBT_SUCCESS) {
ret);
return (IBT_CM_REJECT);
}
RDS_DPRINTF2("rds_handle_cm_req",
"REQ Received: From IP: 0x%x To IP: 0x%x type: %d",
return (IBT_CM_REJECT);
}
/* RDS supports V4 addresses only */
return (IBT_CM_REJECT);
}
return (IBT_CM_REJECT);
}
return (IBT_CM_REJECT);
}
/* user_buffer_size should be same on all nodes */
"UserBufferSize Mismatch, this node: %d remote node: %d",
return (IBT_CM_REJECT);
}
/*
* RDS needs more time to process a failover REQ so send an MRA.
* Otherwise, the remote may retry the REQ and fail the connection.
*/
}
/* Is there a session to the destination node? */
/*
* currently there is no session to the destination
* remote ip in the private data is the local ip and vice
* versa
*/
/* Check the list anyway. */
/*
* The only way this can fail is due to lack
* of kernel resources
*/
return (IBT_CM_REJECT);
}
}
}
/* catch peer-to-peer case as soon as possible */
/* Check possible peer-to-peer case here */
RDS_DPRINTF2("rds_handle_cm_req",
"SP(%p) Peer-peer connection handling", sp);
/* this node is active so reject this request */
return (IBT_CM_REJECT);
} else {
/* this node is passive, change the session */
}
}
}
switch (sp->session_state) {
"RDS_SESSION_STATE_ERROR", sp);
/* FALLTHRU */
case RDS_SESSION_STATE_ERROR:
/*
* Some other thread must be processing this session,
* this thread must wait until the other thread finishes.
*/
/* Handling this will take some time, so send an MRA */
/*
* Any pending completions don't get flushed until the channel
* is closed. So, passing 0 here will not wait for pending
* completions in rds_session_close before closing the channel
*/
/*
* If the session was in ERROR, then either a failover thread
* or event_failure thread would be processing this session.
* This thread should wait for event_failure thread to
* complete. This need not wait for failover thread.
*/
if ((save_state != RDS_SESSION_STATE_CONNECTED) &&
(save_type == RDS_SESSION_PASSIVE)) {
/*
* The other thread is event_failure thread,
* wait until it finishes.
*/
while (!((sp->session_state ==
(sp->session_state ==
}
}
/* move the session to init state */
if (ret != 0) {
RDS_DPRINTF3("rds_handle_cm_req",
"SP(%p) State RDS_SESSION_STATE_FAILED",
sp);
return (IBT_CM_REJECT);
} else {
RDS_DPRINTF3("rds_handle_cm_req",
"SP(%p) State RDS_SESSION_STATE_INIT", sp);
}
} else {
}
break;
}
/* FALLTHRU */
case RDS_SESSION_STATE_FAILED:
case RDS_SESSION_STATE_FINI:
/*
* Initialize both channels, we accept this connection
* only if both channels are initialized
*/
"RDS_SESSION_STATE_CREATED", sp);
if (ret != 0) {
/* Seems like there are not enough resources */
"RDS_SESSION_STATE_FAILED", sp);
return (IBT_CM_REJECT);
}
"RDS_SESSION_STATE_INIT", sp);
/* FALLTHRU */
case RDS_SESSION_STATE_INIT:
/*
* When re-using an existing session, make sure the
* session is still through the same HCA. Otherwise, the
* memory registrations have to moved to the new HCA.
*/
RDS_DPRINTF2("rds_handle_cm_req",
"Existing Session but different gid "
"existing: 0x%llx, new: 0x%llx, "
"sending an MRA",
(void) ibt_cm_delay(IBT_CM_DELAY_REQ,
NULL, 0);
if (ret != 0) {
sp->session_state =
sp->session_failover = 0;
RDS_DPRINTF3("rds_failover_session",
"SP(%p) State "
"RDS_SESSION_STATE_FAILED", sp);
return (IBT_CM_REJECT);
}
}
} else {
}
break;
default:
return (IBT_CM_REJECT);
}
if (cmp.cmp_failover) {
RDS_DPRINTF2("rds_handle_cm_req",
}
/*
* Peer to peer connection. There is an active
* connection pending on this ep. The one with
* greater port guid becomes active and the
* other becomes passive.
*/
RDS_DPRINTF2("rds_handle_cm_req",
"EP(%p) Peer-peer connection handling", ep);
/* this node is active so reject this request */
return (IBT_CM_REJECT);
} else {
/*
* This session is not the active end, change it
* to passive end.
*/
}
} else {
}
/* continue with accepting the connection request for this channel */
return (IBT_CM_REJECT);
}
/* pre-post recv buffers in the RQ */
rds_post_recv_buf((void *)chanhdl);
return (IBT_CM_ACCEPT);
}
/*
* Handle an incoming CM REP
* Pre-post recv buffers for the QP
*/
/* ARGSUSED */
static ibt_cm_status_t
{
/* pre-post recv buffers in the RQ */
sizeof (rds_cm_private_data_t));
rargsp->cm_ret_len = 0;
return (IBT_CM_ACCEPT);
}
/*
* Handle CONN EST
*/
static ibt_cm_status_t
{
(void) rds_session_active(sp);
return (IBT_CM_ACCEPT);
}
/*
* Handle CONN CLOSED
*/
static ibt_cm_status_t
{
/* Catch DREQs but ignore DREPs */
RDS_DPRINTF2("rds_handle_cm_conn_closed",
return (IBT_CM_ACCEPT);
}
/* Ignore this DREQ */
RDS_DPRINTF2("rds_handle_cm_conn_closed",
return (IBT_CM_ACCEPT);
}
sp->session_state);
switch (sp->session_state) {
"RDS_SESSION_STATE_PASSIVE_CLOSING", sp);
break;
"RDS_SESSION_STATE_CLOSED", sp);
RDS_DPRINTF3("rds_handle_cm_conn_closed",
"SP(%p) State RDS_SESSION_STATE_FINI", sp);
break;
case RDS_SESSION_STATE_ERROR:
case RDS_SESSION_STATE_CLOSED:
break;
case RDS_SESSION_STATE_INIT:
"RDS_SESSION_STATE_ERROR", sp);
RDS_DPRINTF3("rds_handle_cm_conn_closed",
"SP(%p) State RDS_SESSION_STATE_FAILED", sp);
break;
default:
RDS_DPRINTF2("rds_handle_cm_conn_closed",
"RDS_SESSION_STATE_FAILED", sp);
}
return (IBT_CM_ACCEPT);
}
/*
* Handle EVENT FAILURE
*/
static ibt_cm_status_t
{
int ret;
"Received REJ with reason IBT_CM_INVALID_SID: "
"RDS may not be loaded on the remote system");
}
return (IBT_CM_ACCEPT);
}
/*
* This end is active, just ignore, ibt_open_rc_channel()
* caller will take care of cleanup.
*/
RDS_DPRINTF2("rds_handle_cm_event_failure",
return (IBT_CM_ACCEPT);
}
RDS_DPRINTF2("rds_handle_cm_event_failure",
RDS_DPRINTF3("rds_handle_cm_event_failure",
"SP(%p) State RDS_SESSION_STATE_ERROR", sp);
/*
* Store the cm_channel for freeing later
* Active side frees it on ibt_open_rc_channel
* failure
*/
}
/*
* rds_passive_session_fini should not be called
* directly in the CM handler. It will cause a deadlock.
*/
rds_cleanup_passive_session, (void *)sp,
if (ret != DDI_SUCCESS) {
RDS_DPRINTF2("rds_handle_cm_event_failure",
}
return (IBT_CM_ACCEPT);
}
}
return (IBT_CM_ACCEPT);
}
/*
* CM Handler
*
* Called by IBCM
* The cm_private type differs for active and passive events.
*/
{
case IBT_CM_EVENT_REQ_RCV:
break;
case IBT_CM_EVENT_REP_RCV:
break;
case IBT_CM_EVENT_MRA_RCV:
/* Not supported */
break;
case IBT_CM_EVENT_CONN_EST:
break;
case IBT_CM_EVENT_CONN_CLOSED:
break;
case IBT_CM_EVENT_FAILURE:
break;
case IBT_CM_EVENT_LAP_RCV:
/* Not supported */
break;
case IBT_CM_EVENT_APR_RCV:
/* Not supported */
break;
default:
break;
}
return (ret);
}
/* This is based on OFED Linux RDS */
/*
* Register the wellknown service with service id: RDS_SERVICE_ID
* Incoming connection requests should arrive on this service id.
*/
{
int ret;
/*
* This is the new service id as per:
* Annex A11: RDMA IP CM Service
*/
if (ret != IBT_SUCCESS) {
"RDS Service (0x%llx) Registration Failed: %d",
return (NULL);
}
return (srvhdl);
}
/* Bind the RDS service on all ports */
int
{
int ret;
/* skip the HCAs that are not fully online */
RDS_DPRINTF2("rds_bind_service",
"Skipping HCA: 0x%llx, state: %d",
continue;
}
/* currently, we have space for only 4 bindhdls */
nports++;
/*
* service bind will be called in the async
* handler when the port comes up. Clear any
* stale bind handle.
*/
continue;
}
/* pass statep as cm_private */
if (ret != IBT_SUCCESS) {
"HCA: 0x%llx Port: %d gid %llx:%llx "
continue;
}
nbinds++;
}
}
#if 0
if (nbinds == 0) {
return (-1);
}
#endif
return (0);
}
/* Open an RC connection */
int
{
sizeof (rds_cm_private_data_t), &cmp);
if (ret != IBT_SUCCESS) {
return (-1);
}
return (-1);
}
if (ret != IBT_SUCCESS) {
(void) ibt_flush_channel(hdl);
(void) ibt_free_channel(hdl);
/* don't cleanup if this failure is due to peer-peer race */
/* cleanup stuff allocated in rds_ep_alloc_rc_channel */
}
return (-1);
}
*chanhdl);
return (0);
}
int
{
int ret;
return (ret);
}