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
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)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
srpt_cm_conn_est_hdlr(srpt_target_port_t * tgt,ibt_cm_event_t * event)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
srpt_cm_conn_closed_hdlr(srpt_target_port_t * tgt,ibt_cm_event_t * event)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
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