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 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 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 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 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 }