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 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * Copyright (c) 2016 by Delphix. All rights reserved. 25 */ 26 27 #include <sys/types.h> 28 #include <sys/ddi.h> 29 #include <sys/types.h> 30 #include <sys/socket.h> 31 #include <netinet/in.h> 32 #include <sys/sunddi.h> 33 #include <sys/ib/ibtl/ibti.h> 34 #include <sys/ib/ibtl/ibtl_types.h> 35 36 #include <sys/ib/clients/iser/iser.h> 37 38 extern idm_transport_ops_t iser_transport_ops; 39 40 /* 41 * iser_cm.c 42 * InfiniBand Communication Manager routines for iSER 43 */ 44 static ibt_cm_status_t iser_ib_handle_cm_req(idm_svc_t *svc_hdl, 45 ibt_cm_event_t *evp, ibt_cm_return_args_t *rargsp, void *rcmp, 46 ibt_priv_data_len_t rcmp_len); 47 48 static ibt_cm_status_t iser_ib_handle_cm_rep(iser_state_t *statep, 49 ibt_cm_event_t *evp, ibt_cm_return_args_t *rargsp, void *rcmp, 50 ibt_priv_data_len_t rcmp_len); 51 52 static ibt_cm_status_t iser_handle_cm_conn_est(ibt_cm_event_t *evp); 53 static ibt_cm_status_t iser_handle_cm_conn_closed(ibt_cm_event_t *evp); 54 static ibt_cm_status_t iser_handle_cm_event_failure(ibt_cm_event_t *evp); 55 56 /* 57 * iser_ib_cm_handler() 58 */ 59 ibt_cm_status_t 60 iser_ib_cm_handler(void *cm_private, ibt_cm_event_t *eventp, 61 ibt_cm_return_args_t *ret_args, void *ret_priv_data, 62 ibt_priv_data_len_t ret_len_max) 63 { 64 ibt_cm_status_t ret = IBT_CM_REJECT; 65 66 switch (eventp->cm_type) { 67 68 case IBT_CM_EVENT_REQ_RCV: 69 ISER_LOG(CE_NOTE, "iser_ib_cm_handler: IBT_CM_EVENT_REQ_RCV"); 70 ret = iser_ib_handle_cm_req((idm_svc_t *)cm_private, eventp, 71 ret_args, ret_priv_data, ret_len_max); 72 break; 73 74 case IBT_CM_EVENT_REP_RCV: 75 ISER_LOG(CE_NOTE, "iser_ib_cm_handler: IBT_CM_EVENT_REP_RCV"); 76 ret = iser_ib_handle_cm_rep((iser_state_t *)cm_private, 77 eventp, ret_args, ret_priv_data, ret_len_max); 78 break; 79 80 case IBT_CM_EVENT_CONN_EST: 81 ISER_LOG(CE_NOTE, "iser_ib_cm_handler: IBT_CM_EVENT_CONN_EST"); 82 ret = iser_handle_cm_conn_est(eventp); 83 break; 84 85 case IBT_CM_EVENT_CONN_CLOSED: 86 ISER_LOG(CE_NOTE, "iser_ib_cm_handler: " 87 "IBT_CM_EVENT_CONN_CLOSED"); 88 ret = iser_handle_cm_conn_closed(eventp); 89 break; 90 91 case IBT_CM_EVENT_FAILURE: 92 ISER_LOG(CE_NOTE, "iser_ib_cm_handler: Event failure"); 93 ret = iser_handle_cm_event_failure(eventp); 94 break; 95 96 case IBT_CM_EVENT_MRA_RCV: 97 /* Not supported */ 98 ISER_LOG(CE_NOTE, "iser_ib_cm_handler: MRA message received"); 99 break; 100 101 case IBT_CM_EVENT_LAP_RCV: 102 /* Not supported */ 103 ISER_LOG(CE_NOTE, "iser_ib_cm_handler: LAP message received"); 104 break; 105 106 case IBT_CM_EVENT_APR_RCV: 107 /* Not supported */ 108 ISER_LOG(CE_NOTE, "iser_ib_cm_handler: APR message received"); 109 break; 110 111 default: 112 ISER_LOG(CE_NOTE, "iser_ib_cm_handler: unknown event (0x%x)", 113 eventp->cm_type); 114 break; 115 } 116 117 return (ret); 118 } 119 120 /* ARGSUSED */ 121 static ibt_cm_status_t 122 iser_ib_handle_cm_req(idm_svc_t *svc_hdl, ibt_cm_event_t *evp, 123 ibt_cm_return_args_t *rargsp, void *rcmp, ibt_priv_data_len_t rcmp_len) 124 { 125 126 iser_private_data_t iser_priv_data; 127 ibt_ip_cm_info_t ipcm_info; 128 iser_chan_t *chan; 129 iser_conn_t *iser_conn; 130 int status; 131 132 /* 133 * CM private data brings IP information 134 * Private data received is a stream of bytes and may not be properly 135 * aligned. So, bcopy the data onto the stack before accessing it. 136 */ 137 bcopy((uint8_t *)evp->cm_priv_data, &iser_priv_data, 138 sizeof (iser_private_data_t)); 139 140 /* extract the CM IP info */ 141 status = ibt_get_ip_data(evp->cm_priv_data_len, evp->cm_priv_data, 142 &ipcm_info); 143 if (status != IBT_SUCCESS) { 144 return (IBT_CM_REJECT); 145 } 146 147 ISER_LOG(CE_NOTE, "iser_ib_handle_cm_req: ipcm_info (0x%p): src IP " 148 "(0x%08x) src port (0x%04x) dst IP: (0x%08x)", (void *)&ipcm_info, 149 ipcm_info.src_addr.un.ip4addr, ipcm_info.src_port, 150 ipcm_info.dst_addr.un.ip4addr); 151 152 /* Allocate a channel to establish the new connection */ 153 chan = iser_ib_alloc_channel_nopathlookup( 154 evp->cm_event.req.req_hca_guid, 155 evp->cm_event.req.req_prim_hca_port); 156 if (chan == NULL) { 157 ISER_LOG(CE_NOTE, "iser_ib_handle_cm_req: failed to allocate " 158 "a channel from src IP (0x%08x) src port (0x%04x) " 159 "to dst IP: (0x%08x) on hca(%llx %d)", 160 ipcm_info.src_addr.un.ip4addr, ipcm_info.src_port, 161 ipcm_info.dst_addr.un.ip4addr, 162 (longlong_t)evp->cm_event.req.req_hca_guid, 163 evp->cm_event.req.req_prim_hca_port); 164 return (IBT_CM_REJECT); 165 } 166 167 /* Set the local and remote ip */ 168 chan->ic_localip = ipcm_info.dst_addr; 169 chan->ic_remoteip = ipcm_info.src_addr; 170 171 /* Set the local and remote port numbers on the channel handle */ 172 chan->ic_lport = svc_hdl->is_svc_req.sr_port; 173 chan->ic_rport = ipcm_info.src_port; 174 175 /* Allocate the iser_conn_t for the IDM svc binding */ 176 iser_conn = kmem_zalloc(sizeof (iser_conn_t), KM_SLEEP); 177 178 /* Set up the iser_conn attributes */ 179 mutex_init(&iser_conn->ic_lock, NULL, MUTEX_DRIVER, NULL); 180 cv_init(&iser_conn->ic_stage_cv, NULL, CV_DEFAULT, NULL); 181 iser_conn->ic_type = ISER_CONN_TYPE_TGT; 182 iser_conn->ic_chan = chan; 183 iser_conn->ic_stage = ISER_CONN_STAGE_ALLOCATED; 184 185 /* Hold a reference to the iSER service handle */ 186 iser_tgt_svc_hold((iser_svc_t *)svc_hdl->is_iser_svc); 187 188 iser_conn->ic_idms = svc_hdl; 189 190 /* 191 * Now set a pointer to the iser_conn in the iser_chan for 192 * access during CM event handling 193 */ 194 chan->ic_conn = iser_conn; 195 196 rargsp->cm_ret.rep.cm_channel = chan->ic_chanhdl; 197 198 return (IBT_CM_ACCEPT); 199 } 200 201 /* ARGSUSED */ 202 static ibt_cm_status_t 203 iser_ib_handle_cm_rep(iser_state_t *statep, ibt_cm_event_t *evp, 204 ibt_cm_return_args_t *rargsp, void *rcmp, ibt_priv_data_len_t rcmp_len) 205 { 206 /* pre-post work requests into the receive queue */ 207 iser_ib_post_recv(evp->cm_channel); 208 209 /* It looks like the RTU need not be send specifically */ 210 return (IBT_CM_ACCEPT); 211 } 212 213 static ibt_cm_status_t 214 iser_handle_cm_conn_est(ibt_cm_event_t *evp) 215 { 216 iser_chan_t *iser_chan; 217 iser_conn_t *iser_conn; 218 iser_svc_t *iser_svc; 219 idm_status_t status; 220 idm_conn_t *ic; 221 222 iser_chan = (iser_chan_t *)ibt_get_chan_private(evp->cm_channel); 223 224 /* 225 * An ibt_open_rc_channel() comes in as a IBT_CM_EVENT_REQ_RCV on the 226 * iSER-IB target, upon which the target sends a Response, accepting 227 * the request. This comes in as a IBT_CM_EVENT_REP_RCV on the iSER-IB 228 * initiator, which then sends an RTU. Upon getting this RTU from the 229 * iSER-IB initiator, the IBT_CM_EVENT_CONN_EST event is generated on 230 * the target. Then subsequently an IBT_CM_EVENT_CONN_EST event is 231 * generated on the initiator. 232 * 233 * Our new connection has been established on the target. If we are 234 * receiving this event on the target side, the iser_channel can be 235 * used as it is already populated. On the target side, an IDM 236 * connection is then allocated and the IDM layer is notified. 237 * If we are on the initiator we needn't do anything, since we 238 * already have the IDM linkage in place for this connection. 239 */ 240 if (iser_chan->ic_conn->ic_type == ISER_CONN_TYPE_TGT) { 241 242 iser_conn = iser_chan->ic_conn; 243 iser_svc = (iser_svc_t *)iser_conn->ic_idms->is_iser_svc; 244 245 mutex_enter(&iser_conn->ic_lock); 246 247 status = idm_svc_conn_create(iser_conn->ic_idms, 248 IDM_TRANSPORT_TYPE_ISER, &ic); 249 if (status != IDM_STATUS_SUCCESS) { 250 /* 251 * No IDM rsrcs or something equally Bad. 252 * Return non-SUCCESS to IBCM. It'll give 253 * us a CONN_CLOSED, which we'll handle 254 * below. 255 */ 256 ISER_LOG(CE_NOTE, "iser_handle_cm_conn_est: " 257 "idm_svc_conn_create_failed"); 258 mutex_exit(&iser_conn->ic_lock); 259 return (IBT_CM_NO_RESOURCE); 260 } 261 262 /* We no longer need the hold on the iSER service handle */ 263 iser_tgt_svc_rele(iser_svc); 264 265 /* Hold a reference on the IDM connection handle */ 266 idm_conn_hold(ic); 267 268 /* Set the transport ops and conn on the idm_conn handle */ 269 ic->ic_transport_ops = &iser_transport_ops; 270 ic->ic_transport_private = (void *)iser_conn; 271 ic->ic_transport_hdrlen = ISER_HEADER_LENGTH; 272 iser_conn->ic_idmc = ic; 273 274 /* 275 * Set the local and remote addresses in the idm conn handle. 276 */ 277 iser_ib_conv_ibtaddr2sockaddr(&ic->ic_laddr, 278 &iser_conn->ic_chan->ic_localip, iser_chan->ic_lport); 279 iser_ib_conv_ibtaddr2sockaddr(&ic->ic_raddr, 280 &iser_conn->ic_chan->ic_remoteip, iser_chan->ic_rport); 281 282 /* 283 * Kick the state machine. At CS_S3_XPT_UP the state machine 284 * will notify the client (target) about the new connection. 285 */ 286 idm_conn_event(ic, CE_CONNECT_ACCEPT, (uintptr_t)NULL); 287 iser_conn->ic_stage = ISER_CONN_STAGE_IC_CONNECTED; 288 mutex_exit(&iser_conn->ic_lock); 289 290 /* 291 * Post work requests on the receive queue 292 */ 293 iser_ib_post_recv(iser_chan->ic_chanhdl); 294 295 } 296 297 return (IBT_CM_ACCEPT); 298 } 299 300 static ibt_cm_status_t 301 iser_handle_cm_conn_closed(ibt_cm_event_t *evp) 302 { 303 304 iser_chan_t *chan; 305 306 chan = (iser_chan_t *)ibt_get_chan_private(evp->cm_channel); 307 308 ISER_LOG(CE_NOTE, "iser_handle_cm_conn_closed: chan (0x%p) " 309 "reason (0x%x)", (void *)chan, evp->cm_event.closed); 310 311 switch (evp->cm_event.closed) { 312 case IBT_CM_CLOSED_DREP_RCVD: /* we requested a disconnect */ 313 case IBT_CM_CLOSED_ALREADY: /* duplicate close */ 314 /* ignore these */ 315 return (IBT_CM_ACCEPT); 316 317 case IBT_CM_CLOSED_DREQ_RCVD: /* request to close the channel */ 318 case IBT_CM_CLOSED_REJ_RCVD: /* reject after conn establishment */ 319 case IBT_CM_CLOSED_DREQ_TIMEOUT: /* our close request timed out */ 320 case IBT_CM_CLOSED_DUP: /* duplicate close request */ 321 case IBT_CM_CLOSED_ABORT: /* aborted connection establishment */ 322 case IBT_CM_CLOSED_STALE: /* stale / unref connection */ 323 /* handle these depending upon our connection state */ 324 mutex_enter(&chan->ic_conn->ic_lock); 325 switch (chan->ic_conn->ic_stage) { 326 case ISER_CONN_STAGE_UNDEFINED: 327 case ISER_CONN_STAGE_CLOSED: 328 /* do nothing, just drop the lock */ 329 mutex_exit(&chan->ic_conn->ic_lock); 330 break; 331 332 case ISER_CONN_STAGE_ALLOCATED: 333 /* 334 * We blew up or were offlined during connection 335 * establishment. Teardown the iSER conn and chan 336 * handles. 337 */ 338 mutex_exit(&chan->ic_conn->ic_lock); 339 iser_internal_conn_destroy(chan->ic_conn); 340 break; 341 342 case ISER_CONN_STAGE_IC_DISCONNECTED: 343 case ISER_CONN_STAGE_IC_FREED: 344 case ISER_CONN_STAGE_CLOSING: 345 /* we're down, set CLOSED */ 346 chan->ic_conn->ic_stage = ISER_CONN_STAGE_CLOSED; 347 mutex_exit(&chan->ic_conn->ic_lock); 348 break; 349 350 case ISER_CONN_STAGE_IC_CONNECTED: 351 case ISER_CONN_STAGE_HELLO_SENT: 352 case ISER_CONN_STAGE_HELLO_SENT_FAIL: 353 case ISER_CONN_STAGE_HELLO_WAIT: 354 case ISER_CONN_STAGE_HELLO_RCV: 355 case ISER_CONN_STAGE_HELLO_RCV_FAIL: 356 case ISER_CONN_STAGE_HELLOREPLY_SENT: 357 case ISER_CONN_STAGE_HELLOREPLY_SENT_FAIL: 358 case ISER_CONN_STAGE_HELLOREPLY_RCV: 359 case ISER_CONN_STAGE_HELLOREPLY_RCV_FAIL: 360 case ISER_CONN_STAGE_LOGGED_IN: 361 /* for all other stages, fail the transport */ 362 idm_conn_event(chan->ic_conn->ic_idmc, 363 CE_TRANSPORT_FAIL, IDM_STATUS_FAIL); 364 chan->ic_conn->ic_stage = ISER_CONN_STAGE_CLOSING; 365 mutex_exit(&chan->ic_conn->ic_lock); 366 break; 367 368 default: 369 mutex_exit(&chan->ic_conn->ic_lock); 370 ASSERT(0); 371 372 } 373 374 /* accept the event */ 375 return (IBT_CM_ACCEPT); 376 377 default: 378 /* unknown event */ 379 ISER_LOG(CE_NOTE, "iser_handle_cm_conn_closed: unknown closed " 380 "event: (0x%x)", evp->cm_event.closed); 381 return (IBT_CM_REJECT); 382 } 383 } 384 385 /* 386 * Handle EVENT FAILURE 387 */ 388 static ibt_cm_status_t 389 iser_handle_cm_event_failure(ibt_cm_event_t *evp) 390 { 391 iser_chan_t *chan; 392 393 chan = (iser_chan_t *)ibt_get_chan_private(evp->cm_channel); 394 395 ISER_LOG(CE_NOTE, "iser_handle_cm_event_failure: chan (0x%p): " 396 "code: %d msg: %d reason: %d", (void *)chan, 397 evp->cm_event.failed.cf_code, evp->cm_event.failed.cf_msg, 398 evp->cm_event.failed.cf_reason); 399 400 if ((evp->cm_channel == NULL) || (chan == NULL)) { 401 /* channel not established yet */ 402 return (IBT_CM_ACCEPT); 403 } 404 405 if ((evp->cm_event.failed.cf_code != IBT_CM_FAILURE_STALE) && 406 (evp->cm_event.failed.cf_msg == IBT_CM_FAILURE_REQ)) { 407 /* 408 * This end is active, just ignore, ibt_open_rc_channel() 409 * caller will take care of cleanup. 410 */ 411 return (IBT_CM_ACCEPT); 412 } 413 414 /* handle depending upon our connection state */ 415 mutex_enter(&chan->ic_conn->ic_lock); 416 switch (chan->ic_conn->ic_stage) { 417 case ISER_CONN_STAGE_UNDEFINED: 418 case ISER_CONN_STAGE_CLOSED: 419 /* do nothing, just drop the lock */ 420 mutex_exit(&chan->ic_conn->ic_lock); 421 break; 422 423 case ISER_CONN_STAGE_ALLOCATED: 424 /* 425 * We blew up or were offlined during connection 426 * establishment. Teardown the iSER conn and chan 427 * handles. 428 */ 429 mutex_exit(&chan->ic_conn->ic_lock); 430 iser_internal_conn_destroy(chan->ic_conn); 431 break; 432 433 case ISER_CONN_STAGE_IC_DISCONNECTED: 434 case ISER_CONN_STAGE_IC_FREED: 435 case ISER_CONN_STAGE_CLOSING: 436 /* update to CLOSED, then drop the lock */ 437 chan->ic_conn->ic_stage = ISER_CONN_STAGE_CLOSED; 438 mutex_exit(&chan->ic_conn->ic_lock); 439 break; 440 441 case ISER_CONN_STAGE_IC_CONNECTED: 442 case ISER_CONN_STAGE_HELLO_SENT: 443 case ISER_CONN_STAGE_HELLO_SENT_FAIL: 444 case ISER_CONN_STAGE_HELLO_WAIT: 445 case ISER_CONN_STAGE_HELLO_RCV: 446 case ISER_CONN_STAGE_HELLO_RCV_FAIL: 447 case ISER_CONN_STAGE_HELLOREPLY_SENT: 448 case ISER_CONN_STAGE_HELLOREPLY_SENT_FAIL: 449 case ISER_CONN_STAGE_HELLOREPLY_RCV: 450 case ISER_CONN_STAGE_HELLOREPLY_RCV_FAIL: 451 case ISER_CONN_STAGE_LOGGED_IN: 452 /* fail the transport and move the conn to CLOSING */ 453 idm_conn_event(chan->ic_conn->ic_idmc, CE_TRANSPORT_FAIL, 454 IDM_STATUS_FAIL); 455 chan->ic_conn->ic_stage = ISER_CONN_STAGE_CLOSING; 456 mutex_exit(&chan->ic_conn->ic_lock); 457 break; 458 459 default: 460 mutex_exit(&chan->ic_conn->ic_lock); 461 ASSERT(0); 462 } 463 464 /* accept the event */ 465 return (IBT_CM_ACCEPT); 466 } 467