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