/*
 * iser_ib_cm_handler()
 */
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)
{
	ibt_cm_status_t	ret = IBT_CM_REJECT;

	switch (eventp->cm_type) {

	case IBT_CM_EVENT_REQ_RCV:
		ISER_LOG(CE_NOTE, "iser_ib_cm_handler: IBT_CM_EVENT_REQ_RCV");
		ret = iser_ib_handle_cm_req((idm_svc_t *)cm_private, eventp,
		    ret_args, ret_priv_data, ret_len_max);
		break;

	case IBT_CM_EVENT_REP_RCV:
		ISER_LOG(CE_NOTE, "iser_ib_cm_handler: IBT_CM_EVENT_REP_RCV");
		ret = iser_ib_handle_cm_rep((iser_state_t *)cm_private,
		    eventp, ret_args, ret_priv_data, ret_len_max);
		break;

	case IBT_CM_EVENT_CONN_EST:
		ISER_LOG(CE_NOTE, "iser_ib_cm_handler: IBT_CM_EVENT_CONN_EST");
		ret = iser_handle_cm_conn_est(eventp);
		break;

	case IBT_CM_EVENT_CONN_CLOSED:
		ISER_LOG(CE_NOTE, "iser_ib_cm_handler: "
		    "IBT_CM_EVENT_CONN_CLOSED");
		ret = iser_handle_cm_conn_closed(eventp);
		break;

	case IBT_CM_EVENT_FAILURE:
		ISER_LOG(CE_NOTE, "iser_ib_cm_handler:  Event failure");
		ret = iser_handle_cm_event_failure(eventp);
		break;

	case IBT_CM_EVENT_MRA_RCV:
		/* Not supported */
		ISER_LOG(CE_NOTE, "iser_ib_cm_handler:  MRA message received");
		break;

	case IBT_CM_EVENT_LAP_RCV:
		/* Not supported */
		ISER_LOG(CE_NOTE, "iser_ib_cm_handler: LAP message received");
		break;

	case IBT_CM_EVENT_APR_RCV:
		/* Not supported */
		ISER_LOG(CE_NOTE, "iser_ib_cm_handler: APR message received");
		break;

	default:
		ISER_LOG(CE_NOTE, "iser_ib_cm_handler: unknown event (0x%x)",
		    eventp->cm_type);
		break;
	}

	return (ret);
}
Beispiel #2
0
/*
 * iser_tgt_svc_create()
 * Establish the CM service for inbound iSER service requests on the port
 * indicated by sr->sr_port.
 * idm_svc_req_t contains the service parameters.
 */
idm_status_t
iser_tgt_svc_create(idm_svc_req_t *sr, idm_svc_t *is)
{
    iser_svc_t		*iser_svc;

    int			rc;

    iser_svc = kmem_zalloc(sizeof (iser_svc_t), KM_SLEEP);
    is->is_iser_svc = (void *)iser_svc;

    idm_refcnt_init(&iser_svc->is_refcnt, iser_svc);

    list_create(&iser_svc->is_sbindlist, sizeof (iser_sbind_t),
                offsetof(iser_sbind_t, is_list_node));
    iser_svc->is_svcid = ibt_get_ip_sid(IPPROTO_TCP, sr->sr_port);

    /*
     * Register an iSER target service for the requested port
     * and set the iser_svc structure in the idm_svc handle.
     */
    rc = iser_register_service(is);
    if (rc != DDI_SUCCESS) {
        ISER_LOG(CE_NOTE, "iser_tgt_svc_create: iser_register_service "
                 "failed on port (%d): rc (0x%x)", sr->sr_port, rc);
        (void) ibt_release_ip_sid(iser_svc->is_svcid);
        list_destroy(&iser_svc->is_sbindlist);
        idm_refcnt_destroy(&iser_svc->is_refcnt);
        kmem_free(iser_svc, sizeof (iser_svc_t));
        return (IDM_STATUS_FAIL);
    }

    return (IDM_STATUS_SUCCESS);
}
Beispiel #3
0
/*
 * iser_ini_conn_connect()
 * Establish the connection referred to by the handle previously allocated via
 * iser_ini_conn_create().
 */
