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  * Copyright 2019, Joyent, Inc.
28  */
29 
30 /*
31  * IB CM handlers for s Solaris SCSI RDMA Protocol Target (SRP)
32  * transport port provider module for the COMSTAR framework.
33  */
34 
35 #include <sys/cpuvar.h>
36 #include <sys/types.h>
37 #include <sys/conf.h>
38 #include <sys/stat.h>
39 #include <sys/file.h>
40 #include <sys/ddi.h>
41 #include <sys/sunddi.h>
42 #include <sys/modctl.h>
43 #include <sys/sysmacros.h>
44 #include <sys/sdt.h>
45 #include <sys/taskq.h>
46 #include <sys/ib/ibtl/ibti.h>
47 
48 #include <sys/stmf.h>
49 #include <sys/stmf_ioctl.h>
50 #include <sys/portif.h>
51 
52 #include "srp.h"
53 #include "srpt_impl.h"
54 #include "srpt_cm.h"
55 #include "srpt_stp.h"
56 #include "srpt_ch.h"
57 
58 extern uint16_t srpt_send_msg_depth;
59 extern srpt_ctxt_t  *srpt_ctxt;
60 
61 /*
62  * srpt_cm_req_hdlr() - Login request
63  *
64  * CM has called back with a CM REQ message associated with an
65  * SRP initiator login request.
66  */
67 static ibt_cm_status_t
srpt_cm_req_hdlr(srpt_target_port_t * tgt,ibt_cm_event_t * event,ibt_cm_return_args_t * ret_args,void * ret_priv_data,ibt_priv_data_len_t ret_priv_data_len)68 srpt_cm_req_hdlr(srpt_target_port_t *tgt, ibt_cm_event_t *event,
69     ibt_cm_return_args_t *ret_args, void *ret_priv_data,
70     ibt_priv_data_len_t ret_priv_data_len)
71 {
72 	ibt_cm_status_t		status;
73 	ibt_cm_req_rcv_t	*req;
74 	srp_login_req_t		login;
75 	srp_login_rej_t		login_rej;
76 	srp_login_rsp_t		login_rsp;
77 	srpt_channel_t		*ch = NULL;
78 	char			remote_gid[SRPT_ALIAS_LEN];
79 	char			local_gid[SRPT_ALIAS_LEN];
80 
81 	ASSERT(tgt != NULL);
82 	req = &event->cm_event.req;
83 
84 	if (event->cm_priv_data_len <  sizeof (srp_login_req_t)) {
85 		SRPT_DPRINTF_L2("cm_req_hdlr, IU size expected (>= %d),"
86 		    " received size (%d)", (uint_t)sizeof (srp_login_req_t),
87 		    event->cm_priv_data_len);
88 		return (IBT_CM_REJECT);
89 	}
90 
91 	if (event->cm_priv_data == NULL) {
92 		SRPT_DPRINTF_L2("cm_req_hdlr, NULL ULP private data pointer");
93 		return (IBT_CM_REJECT);
94 	}
95 
96 	if (ret_priv_data_len <  sizeof (srp_login_rej_t)) {
97 		SRPT_DPRINTF_L2("cm_req_hdlr, return private len too"
98 		    " small (%d)", ret_priv_data_len);
99 		return (IBT_CM_REJECT);
100 	}
101 
102 	if (ret_priv_data == NULL) {
103 		SRPT_DPRINTF_L2("cm_req_hdlr, NULL ULP return private data"
104 		    " pointer");
105 		return (IBT_CM_REJECT);
106 	}
107 
108 	/*
109 	 * Copy to avoid potential alignment problems, process login
110 	 * creating a new channel and possibly session.
111 	 */
112 	bcopy(event->cm_priv_data, &login,  sizeof (login));
113 
114 	ALIAS_STR(local_gid,
115 	    req->req_prim_addr.av_sgid.gid_prefix,
116 	    req->req_prim_addr.av_sgid.gid_guid);
117 	ALIAS_STR(remote_gid,
118 	    req->req_prim_addr.av_dgid.gid_prefix,
119 	    req->req_prim_addr.av_dgid.gid_guid);
120 
121 	ch = srpt_stp_login(tgt, &login, &login_rsp,
122 	    &login_rej, req->req_prim_hca_port, local_gid, remote_gid);
123 	if (ch != NULL) {
124 		bcopy(&login_rsp, ret_priv_data,  SRP_LOGIN_RSP_SIZE);
125 		ret_args->cm_ret_len = SRP_LOGIN_RSP_SIZE;
126 
127 		SRPT_DPRINTF_L3("cm_req_hdlr, rsp priv len(%d)"
128 		    " ch created on port(%d)"
129 		    ", cm_req_hdlr, req ra_out(%d), ra_in(%d)"
130 		    ", retry(%d)",
131 		    ret_args->cm_ret_len, req->req_prim_hca_port,
132 		    req->req_rdma_ra_out, req->req_rdma_ra_in,
133 		    req->req_retry_cnt);
134 
135 		ret_args->cm_ret.rep.cm_channel = ch->ch_chan_hdl;
136 		ret_args->cm_ret.rep.cm_rdma_ra_out =
137 		    min(tgt->tp_ioc->ioc_attr.hca_max_rdma_out_chan,
138 		    req->req_rdma_ra_in);
139 		ret_args->cm_ret.rep.cm_rdma_ra_in =
140 		    min(tgt->tp_ioc->ioc_attr.hca_max_rdma_in_chan,
141 		    req->req_rdma_ra_out);
142 		ret_args->cm_ret.rep.cm_rnr_retry_cnt = req->req_retry_cnt;
143 
144 		SRPT_DPRINTF_L3("cm_req_hdlr, hca_max_rdma_in_chan (%d)"
145 		    ", hca_max_rdma_out_chan (%d)"
146 		    ", updated ra_out(%d), ra_in(%d), retry(%d)",
147 		    tgt->tp_ioc->ioc_attr.hca_max_rdma_in_chan,
148 		    tgt->tp_ioc->ioc_attr.hca_max_rdma_out_chan,
149 		    ret_args->cm_ret.rep.cm_rdma_ra_out,
150 		    ret_args->cm_ret.rep.cm_rdma_ra_in,
151 		    ret_args->cm_ret.rep.cm_rnr_retry_cnt);
152 		status = IBT_CM_ACCEPT;
153 
154 	} else {
155 		bcopy(&login_rej, ret_priv_data,  sizeof (login_rej));
156 		ret_args->cm_ret_len =  sizeof (login_rej);
157 		status = IBT_CM_REJECT;
158 	}
159 
160 	return (status);
161 }
162 
163 /*
164  * srpt_cm_conn_est_hdlr() - Connection established
165  *
166  * CM has called back to inform us that a connection attempt has
167  * completed (explicit or implicit) and may now be used.
168  */
169 /* ARGSUSED */
170 static ibt_cm_status_t
srpt_cm_conn_est_hdlr(srpt_target_port_t * tgt,ibt_cm_event_t * event)171 srpt_cm_conn_est_hdlr(srpt_target_port_t *tgt, ibt_cm_event_t *event)
172 {
173 	srpt_channel_t		*ch;
174 
175 	ASSERT(tgt != NULL);
176 	ASSERT(event != NULL);
177 
178 	ch = (srpt_channel_t *)ibt_get_chan_private(event->cm_channel);
179 	ASSERT(ch != NULL);
180 
181 	SRPT_DPRINTF_L3("cm_conn_est_hdlr, invoked for ch(%p)",
182 	    (void *)ch);
183 
184 	rw_enter(&ch->ch_rwlock, RW_WRITER);
185 	if (ch->ch_state != SRPT_CHANNEL_CONNECTING &&
186 	    ch->ch_state != SRPT_CHANNEL_CONNECTED) {
187 		SRPT_DPRINTF_L2("cm_conn_est_hdlr, invalid ch state (%d)",
188 		    ch->ch_state);
189 		rw_exit(&ch->ch_rwlock);
190 		return (IBT_CM_REJECT);
191 	}
192 
193 	ch->ch_state = SRPT_CHANNEL_CONNECTED;
194 
195 	rw_exit(&ch->ch_rwlock);
196 	return (IBT_CM_ACCEPT);
197 }
198 
199 /*
200  * srpt_cm_conn_closed_hdlr() - Channel closed
201  *
202  * CM callback indicating a channel has been completely closed.
203  */
204 /* ARGSUSED */
205 static ibt_cm_status_t
srpt_cm_conn_closed_hdlr(srpt_target_port_t * tgt,ibt_cm_event_t * event)206 srpt_cm_conn_closed_hdlr(srpt_target_port_t *tgt, ibt_cm_event_t *event)
207 {
208 	ibt_cm_status_t		status = IBT_CM_ACCEPT;
209 	srpt_channel_t		*ch;
210 
211 	ASSERT(tgt != NULL);
212 	ASSERT(event != NULL);
213 
214 	ch = (srpt_channel_t *)ibt_get_chan_private(event->cm_channel);
215 	ASSERT(ch != NULL);
216 
217 	SRPT_DPRINTF_L3("cm_conn_closed_hdlr, invoked for chan_hdl(%p),"
218 	    " event(%d)", (void *)ch->ch_chan_hdl,
219 	    event->cm_event.closed);
220 
221 	switch (event->cm_event.closed) {
222 
223 	case IBT_CM_CLOSED_DREP_RCVD:
224 	case IBT_CM_CLOSED_DREQ_TIMEOUT:
225 	case IBT_CM_CLOSED_DUP:
226 	case IBT_CM_CLOSED_ABORT:
227 	case IBT_CM_CLOSED_ALREADY:
228 		/*
229 		 * These cases indicate the SRP target initiated
230 		 * the closing of the channel and it is now closed.
231 		 * Cleanup the channel (which will remove the targets
232 		 * reference) and then release CM's reference.
233 		 */
234 		SRPT_DPRINTF_L3("cm_conn_closed_hdlr, local close call-back");
235 		srpt_ch_cleanup(ch);
236 		srpt_ch_release_ref(ch, 1);
237 		break;
238 
239 	case IBT_CM_CLOSED_DREQ_RCVD:
240 	case IBT_CM_CLOSED_REJ_RCVD:
241 	case IBT_CM_CLOSED_STALE:
242 		/*
243 		 * These cases indicate that the SRP initiator is closing
244 		 * the channel.  CM will have already closed the RC channel,
245 		 * so simply initiate cleanup which will remove the target
246 		 * ports reference to the channel and then release the
247 		 * reference held by the CM.
248 		 */
249 		SRPT_DPRINTF_L3("cm_conn_closed_hdlr, remote close,"
250 		    " free channel");
251 		srpt_ch_cleanup(ch);
252 		srpt_ch_release_ref(ch, 1);
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
srpt_cm_failure_hdlr(ibt_cm_event_t * event)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
srpt_cm_hdlr(void * cm_private,ibt_cm_event_t * event,ibt_cm_return_args_t * ret_args,void * ret_priv_data,ibt_priv_data_len_t ret_len_max)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