1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. 24 */ 25 26 /* 27 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 28 * Use is subject to license terms. 29 */ 30 31 /* 32 * 33 * MODULE: dapl_ep_disconnect.c 34 * 35 * PURPOSE: Endpoint management 36 * Description: Interfaces in this file are completely described in 37 * the DAPL 1.1 API, Chapter 6, section 5 38 * 39 * $Id: dapl_ep_disconnect.c,v 1.15 2003/07/30 18:13:37 hobie16 Exp $ 40 */ 41 42 #include "dapl.h" 43 #include "dapl_ia_util.h" 44 #include "dapl_ep_util.h" 45 #include "dapl_evd_util.h" 46 #include "dapl_adapter_util.h" 47 48 /* 49 * dapl_ep_disconnect 50 * 51 * DAPL Requirements Version xxx, 6.5.9 52 * 53 * Terminate a connection. 54 * 55 * Input: 56 * ep_handle 57 * disconnect_flags 58 * 59 * Output: 60 * None 61 * 62 * Returns: 63 * DAT_SUCCESS 64 * DAT_INSUFFICIENT_RESOURCES 65 * DAT_INVALID_PARAMETER 66 */ 67 DAT_RETURN 68 dapl_ep_disconnect( 69 IN DAT_EP_HANDLE ep_handle, 70 IN DAT_CLOSE_FLAGS disconnect_flags) 71 { 72 DAPL_EP *ep_ptr; 73 DAT_RETURN dat_status; 74 75 dapl_dbg_log(DAPL_DBG_TYPE_API | DAPL_DBG_TYPE_CM, 76 "dapl_ep_disconnect (%p, %x)\n", ep_handle, disconnect_flags); 77 78 ep_ptr = (DAPL_EP *) ep_handle; 79 80 /* 81 * Verify parameter & state 82 */ 83 if (DAPL_BAD_HANDLE(ep_ptr, DAPL_MAGIC_EP)) { 84 dat_status = DAT_ERROR(DAT_INVALID_HANDLE, 85 DAT_INVALID_HANDLE_EP); 86 goto bail; 87 } 88 89 /* 90 * Do the verification of parameters and the state change 91 * atomically. 92 */ 93 dapl_os_lock(&ep_ptr->header.lock); 94 95 /* 96 * Check the EP state to ensure we are queiscent. Note that 97 * we may get called in UNCONNECTED state in order to remove 98 * RECV requests from the queue prior to destroying an EP. 99 * See the states in the spec at 6.5.1 Endpont Lifecycle 100 */ 101 102 if (ep_ptr->param.ep_state != DAT_EP_STATE_CONNECTED && 103 ep_ptr->param.ep_state != DAT_EP_STATE_DISCONNECTED && 104 ep_ptr->param.ep_state != DAT_EP_STATE_ACTIVE_CONNECTION_PENDING && 105 ep_ptr->param.ep_state != DAT_EP_STATE_COMPLETION_PENDING && 106 ep_ptr->param.ep_state != DAT_EP_STATE_DISCONNECT_PENDING) { 107 dapl_os_unlock(&ep_ptr->header.lock); 108 dat_status = DAT_ERROR(DAT_INVALID_STATE, 109 dapls_ep_state_subtype(ep_ptr)); 110 goto bail; 111 } 112 113 if (ep_ptr->param.ep_state == DAT_EP_STATE_DISCONNECTED) { 114 /* 115 * Calling disconnect when DISCONNECTED is a NOOP, just return 116 * good. 117 */ 118 dapl_os_unlock(&ep_ptr->header.lock); 119 dat_status = DAT_SUCCESS; 120 goto bail; 121 } 122 123 if (ep_ptr->param.ep_state == DAT_EP_STATE_DISCONNECT_PENDING && 124 disconnect_flags != DAT_CLOSE_ABRUPT_FLAG) { 125 /* 126 * If in state DISCONNECT_PENDING then this must be an 127 * ABRUPT disconnect 128 */ 129 dapl_os_unlock(&ep_ptr->header.lock); 130 dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG2); 131 goto bail; 132 } 133 134 if (ep_ptr->param.ep_state == DAT_EP_STATE_ACTIVE_CONNECTION_PENDING || 135 ep_ptr->param.ep_state == DAT_EP_STATE_COMPLETION_PENDING) { 136 /* 137 * transition ep_state to DISCONNECT_PENDING 138 */ 139 ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECT_PENDING; 140 dapl_os_unlock(&ep_ptr->header.lock); 141 dapls_ib_disconnect_clean(ep_ptr, DAT_TRUE, 142 IB_CME_CONNECTION_REQUEST_PENDING); 143 144 /* 145 * we do not have to post an event here. 146 * the CM will generate one. 147 */ 148 dat_status = DAT_SUCCESS; 149 goto bail; 150 } 151 152 /* 153 * Transition the EP state to DISCONNECT_PENDING if we are 154 * CONNECTED. Otherwise we do not get a disconnect event and will be 155 * stuck in DISCONNECT_PENDING. 156 * 157 * If the user specifies a graceful disconnect, the underlying 158 * provider should complete all DTOs before disconnecting; in IB 159 * terms, this means setting the QP state to SQD before completing 160 * the disconnect state transitions. 161 */ 162 if (ep_ptr->param.ep_state == DAT_EP_STATE_CONNECTED) { 163 ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECT_PENDING; 164 } 165 dapl_os_unlock(&ep_ptr->header.lock); 166 dat_status = dapls_ib_disconnect(ep_ptr, disconnect_flags); 167 168 bail: 169 dapl_dbg_log(DAPL_DBG_TYPE_RTN | DAPL_DBG_TYPE_CM, 170 "dapl_ep_disconnect () returns 0x%x\n", dat_status); 171 172 return (dat_status); 173 } 174