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
dapl_ep_disconnect(IN DAT_EP_HANDLE ep_handle,IN DAT_CLOSE_FLAGS disconnect_flags)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