static idm_status_t
iser_ini_conn_connect(idm_conn_t *ic)
{
    iser_conn_t		*iser_conn;
    iser_status_t		status;

    iser_conn = (iser_conn_t *)ic->ic_transport_private;

    status = iser_channel_open(iser_conn->ic_chan);
    if (status != ISER_STATUS_SUCCESS) {
        ISER_LOG(CE_WARN, "iser: failed to open channel");
        return (IDM_STATUS_FAIL);
    }

    /*
     * Set the local and remote addresses in the idm conn handle.
     */
    iser_ib_conv_ibtaddr2sockaddr(&ic->ic_laddr,
                                  &iser_conn->ic_chan->ic_localip, iser_conn->ic_chan->ic_lport);
    iser_ib_conv_ibtaddr2sockaddr(&ic->ic_raddr,
                                  &iser_conn->ic_chan->ic_remoteip, iser_conn->ic_chan->ic_rport);

    mutex_enter(&iser_conn->ic_lock);
    /* Hold a reference on the IDM connection handle */
    idm_conn_hold(ic);
    iser_conn->ic_stage = ISER_CONN_STAGE_IC_CONNECTED;
    mutex_exit(&iser_conn->ic_lock);

    return (IDM_STATUS_SUCCESS);
}
Beispiel #4
0
/* ARGSUSED */
static idm_status_t
iser_buf_alloc(idm_buf_t *idb, uint64_t buflen)
{
    iser_conn_t	*iser_conn;
    iser_hca_t	*iser_hca;
    iser_buf_t	*iser_buf;

    if (buflen > ISER_DEFAULT_BUFLEN) {
        return (IDM_STATUS_FAIL);
    }

    iser_conn = (iser_conn_t *)idb->idb_ic->ic_transport_private;
    iser_hca = iser_conn->ic_chan->ic_hca;

    /*
     * Allocate a buffer from this HCA's cache. Once initialized, these
     * will remain allocated and registered (see above).
     */
    iser_buf = kmem_cache_alloc(iser_hca->iser_buf_cache, KM_NOSLEEP);
    if (iser_buf == NULL) {
        ISER_LOG(CE_NOTE, "iser_buf_alloc: alloc failed");
        return (IDM_STATUS_FAIL);
    }

    /* Set the allocated data buffer pointer in the IDM buf handle */
    idb->idb_buf = iser_buf->buf;

    /* Set the private buf and reg handles in the IDM buf handle */
    idb->idb_buf_private = (void *)iser_buf;
    idb->idb_reg_private = (void *)iser_buf->iser_mr;

    return (IDM_STATUS_SUCCESS);
}
Beispiel #5
0
/*
 * iser_buf_tx_from_ini() transmits data from the initiator into the buffer
 * in idb to fulfill SCSI Write commands. An iser_xfer routine is invoked
 * to implement the RDMA operations.
 *
 * Caller holds idt->idt_mutex.
 */
static idm_status_t
iser_buf_rx_from_ini(idm_task_t *idt, idm_buf_t *idb)
{
    iser_status_t	iser_status;
    idm_status_t	idm_status = IDM_STATUS_SUCCESS;

    ASSERT(mutex_owned(&idt->idt_mutex));

    iser_status = iser_xfer_buf_from_ini(idt, idb);

    if (iser_status != ISER_STATUS_SUCCESS) {
        ISER_LOG(CE_WARN, "iser_buf_rx_from_ini: failed "
                 "iser_xfer_buf_from_ini: idt (0x%p) idb (0x%p)",
                 (void *) idt, (void *) idb);
        idm_buf_rx_from_ini_done(idt, idb, IDM_STATUS_ABORTED);
        return (IDM_STATUS_FAIL);
    }

    /*
     * iSCSIt's Data Completion Notify callback is invoked from
     * the Work Request Send completion Handler
     */

    mutex_exit(&idt->idt_mutex);
    return (idm_status);
}
Beispiel #6
0
/*
 * iser_ini_conn_create()
 * Allocate an iSER initiator connection context
 */
