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