130e7468fSPeter Dunlap /*
230e7468fSPeter Dunlap  * CDDL HEADER START
330e7468fSPeter Dunlap  *
430e7468fSPeter Dunlap  * The contents of this file are subject to the terms of the
530e7468fSPeter Dunlap  * Common Development and Distribution License (the "License").
630e7468fSPeter Dunlap  * You may not use this file except in compliance with the License.
730e7468fSPeter Dunlap  *
830e7468fSPeter Dunlap  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
930e7468fSPeter Dunlap  * or http://www.opensolaris.org/os/licensing.
1030e7468fSPeter Dunlap  * See the License for the specific language governing permissions
1130e7468fSPeter Dunlap  * and limitations under the License.
1230e7468fSPeter Dunlap  *
1330e7468fSPeter Dunlap  * When distributing Covered Code, include this CDDL HEADER in each
1430e7468fSPeter Dunlap  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1530e7468fSPeter Dunlap  * If applicable, add the following below this CDDL HEADER, with the
1630e7468fSPeter Dunlap  * fields enclosed by brackets "[]" replaced with your own identifying
1730e7468fSPeter Dunlap  * information: Portions Copyright [yyyy] [name of copyright owner]
1830e7468fSPeter Dunlap  *
1930e7468fSPeter Dunlap  * CDDL HEADER END
2030e7468fSPeter Dunlap  */
2130e7468fSPeter Dunlap /*
2230e7468fSPeter Dunlap  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
2330e7468fSPeter Dunlap  * Use is subject to license terms.
2448bbca81SDaniel Hoffman  * Copyright (c) 2016 by Delphix. All rights reserved.
2530e7468fSPeter Dunlap  */
2630e7468fSPeter Dunlap 
2730e7468fSPeter Dunlap #include <sys/types.h>
2830e7468fSPeter Dunlap #include <sys/ddi.h>
2930e7468fSPeter Dunlap #include <sys/types.h>
3030e7468fSPeter Dunlap #include <sys/socket.h>
3130e7468fSPeter Dunlap #include <netinet/in.h>
3230e7468fSPeter Dunlap #include <sys/sunddi.h>
3330e7468fSPeter Dunlap #include <sys/ib/ibtl/ibti.h>
3430e7468fSPeter Dunlap #include <sys/ib/ibtl/ibtl_types.h>
3530e7468fSPeter Dunlap 
3630e7468fSPeter Dunlap #include <sys/ib/clients/iser/iser.h>
3730e7468fSPeter Dunlap 
3830e7468fSPeter Dunlap extern idm_transport_ops_t	iser_transport_ops;
3930e7468fSPeter Dunlap 
4030e7468fSPeter Dunlap /*
4130e7468fSPeter Dunlap  * iser_cm.c
4230e7468fSPeter Dunlap  *    InfiniBand Communication Manager routines for iSER
4330e7468fSPeter Dunlap  */
4430e7468fSPeter Dunlap static ibt_cm_status_t iser_ib_handle_cm_req(idm_svc_t *svc_hdl,
4530e7468fSPeter Dunlap     ibt_cm_event_t *evp, ibt_cm_return_args_t *rargsp, void *rcmp,
4630e7468fSPeter Dunlap     ibt_priv_data_len_t rcmp_len);
4730e7468fSPeter Dunlap 
4830e7468fSPeter Dunlap static ibt_cm_status_t iser_ib_handle_cm_rep(iser_state_t *statep,
4930e7468fSPeter Dunlap     ibt_cm_event_t *evp, ibt_cm_return_args_t *rargsp, void *rcmp,
5030e7468fSPeter Dunlap     ibt_priv_data_len_t rcmp_len);
5130e7468fSPeter Dunlap 
5230e7468fSPeter Dunlap static ibt_cm_status_t iser_handle_cm_conn_est(ibt_cm_event_t *evp);
5330e7468fSPeter Dunlap static ibt_cm_status_t iser_handle_cm_conn_closed(ibt_cm_event_t *evp);
5430e7468fSPeter Dunlap static ibt_cm_status_t iser_handle_cm_event_failure(ibt_cm_event_t *evp);
5530e7468fSPeter Dunlap 
5630e7468fSPeter Dunlap /*
5730e7468fSPeter Dunlap  * iser_ib_cm_handler()
5830e7468fSPeter Dunlap  */
5930e7468fSPeter Dunlap ibt_cm_status_t
iser_ib_cm_handler(void * cm_private,ibt_cm_event_t * eventp,ibt_cm_return_args_t * ret_args,void * ret_priv_data,ibt_priv_data_len_t ret_len_max)6030e7468fSPeter Dunlap iser_ib_cm_handler(void *cm_private, ibt_cm_event_t *eventp,
6130e7468fSPeter Dunlap     ibt_cm_return_args_t *ret_args, void *ret_priv_data,
6230e7468fSPeter Dunlap     ibt_priv_data_len_t ret_len_max)
6330e7468fSPeter Dunlap {
6430e7468fSPeter Dunlap 	ibt_cm_status_t	ret = IBT_CM_REJECT;
6530e7468fSPeter Dunlap 
6630e7468fSPeter Dunlap 	switch (eventp->cm_type) {
6730e7468fSPeter Dunlap 
6830e7468fSPeter Dunlap 	case IBT_CM_EVENT_REQ_RCV:
6930e7468fSPeter Dunlap 		ISER_LOG(CE_NOTE, "iser_ib_cm_handler: IBT_CM_EVENT_REQ_RCV");
7030e7468fSPeter Dunlap 		ret = iser_ib_handle_cm_req((idm_svc_t *)cm_private, eventp,
7130e7468fSPeter Dunlap 		    ret_args, ret_priv_data, ret_len_max);
7230e7468fSPeter Dunlap 		break;
7330e7468fSPeter Dunlap 
7430e7468fSPeter Dunlap 	case IBT_CM_EVENT_REP_RCV:
7530e7468fSPeter Dunlap 		ISER_LOG(CE_NOTE, "iser_ib_cm_handler: IBT_CM_EVENT_REP_RCV");
7630e7468fSPeter Dunlap 		ret = iser_ib_handle_cm_rep((iser_state_t *)cm_private,
7730e7468fSPeter Dunlap 		    eventp, ret_args, ret_priv_data, ret_len_max);
7830e7468fSPeter Dunlap 		break;
7930e7468fSPeter Dunlap 
8030e7468fSPeter Dunlap 	case IBT_CM_EVENT_CONN_EST:
8130e7468fSPeter Dunlap 		ISER_LOG(CE_NOTE, "iser_ib_cm_handler: IBT_CM_EVENT_CONN_EST");
8230e7468fSPeter Dunlap 		ret = iser_handle_cm_conn_est(eventp);
8330e7468fSPeter Dunlap 		break;
8430e7468fSPeter Dunlap 
8530e7468fSPeter Dunlap 	case IBT_CM_EVENT_CONN_CLOSED:
8630e7468fSPeter Dunlap 		ISER_LOG(CE_NOTE, "iser_ib_cm_handler: "
8730e7468fSPeter Dunlap 		    "IBT_CM_EVENT_CONN_CLOSED");
8830e7468fSPeter Dunlap 		ret = iser_handle_cm_conn_closed(eventp);
8930e7468fSPeter Dunlap 		break;
9030e7468fSPeter Dunlap 
9130e7468fSPeter Dunlap 	case IBT_CM_EVENT_FAILURE:
9230e7468fSPeter Dunlap 		ISER_LOG(CE_NOTE, "iser_ib_cm_handler:  Event failure");
9330e7468fSPeter Dunlap 		ret = iser_handle_cm_event_failure(eventp);
9430e7468fSPeter Dunlap 		break;
9530e7468fSPeter Dunlap 
9630e7468fSPeter Dunlap 	case IBT_CM_EVENT_MRA_RCV:
9730e7468fSPeter Dunlap 		/* Not supported */
9830e7468fSPeter Dunlap 		ISER_LOG(CE_NOTE, "iser_ib_cm_handler:  MRA message received");
9930e7468fSPeter Dunlap 		break;
10030e7468fSPeter Dunlap 
10130e7468fSPeter Dunlap 	case IBT_CM_EVENT_LAP_RCV:
10230e7468fSPeter Dunlap 		/* Not supported */
10330e7468fSPeter Dunlap 		ISER_LOG(CE_NOTE, "iser_ib_cm_handler: LAP message received");
10430e7468fSPeter Dunlap 		break;
10530e7468fSPeter Dunlap 
10630e7468fSPeter Dunlap 	case IBT_CM_EVENT_APR_RCV:
10730e7468fSPeter Dunlap 		/* Not supported */
10830e7468fSPeter Dunlap 		ISER_LOG(CE_NOTE, "iser_ib_cm_handler: APR message received");
10930e7468fSPeter Dunlap 		break;
11030e7468fSPeter Dunlap 
11130e7468fSPeter Dunlap 	default:
11230e7468fSPeter Dunlap 		ISER_LOG(CE_NOTE, "iser_ib_cm_handler: unknown event (0x%x)",
11330e7468fSPeter Dunlap 		    eventp->cm_type);
11430e7468fSPeter Dunlap 		break;
11530e7468fSPeter Dunlap 	}
11630e7468fSPeter Dunlap 
11730e7468fSPeter Dunlap 	return (ret);
11830e7468fSPeter Dunlap }
11930e7468fSPeter Dunlap 
12030e7468fSPeter Dunlap /* ARGSUSED */
12130e7468fSPeter Dunlap static ibt_cm_status_t
iser_ib_handle_cm_req(idm_svc_t * svc_hdl,ibt_cm_event_t * evp,ibt_cm_return_args_t * rargsp,void * rcmp,ibt_priv_data_len_t rcmp_len)12230e7468fSPeter Dunlap iser_ib_handle_cm_req(idm_svc_t *svc_hdl, ibt_cm_event_t *evp,
12330e7468fSPeter Dunlap     ibt_cm_return_args_t *rargsp, void *rcmp, ibt_priv_data_len_t rcmp_len)
12430e7468fSPeter Dunlap {
12530e7468fSPeter Dunlap 
12630e7468fSPeter Dunlap 	iser_private_data_t	iser_priv_data;
12730e7468fSPeter Dunlap 	ibt_ip_cm_info_t	ipcm_info;
12830e7468fSPeter Dunlap 	iser_chan_t		*chan;
12930e7468fSPeter Dunlap 	iser_conn_t		*iser_conn;
13030e7468fSPeter Dunlap 	int			status;
13130e7468fSPeter Dunlap 
13230e7468fSPeter Dunlap 	/*
13330e7468fSPeter Dunlap 	 * CM private data brings IP information
13430e7468fSPeter Dunlap 	 * Private data received is a stream of bytes and may not be properly
13530e7468fSPeter Dunlap 	 * aligned. So, bcopy the data onto the stack before accessing it.
13630e7468fSPeter Dunlap 	 */
13730e7468fSPeter Dunlap 	bcopy((uint8_t *)evp->cm_priv_data, &iser_priv_data,
13830e7468fSPeter Dunlap 	    sizeof (iser_private_data_t));
13930e7468fSPeter Dunlap 
14030e7468fSPeter Dunlap 	/* extract the CM IP info */
14130e7468fSPeter Dunlap 	status = ibt_get_ip_data(evp->cm_priv_data_len, evp->cm_priv_data,
14230e7468fSPeter Dunlap 	    &ipcm_info);
14330e7468fSPeter Dunlap 	if (status != IBT_SUCCESS) {
14430e7468fSPeter Dunlap 		return (IBT_CM_REJECT);
14530e7468fSPeter Dunlap 	}
14630e7468fSPeter Dunlap 
14730e7468fSPeter Dunlap 	ISER_LOG(CE_NOTE, "iser_ib_handle_cm_req: ipcm_info (0x%p): src IP "
14830e7468fSPeter Dunlap 	    "(0x%08x) src port (0x%04x) dst IP: (0x%08x)", (void *)&ipcm_info,
14930e7468fSPeter Dunlap 	    ipcm_info.src_addr.un.ip4addr, ipcm_info.src_port,
15030e7468fSPeter Dunlap 	    ipcm_info.dst_addr.un.ip4addr);
15130e7468fSPeter Dunlap 
15230e7468fSPeter Dunlap 	/* Allocate a channel to establish the new connection */
1531d73e59fSPriya Krishnan 	chan = iser_ib_alloc_channel_nopathlookup(
1541d73e59fSPriya Krishnan 	    evp->cm_event.req.req_hca_guid,
1551d73e59fSPriya Krishnan 	    evp->cm_event.req.req_prim_hca_port);
15630e7468fSPeter Dunlap 	if (chan == NULL) {
1571d73e59fSPriya Krishnan 		ISER_LOG(CE_NOTE, "iser_ib_handle_cm_req: failed to allocate "
1581d73e59fSPriya Krishnan 		    "a channel from src IP (0x%08x) src port (0x%04x) "
1591d73e59fSPriya Krishnan 		    "to dst IP: (0x%08x) on hca(%llx %d)",
1601d73e59fSPriya Krishnan 		    ipcm_info.src_addr.un.ip4addr, ipcm_info.src_port,
1611d73e59fSPriya Krishnan 		    ipcm_info.dst_addr.un.ip4addr,
1621d73e59fSPriya Krishnan 		    (longlong_t)evp->cm_event.req.req_hca_guid,
1631d73e59fSPriya Krishnan 		    evp->cm_event.req.req_prim_hca_port);
16430e7468fSPeter Dunlap 		return (IBT_CM_REJECT);
16530e7468fSPeter Dunlap 	}
16630e7468fSPeter Dunlap 
1671d73e59fSPriya Krishnan 	/* Set the local and remote ip */
1681d73e59fSPriya Krishnan 	chan->ic_localip = ipcm_info.dst_addr;
1691d73e59fSPriya Krishnan 	chan->ic_remoteip = ipcm_info.src_addr;
1701d73e59fSPriya Krishnan 
17130e7468fSPeter Dunlap 	/* Set the local and remote port numbers on the channel handle */
17230e7468fSPeter Dunlap 	chan->ic_lport = svc_hdl->is_svc_req.sr_port;
17330e7468fSPeter Dunlap 	chan->ic_rport = ipcm_info.src_port;
17430e7468fSPeter Dunlap 
17530e7468fSPeter Dunlap 	/* Allocate the iser_conn_t for the IDM svc binding */
17630e7468fSPeter Dunlap 	iser_conn = kmem_zalloc(sizeof (iser_conn_t), KM_SLEEP);
17730e7468fSPeter Dunlap 
17830e7468fSPeter Dunlap 	/* Set up the iser_conn attributes */
17930e7468fSPeter Dunlap 	mutex_init(&iser_conn->ic_lock, NULL, MUTEX_DRIVER, NULL);
18030e7468fSPeter Dunlap 	cv_init(&iser_conn->ic_stage_cv, NULL, CV_DEFAULT, NULL);
18130e7468fSPeter Dunlap 	iser_conn->ic_type = ISER_CONN_TYPE_TGT;
18230e7468fSPeter Dunlap 	iser_conn->ic_chan = chan;
18330e7468fSPeter Dunlap 	iser_conn->ic_stage = ISER_CONN_STAGE_ALLOCATED;
18430e7468fSPeter Dunlap 
18530e7468fSPeter Dunlap 	/* Hold a reference to the iSER service handle */
18630e7468fSPeter Dunlap 	iser_tgt_svc_hold((iser_svc_t *)svc_hdl->is_iser_svc);
18730e7468fSPeter Dunlap 
18830e7468fSPeter Dunlap 	iser_conn->ic_idms = svc_hdl;
18930e7468fSPeter Dunlap 
19030e7468fSPeter Dunlap 	/*
19130e7468fSPeter Dunlap 	 * Now set a pointer to the iser_conn in the iser_chan for
19230e7468fSPeter Dunlap 	 * access during CM event handling
19330e7468fSPeter Dunlap 	 */
19430e7468fSPeter Dunlap 	chan->ic_conn = iser_conn;
19530e7468fSPeter Dunlap 
19630e7468fSPeter Dunlap 	rargsp->cm_ret.rep.cm_channel = chan->ic_chanhdl;
19730e7468fSPeter Dunlap 
19830e7468fSPeter Dunlap 	return (IBT_CM_ACCEPT);
19930e7468fSPeter Dunlap }
20030e7468fSPeter Dunlap 
20130e7468fSPeter Dunlap /* ARGSUSED */
20230e7468fSPeter Dunlap static ibt_cm_status_t
iser_ib_handle_cm_rep(iser_state_t * statep,ibt_cm_event_t * evp,ibt_cm_return_args_t * rargsp,void * rcmp,ibt_priv_data_len_t rcmp_len)20330e7468fSPeter Dunlap iser_ib_handle_cm_rep(iser_state_t *statep, ibt_cm_event_t *evp,
20430e7468fSPeter Dunlap     ibt_cm_return_args_t *rargsp, void *rcmp, ibt_priv_data_len_t rcmp_len)
20530e7468fSPeter Dunlap {
20630e7468fSPeter Dunlap 	/* pre-post work requests into the receive queue */
20730e7468fSPeter Dunlap 	iser_ib_post_recv(evp->cm_channel);
20830e7468fSPeter Dunlap 
20930e7468fSPeter Dunlap 	/* It looks like the RTU need not be send specifically */
21030e7468fSPeter Dunlap 	return (IBT_CM_ACCEPT);
21130e7468fSPeter Dunlap }
21230e7468fSPeter Dunlap 
21330e7468fSPeter Dunlap static ibt_cm_status_t
iser_handle_cm_conn_est(ibt_cm_event_t * evp)21430e7468fSPeter Dunlap iser_handle_cm_conn_est(ibt_cm_event_t *evp)
21530e7468fSPeter Dunlap {
21630e7468fSPeter Dunlap 	iser_chan_t	*iser_chan;
21730e7468fSPeter Dunlap 	iser_conn_t	*iser_conn;
21830e7468fSPeter Dunlap 	iser_svc_t	*iser_svc;
21930e7468fSPeter Dunlap 	idm_status_t	status;
22030e7468fSPeter Dunlap 	idm_conn_t	*ic;
22130e7468fSPeter Dunlap 
22230e7468fSPeter Dunlap 	iser_chan = (iser_chan_t *)ibt_get_chan_private(evp->cm_channel);
22330e7468fSPeter Dunlap 
22430e7468fSPeter Dunlap 	/*
22530e7468fSPeter Dunlap 	 * An ibt_open_rc_channel() comes in as a IBT_CM_EVENT_REQ_RCV on the
22630e7468fSPeter Dunlap 	 * iSER-IB target, upon which the target sends a Response, accepting
22730e7468fSPeter Dunlap 	 * the request. This comes in as a IBT_CM_EVENT_REP_RCV on the iSER-IB
22830e7468fSPeter Dunlap 	 * initiator, which then sends an RTU. Upon getting this RTU from the
22930e7468fSPeter Dunlap 	 * iSER-IB initiator, the IBT_CM_EVENT_CONN_EST event is generated on
23030e7468fSPeter Dunlap 	 * the target. Then subsequently an IBT_CM_EVENT_CONN_EST event is
23130e7468fSPeter Dunlap 	 * generated on the initiator.
23230e7468fSPeter Dunlap 	 *
23330e7468fSPeter Dunlap 	 * Our new connection has been established on the target. If we are
23430e7468fSPeter Dunlap 	 * receiving this event on the target side, the iser_channel can be
23530e7468fSPeter Dunlap 	 * used as it is already populated. On the target side, an IDM
23630e7468fSPeter Dunlap 	 * connection is then allocated and the IDM layer is notified.
23730e7468fSPeter Dunlap 	 * If we are on the initiator we needn't do anything, since we
23830e7468fSPeter Dunlap 	 * already have the IDM linkage in place for this connection.
23930e7468fSPeter Dunlap 	 */
24030e7468fSPeter Dunlap 	if (iser_chan->ic_conn->ic_type == ISER_CONN_TYPE_TGT) {
24130e7468fSPeter Dunlap 
24230e7468fSPeter Dunlap 		iser_conn = iser_chan->ic_conn;
24330e7468fSPeter Dunlap 		iser_svc  = (iser_svc_t *)iser_conn->ic_idms->is_iser_svc;
24430e7468fSPeter Dunlap 
24530e7468fSPeter Dunlap 		mutex_enter(&iser_conn->ic_lock);
24630e7468fSPeter Dunlap 
24730e7468fSPeter Dunlap 		status = idm_svc_conn_create(iser_conn->ic_idms,
24830e7468fSPeter Dunlap 		    IDM_TRANSPORT_TYPE_ISER, &ic);
24930e7468fSPeter Dunlap 		if (status != IDM_STATUS_SUCCESS) {
25030e7468fSPeter Dunlap 			/*
25130e7468fSPeter Dunlap 			 * No IDM rsrcs or something equally Bad.
25248bbca81SDaniel Hoffman 			 * Return non-SUCCESS to IBCM. It'll give
25330e7468fSPeter Dunlap 			 * us a CONN_CLOSED, which we'll handle
25430e7468fSPeter Dunlap 			 * below.
25530e7468fSPeter Dunlap 			 */
25630e7468fSPeter Dunlap 			ISER_LOG(CE_NOTE, "iser_handle_cm_conn_est: "
25730e7468fSPeter Dunlap 			    "idm_svc_conn_create_failed");
25830e7468fSPeter Dunlap 			mutex_exit(&iser_conn->ic_lock);
25930e7468fSPeter Dunlap 			return (IBT_CM_NO_RESOURCE);
26030e7468fSPeter Dunlap 		}
26130e7468fSPeter Dunlap 
26230e7468fSPeter Dunlap 		/* We no longer need the hold on the iSER service handle */
26330e7468fSPeter Dunlap 		iser_tgt_svc_rele(iser_svc);
26430e7468fSPeter Dunlap 
26530e7468fSPeter Dunlap 		/* Hold a reference on the IDM connection handle */
26630e7468fSPeter Dunlap 		idm_conn_hold(ic);
26730e7468fSPeter Dunlap 
26830e7468fSPeter Dunlap 		/* Set the transport ops and conn on the idm_conn handle */
26930e7468fSPeter Dunlap 		ic->ic_transport_ops = &iser_transport_ops;
27030e7468fSPeter Dunlap 		ic->ic_transport_private = (void *)iser_conn;
27130e7468fSPeter Dunlap 		ic->ic_transport_hdrlen = ISER_HEADER_LENGTH;
27230e7468fSPeter Dunlap 		iser_conn->ic_idmc = ic;
27330e7468fSPeter Dunlap 
27430e7468fSPeter Dunlap 		/*
27530e7468fSPeter Dunlap 		 * Set the local and remote addresses in the idm conn handle.
27630e7468fSPeter Dunlap 		 */
27730e7468fSPeter Dunlap 		iser_ib_conv_ibtaddr2sockaddr(&ic->ic_laddr,
27830e7468fSPeter Dunlap 		    &iser_conn->ic_chan->ic_localip, iser_chan->ic_lport);
27930e7468fSPeter Dunlap 		iser_ib_conv_ibtaddr2sockaddr(&ic->ic_raddr,
28030e7468fSPeter Dunlap 		    &iser_conn->ic_chan->ic_remoteip, iser_chan->ic_rport);
28130e7468fSPeter Dunlap 
28230e7468fSPeter Dunlap 		/*
28330e7468fSPeter Dunlap 		 * Kick the state machine.  At CS_S3_XPT_UP the state machine
28430e7468fSPeter Dunlap 		 * will notify the client (target) about the new connection.
28530e7468fSPeter Dunlap 		 */
286*d70bcb72SToomas Soome 		idm_conn_event(ic, CE_CONNECT_ACCEPT, (uintptr_t)NULL);
28730e7468fSPeter Dunlap 		iser_conn->ic_stage = ISER_CONN_STAGE_IC_CONNECTED;
28830e7468fSPeter Dunlap 		mutex_exit(&iser_conn->ic_lock);
28930e7468fSPeter Dunlap 
29030e7468fSPeter Dunlap 		/*
29130e7468fSPeter Dunlap 		 * Post work requests on the receive queue
29230e7468fSPeter Dunlap 		 */
29330e7468fSPeter Dunlap 		iser_ib_post_recv(iser_chan->ic_chanhdl);
29430e7468fSPeter Dunlap 
29530e7468fSPeter Dunlap 	}
29630e7468fSPeter Dunlap 
29730e7468fSPeter Dunlap 	return (IBT_CM_ACCEPT);
29830e7468fSPeter Dunlap }
29930e7468fSPeter Dunlap 
30030e7468fSPeter Dunlap static ibt_cm_status_t
iser_handle_cm_conn_closed(ibt_cm_event_t * evp)30130e7468fSPeter Dunlap iser_handle_cm_conn_closed(ibt_cm_event_t *evp)
30230e7468fSPeter Dunlap {
30330e7468fSPeter Dunlap 
30430e7468fSPeter Dunlap 	iser_chan_t	*chan;
30530e7468fSPeter Dunlap 
30630e7468fSPeter Dunlap 	chan = (iser_chan_t *)ibt_get_chan_private(evp->cm_channel);
30730e7468fSPeter Dunlap 
30830e7468fSPeter Dunlap 	ISER_LOG(CE_NOTE, "iser_handle_cm_conn_closed: chan (0x%p) "
30930e7468fSPeter Dunlap 	    "reason (0x%x)", (void *)chan, evp->cm_event.closed);
31030e7468fSPeter Dunlap 
31130e7468fSPeter Dunlap 	switch (evp->cm_event.closed) {
31230e7468fSPeter Dunlap 	case IBT_CM_CLOSED_DREP_RCVD:	/* we requested a disconnect */
31330e7468fSPeter Dunlap 	case IBT_CM_CLOSED_ALREADY:	/* duplicate close */
31430e7468fSPeter Dunlap 		/* ignore these */
31530e7468fSPeter Dunlap 		return (IBT_CM_ACCEPT);
31630e7468fSPeter Dunlap 
31730e7468fSPeter Dunlap 	case IBT_CM_CLOSED_DREQ_RCVD:	/* request to close the channel */
31830e7468fSPeter Dunlap 	case IBT_CM_CLOSED_REJ_RCVD:	/* reject after conn establishment */
31930e7468fSPeter Dunlap 	case IBT_CM_CLOSED_DREQ_TIMEOUT: /* our close request timed out */
32030e7468fSPeter Dunlap 	case IBT_CM_CLOSED_DUP:		/* duplicate close request */
32130e7468fSPeter Dunlap 	case IBT_CM_CLOSED_ABORT:	/* aborted connection establishment */
32230e7468fSPeter Dunlap 	case IBT_CM_CLOSED_STALE:	/* stale / unref connection */
32330e7468fSPeter Dunlap 		/* handle these depending upon our connection state */
32430e7468fSPeter Dunlap 		mutex_enter(&chan->ic_conn->ic_lock);
32530e7468fSPeter Dunlap 		switch (chan->ic_conn->ic_stage) {
32630e7468fSPeter Dunlap 		case ISER_CONN_STAGE_UNDEFINED:
32730e7468fSPeter Dunlap 		case ISER_CONN_STAGE_CLOSED:
32830e7468fSPeter Dunlap 			/* do nothing, just drop the lock */
32930e7468fSPeter Dunlap 			mutex_exit(&chan->ic_conn->ic_lock);
33030e7468fSPeter Dunlap 			break;
33130e7468fSPeter Dunlap 
33230e7468fSPeter Dunlap 		case ISER_CONN_STAGE_ALLOCATED:
33330e7468fSPeter Dunlap 			/*
33430e7468fSPeter Dunlap 			 * We blew up or were offlined during connection
33530e7468fSPeter Dunlap 			 * establishment. Teardown the iSER conn and chan
33630e7468fSPeter Dunlap 			 * handles.
33730e7468fSPeter Dunlap 			 */
33830e7468fSPeter Dunlap 			mutex_exit(&chan->ic_conn->ic_lock);
33930e7468fSPeter Dunlap 			iser_internal_conn_destroy(chan->ic_conn);
34030e7468fSPeter Dunlap 			break;
34130e7468fSPeter Dunlap 
34230e7468fSPeter Dunlap 		case ISER_CONN_STAGE_IC_DISCONNECTED:
34330e7468fSPeter Dunlap 		case ISER_CONN_STAGE_IC_FREED:
34430e7468fSPeter Dunlap 		case ISER_CONN_STAGE_CLOSING:
34530e7468fSPeter Dunlap 			/* we're down, set CLOSED */
34630e7468fSPeter Dunlap 			chan->ic_conn->ic_stage = ISER_CONN_STAGE_CLOSED;
34730e7468fSPeter Dunlap 			mutex_exit(&chan->ic_conn->ic_lock);
34830e7468fSPeter Dunlap 			break;
34930e7468fSPeter Dunlap 
35030e7468fSPeter Dunlap 		case ISER_CONN_STAGE_IC_CONNECTED:
35130e7468fSPeter Dunlap 		case ISER_CONN_STAGE_HELLO_SENT:
35230e7468fSPeter Dunlap 		case ISER_CONN_STAGE_HELLO_SENT_FAIL:
35330e7468fSPeter Dunlap 		case ISER_CONN_STAGE_HELLO_WAIT:
35430e7468fSPeter Dunlap 		case ISER_CONN_STAGE_HELLO_RCV:
35530e7468fSPeter Dunlap 		case ISER_CONN_STAGE_HELLO_RCV_FAIL:
35630e7468fSPeter Dunlap 		case ISER_CONN_STAGE_HELLOREPLY_SENT:
35730e7468fSPeter Dunlap 		case ISER_CONN_STAGE_HELLOREPLY_SENT_FAIL:
35830e7468fSPeter Dunlap 		case ISER_CONN_STAGE_HELLOREPLY_RCV:
35930e7468fSPeter Dunlap 		case ISER_CONN_STAGE_HELLOREPLY_RCV_FAIL:
36030e7468fSPeter Dunlap 		case ISER_CONN_STAGE_LOGGED_IN:
36130e7468fSPeter Dunlap 			/* for all other stages, fail the transport */
36230e7468fSPeter Dunlap 			idm_conn_event(chan->ic_conn->ic_idmc,
36330e7468fSPeter Dunlap 			    CE_TRANSPORT_FAIL, IDM_STATUS_FAIL);
36430e7468fSPeter Dunlap 			chan->ic_conn->ic_stage = ISER_CONN_STAGE_CLOSING;
36530e7468fSPeter Dunlap 			mutex_exit(&chan->ic_conn->ic_lock);
36630e7468fSPeter Dunlap 			break;
36730e7468fSPeter Dunlap 
36830e7468fSPeter Dunlap 		default:
36930e7468fSPeter Dunlap 			mutex_exit(&chan->ic_conn->ic_lock);
37030e7468fSPeter Dunlap 			ASSERT(0);
37130e7468fSPeter Dunlap 
37230e7468fSPeter Dunlap 		}
37330e7468fSPeter Dunlap 
37430e7468fSPeter Dunlap 		/* accept the event */
37530e7468fSPeter Dunlap 		return (IBT_CM_ACCEPT);
37630e7468fSPeter Dunlap 
37730e7468fSPeter Dunlap 	default:
37830e7468fSPeter Dunlap 		/* unknown event */
37930e7468fSPeter Dunlap 		ISER_LOG(CE_NOTE, "iser_handle_cm_conn_closed: unknown closed "
38030e7468fSPeter Dunlap 		    "event: (0x%x)", evp->cm_event.closed);
38130e7468fSPeter Dunlap 		return (IBT_CM_REJECT);
38230e7468fSPeter Dunlap 	}
38330e7468fSPeter Dunlap }
38430e7468fSPeter Dunlap 
38530e7468fSPeter Dunlap /*
38630e7468fSPeter Dunlap  * Handle EVENT FAILURE
38730e7468fSPeter Dunlap  */
38830e7468fSPeter Dunlap static ibt_cm_status_t
iser_handle_cm_event_failure(ibt_cm_event_t * evp)38930e7468fSPeter Dunlap iser_handle_cm_event_failure(ibt_cm_event_t *evp)
39030e7468fSPeter Dunlap {
39130e7468fSPeter Dunlap 	iser_chan_t	*chan;
39230e7468fSPeter Dunlap 
39330e7468fSPeter Dunlap 	chan = (iser_chan_t *)ibt_get_chan_private(evp->cm_channel);
39430e7468fSPeter Dunlap 
39530e7468fSPeter Dunlap 	ISER_LOG(CE_NOTE, "iser_handle_cm_event_failure: chan (0x%p): "
39630e7468fSPeter Dunlap 	    "code: %d msg: %d reason: %d", (void *)chan,
39730e7468fSPeter Dunlap 	    evp->cm_event.failed.cf_code, evp->cm_event.failed.cf_msg,
39830e7468fSPeter Dunlap 	    evp->cm_event.failed.cf_reason);
39930e7468fSPeter Dunlap 
40030e7468fSPeter Dunlap 	if ((evp->cm_channel == NULL) || (chan == NULL)) {
40130e7468fSPeter Dunlap 		/* channel not established yet */
40230e7468fSPeter Dunlap 		return (IBT_CM_ACCEPT);
40330e7468fSPeter Dunlap 	}
40430e7468fSPeter Dunlap 
40530e7468fSPeter Dunlap 	if ((evp->cm_event.failed.cf_code != IBT_CM_FAILURE_STALE) &&
40630e7468fSPeter Dunlap 	    (evp->cm_event.failed.cf_msg == IBT_CM_FAILURE_REQ)) {
40730e7468fSPeter Dunlap 		/*
40830e7468fSPeter Dunlap 		 * This end is active, just ignore, ibt_open_rc_channel()
40930e7468fSPeter Dunlap 		 * caller will take care of cleanup.
41030e7468fSPeter Dunlap 		 */
41130e7468fSPeter Dunlap 		return (IBT_CM_ACCEPT);
41230e7468fSPeter Dunlap 	}
41330e7468fSPeter Dunlap 
41430e7468fSPeter Dunlap 	/* handle depending upon our connection state */
41530e7468fSPeter Dunlap 	mutex_enter(&chan->ic_conn->ic_lock);
41630e7468fSPeter Dunlap 	switch (chan->ic_conn->ic_stage) {
41730e7468fSPeter Dunlap 	case ISER_CONN_STAGE_UNDEFINED:
41830e7468fSPeter Dunlap 	case ISER_CONN_STAGE_CLOSED:
41930e7468fSPeter Dunlap 		/* do nothing, just drop the lock */
42030e7468fSPeter Dunlap 		mutex_exit(&chan->ic_conn->ic_lock);
42130e7468fSPeter Dunlap 		break;
42230e7468fSPeter Dunlap 
42330e7468fSPeter Dunlap 	case ISER_CONN_STAGE_ALLOCATED:
42430e7468fSPeter Dunlap 		/*
42530e7468fSPeter Dunlap 		 * We blew up or were offlined during connection
42630e7468fSPeter Dunlap 		 * establishment. Teardown the iSER conn and chan
42730e7468fSPeter Dunlap 		 * handles.
42830e7468fSPeter Dunlap 		 */
42930e7468fSPeter Dunlap 		mutex_exit(&chan->ic_conn->ic_lock);
43030e7468fSPeter Dunlap 		iser_internal_conn_destroy(chan->ic_conn);
43130e7468fSPeter Dunlap 		break;
43230e7468fSPeter Dunlap 
43330e7468fSPeter Dunlap 	case ISER_CONN_STAGE_IC_DISCONNECTED:
43430e7468fSPeter Dunlap 	case ISER_CONN_STAGE_IC_FREED:
43530e7468fSPeter Dunlap 	case ISER_CONN_STAGE_CLOSING:
43630e7468fSPeter Dunlap 		/* update to CLOSED, then drop the lock */
43730e7468fSPeter Dunlap 		chan->ic_conn->ic_stage = ISER_CONN_STAGE_CLOSED;
43830e7468fSPeter Dunlap 		mutex_exit(&chan->ic_conn->ic_lock);
43930e7468fSPeter Dunlap 		break;
44030e7468fSPeter Dunlap 
44130e7468fSPeter Dunlap 	case ISER_CONN_STAGE_IC_CONNECTED:
44230e7468fSPeter Dunlap 	case ISER_CONN_STAGE_HELLO_SENT:
44330e7468fSPeter Dunlap 	case ISER_CONN_STAGE_HELLO_SENT_FAIL:
44430e7468fSPeter Dunlap 	case ISER_CONN_STAGE_HELLO_WAIT:
44530e7468fSPeter Dunlap 	case ISER_CONN_STAGE_HELLO_RCV:
44630e7468fSPeter Dunlap 	case ISER_CONN_STAGE_HELLO_RCV_FAIL:
44730e7468fSPeter Dunlap 	case ISER_CONN_STAGE_HELLOREPLY_SENT:
44830e7468fSPeter Dunlap 	case ISER_CONN_STAGE_HELLOREPLY_SENT_FAIL:
44930e7468fSPeter Dunlap 	case ISER_CONN_STAGE_HELLOREPLY_RCV:
45030e7468fSPeter Dunlap 	case ISER_CONN_STAGE_HELLOREPLY_RCV_FAIL:
45130e7468fSPeter Dunlap 	case ISER_CONN_STAGE_LOGGED_IN:
45230e7468fSPeter Dunlap 		/* fail the transport and move the conn to CLOSING */
45330e7468fSPeter Dunlap 		idm_conn_event(chan->ic_conn->ic_idmc, CE_TRANSPORT_FAIL,
45430e7468fSPeter Dunlap 		    IDM_STATUS_FAIL);
45530e7468fSPeter Dunlap 		chan->ic_conn->ic_stage = ISER_CONN_STAGE_CLOSING;
45630e7468fSPeter Dunlap 		mutex_exit(&chan->ic_conn->ic_lock);
45730e7468fSPeter Dunlap 		break;
45830e7468fSPeter Dunlap 
45930e7468fSPeter Dunlap 	default:
46030e7468fSPeter Dunlap 		mutex_exit(&chan->ic_conn->ic_lock);
46130e7468fSPeter Dunlap 		ASSERT(0);
46230e7468fSPeter Dunlap 	}
46330e7468fSPeter Dunlap 
46430e7468fSPeter Dunlap 	/* accept the event */
46530e7468fSPeter Dunlap 	return (IBT_CM_ACCEPT);
46630e7468fSPeter Dunlap }
467