static idm_status_t
iser_ini_conn_create(idm_conn_req_t *cr, idm_conn_t *ic)
{
    iser_chan_t	*iser_chan = NULL;
    iser_conn_t	*iser_conn;

    /* Allocate and set up a connection handle */
    iser_conn = kmem_zalloc(sizeof (iser_conn_t), KM_SLEEP);
    mutex_init(&iser_conn->ic_lock, NULL, MUTEX_DRIVER, NULL);

    /* Allocate and open a channel to the target node */
    iser_chan = iser_channel_alloc(NULL, &cr->cr_ini_dst_addr);
    if (iser_chan == NULL) {
        ISER_LOG(CE_WARN, "iser: failed to allocate channel");
        mutex_destroy(&iser_conn->ic_lock);
        kmem_free(iser_conn, sizeof (iser_conn_t));
        return (IDM_STATUS_FAIL);
    }

    /*
     * The local IP and remote IP are filled in iser_channel_alloc. The
     * remote port needs to be filled in from idm_conn_req_t. The local
     * port is irrelevant. Internal representation of the port in the
     * IDM sockaddr structure is in network byte order. IBT expects the
     * port in host byte order.
     */
    switch (cr->cr_ini_dst_addr.sin.sa_family) {
    case AF_INET:
        iser_chan->ic_rport = ntohs(cr->cr_ini_dst_addr.sin4.sin_port);
        break;
    case AF_INET6:
        iser_chan->ic_rport = ntohs(cr->cr_ini_dst_addr.sin6.sin6_port);
        break;
    default:
        iser_chan->ic_rport = ISCSI_LISTEN_PORT;
    }
    iser_chan->ic_lport = 0;

    cv_init(&iser_conn->ic_stage_cv, NULL, CV_DEFAULT, NULL);
    iser_conn->ic_type = ISER_CONN_TYPE_INI;
    iser_conn->ic_stage = ISER_CONN_STAGE_ALLOCATED;
    iser_conn->ic_chan = iser_chan;
    iser_conn->ic_idmc = ic;

    /*
     * Set a pointer to the iser_conn in the iser_chan for easy
     * access during CM event handling
     */
    iser_chan->ic_conn = iser_conn;

    /* Set the iSER conn handle in the IDM conn private handle */
    ic->ic_transport_private = (void *)iser_conn;

    /* Set the transport header length */
    ic->ic_transport_hdrlen = ISER_HEADER_LENGTH;

    return (IDM_STATUS_SUCCESS);
}
Beispiel #7
0
int
iser_idm_register()
{
    idm_transport_attr_t	attr;
    idm_status_t		status;

    attr.type	= IDM_TRANSPORT_TYPE_ISER;
    attr.it_ops	= &iser_transport_ops;
    attr.it_caps	= &iser_transport_caps;

    status = idm_transport_register(&attr);
    if (status != IDM_STATUS_SUCCESS) {
        ISER_LOG(CE_WARN, "Failed to register iSER transport with IDM");
        return (DDI_FAILURE);
    }

    ISER_LOG(CE_NOTE, "Registered iSER transport with IDM");

    return (DDI_SUCCESS);
}
Beispiel #8
0
/*
 * iser_tgt_svc_online()
 * Bind the CM service allocated via iser_tgt_svc_create().
 */
static idm_status_t
iser_tgt_svc_online(idm_svc_t *is)
{
    iser_status_t	status;

    mutex_enter(&is->is_mutex);

    /*
     * Pass the IDM service handle as the client private data for
     * later use.
     */
    status = iser_bind_service(is);
    if (status != ISER_STATUS_SUCCESS) {
        ISER_LOG(CE_NOTE, "iser_tgt_svc_online: failed bind service");
        mutex_exit(&is->is_mutex);
        return (IDM_STATUS_FAIL);
    }

    mutex_exit(&is->is_mutex);
    return (IDM_STATUS_SUCCESS);
}
Beispiel #9
0
/*
 * iser_pdu_tx() transmits a Control PDU via the iSER channel. We pull the
 * channel out of the idm_conn_t passed in, and pass it and the pdu to the
 * iser_xfer routine.
 */
