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 }