xref: /illumos-gate/usr/src/uts/common/io/comstar/port/srpt/srpt_cm.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * IB CM handlers for s Solaris SCSI RDMA Protocol Target (SRP)
29  * transport port provider module for the COMSTAR framework.
30  */
31 
32 #include <sys/cpuvar.h>
33 #include <sys/types.h>
34 #include <sys/conf.h>
35 #include <sys/stat.h>
36 #include <sys/file.h>
37 #include <sys/ddi.h>
38 #include <sys/sunddi.h>
39 #include <sys/modctl.h>
40 #include <sys/sysmacros.h>
41 #include <sys/sdt.h>
42 #include <sys/taskq.h>
43 #include <sys/ib/ibtl/ibti.h>
44 
45 #include <stmf.h>
46 #include <stmf_ioctl.h>
47 #include <portif.h>
48 
49 #include "srp.h"
50 #include "srpt_impl.h"
51 #include "srpt_cm.h"
52 #include "srpt_stp.h"
53 #include "srpt_ch.h"
54 
55 extern uint16_t srpt_send_msg_depth;
56 extern srpt_ctxt_t  *srpt_ctxt;
57 
58 /*
59  * srpt_cm_req_hdlr() - Login request
60  *
61  * CM has called back with a CM REQ message associated with an
62  * SRP initiator login request.
63  */
64 static ibt_cm_status_t
65 srpt_cm_req_hdlr(srpt_target_port_t *tgt, ibt_cm_event_t *event,
66 	ibt_cm_return_args_t *ret_args, void *ret_priv_data,
67 	ibt_priv_data_len_t ret_priv_data_len)
68 {
69 	ibt_cm_status_t		status;
70 	ibt_cm_req_rcv_t	*req;
71 	srp_login_req_t		login;
72 	srp_login_rej_t		login_rej;
73 	srp_login_rsp_t		login_rsp;
74 	srpt_channel_t		*ch = NULL;
75 	char			remote_gid[SRPT_ALIAS_LEN];
76 	char			local_gid[SRPT_ALIAS_LEN];
77 
78 	ASSERT(tgt != NULL);
79 	req = &event->cm_event.req;
80 
81 	if (event->cm_priv_data_len <  sizeof (srp_login_req_t)) {
82 		SRPT_DPRINTF_L2("cm_req_hdlr, IU size expected (>= %d),"
83 		    " received size (%d)", (uint_t)sizeof (srp_login_req_t),
84 		    event->cm_priv_data_len);
85 		return (IBT_CM_REJECT);
86 	}
87 
88 	if (event->cm_priv_data == NULL) {
89 		SRPT_DPRINTF_L2("cm_req_hdlr, NULL ULP private data pointer");
90 		return (IBT_CM_REJECT);
91 	}
92 
93 	if (ret_priv_data_len <  sizeof (srp_login_rej_t)) {
94 		SRPT_DPRINTF_L2("cm_req_hdlr, return private len too"
95 		    " small (%d)", ret_priv_data_len);
96 		return (IBT_CM_REJECT);
97 	}
98 
99 	if (ret_priv_data == NULL) {
100 		SRPT_DPRINTF_L2("cm_req_hdlr, NULL ULP return private data"
101 		    " pointer");
102 		return (IBT_CM_REJECT);
103 	}
104 
105 	/*
106 	 * Copy to avoid potential alignment problems, process login
107 	 * creating a new channel and possibly session.
108 	 */
109 	bcopy(event->cm_priv_data, &login,  sizeof (login));
110 
111 	ALIAS_STR(local_gid,
112 	    req->req_prim_addr.av_sgid.gid_prefix,
113 	    req->req_prim_addr.av_sgid.gid_guid);
114 	ALIAS_STR(remote_gid,
115 	    req->req_prim_addr.av_dgid.gid_prefix,
116 	    req->req_prim_addr.av_dgid.gid_guid);
117 
118 	ch = srpt_stp_login(tgt, &login, &login_rsp,
119 	    &login_rej, req->req_prim_hca_port, local_gid, remote_gid);
120 	if (ch != NULL) {
121 		bcopy(&login_rsp, ret_priv_data,  SRP_LOGIN_RSP_SIZE);
122 		ret_args->cm_ret_len = SRP_LOGIN_RSP_SIZE;
123 
124 		SRPT_DPRINTF_L3("cm_req_hdlr, rsp priv len(%d)"
125 		    " ch created on port(%d)"
126 		    ", cm_req_hdlr, req ra_out(%d), ra_in(%d)"
127 		    ", retry(%d)",
128 		    ret_args->cm_ret_len, req->req_prim_hca_port,
129 		    req->req_rdma_ra_out, req->req_rdma_ra_in,
130 		    req->req_retry_cnt);
131 
132 		ret_args->cm_ret.rep.cm_channel = ch->ch_chan_hdl;
133 		ret_args->cm_ret.rep.cm_rdma_ra_out =
134 		    min(tgt->tp_ioc->ioc_attr.hca_max_rdma_out_chan,
135 		    req->req_rdma_ra_in);
136 		ret_args->cm_ret.rep.cm_rdma_ra_in =
137 		    min(tgt->tp_ioc->ioc_attr.hca_max_rdma_in_chan,
138 		    req->req_rdma_ra_out);
139 		ret_args->cm_ret.rep.cm_rnr_retry_cnt = req->req_retry_cnt;
140 
141 		SRPT_DPRINTF_L3("cm_req_hdlr, hca_max_rdma_in_chan (%d)"
142 		    ", hca_max_rdma_out_chan (%d)"
143 		    ", updated ra_out(%d), ra_in(%d), retry(%d)",
144 		    tgt->tp_ioc->ioc_attr.hca_max_rdma_in_chan,
145 		    tgt->tp_ioc->ioc_attr.hca_max_rdma_out_chan,
146 		    ret_args->cm_ret.rep.cm_rdma_ra_out,
147 		    ret_args->cm_ret.rep.cm_rdma_ra_in,
148 		    ret_args->cm_ret.rep.cm_rnr_retry_cnt);
149 		status = IBT_CM_ACCEPT;
150 
151 	} else {
152 		bcopy(&login_rej, ret_priv_data,  sizeof (login_rej));
153 		ret_args->cm_ret_len =  sizeof (login_rej);
154 		status = IBT_CM_REJECT;
155 	}
156 
157 	return (status);
158 }
159 
160 /*
161  * srpt_cm_conn_est_hdlr() - Connection established
162  *
163  * CM has called back to inform us that a connection attempt has
164  * completed (explicit or implicit) and may now be used.
165  */
166 /* ARGSUSED */
167 static ibt_cm_status_t
168 srpt_cm_conn_est_hdlr(srpt_target_port_t *tgt, ibt_cm_event_t *event)
169 {
170 	srpt_channel_t		*ch;
171 
172 	ASSERT(tgt != NULL);
173 	ASSERT(event != NULL);
174 
175 	ch = (srpt_channel_t *)ibt_get_chan_private(event->cm_channel);
176 	ASSERT(ch != NULL);
177 
178 	SRPT_DPRINTF_L3("cm_conn_est_hdlr, invoked for ch(%p)",
179 	    (void *)ch);
180 
181 	rw_enter(&ch->ch_rwlock, RW_WRITER);
182 	if (ch->ch_state != SRPT_CHANNEL_CONNECTING &&
183 	    ch->ch_state != SRPT_CHANNEL_CONNECTED) {
184 		SRPT_DPRINTF_L2("cm_conn_est_hdlr, invalid ch state (%d)",
185 		    ch->ch_state);
186 		rw_exit(&ch->ch_rwlock);
187 		return (IBT_CM_REJECT);
188 	}
189 
190 	ch->ch_state = SRPT_CHANNEL_CONNECTED;
191 
192 	rw_exit(&ch->ch_rwlock);
193 	return (IBT_CM_ACCEPT);
194 }
195 
196 /*
197  * srpt_cm_conn_closed_hdlr() - Channel closed
198  *
199  * CM callback indicating a channel has been completely closed.
200  */
201 /* ARGSUSED */
202 static ibt_cm_status_t
203 srpt_cm_conn_closed_hdlr(srpt_target_port_t *tgt, ibt_cm_event_t *event)
204 {
205 	ibt_cm_status_t		status = IBT_CM_ACCEPT;
206 	srpt_channel_t		*ch;
207 
208 	ASSERT(tgt != NULL);
209 	ASSERT(event != NULL);
210 
211 	ch = (srpt_channel_t *)ibt_get_chan_private(event->cm_channel);
212 	ASSERT(ch != NULL);
213 
214 	SRPT_DPRINTF_L3("cm_conn_closed_hdlr, invoked for chan_hdl(%p),"
215 	    " event(%d)", (void *)ch->ch_chan_hdl,
216 	    event->cm_event.closed);
217 
218 	switch (event->cm_event.closed) {
219 
220 	case IBT_CM_CLOSED_DREP_RCVD:
221 	case IBT_CM_CLOSED_DREQ_TIMEOUT:
222 	case IBT_CM_CLOSED_DUP:
223 	case IBT_CM_CLOSED_ABORT:
224 	case IBT_CM_CLOSED_ALREADY:
225 		/*
226 		 * These cases indicate the SRP target initiated
227 		 * the closing of the channel and it is now closed.
228 		 * Cleanup the channel (which will remove the targets
229 		 * reference) and then release CM's reference.
230 		 */
231 		SRPT_DPRINTF_L3("cm_conn_closed_hdlr, local close call-back");
232 		srpt_ch_cleanup(ch);
233 		srpt_ch_release_ref(ch, 1);
234 		break;
235 
236 	case IBT_CM_CLOSED_DREQ_RCVD:
237 	case IBT_CM_CLOSED_REJ_RCVD:
238 	case IBT_CM_CLOSED_STALE:
239 		/*
240 		 * These cases indicate that the SRP initiator is closing
241 		 * the channel.  CM will have already closed the RC channel,
242 		 * so simply initiate cleanup which will remove the target
243 		 * ports reference to the channel and then release the
244 		 * reference held by the CM.
245 		 */
246 		SRPT_DPRINTF_L3("cm_conn_closed_hdlr, remote close,"
247 		    " free channel");
248 		if (ch != NULL) {
249 			srpt_ch_cleanup(ch);
250 			srpt_ch_release_ref(ch, 1);
251 		} else {
252 			SRPT_DPRINTF_L2("cm_conn_closed_hdlr, NULL channel");
253 		}
254 		break;
255 
256 	default:
257 		SRPT_DPRINTF_L2("cm_conn_closed_hdlr, unknown close type (%d)",
258 		    event->cm_event.closed);
259 		status = IBT_CM_DEFAULT;
260 		break;
261 	}
262 	return (status);
263 }
264 
265 /*
266  * srpt_cm_failure_hdlr() - Called when the channel is in error.  Cleanup
267  * and release the channel.
268  */
269 static ibt_cm_status_t
270 srpt_cm_failure_hdlr(ibt_cm_event_t *event)
271 {
272 	srpt_channel_t		*ch;
273 
274 	ASSERT(event != NULL);
275 
276 	ch = (srpt_channel_t *)ibt_get_chan_private(event->cm_channel);
277 	ASSERT(ch != NULL);
278 
279 	SRPT_DPRINTF_L3("cm_failure_hdlr, chan_hdl: 0x%p, code: %d"
280 	    "msg: %d reason: %d", (void *)event->cm_channel,
281 	    event->cm_event.failed.cf_code,
282 	    event->cm_event.failed.cf_msg,
283 	    event->cm_event.failed.cf_reason);
284 
285 	srpt_ch_cleanup(ch);
286 	srpt_ch_release_ref(ch, 1);
287 
288 	return (IBT_CM_ACCEPT);
289 }
290 
291 /*
292  * srpt_cm_hdlr() - CM call-back handler.
293  */
294 ibt_cm_status_t
295 srpt_cm_hdlr(void *cm_private, ibt_cm_event_t *event,
296 	ibt_cm_return_args_t *ret_args, void *ret_priv_data,
297 	ibt_priv_data_len_t ret_len_max)
298 {
299 	ibt_cm_status_t		status = IBT_CM_ACCEPT;
300 
301 	switch (event->cm_type) {
302 
303 	case IBT_CM_EVENT_REQ_RCV:
304 		SRPT_DPRINTF_L3("cm_hdlr, REQ received");
305 		status = srpt_cm_req_hdlr((srpt_target_port_t *)cm_private,
306 		    event, ret_args, ret_priv_data, ret_len_max);
307 		break;
308 
309 	case IBT_CM_EVENT_REP_RCV:
310 		SRPT_DPRINTF_L3("cm_hdlr, REP received");
311 		break;
312 
313 	case IBT_CM_EVENT_MRA_RCV:
314 		SRPT_DPRINTF_L3("cm_hdlr, MRA received");
315 		break;
316 
317 	case IBT_CM_EVENT_CONN_EST:
318 		SRPT_DPRINTF_L3("cm_hdlr, Connection established");
319 		status = srpt_cm_conn_est_hdlr(
320 		    (srpt_target_port_t *)cm_private, event);
321 		break;
322 
323 	case IBT_CM_EVENT_CONN_CLOSED:
324 		SRPT_DPRINTF_L3("cm_hdlr, Connection closed");
325 		status = srpt_cm_conn_closed_hdlr(
326 		    (srpt_target_port_t *)cm_private, event);
327 		break;
328 
329 	case IBT_CM_EVENT_FAILURE:
330 		SRPT_DPRINTF_L3("cm_hdlr, Event failure");
331 		status = srpt_cm_failure_hdlr(event);
332 		break;
333 
334 	case IBT_CM_EVENT_LAP_RCV:
335 		SRPT_DPRINTF_L3("cm_hdlr, LAP received");
336 		break;
337 
338 	case IBT_CM_EVENT_APR_RCV:
339 		SRPT_DPRINTF_L3("cm_hdlr, APR received");
340 		break;
341 
342 	default:
343 		SRPT_DPRINTF_L3("cm_hdlr, unknown event received");
344 		break;
345 	}
346 
347 	return (status);
348 }
349