static void
iser_pdu_tx(idm_conn_t *ic, idm_pdu_t *pdu)
{
    iser_conn_t	*iser_conn;
    iser_status_t	iser_status;

    iser_conn = (iser_conn_t *)ic->ic_transport_private;

    iser_status = iser_xfer_ctrlpdu(iser_conn->ic_chan, pdu);
    if (iser_status != ISER_STATUS_SUCCESS) {
        ISER_LOG(CE_WARN, "iser_pdu_tx: failed iser_xfer_ctrlpdu: "
                 "ic (0x%p) pdu (0x%p)", (void *) ic, (void *) pdu);
        /* Fail this PDU transmission */
        idm_pdu_complete(pdu, IDM_STATUS_FAIL);
    }

    /*
     * We successfully posted this PDU for transmission.
     * The completion handler will invoke idm_pdu_complete()
     * with the completion status. See iser_cq.c for more
     * information.
     */
}
/*
 * Handle EVENT FAILURE
 */
static ibt_cm_status_t
iser_handle_cm_event_failure(ibt_cm_event_t *evp)
{
	iser_chan_t	*chan;

	chan = (iser_chan_t *)ibt_get_chan_private(evp->cm_channel);

	ISER_LOG(CE_NOTE, "iser_handle_cm_event_failure: chan (0x%p): "
	    "code: %d msg: %d reason: %d", (void *)chan,
	    evp->cm_event.failed.cf_code, evp->cm_event.failed.cf_msg,
	    evp->cm_event.failed.cf_reason);

	if ((evp->cm_channel == NULL) || (chan == NULL)) {
		/* channel not established yet */
		return (IBT_CM_ACCEPT);
	}

	if ((evp->cm_event.failed.cf_code != IBT_CM_FAILURE_STALE) &&
	    (evp->cm_event.failed.cf_msg == IBT_CM_FAILURE_REQ)) {
		/*
		 * This end is active, just ignore, ibt_open_rc_channel()
		 * caller will take care of cleanup.
		 */
		return (IBT_CM_ACCEPT);
	}

	/* handle depending upon our connection state */
	mutex_enter(&chan->ic_conn->ic_lock);
	switch (chan->ic_conn->ic_stage) {
	case ISER_CONN_STAGE_UNDEFINED:
	case ISER_CONN_STAGE_CLOSED:
		/* do nothing, just drop the lock */
		mutex_exit(&chan->ic_conn->ic_lock);
		break;

	case ISER_CONN_STAGE_ALLOCATED:
		/*
		 * We blew up or were offlined during connection
		 * establishment. Teardown the iSER conn and chan
		 * handles.
		 */
		mutex_exit(&chan->ic_conn->ic_lock);
		iser_internal_conn_destroy(chan->ic_conn);
		break;

	case ISER_CONN_STAGE_IC_DISCONNECTED:
	case ISER_CONN_STAGE_IC_FREED:
	case ISER_CONN_STAGE_CLOSING:
		/* update to CLOSED, then drop the lock */
		chan->ic_conn->ic_stage = ISER_CONN_STAGE_CLOSED;
		mutex_exit(&chan->ic_conn->ic_lock);
		break;

	case ISER_CONN_STAGE_IC_CONNECTED:
	case ISER_CONN_STAGE_HELLO_SENT:
	case ISER_CONN_STAGE_HELLO_SENT_FAIL:
	case ISER_CONN_STAGE_HELLO_WAIT:
	case ISER_CONN_STAGE_HELLO_RCV:
	case ISER_CONN_STAGE_HELLO_RCV_FAIL:
	case ISER_CONN_STAGE_HELLOREPLY_SENT:
	case ISER_CONN_STAGE_HELLOREPLY_SENT_FAIL:
	case ISER_CONN_STAGE_HELLOREPLY_RCV:
	case ISER_CONN_STAGE_HELLOREPLY_RCV_FAIL:
	case ISER_CONN_STAGE_LOGGED_IN:
		/* fail the transport and move the conn to CLOSING */
		idm_conn_event(chan->ic_conn->ic_idmc, CE_TRANSPORT_FAIL,
		    IDM_STATUS_FAIL);
		chan->ic_conn->ic_stage = ISER_CONN_STAGE_CLOSING;
		mutex_exit(&chan->ic_conn->ic_lock);
		break;

	default:
		mutex_exit(&chan->ic_conn->ic_lock);
		ASSERT(0);
	}

	/* accept the event */
	return (IBT_CM_ACCEPT);
}
static ibt_cm_status_t
iser_handle_cm_conn_closed(ibt_cm_event_t *evp)
{

	iser_chan_t	*chan;

	chan = (iser_chan_t *)ibt_get_chan_private(evp->cm_channel);

	ISER_LOG(CE_NOTE, "iser_handle_cm_conn_closed: chan (0x%p) "
	    "reason (0x%x)", (void *)chan, evp->cm_event.closed);

	switch (evp->cm_event.closed) {
	case IBT_CM_CLOSED_DREP_RCVD:	/* we requested a disconnect */
	case IBT_CM_CLOSED_ALREADY:	/* duplicate close */
		/* ignore these */
		return (IBT_CM_ACCEPT);

	case IBT_CM_CLOSED_DREQ_RCVD:	/* request to close the channel */
	case IBT_CM_CLOSED_REJ_RCVD:	/* reject after conn establishment */
	case IBT_CM_CLOSED_DREQ_TIMEOUT: /* our close request timed out */
	case IBT_CM_CLOSED_DUP:		/* duplicate close request */
	case IBT_CM_CLOSED_ABORT:	/* aborted connection establishment */
	case IBT_CM_CLOSED_STALE:	/* stale / unref connection */
		/* handle these depending upon our connection state */
		mutex_enter(&chan->ic_conn->ic_lock);
		switch (chan->ic_conn->ic_stage) {
		case ISER_CONN_STAGE_UNDEFINED:
		case ISER_CONN_STAGE_CLOSED:
			/* do nothing, just drop the lock */
			mutex_exit(&chan->ic_conn->ic_lock);
			break;

		case ISER_CONN_STAGE_ALLOCATED:
			/*
			 * We blew up or were offlined during connection
			 * establishment. Teardown the iSER conn and chan
			 * handles.
			 */
			mutex_exit(&chan->ic_conn->ic_lock);
			iser_internal_conn_destroy(chan->ic_conn);
			break;

		case ISER_CONN_STAGE_IC_DISCONNECTED:
		case ISER_CONN_STAGE_IC_FREED:
		case ISER_CONN_STAGE_CLOSING:
			/* we're down, set CLOSED */
			chan->ic_conn->ic_stage = ISER_CONN_STAGE_CLOSED;
			mutex_exit(&chan->ic_conn->ic_lock);
			break;

		case ISER_CONN_STAGE_IC_CONNECTED:
		case ISER_CONN_STAGE_HELLO_SENT:
		case ISER_CONN_STAGE_HELLO_SENT_FAIL:
		case ISER_CONN_STAGE_HELLO_WAIT:
		case ISER_CONN_STAGE_HELLO_RCV:
		case ISER_CONN_STAGE_HELLO_RCV_FAIL:
		case ISER_CONN_STAGE_HELLOREPLY_SENT:
		case ISER_CONN_STAGE_HELLOREPLY_SENT_FAIL:
		case ISER_CONN_STAGE_HELLOREPLY_RCV:
		case ISER_CONN_STAGE_HELLOREPLY_RCV_FAIL:
		case ISER_CONN_STAGE_LOGGED_IN:
			/* for all other stages, fail the transport */
			idm_conn_event(chan->ic_conn->ic_idmc,
			    CE_TRANSPORT_FAIL, IDM_STATUS_FAIL);
			chan->ic_conn->ic_stage = ISER_CONN_STAGE_CLOSING;
			mutex_exit(&chan->ic_conn->ic_lock);
			break;

		default:
			mutex_exit(&chan->ic_conn->ic_lock);
			ASSERT(0);

		}

		/* accept the event */
		return (IBT_CM_ACCEPT);

	default:
		/* unknown event */
		ISER_LOG(CE_NOTE, "iser_handle_cm_conn_closed: unknown closed "
		    "event: (0x%x)", evp->cm_event.closed);
		return (IBT_CM_REJECT);
	}
}
static ibt_cm_status_t
iser_handle_cm_conn_est(ibt_cm_event_t *evp)
{
	iser_chan_t	*iser_chan;
	iser_conn_t	*iser_conn;
	iser_svc_t	*iser_svc;
	idm_status_t	status;
	idm_conn_t	*ic;

	iser_chan = (iser_chan_t *)ibt_get_chan_private(evp->cm_channel);

	/*
	 * An ibt_open_rc_channel() comes in as a IBT_CM_EVENT_REQ_RCV on the
	 * iSER-IB target, upon which the target sends a Response, accepting
	 * the request. This comes in as a IBT_CM_EVENT_REP_RCV on the iSER-IB
	 * initiator, which then sends an RTU. Upon getting this RTU from the
	 * iSER-IB initiator, the IBT_CM_EVENT_CONN_EST event is generated on
	 * the target. Then subsequently an IBT_CM_EVENT_CONN_EST event is
	 * generated on the initiator.
	 *
	 * Our new connection has been established on the target. If we are
	 * receiving this event on the target side, the iser_channel can be
	 * used as it is already populated. On the target side, an IDM
	 * connection is then allocated and the IDM layer is notified.
	 * If we are on the initiator we needn't do anything, since we
	 * already have the IDM linkage in place for this connection.
	 */
	if (iser_chan->ic_conn->ic_type == ISER_CONN_TYPE_TGT) {

		iser_conn = iser_chan->ic_conn;
		iser_svc  = (iser_svc_t *)iser_conn->ic_idms->is_iser_svc;

		mutex_enter(&iser_conn->ic_lock);

		status = idm_svc_conn_create(iser_conn->ic_idms,
		    IDM_TRANSPORT_TYPE_ISER, &ic);
		if (status != IDM_STATUS_SUCCESS) {
			/*
			 * No IDM rsrcs or something equally Bad.
			 * Return non-SUCCESS to IBCM. He'll give
			 * us a CONN_CLOSED, which we'll handle
			 * below.
			 */
			ISER_LOG(CE_NOTE, "iser_handle_cm_conn_est: "
			    "idm_svc_conn_create_failed");
			mutex_exit(&iser_conn->ic_lock);
			return (IBT_CM_NO_RESOURCE);
		}

		/* We no longer need the hold on the iSER service handle */
		iser_tgt_svc_rele(iser_svc);

		/* Hold a reference on the IDM connection handle */
		idm_conn_hold(ic);

		/* Set the transport ops and conn on the idm_conn handle */
		ic->ic_transport_ops = &iser_transport_ops;
		ic->ic_transport_private = (void *)iser_conn;
		ic->ic_transport_hdrlen = ISER_HEADER_LENGTH;
		iser_conn->ic_idmc = ic;

		/*
		 * Set the local and remote addresses in the idm conn handle.
		 */
		iser_ib_conv_ibtaddr2sockaddr(&ic->ic_laddr,
		    &iser_conn->ic_chan->ic_localip, iser_chan->ic_lport);
		iser_ib_conv_ibtaddr2sockaddr(&ic->ic_raddr,
		    &iser_conn->ic_chan->ic_remoteip, iser_chan->ic_rport);

		/*
		 * Kick the state machine.  At CS_S3_XPT_UP the state machine
		 * will notify the client (target) about the new connection.
		 */
		idm_conn_event(ic, CE_CONNECT_ACCEPT, NULL);
		iser_conn->ic_stage = ISER_CONN_STAGE_IC_CONNECTED;
		mutex_exit(&iser_conn->ic_lock);

		/*
		 * Post work requests on the receive queue
		 */
		iser_ib_post_recv(iser_chan->ic_chanhdl);

	}

	return (IBT_CM_ACCEPT);
}
/* ARGSUSED */
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)
{

	iser_private_data_t	iser_priv_data;
	ibt_ip_cm_info_t	ipcm_info;
	iser_chan_t		*chan;
	iser_conn_t		*iser_conn;
	int			status;

	/*
	 * CM private data brings IP information
	 * Private data received is a stream of bytes and may not be properly
	 * aligned. So, bcopy the data onto the stack before accessing it.
	 */
	bcopy((uint8_t *)evp->cm_priv_data, &iser_priv_data,
	    sizeof (iser_private_data_t));

	/* extract the CM IP info */
	status = ibt_get_ip_data(evp->cm_priv_data_len, evp->cm_priv_data,
	    &ipcm_info);
	if (status != IBT_SUCCESS) {
		return (IBT_CM_REJECT);
	}

	ISER_LOG(CE_NOTE, "iser_ib_handle_cm_req: ipcm_info (0x%p): src IP "
	    "(0x%08x) src port (0x%04x) dst IP: (0x%08x)", (void *)&ipcm_info,
	    ipcm_info.src_addr.un.ip4addr, ipcm_info.src_port,
	    ipcm_info.dst_addr.un.ip4addr);

	/* Allocate a channel to establish the new connection */
	chan = iser_ib_alloc_channel_nopathlookup(
	    evp->cm_event.req.req_hca_guid,
	    evp->cm_event.req.req_prim_hca_port);
	if (chan == NULL) {
		ISER_LOG(CE_NOTE, "iser_ib_handle_cm_req: failed to allocate "
		    "a channel from src IP (0x%08x) src port (0x%04x) "
		    "to dst IP: (0x%08x) on hca(%llx %d)",
		    ipcm_info.src_addr.un.ip4addr, ipcm_info.src_port,
		    ipcm_info.dst_addr.un.ip4addr,
		    (longlong_t)evp->cm_event.req.req_hca_guid,
		    evp->cm_event.req.req_prim_hca_port);
		return (IBT_CM_REJECT);
	}

	/* Set the local and remote ip */
	chan->ic_localip = ipcm_info.dst_addr;
	chan->ic_remoteip = ipcm_info.src_addr;

	/* Set the local and remote port numbers on the channel handle */
	chan->ic_lport = svc_hdl->is_svc_req.sr_port;
	chan->ic_rport = ipcm_info.src_port;

	/* Allocate the iser_conn_t for the IDM svc binding */
	iser_conn = kmem_zalloc(sizeof (iser_conn_t), KM_SLEEP);

	/* Set up the iser_conn attributes */
	mutex_init(&iser_conn->ic_lock, NULL, MUTEX_DRIVER, NULL);
	cv_init(&iser_conn->ic_stage_cv, NULL, CV_DEFAULT, NULL);
	iser_conn->ic_type = ISER_CONN_TYPE_TGT;
	iser_conn->ic_chan = chan;
	iser_conn->ic_stage = ISER_CONN_STAGE_ALLOCATED;

	/* Hold a reference to the iSER service handle */
	iser_tgt_svc_hold((iser_svc_t *)svc_hdl->is_iser_svc);

	iser_conn->ic_idms = svc_hdl;

	/*
	 * Now set a pointer to the iser_conn in the iser_chan for
	 * access during CM event handling
	 */
	chan->ic_conn = iser_conn;

	rargsp->cm_ret.rep.cm_channel = chan->ic_chanhdl;

	return (IBT_CM_ACCEPT);
}