xref: /onnv-gate/usr/src/uts/common/io/ib/clients/iser/iser_ib.c (revision 12485:c8d0d0397145)
19162SPeter.Dunlap@Sun.COM /*
29162SPeter.Dunlap@Sun.COM  * CDDL HEADER START
39162SPeter.Dunlap@Sun.COM  *
49162SPeter.Dunlap@Sun.COM  * The contents of this file are subject to the terms of the
59162SPeter.Dunlap@Sun.COM  * Common Development and Distribution License (the "License").
69162SPeter.Dunlap@Sun.COM  * You may not use this file except in compliance with the License.
79162SPeter.Dunlap@Sun.COM  *
89162SPeter.Dunlap@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99162SPeter.Dunlap@Sun.COM  * or http://www.opensolaris.org/os/licensing.
109162SPeter.Dunlap@Sun.COM  * See the License for the specific language governing permissions
119162SPeter.Dunlap@Sun.COM  * and limitations under the License.
129162SPeter.Dunlap@Sun.COM  *
139162SPeter.Dunlap@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
149162SPeter.Dunlap@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159162SPeter.Dunlap@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
169162SPeter.Dunlap@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
179162SPeter.Dunlap@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
189162SPeter.Dunlap@Sun.COM  *
199162SPeter.Dunlap@Sun.COM  * CDDL HEADER END
209162SPeter.Dunlap@Sun.COM  */
219162SPeter.Dunlap@Sun.COM /*
22*12485SPeter.Gill@Sun.COM  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
239162SPeter.Dunlap@Sun.COM  */
249162SPeter.Dunlap@Sun.COM 
259162SPeter.Dunlap@Sun.COM #include <sys/types.h>
269162SPeter.Dunlap@Sun.COM #include <sys/ddi.h>
279162SPeter.Dunlap@Sun.COM #include <sys/types.h>
289162SPeter.Dunlap@Sun.COM #include <sys/socket.h>
299162SPeter.Dunlap@Sun.COM #include <netinet/in.h>
309162SPeter.Dunlap@Sun.COM #include <sys/sunddi.h>
319162SPeter.Dunlap@Sun.COM #include <sys/sysmacros.h>
329162SPeter.Dunlap@Sun.COM #include <sys/iscsi_protocol.h>
339162SPeter.Dunlap@Sun.COM 
349162SPeter.Dunlap@Sun.COM #include <sys/ib/clients/iser/iser.h>
359162SPeter.Dunlap@Sun.COM #include <sys/ib/clients/iser/iser_idm.h>
369162SPeter.Dunlap@Sun.COM 
379162SPeter.Dunlap@Sun.COM /*
389162SPeter.Dunlap@Sun.COM  * iser_ib.c
399162SPeter.Dunlap@Sun.COM  * Routines for InfiniBand transport for iSER
409162SPeter.Dunlap@Sun.COM  *
419162SPeter.Dunlap@Sun.COM  * This file contains the routines to interface with the IBT API to attach and
429162SPeter.Dunlap@Sun.COM  * allocate IB resources, handle async events, and post recv work requests.
439162SPeter.Dunlap@Sun.COM  *
449162SPeter.Dunlap@Sun.COM  */
459162SPeter.Dunlap@Sun.COM 
469162SPeter.Dunlap@Sun.COM static iser_hca_t *iser_ib_gid2hca(ib_gid_t gid);
479162SPeter.Dunlap@Sun.COM static iser_hca_t *iser_ib_guid2hca(ib_guid_t guid);
489162SPeter.Dunlap@Sun.COM 
499162SPeter.Dunlap@Sun.COM static iser_hca_t *iser_ib_alloc_hca(ib_guid_t guid);
509162SPeter.Dunlap@Sun.COM static int iser_ib_free_hca(iser_hca_t *hca);
519162SPeter.Dunlap@Sun.COM static int iser_ib_update_hcaports(iser_hca_t *hca);
529162SPeter.Dunlap@Sun.COM static int iser_ib_init_hcas(void);
539162SPeter.Dunlap@Sun.COM static int iser_ib_fini_hcas(void);
549162SPeter.Dunlap@Sun.COM 
559162SPeter.Dunlap@Sun.COM static iser_sbind_t *iser_ib_get_bind(
569162SPeter.Dunlap@Sun.COM     iser_svc_t *iser_svc, ib_guid_t hca_guid, ib_gid_t gid);
579162SPeter.Dunlap@Sun.COM static int iser_ib_activate_port(
589162SPeter.Dunlap@Sun.COM     idm_svc_t *idm_svc, ib_guid_t guid, ib_gid_t gid);
599162SPeter.Dunlap@Sun.COM static void iser_ib_deactivate_port(ib_guid_t hca_guid, ib_gid_t gid);
609162SPeter.Dunlap@Sun.COM 
619162SPeter.Dunlap@Sun.COM static void iser_ib_init_qp(iser_chan_t *chan, uint_t sq_size, uint_t rq_size);
629162SPeter.Dunlap@Sun.COM static void iser_ib_fini_qp(iser_qp_t *qp);
639162SPeter.Dunlap@Sun.COM 
649162SPeter.Dunlap@Sun.COM static int iser_ib_setup_cq(ibt_hca_hdl_t hca_hdl, uint_t cq_size,
659162SPeter.Dunlap@Sun.COM     ibt_cq_hdl_t *cq_hdl);
669162SPeter.Dunlap@Sun.COM 
679162SPeter.Dunlap@Sun.COM static void iser_ib_setup_chanargs(uint8_t hca_port, ibt_cq_hdl_t scq_hdl,
689162SPeter.Dunlap@Sun.COM     ibt_cq_hdl_t rcq_hdl, uint_t sq_size, uint_t rq_size,
699162SPeter.Dunlap@Sun.COM     ibt_pd_hdl_t hca_pdhdl, ibt_rc_chan_alloc_args_t *cargs);
709162SPeter.Dunlap@Sun.COM 
719162SPeter.Dunlap@Sun.COM static void iser_ib_handle_portup_event(ibt_hca_hdl_t hdl,
729162SPeter.Dunlap@Sun.COM     ibt_async_event_t *event);
739162SPeter.Dunlap@Sun.COM static void iser_ib_handle_portdown_event(ibt_hca_hdl_t hdl,
749162SPeter.Dunlap@Sun.COM     ibt_async_event_t *event);
759162SPeter.Dunlap@Sun.COM static void iser_ib_handle_hca_detach_event(ibt_hca_hdl_t hdl,
769162SPeter.Dunlap@Sun.COM     ibt_async_event_t *event);
779162SPeter.Dunlap@Sun.COM 
789247SPeter.Dunlap@Sun.COM static void iser_ib_post_recv_task(void *arg);
799247SPeter.Dunlap@Sun.COM 
809162SPeter.Dunlap@Sun.COM static struct ibt_clnt_modinfo_s iser_ib_modinfo = {
819162SPeter.Dunlap@Sun.COM 	IBTI_V_CURR,
829162SPeter.Dunlap@Sun.COM 	IBT_STORAGE_DEV,
839162SPeter.Dunlap@Sun.COM 	iser_ib_async_handler,
849162SPeter.Dunlap@Sun.COM 	NULL,
859162SPeter.Dunlap@Sun.COM 	"iSER"
869162SPeter.Dunlap@Sun.COM };
879162SPeter.Dunlap@Sun.COM 
889162SPeter.Dunlap@Sun.COM /*
899162SPeter.Dunlap@Sun.COM  * iser_ib_init
909162SPeter.Dunlap@Sun.COM  *
919162SPeter.Dunlap@Sun.COM  * This function registers the HCA drivers with IBTF and registers and binds
929162SPeter.Dunlap@Sun.COM  * iSER as a service with IBTF.
939162SPeter.Dunlap@Sun.COM  */
949162SPeter.Dunlap@Sun.COM int
iser_ib_init(void)959162SPeter.Dunlap@Sun.COM iser_ib_init(void)
969162SPeter.Dunlap@Sun.COM {
979162SPeter.Dunlap@Sun.COM 	int		status;
989162SPeter.Dunlap@Sun.COM 
999162SPeter.Dunlap@Sun.COM 	/* Register with IBTF */
1009162SPeter.Dunlap@Sun.COM 	status = ibt_attach(&iser_ib_modinfo, iser_state->is_dip, iser_state,
1019162SPeter.Dunlap@Sun.COM 	    &iser_state->is_ibhdl);
1029162SPeter.Dunlap@Sun.COM 	if (status != DDI_SUCCESS) {
1039162SPeter.Dunlap@Sun.COM 		ISER_LOG(CE_NOTE, "iser_ib_init: ibt_attach failed (0x%x)",
1049162SPeter.Dunlap@Sun.COM 		    status);
1059162SPeter.Dunlap@Sun.COM 		return (DDI_FAILURE);
1069162SPeter.Dunlap@Sun.COM 	}
1079162SPeter.Dunlap@Sun.COM 
1089162SPeter.Dunlap@Sun.COM 	/* Create the global work request kmem_cache */
1099162SPeter.Dunlap@Sun.COM 	iser_state->iser_wr_cache = kmem_cache_create("iser_wr_cache",
1109162SPeter.Dunlap@Sun.COM 	    sizeof (iser_wr_t), 0, NULL, NULL, NULL,
1119162SPeter.Dunlap@Sun.COM 	    iser_state, NULL, KM_SLEEP);
1129162SPeter.Dunlap@Sun.COM 
1139162SPeter.Dunlap@Sun.COM 	/* Populate our list of HCAs */
1149162SPeter.Dunlap@Sun.COM 	status = iser_ib_init_hcas();
1159162SPeter.Dunlap@Sun.COM 	if (status != DDI_SUCCESS) {
1169162SPeter.Dunlap@Sun.COM 		/* HCAs failed to initialize, tear it down */
1179162SPeter.Dunlap@Sun.COM 		kmem_cache_destroy(iser_state->iser_wr_cache);
1189162SPeter.Dunlap@Sun.COM 		(void) ibt_detach(iser_state->is_ibhdl);
1199162SPeter.Dunlap@Sun.COM 		iser_state->is_ibhdl = NULL;
1209162SPeter.Dunlap@Sun.COM 		ISER_LOG(CE_NOTE, "iser_ib_init: failed to initialize HCAs");
1219162SPeter.Dunlap@Sun.COM 		return (DDI_FAILURE);
1229162SPeter.Dunlap@Sun.COM 	}
1239162SPeter.Dunlap@Sun.COM 
1249162SPeter.Dunlap@Sun.COM 	/* Target will register iSER as a service with IBTF when required */
1259162SPeter.Dunlap@Sun.COM 
1269162SPeter.Dunlap@Sun.COM 	/* Target will bind this service when it comes online */
1279162SPeter.Dunlap@Sun.COM 
1289162SPeter.Dunlap@Sun.COM 	return (DDI_SUCCESS);
1299162SPeter.Dunlap@Sun.COM }
1309162SPeter.Dunlap@Sun.COM 
1319162SPeter.Dunlap@Sun.COM /*
1329162SPeter.Dunlap@Sun.COM  * iser_ib_fini
1339162SPeter.Dunlap@Sun.COM  *
1349162SPeter.Dunlap@Sun.COM  * This function unbinds and degisters the iSER service from IBTF
1359162SPeter.Dunlap@Sun.COM  */
1369162SPeter.Dunlap@Sun.COM int
iser_ib_fini(void)1379162SPeter.Dunlap@Sun.COM iser_ib_fini(void)
1389162SPeter.Dunlap@Sun.COM {
1399162SPeter.Dunlap@Sun.COM 	/* IDM would have already disabled all the services */
1409162SPeter.Dunlap@Sun.COM 
1419162SPeter.Dunlap@Sun.COM 	/* Teardown the HCA list and associated resources */
1429162SPeter.Dunlap@Sun.COM 	if (iser_ib_fini_hcas() != DDI_SUCCESS)
1439162SPeter.Dunlap@Sun.COM 		return (DDI_FAILURE);
1449162SPeter.Dunlap@Sun.COM 
1459162SPeter.Dunlap@Sun.COM 	/* Teardown the global work request kmem_cache */
1469162SPeter.Dunlap@Sun.COM 	kmem_cache_destroy(iser_state->iser_wr_cache);
1479162SPeter.Dunlap@Sun.COM 
1489162SPeter.Dunlap@Sun.COM 	/* Deregister with IBTF */
1499162SPeter.Dunlap@Sun.COM 	if (iser_state->is_ibhdl != NULL) {
1509162SPeter.Dunlap@Sun.COM 		(void) ibt_detach(iser_state->is_ibhdl);
1519162SPeter.Dunlap@Sun.COM 		iser_state->is_ibhdl = NULL;
1529162SPeter.Dunlap@Sun.COM 	}
1539162SPeter.Dunlap@Sun.COM 
1549162SPeter.Dunlap@Sun.COM 	return (DDI_SUCCESS);
1559162SPeter.Dunlap@Sun.COM }
1569162SPeter.Dunlap@Sun.COM 
1579162SPeter.Dunlap@Sun.COM /*
1589162SPeter.Dunlap@Sun.COM  * iser_ib_register_service
1599162SPeter.Dunlap@Sun.COM  *
1609162SPeter.Dunlap@Sun.COM  * This function registers the iSER service using the RDMA-Aware Service ID.
1619162SPeter.Dunlap@Sun.COM  */
1629162SPeter.Dunlap@Sun.COM int
iser_ib_register_service(idm_svc_t * idm_svc)1639162SPeter.Dunlap@Sun.COM iser_ib_register_service(idm_svc_t *idm_svc)
1649162SPeter.Dunlap@Sun.COM {
1659162SPeter.Dunlap@Sun.COM 	ibt_srv_desc_t	srvdesc;
1669162SPeter.Dunlap@Sun.COM 	iser_svc_t	*iser_svc;
1679162SPeter.Dunlap@Sun.COM 	int		status;
1689162SPeter.Dunlap@Sun.COM 
1699162SPeter.Dunlap@Sun.COM 	bzero(&srvdesc, sizeof (ibt_srv_desc_t));
1709162SPeter.Dunlap@Sun.COM 
1719162SPeter.Dunlap@Sun.COM 	/* Set up IBTI client callback handler from the CM */
1729162SPeter.Dunlap@Sun.COM 	srvdesc.sd_handler = iser_ib_cm_handler;
1739162SPeter.Dunlap@Sun.COM 
1749162SPeter.Dunlap@Sun.COM 	srvdesc.sd_flags = IBT_SRV_NO_FLAGS;
1759162SPeter.Dunlap@Sun.COM 
1769162SPeter.Dunlap@Sun.COM 	iser_svc = (iser_svc_t *)idm_svc->is_iser_svc;
1779162SPeter.Dunlap@Sun.COM 
1789162SPeter.Dunlap@Sun.COM 	/* Register the service on the specified port */
1799162SPeter.Dunlap@Sun.COM 	status = ibt_register_service(
1809162SPeter.Dunlap@Sun.COM 	    iser_state->is_ibhdl, &srvdesc,
1819162SPeter.Dunlap@Sun.COM 	    iser_svc->is_svcid, 1, &iser_svc->is_srvhdl, NULL);
1829162SPeter.Dunlap@Sun.COM 
1839162SPeter.Dunlap@Sun.COM 	return (status);
1849162SPeter.Dunlap@Sun.COM }
1859162SPeter.Dunlap@Sun.COM 
1869162SPeter.Dunlap@Sun.COM /*
1879162SPeter.Dunlap@Sun.COM  * iser_ib_bind_service
1889162SPeter.Dunlap@Sun.COM  *
18910084SPriya.Krishnan@Sun.COM  * This function binds a given iSER service on all available HCA ports. The
19010084SPriya.Krishnan@Sun.COM  * current specification does not allow user to specify transport bindings
19110084SPriya.Krishnan@Sun.COM  * for each iscsi target. The ULP invokes this function to bind the target
19210084SPriya.Krishnan@Sun.COM  * to all available iser ports after checking for the presence of an IB HCA.
19310084SPriya.Krishnan@Sun.COM  * iSER is "configured" whenever an IB-capable IP address exists. The lack
19410084SPriya.Krishnan@Sun.COM  * of active IB ports is a less-fatal condition, and sockets would be used
19510084SPriya.Krishnan@Sun.COM  * as the transport even though an Infiniband HCA is configured but unusable.
19610084SPriya.Krishnan@Sun.COM  *
1979162SPeter.Dunlap@Sun.COM  */
1989162SPeter.Dunlap@Sun.COM int
iser_ib_bind_service(idm_svc_t * idm_svc)1999162SPeter.Dunlap@Sun.COM iser_ib_bind_service(idm_svc_t *idm_svc)
2009162SPeter.Dunlap@Sun.COM {
2019162SPeter.Dunlap@Sun.COM 	iser_hca_t	*hca;
2029162SPeter.Dunlap@Sun.COM 	ib_gid_t	gid;
2039162SPeter.Dunlap@Sun.COM 	int		num_ports = 0;
2049162SPeter.Dunlap@Sun.COM 	int		num_binds = 0;
20510084SPriya.Krishnan@Sun.COM 	int		num_inactive_binds = 0; /* if HCA ports inactive */
2069162SPeter.Dunlap@Sun.COM 	int		status;
2079162SPeter.Dunlap@Sun.COM 	int		i;
2089162SPeter.Dunlap@Sun.COM 
2099162SPeter.Dunlap@Sun.COM 	ASSERT(idm_svc != NULL);
2109162SPeter.Dunlap@Sun.COM 	ASSERT(idm_svc->is_iser_svc != NULL);
2119162SPeter.Dunlap@Sun.COM 
2129162SPeter.Dunlap@Sun.COM 	/* Register the iSER service on all available ports */
2139162SPeter.Dunlap@Sun.COM 	mutex_enter(&iser_state->is_hcalist_lock);
2149162SPeter.Dunlap@Sun.COM 
2159162SPeter.Dunlap@Sun.COM 	for (hca = list_head(&iser_state->is_hcalist);
2169162SPeter.Dunlap@Sun.COM 	    hca != NULL;
2179162SPeter.Dunlap@Sun.COM 	    hca = list_next(&iser_state->is_hcalist, hca)) {
2189162SPeter.Dunlap@Sun.COM 
2199162SPeter.Dunlap@Sun.COM 		for (i = 0; i < hca->hca_num_ports; i++) {
2209162SPeter.Dunlap@Sun.COM 			num_ports++;
2219162SPeter.Dunlap@Sun.COM 			if (hca->hca_port_info[i].p_linkstate !=
2229162SPeter.Dunlap@Sun.COM 			    IBT_PORT_ACTIVE) {
2239162SPeter.Dunlap@Sun.COM 				/*
2249162SPeter.Dunlap@Sun.COM 				 * Move on. We will attempt to bind service
2259162SPeter.Dunlap@Sun.COM 				 * in our async handler if the port comes up
2269162SPeter.Dunlap@Sun.COM 				 * at a later time.
2279162SPeter.Dunlap@Sun.COM 				 */
22810084SPriya.Krishnan@Sun.COM 				num_inactive_binds++;
2299162SPeter.Dunlap@Sun.COM 				continue;
2309162SPeter.Dunlap@Sun.COM 			}
2319162SPeter.Dunlap@Sun.COM 
2329162SPeter.Dunlap@Sun.COM 			gid = hca->hca_port_info[i].p_sgid_tbl[0];
2339162SPeter.Dunlap@Sun.COM 
2349162SPeter.Dunlap@Sun.COM 			/* If the port is already bound, skip */
2359162SPeter.Dunlap@Sun.COM 			if (iser_ib_get_bind(
2369162SPeter.Dunlap@Sun.COM 			    idm_svc->is_iser_svc, hca->hca_guid, gid) == NULL) {
2379162SPeter.Dunlap@Sun.COM 
2389162SPeter.Dunlap@Sun.COM 				status = iser_ib_activate_port(
2399162SPeter.Dunlap@Sun.COM 				    idm_svc, hca->hca_guid, gid);
2409162SPeter.Dunlap@Sun.COM 				if (status != IBT_SUCCESS) {
2419162SPeter.Dunlap@Sun.COM 					ISER_LOG(CE_NOTE,
2429162SPeter.Dunlap@Sun.COM 					    "iser_ib_bind_service: "
2439162SPeter.Dunlap@Sun.COM 					    "iser_ib_activate_port failure "
2449162SPeter.Dunlap@Sun.COM 					    "(0x%x)", status);
2459162SPeter.Dunlap@Sun.COM 					continue;
2469162SPeter.Dunlap@Sun.COM 				}
2479162SPeter.Dunlap@Sun.COM 			}
2489162SPeter.Dunlap@Sun.COM 			num_binds++;
2499162SPeter.Dunlap@Sun.COM 		}
2509162SPeter.Dunlap@Sun.COM 	}
2519162SPeter.Dunlap@Sun.COM 	mutex_exit(&iser_state->is_hcalist_lock);
2529162SPeter.Dunlap@Sun.COM 
2539162SPeter.Dunlap@Sun.COM 	if (num_binds) {
2549162SPeter.Dunlap@Sun.COM 		ISER_LOG(CE_NOTE, "iser_ib_bind_service: Service available on "
2559162SPeter.Dunlap@Sun.COM 		    "(%d) of (%d) ports", num_binds, num_ports);
2569162SPeter.Dunlap@Sun.COM 		return (ISER_STATUS_SUCCESS);
25710084SPriya.Krishnan@Sun.COM 	} else if (num_inactive_binds) {
25810084SPriya.Krishnan@Sun.COM 		ISER_LOG(CE_NOTE, "iser_ib_bind_service: Could not bind "
25910084SPriya.Krishnan@Sun.COM 		    "service, HCA ports are not active.");
26010084SPriya.Krishnan@Sun.COM 		/*
26110084SPriya.Krishnan@Sun.COM 		 * still considered success, the async handler will bind
26210084SPriya.Krishnan@Sun.COM 		 * the service when the port comes up at a later time
26310084SPriya.Krishnan@Sun.COM 		 */
26410084SPriya.Krishnan@Sun.COM 		return (ISER_STATUS_SUCCESS);
2659162SPeter.Dunlap@Sun.COM 	} else {
2669162SPeter.Dunlap@Sun.COM 		ISER_LOG(CE_NOTE, "iser_ib_bind_service: Did not bind service");
2679162SPeter.Dunlap@Sun.COM 		return (ISER_STATUS_FAIL);
2689162SPeter.Dunlap@Sun.COM 	}
2699162SPeter.Dunlap@Sun.COM }
2709162SPeter.Dunlap@Sun.COM 
2719162SPeter.Dunlap@Sun.COM /*
2729162SPeter.Dunlap@Sun.COM  * iser_ib_unbind_service
2739162SPeter.Dunlap@Sun.COM  *
2749162SPeter.Dunlap@Sun.COM  * This function unbinds a given service on a all HCA ports
2759162SPeter.Dunlap@Sun.COM  */
2769162SPeter.Dunlap@Sun.COM void
iser_ib_unbind_service(idm_svc_t * idm_svc)2779162SPeter.Dunlap@Sun.COM iser_ib_unbind_service(idm_svc_t *idm_svc)
2789162SPeter.Dunlap@Sun.COM {
2799162SPeter.Dunlap@Sun.COM 	iser_svc_t	*iser_svc;
2809162SPeter.Dunlap@Sun.COM 	iser_sbind_t	*is_sbind, *next_sb;
2819162SPeter.Dunlap@Sun.COM 
2829162SPeter.Dunlap@Sun.COM 	if (idm_svc != NULL && idm_svc->is_iser_svc != NULL) {
2839162SPeter.Dunlap@Sun.COM 
2849162SPeter.Dunlap@Sun.COM 		iser_svc = idm_svc->is_iser_svc;
2859162SPeter.Dunlap@Sun.COM 
2869162SPeter.Dunlap@Sun.COM 		for (is_sbind = list_head(&iser_svc->is_sbindlist);
2879162SPeter.Dunlap@Sun.COM 		    is_sbind != NULL;
2889162SPeter.Dunlap@Sun.COM 		    is_sbind = next_sb) {
2899162SPeter.Dunlap@Sun.COM 			next_sb = list_next(&iser_svc->is_sbindlist, is_sbind);
29011093SSrivijitha.Dugganapalli@Sun.COM 			(void) ibt_unbind_service(iser_svc->is_srvhdl,
2919162SPeter.Dunlap@Sun.COM 			    is_sbind->is_sbindhdl);
2929162SPeter.Dunlap@Sun.COM 			list_remove(&iser_svc->is_sbindlist, is_sbind);
2939162SPeter.Dunlap@Sun.COM 			kmem_free(is_sbind, sizeof (iser_sbind_t));
2949162SPeter.Dunlap@Sun.COM 		}
2959162SPeter.Dunlap@Sun.COM 	}
2969162SPeter.Dunlap@Sun.COM }
2979162SPeter.Dunlap@Sun.COM 
2989162SPeter.Dunlap@Sun.COM /* ARGSUSED */
2999162SPeter.Dunlap@Sun.COM void
iser_ib_deregister_service(idm_svc_t * idm_svc)3009162SPeter.Dunlap@Sun.COM iser_ib_deregister_service(idm_svc_t *idm_svc)
3019162SPeter.Dunlap@Sun.COM {
3029162SPeter.Dunlap@Sun.COM 	iser_svc_t	*iser_svc;
3039162SPeter.Dunlap@Sun.COM 
3049162SPeter.Dunlap@Sun.COM 	if (idm_svc != NULL && idm_svc->is_iser_svc != NULL) {
3059162SPeter.Dunlap@Sun.COM 
3069162SPeter.Dunlap@Sun.COM 		iser_svc = (iser_svc_t *)idm_svc->is_iser_svc;
30711093SSrivijitha.Dugganapalli@Sun.COM 		(void) ibt_deregister_service(iser_state->is_ibhdl,
3089162SPeter.Dunlap@Sun.COM 		    iser_svc->is_srvhdl);
30911093SSrivijitha.Dugganapalli@Sun.COM 		(void) ibt_release_ip_sid(iser_svc->is_svcid);
3109162SPeter.Dunlap@Sun.COM 	}
3119162SPeter.Dunlap@Sun.COM }
3129162SPeter.Dunlap@Sun.COM 
3139162SPeter.Dunlap@Sun.COM /*
3149162SPeter.Dunlap@Sun.COM  * iser_ib_get_paths
3159162SPeter.Dunlap@Sun.COM  * This function finds the IB path between the local and the remote address.
3169162SPeter.Dunlap@Sun.COM  *
3179162SPeter.Dunlap@Sun.COM  */
3189162SPeter.Dunlap@Sun.COM int
iser_ib_get_paths(ibt_ip_addr_t * local_ip,ibt_ip_addr_t * remote_ip,ibt_path_info_t * path,ibt_path_ip_src_t * path_src_ip)3199162SPeter.Dunlap@Sun.COM iser_ib_get_paths(ibt_ip_addr_t *local_ip, ibt_ip_addr_t *remote_ip,
3209162SPeter.Dunlap@Sun.COM     ibt_path_info_t *path, ibt_path_ip_src_t *path_src_ip)
3219162SPeter.Dunlap@Sun.COM {
3229162SPeter.Dunlap@Sun.COM 	ibt_ip_path_attr_t	ipattr;
3239162SPeter.Dunlap@Sun.COM 	int			status;
3249162SPeter.Dunlap@Sun.COM 
3259162SPeter.Dunlap@Sun.COM 	(void) bzero(&ipattr, sizeof (ibt_ip_path_attr_t));
3269162SPeter.Dunlap@Sun.COM 	ipattr.ipa_dst_ip	= remote_ip;
3279162SPeter.Dunlap@Sun.COM 	ipattr.ipa_src_ip	= *local_ip;
3289162SPeter.Dunlap@Sun.COM 	ipattr.ipa_max_paths	= 1;
3299162SPeter.Dunlap@Sun.COM 	ipattr.ipa_ndst		= 1;
3309162SPeter.Dunlap@Sun.COM 
3319162SPeter.Dunlap@Sun.COM 	(void) bzero(path, sizeof (ibt_path_info_t));
3329162SPeter.Dunlap@Sun.COM 	status = ibt_get_ip_paths(iser_state->is_ibhdl, IBT_PATH_NO_FLAGS,
3339162SPeter.Dunlap@Sun.COM 	    &ipattr, path, NULL, path_src_ip);
3349162SPeter.Dunlap@Sun.COM 	if (status != IBT_SUCCESS) {
3359162SPeter.Dunlap@Sun.COM 		ISER_LOG(CE_NOTE, "ibt_get_ip_paths: ibt_get_ip_paths "
3369162SPeter.Dunlap@Sun.COM 		    "failure: status (%d)", status);
3379162SPeter.Dunlap@Sun.COM 		return (status);
3389162SPeter.Dunlap@Sun.COM 	}
3399162SPeter.Dunlap@Sun.COM 
3409162SPeter.Dunlap@Sun.COM 	if (local_ip != NULL) {
3419162SPeter.Dunlap@Sun.COM 		ISER_LOG(CE_NOTE, "iser_ib_get_paths success: IP[%x to %x]",
3429162SPeter.Dunlap@Sun.COM 		    local_ip->un.ip4addr, remote_ip->un.ip4addr);
3439162SPeter.Dunlap@Sun.COM 	} else {
3449162SPeter.Dunlap@Sun.COM 		ISER_LOG(CE_NOTE, "iser_ib_get_paths success: "
3459162SPeter.Dunlap@Sun.COM 		    "IP[INADDR_ANY to %x]", remote_ip->un.ip4addr);
3469162SPeter.Dunlap@Sun.COM 	}
3479162SPeter.Dunlap@Sun.COM 
3489162SPeter.Dunlap@Sun.COM 	return (ISER_STATUS_SUCCESS);
3499162SPeter.Dunlap@Sun.COM }
3509162SPeter.Dunlap@Sun.COM 
3519162SPeter.Dunlap@Sun.COM /*
35210322SPriya.Krishnan@Sun.COM  * iser_ib_alloc_channel_nopathlookup
35310322SPriya.Krishnan@Sun.COM  *
35410322SPriya.Krishnan@Sun.COM  * This function allocates a reliable connected channel. This function does
35510322SPriya.Krishnan@Sun.COM  * not invoke ibt_get_ip_paths() to do the path lookup. The HCA GUID and
35610322SPriya.Krishnan@Sun.COM  * port are input to this function.
35710322SPriya.Krishnan@Sun.COM  */
35810322SPriya.Krishnan@Sun.COM iser_chan_t *
iser_ib_alloc_channel_nopathlookup(ib_guid_t hca_guid,uint8_t hca_port)35910322SPriya.Krishnan@Sun.COM iser_ib_alloc_channel_nopathlookup(ib_guid_t hca_guid, uint8_t hca_port)
36010322SPriya.Krishnan@Sun.COM {
36110322SPriya.Krishnan@Sun.COM 	iser_hca_t	*hca;
36210322SPriya.Krishnan@Sun.COM 	iser_chan_t	*chan;
36310322SPriya.Krishnan@Sun.COM 
36410322SPriya.Krishnan@Sun.COM 	/* Lookup the hca using the gid in the path info */
36510322SPriya.Krishnan@Sun.COM 	hca = iser_ib_guid2hca(hca_guid);
36610322SPriya.Krishnan@Sun.COM 	if (hca == NULL) {
36710322SPriya.Krishnan@Sun.COM 		ISER_LOG(CE_NOTE, "iser_ib_alloc_channel_nopathlookup: failed "
36810322SPriya.Krishnan@Sun.COM 		    "to lookup HCA(%llx) handle", (longlong_t)hca_guid);
36910322SPriya.Krishnan@Sun.COM 		return (NULL);
37010322SPriya.Krishnan@Sun.COM 	}
37110322SPriya.Krishnan@Sun.COM 
37210322SPriya.Krishnan@Sun.COM 	chan = iser_ib_alloc_rc_channel(hca, hca_port);
37310322SPriya.Krishnan@Sun.COM 	if (chan == NULL) {
37410322SPriya.Krishnan@Sun.COM 		ISER_LOG(CE_NOTE, "iser_ib_alloc_channel_nopathlookup: failed "
37510322SPriya.Krishnan@Sun.COM 		    "to alloc channel on HCA(%llx) %d",
37610322SPriya.Krishnan@Sun.COM 		    (longlong_t)hca_guid, hca_port);
37710322SPriya.Krishnan@Sun.COM 		return (NULL);
37810322SPriya.Krishnan@Sun.COM 	}
37910322SPriya.Krishnan@Sun.COM 
38010322SPriya.Krishnan@Sun.COM 	ISER_LOG(CE_NOTE, "iser_ib_alloc_channel_pathlookup success: "
38110322SPriya.Krishnan@Sun.COM 	    "chanhdl (0x%p), HCA(%llx) %d",
38210322SPriya.Krishnan@Sun.COM 	    (void *)chan->ic_chanhdl, (longlong_t)hca_guid, hca_port);
38310322SPriya.Krishnan@Sun.COM 
38410322SPriya.Krishnan@Sun.COM 	return (chan);
38510322SPriya.Krishnan@Sun.COM }
38610322SPriya.Krishnan@Sun.COM 
38710322SPriya.Krishnan@Sun.COM /*
38810322SPriya.Krishnan@Sun.COM  * iser_ib_alloc_channel_pathlookup
38910322SPriya.Krishnan@Sun.COM  *
39010322SPriya.Krishnan@Sun.COM  * This function allocates a reliable connected channel but first invokes
39110322SPriya.Krishnan@Sun.COM  * ibt_get_ip_paths() with the given local and remote addres to get the
39210322SPriya.Krishnan@Sun.COM  * HCA lgid and the port number.
39310322SPriya.Krishnan@Sun.COM  */
39410322SPriya.Krishnan@Sun.COM iser_chan_t *
iser_ib_alloc_channel_pathlookup(ibt_ip_addr_t * local_ip,ibt_ip_addr_t * remote_ip)39510322SPriya.Krishnan@Sun.COM iser_ib_alloc_channel_pathlookup(
39610322SPriya.Krishnan@Sun.COM     ibt_ip_addr_t *local_ip, ibt_ip_addr_t *remote_ip)
39710322SPriya.Krishnan@Sun.COM {
39810322SPriya.Krishnan@Sun.COM 	ibt_path_info_t		ibt_path;
39910322SPriya.Krishnan@Sun.COM 	ibt_path_ip_src_t	path_src_ip;
40010322SPriya.Krishnan@Sun.COM 	ib_gid_t		lgid;
40110322SPriya.Krishnan@Sun.COM 	uint8_t			hca_port; /* from path */
40210322SPriya.Krishnan@Sun.COM 	iser_hca_t		*hca;
40310322SPriya.Krishnan@Sun.COM 	iser_chan_t		*chan;
40410322SPriya.Krishnan@Sun.COM 	int			status;
40510322SPriya.Krishnan@Sun.COM 
40610322SPriya.Krishnan@Sun.COM 	/* Lookup a path to the given destination */
40710322SPriya.Krishnan@Sun.COM 	status = iser_ib_get_paths(
40810322SPriya.Krishnan@Sun.COM 	    local_ip, remote_ip, &ibt_path, &path_src_ip);
40910322SPriya.Krishnan@Sun.COM 
41010322SPriya.Krishnan@Sun.COM 	if (status != ISER_STATUS_SUCCESS) {
41110322SPriya.Krishnan@Sun.COM 		ISER_LOG(CE_NOTE, "iser_ib_alloc_channel_pathlookup: faild "
41210322SPriya.Krishnan@Sun.COM 		    "Path lookup IP:[%llx to %llx] failed: status (%d)",
41310322SPriya.Krishnan@Sun.COM 		    (longlong_t)local_ip->un.ip4addr,
41410322SPriya.Krishnan@Sun.COM 		    (longlong_t)remote_ip->un.ip4addr,
41510322SPriya.Krishnan@Sun.COM 		    status);
41610322SPriya.Krishnan@Sun.COM 		return (NULL);
41710322SPriya.Krishnan@Sun.COM 	}
41810322SPriya.Krishnan@Sun.COM 
41910322SPriya.Krishnan@Sun.COM 	/* get the local gid from the path info */
42010322SPriya.Krishnan@Sun.COM 	lgid = ibt_path.pi_prim_cep_path.cep_adds_vect.av_sgid;
42110322SPriya.Krishnan@Sun.COM 
42210322SPriya.Krishnan@Sun.COM 	/* get the hca port from the path info */
42310322SPriya.Krishnan@Sun.COM 	hca_port = ibt_path.pi_prim_cep_path.cep_hca_port_num;
42410322SPriya.Krishnan@Sun.COM 
42510322SPriya.Krishnan@Sun.COM 	/* Lookup the hca using the gid in the path info */
42610322SPriya.Krishnan@Sun.COM 	hca = iser_ib_gid2hca(lgid);
42710322SPriya.Krishnan@Sun.COM 	if (hca == NULL) {
42810322SPriya.Krishnan@Sun.COM 		ISER_LOG(CE_NOTE, "iser_ib_alloc_channel_pathlookup: failed "
42910322SPriya.Krishnan@Sun.COM 		    "to lookup HCA (%llx) handle",
43010322SPriya.Krishnan@Sun.COM 		    (longlong_t)hca->hca_guid);
43110322SPriya.Krishnan@Sun.COM 		return (NULL);
43210322SPriya.Krishnan@Sun.COM 	}
43310322SPriya.Krishnan@Sun.COM 
43410322SPriya.Krishnan@Sun.COM 	chan = iser_ib_alloc_rc_channel(hca, hca_port);
43510322SPriya.Krishnan@Sun.COM 	if (chan == NULL) {
43610322SPriya.Krishnan@Sun.COM 		ISER_LOG(CE_NOTE, "iser_ib_alloc_channel_pathlookup: failed "
43710322SPriya.Krishnan@Sun.COM 		    "to alloc channel from IP:[%llx to %llx] on HCA (%llx) %d",
43810322SPriya.Krishnan@Sun.COM 		    (longlong_t)local_ip->un.ip4addr,
43910322SPriya.Krishnan@Sun.COM 		    (longlong_t)remote_ip->un.ip4addr,
44010322SPriya.Krishnan@Sun.COM 		    (longlong_t)hca->hca_guid, hca_port);
44110322SPriya.Krishnan@Sun.COM 		return (NULL);
44210322SPriya.Krishnan@Sun.COM 	}
44310322SPriya.Krishnan@Sun.COM 
44410322SPriya.Krishnan@Sun.COM 	ISER_LOG(CE_NOTE, "iser_ib_alloc_channel_pathlookup success: "
44510322SPriya.Krishnan@Sun.COM 	    "chanhdl (0x%p), IP:[%llx to %llx], lgid (%llx:%llx), HCA(%llx) %d",
44610322SPriya.Krishnan@Sun.COM 	    (void *)chan->ic_chanhdl,
44710322SPriya.Krishnan@Sun.COM 	    (longlong_t)local_ip->un.ip4addr,
44810322SPriya.Krishnan@Sun.COM 	    (longlong_t)remote_ip->un.ip4addr,
44910322SPriya.Krishnan@Sun.COM 	    (longlong_t)lgid.gid_prefix, (longlong_t)lgid.gid_guid,
45010322SPriya.Krishnan@Sun.COM 	    (longlong_t)hca->hca_guid, hca_port);
45110322SPriya.Krishnan@Sun.COM 
45210322SPriya.Krishnan@Sun.COM 	chan->ic_ibt_path	= ibt_path;
45310322SPriya.Krishnan@Sun.COM 	chan->ic_localip	= path_src_ip.ip_primary;
45410322SPriya.Krishnan@Sun.COM 	chan->ic_remoteip	= *remote_ip;
45510322SPriya.Krishnan@Sun.COM 
45610322SPriya.Krishnan@Sun.COM 	return (chan);
45710322SPriya.Krishnan@Sun.COM }
45810322SPriya.Krishnan@Sun.COM 
45910322SPriya.Krishnan@Sun.COM /*
4609162SPeter.Dunlap@Sun.COM  * iser_ib_alloc_rc_channel
4619162SPeter.Dunlap@Sun.COM  *
4629162SPeter.Dunlap@Sun.COM  * This function allocates a reliable communication channel using the specified
4639162SPeter.Dunlap@Sun.COM  * channel attributes.
4649162SPeter.Dunlap@Sun.COM  */
4659162SPeter.Dunlap@Sun.COM iser_chan_t *
iser_ib_alloc_rc_channel(iser_hca_t * hca,uint8_t hca_port)46610322SPriya.Krishnan@Sun.COM iser_ib_alloc_rc_channel(iser_hca_t *hca, uint8_t hca_port)
4679162SPeter.Dunlap@Sun.COM {
4689162SPeter.Dunlap@Sun.COM 
4699162SPeter.Dunlap@Sun.COM 	iser_chan_t			*chan;
4709162SPeter.Dunlap@Sun.COM 	ibt_rc_chan_alloc_args_t	chanargs;
4719162SPeter.Dunlap@Sun.COM 	uint_t				sq_size, rq_size;
4729162SPeter.Dunlap@Sun.COM 	int				status;
4739162SPeter.Dunlap@Sun.COM 
4749162SPeter.Dunlap@Sun.COM 	chan = kmem_zalloc(sizeof (iser_chan_t), KM_SLEEP);
4759162SPeter.Dunlap@Sun.COM 
47611078SPeter.Cudhea@Sun.COM 	mutex_init(&chan->ic_chan_lock, NULL, MUTEX_DRIVER, NULL);
4779162SPeter.Dunlap@Sun.COM 	mutex_init(&chan->ic_sq_post_lock, NULL, MUTEX_DRIVER, NULL);
4789162SPeter.Dunlap@Sun.COM 
47910322SPriya.Krishnan@Sun.COM 	/* Set up the iSER channel handle with HCA */
4809162SPeter.Dunlap@Sun.COM 	chan->ic_hca		= hca;
4819162SPeter.Dunlap@Sun.COM 
4829162SPeter.Dunlap@Sun.COM 	/*
4839162SPeter.Dunlap@Sun.COM 	 * Determine the queue sizes, based upon the HCA query data.
4849162SPeter.Dunlap@Sun.COM 	 * For our Work Queues, we will use either our default value,
4859162SPeter.Dunlap@Sun.COM 	 * or the HCA's maximum value, whichever is smaller.
4869162SPeter.Dunlap@Sun.COM 	 */
4879162SPeter.Dunlap@Sun.COM 	sq_size = min(hca->hca_attr.hca_max_chan_sz, ISER_IB_SENDQ_SIZE);
4889162SPeter.Dunlap@Sun.COM 	rq_size = min(hca->hca_attr.hca_max_chan_sz, ISER_IB_RECVQ_SIZE);
4899162SPeter.Dunlap@Sun.COM 
4909162SPeter.Dunlap@Sun.COM 	/*
4919162SPeter.Dunlap@Sun.COM 	 * For our Completion Queues, we again check the device maximum.
4929162SPeter.Dunlap@Sun.COM 	 * We want to end up with CQs that are the next size up from the
4939162SPeter.Dunlap@Sun.COM 	 * WQs they are servicing so that they have some overhead.
4949162SPeter.Dunlap@Sun.COM 	 */
4959162SPeter.Dunlap@Sun.COM 	if (hca->hca_attr.hca_max_cq_sz >= (sq_size + 1)) {
4969162SPeter.Dunlap@Sun.COM 		chan->ic_sendcq_sz = sq_size + 1;
4979162SPeter.Dunlap@Sun.COM 	} else {
4989162SPeter.Dunlap@Sun.COM 		chan->ic_sendcq_sz = hca->hca_attr.hca_max_cq_sz;
4999162SPeter.Dunlap@Sun.COM 		sq_size = chan->ic_sendcq_sz - 1;
5009162SPeter.Dunlap@Sun.COM 	}
5019162SPeter.Dunlap@Sun.COM 
5029162SPeter.Dunlap@Sun.COM 	if (hca->hca_attr.hca_max_cq_sz >= (rq_size + 1)) {
5039162SPeter.Dunlap@Sun.COM 		chan->ic_recvcq_sz = rq_size + 1;
5049162SPeter.Dunlap@Sun.COM 	} else {
5059162SPeter.Dunlap@Sun.COM 		chan->ic_recvcq_sz = hca->hca_attr.hca_max_cq_sz;
5069162SPeter.Dunlap@Sun.COM 		rq_size = chan->ic_recvcq_sz - 1;
5079162SPeter.Dunlap@Sun.COM 	}
5089162SPeter.Dunlap@Sun.COM 
5099162SPeter.Dunlap@Sun.COM 	/* Initialize the iSER channel's QP handle */
5109162SPeter.Dunlap@Sun.COM 	iser_ib_init_qp(chan, sq_size, rq_size);
5119162SPeter.Dunlap@Sun.COM 
5129162SPeter.Dunlap@Sun.COM 	/* Set up the Send Completion Queue */
5139162SPeter.Dunlap@Sun.COM 	status = iser_ib_setup_cq(hca->hca_hdl, chan->ic_sendcq_sz,
5149162SPeter.Dunlap@Sun.COM 	    &chan->ic_sendcq);
5159162SPeter.Dunlap@Sun.COM 	if (status != ISER_STATUS_SUCCESS) {
5169162SPeter.Dunlap@Sun.COM 		iser_ib_fini_qp(&chan->ic_qp);
51711078SPeter.Cudhea@Sun.COM 		mutex_destroy(&chan->ic_chan_lock);
5189162SPeter.Dunlap@Sun.COM 		mutex_destroy(&chan->ic_sq_post_lock);
5199162SPeter.Dunlap@Sun.COM 		kmem_free(chan, sizeof (iser_chan_t));
5209162SPeter.Dunlap@Sun.COM 		return (NULL);
5219162SPeter.Dunlap@Sun.COM 	}
5229162SPeter.Dunlap@Sun.COM 	ibt_set_cq_handler(chan->ic_sendcq, iser_ib_sendcq_handler, chan);
52311093SSrivijitha.Dugganapalli@Sun.COM 	(void) ibt_enable_cq_notify(chan->ic_sendcq, IBT_NEXT_COMPLETION);
5249162SPeter.Dunlap@Sun.COM 
5259162SPeter.Dunlap@Sun.COM 	/* Set up the Receive Completion Queue */
5269162SPeter.Dunlap@Sun.COM 	status = iser_ib_setup_cq(hca->hca_hdl, chan->ic_recvcq_sz,
5279162SPeter.Dunlap@Sun.COM 	    &chan->ic_recvcq);
5289162SPeter.Dunlap@Sun.COM 	if (status != ISER_STATUS_SUCCESS) {
5299162SPeter.Dunlap@Sun.COM 		(void) ibt_free_cq(chan->ic_sendcq);
5309162SPeter.Dunlap@Sun.COM 		iser_ib_fini_qp(&chan->ic_qp);
53111078SPeter.Cudhea@Sun.COM 		mutex_destroy(&chan->ic_chan_lock);
5329162SPeter.Dunlap@Sun.COM 		mutex_destroy(&chan->ic_sq_post_lock);
5339162SPeter.Dunlap@Sun.COM 		kmem_free(chan, sizeof (iser_chan_t));
5349162SPeter.Dunlap@Sun.COM 		return (NULL);
5359162SPeter.Dunlap@Sun.COM 	}
5369162SPeter.Dunlap@Sun.COM 	ibt_set_cq_handler(chan->ic_recvcq, iser_ib_recvcq_handler, chan);
53711093SSrivijitha.Dugganapalli@Sun.COM 	(void) ibt_enable_cq_notify(chan->ic_recvcq, IBT_NEXT_COMPLETION);
5389162SPeter.Dunlap@Sun.COM 
5399162SPeter.Dunlap@Sun.COM 	/* Setup the channel arguments */
5409162SPeter.Dunlap@Sun.COM 	iser_ib_setup_chanargs(hca_port, chan->ic_sendcq, chan->ic_recvcq,
5419162SPeter.Dunlap@Sun.COM 	    sq_size, rq_size, hca->hca_pdhdl, &chanargs);
5429162SPeter.Dunlap@Sun.COM 
5439162SPeter.Dunlap@Sun.COM 	status = ibt_alloc_rc_channel(hca->hca_hdl,
5449162SPeter.Dunlap@Sun.COM 	    IBT_ACHAN_NO_FLAGS, &chanargs, &chan->ic_chanhdl, NULL);
5459162SPeter.Dunlap@Sun.COM 	if (status != IBT_SUCCESS) {
5469162SPeter.Dunlap@Sun.COM 		ISER_LOG(CE_NOTE, "iser_ib_alloc_rc_channel: failed "
5479162SPeter.Dunlap@Sun.COM 		    "ibt_alloc_rc_channel: status (%d)", status);
5489162SPeter.Dunlap@Sun.COM 		(void) ibt_free_cq(chan->ic_sendcq);
5499162SPeter.Dunlap@Sun.COM 		(void) ibt_free_cq(chan->ic_recvcq);
5509162SPeter.Dunlap@Sun.COM 		iser_ib_fini_qp(&chan->ic_qp);
55111078SPeter.Cudhea@Sun.COM 		mutex_destroy(&chan->ic_chan_lock);
5529162SPeter.Dunlap@Sun.COM 		mutex_destroy(&chan->ic_sq_post_lock);
5539162SPeter.Dunlap@Sun.COM 		kmem_free(chan, sizeof (iser_chan_t));
5549162SPeter.Dunlap@Sun.COM 		return (NULL);
5559162SPeter.Dunlap@Sun.COM 	}
5569162SPeter.Dunlap@Sun.COM 
5579162SPeter.Dunlap@Sun.COM 	/* Set the 'channel' as the client private data */
5589162SPeter.Dunlap@Sun.COM 	(void) ibt_set_chan_private(chan->ic_chanhdl, chan);
5599162SPeter.Dunlap@Sun.COM 
5609162SPeter.Dunlap@Sun.COM 	return (chan);
5619162SPeter.Dunlap@Sun.COM }
5629162SPeter.Dunlap@Sun.COM 
5639162SPeter.Dunlap@Sun.COM /*
5649162SPeter.Dunlap@Sun.COM  * iser_ib_open_rc_channel
5659162SPeter.Dunlap@Sun.COM  * This function opens a RC connection on the given allocated RC channel
5669162SPeter.Dunlap@Sun.COM  */
5679162SPeter.Dunlap@Sun.COM int
iser_ib_open_rc_channel(iser_chan_t * chan)5689162SPeter.Dunlap@Sun.COM iser_ib_open_rc_channel(iser_chan_t *chan)
5699162SPeter.Dunlap@Sun.COM {
5709162SPeter.Dunlap@Sun.COM 	ibt_ip_cm_info_t	ipcm_info;
5719162SPeter.Dunlap@Sun.COM 	iser_private_data_t	iser_priv_data;
5729162SPeter.Dunlap@Sun.COM 	ibt_chan_open_args_t	ocargs;
5739162SPeter.Dunlap@Sun.COM 	ibt_rc_returns_t	ocreturns;
5749162SPeter.Dunlap@Sun.COM 	int			status;
5759162SPeter.Dunlap@Sun.COM 
57611078SPeter.Cudhea@Sun.COM 	mutex_enter(&chan->ic_chan_lock);
5779162SPeter.Dunlap@Sun.COM 
5789162SPeter.Dunlap@Sun.COM 	/*
5799162SPeter.Dunlap@Sun.COM 	 * For connection establishment, the initiator sends a CM REQ using the
5809162SPeter.Dunlap@Sun.COM 	 * iSER RDMA-Aware Service ID. Included are the source and destination
5819162SPeter.Dunlap@Sun.COM 	 * IP addresses, and the src port.
5829162SPeter.Dunlap@Sun.COM 	 */
5839162SPeter.Dunlap@Sun.COM 	bzero(&ipcm_info, sizeof (ibt_ip_cm_info_t));
5849162SPeter.Dunlap@Sun.COM 	ipcm_info.src_addr = chan->ic_localip;
5859162SPeter.Dunlap@Sun.COM 	ipcm_info.dst_addr = chan->ic_remoteip;
5869162SPeter.Dunlap@Sun.COM 	ipcm_info.src_port = chan->ic_lport;
5879162SPeter.Dunlap@Sun.COM 
5889162SPeter.Dunlap@Sun.COM 	/*
5899162SPeter.Dunlap@Sun.COM 	 * The CM Private Data field defines the iSER connection parameters
5909162SPeter.Dunlap@Sun.COM 	 * such as zero based virtual address exception (ZBVAE) and Send with
5919162SPeter.Dunlap@Sun.COM 	 * invalidate Exception (SIE).
5929162SPeter.Dunlap@Sun.COM 	 *
5939162SPeter.Dunlap@Sun.COM 	 * Solaris IBT does not currently support ZBVAE or SIE.
5949162SPeter.Dunlap@Sun.COM 	 */
5959162SPeter.Dunlap@Sun.COM 	iser_priv_data.rsvd1	= 0;
5969162SPeter.Dunlap@Sun.COM 	iser_priv_data.sie	= 1;
5979162SPeter.Dunlap@Sun.COM 	iser_priv_data.zbvae	= 1;
5989162SPeter.Dunlap@Sun.COM 
5999162SPeter.Dunlap@Sun.COM 	status = ibt_format_ip_private_data(&ipcm_info,
6009162SPeter.Dunlap@Sun.COM 	    sizeof (iser_private_data_t), &iser_priv_data);
6019162SPeter.Dunlap@Sun.COM 	if (status != IBT_SUCCESS) {
6029162SPeter.Dunlap@Sun.COM 		ISER_LOG(CE_NOTE, "iser_ib_open_rc_channel failed: %d", status);
60311078SPeter.Cudhea@Sun.COM 		mutex_exit(&chan->ic_chan_lock);
6049162SPeter.Dunlap@Sun.COM 		return (status);
6059162SPeter.Dunlap@Sun.COM 	}
6069162SPeter.Dunlap@Sun.COM 
6079162SPeter.Dunlap@Sun.COM 	/*
6089162SPeter.Dunlap@Sun.COM 	 * Set the SID we are attempting to connect to, based upon the
6099162SPeter.Dunlap@Sun.COM 	 * remote port number.
6109162SPeter.Dunlap@Sun.COM 	 */
6119162SPeter.Dunlap@Sun.COM 	chan->ic_ibt_path.pi_sid = ibt_get_ip_sid(IPPROTO_TCP, chan->ic_rport);
6129162SPeter.Dunlap@Sun.COM 
6139162SPeter.Dunlap@Sun.COM 	/* Set up the args for the channel open */
6149162SPeter.Dunlap@Sun.COM 	bzero(&ocargs, sizeof (ibt_chan_open_args_t));
6159162SPeter.Dunlap@Sun.COM 	ocargs.oc_path			= &chan->ic_ibt_path;
6169162SPeter.Dunlap@Sun.COM 	ocargs.oc_cm_handler		= iser_ib_cm_handler;
6179162SPeter.Dunlap@Sun.COM 	ocargs.oc_cm_clnt_private	= iser_state;
6189162SPeter.Dunlap@Sun.COM 	ocargs.oc_rdma_ra_out		= 4;
6199162SPeter.Dunlap@Sun.COM 	ocargs.oc_rdma_ra_in		= 4;
6209162SPeter.Dunlap@Sun.COM 	ocargs.oc_path_retry_cnt	= 2;
6219162SPeter.Dunlap@Sun.COM 	ocargs.oc_path_rnr_retry_cnt	= 2;
6229162SPeter.Dunlap@Sun.COM 	ocargs.oc_priv_data_len		= sizeof (iser_private_data_t);
6239162SPeter.Dunlap@Sun.COM 	ocargs.oc_priv_data		= &iser_priv_data;
6249162SPeter.Dunlap@Sun.COM 
6259162SPeter.Dunlap@Sun.COM 	bzero(&ocreturns, sizeof (ibt_rc_returns_t));
6269162SPeter.Dunlap@Sun.COM 
6279162SPeter.Dunlap@Sun.COM 	status = ibt_open_rc_channel(chan->ic_chanhdl,
6289162SPeter.Dunlap@Sun.COM 	    IBT_OCHAN_NO_FLAGS, IBT_BLOCKING, &ocargs, &ocreturns);
6299162SPeter.Dunlap@Sun.COM 
6309162SPeter.Dunlap@Sun.COM 	if (status != IBT_SUCCESS) {
6319162SPeter.Dunlap@Sun.COM 		ISER_LOG(CE_NOTE, "iser_ib_open_rc_channel failed: %d", status);
63211078SPeter.Cudhea@Sun.COM 		mutex_exit(&chan->ic_chan_lock);
6339162SPeter.Dunlap@Sun.COM 		return (status);
6349162SPeter.Dunlap@Sun.COM 	}
6359162SPeter.Dunlap@Sun.COM 
63611078SPeter.Cudhea@Sun.COM 	mutex_exit(&chan->ic_chan_lock);
6379162SPeter.Dunlap@Sun.COM 	return (IDM_STATUS_SUCCESS);
6389162SPeter.Dunlap@Sun.COM }
6399162SPeter.Dunlap@Sun.COM 
6409162SPeter.Dunlap@Sun.COM /*
6419162SPeter.Dunlap@Sun.COM  * iser_ib_close_rc_channel
6429162SPeter.Dunlap@Sun.COM  * This function closes the RC channel related to this iser_chan handle.
6439162SPeter.Dunlap@Sun.COM  * We invoke this in a non-blocking, no callbacks context.
6449162SPeter.Dunlap@Sun.COM  */
6459162SPeter.Dunlap@Sun.COM void
iser_ib_close_rc_channel(iser_chan_t * chan)6469162SPeter.Dunlap@Sun.COM iser_ib_close_rc_channel(iser_chan_t *chan)
6479162SPeter.Dunlap@Sun.COM {
6489162SPeter.Dunlap@Sun.COM 	int			status;
6499162SPeter.Dunlap@Sun.COM 
65011078SPeter.Cudhea@Sun.COM 	mutex_enter(&chan->ic_chan_lock);
6519162SPeter.Dunlap@Sun.COM 	status = ibt_close_rc_channel(chan->ic_chanhdl, IBT_BLOCKING, NULL,
6529162SPeter.Dunlap@Sun.COM 	    0, NULL, NULL, 0);
6539162SPeter.Dunlap@Sun.COM 	if (status != IBT_SUCCESS) {
6549162SPeter.Dunlap@Sun.COM 		ISER_LOG(CE_NOTE, "iser_ib_close_rc_channel: "
6559162SPeter.Dunlap@Sun.COM 		    "ibt_close_rc_channel failed: status (%d)", status);
6569162SPeter.Dunlap@Sun.COM 	}
65711078SPeter.Cudhea@Sun.COM 	mutex_exit(&chan->ic_chan_lock);
6589162SPeter.Dunlap@Sun.COM }
6599162SPeter.Dunlap@Sun.COM 
6609162SPeter.Dunlap@Sun.COM /*
6619162SPeter.Dunlap@Sun.COM  * iser_ib_free_rc_channel
6629162SPeter.Dunlap@Sun.COM  *
6639162SPeter.Dunlap@Sun.COM  * This function tears down an RC channel's QP initialization and frees it.
6649162SPeter.Dunlap@Sun.COM  * Note that we do not need synchronization here; the channel has been
6659162SPeter.Dunlap@Sun.COM  * closed already, so we should only have completion polling occuring.  Once
6669162SPeter.Dunlap@Sun.COM  * complete, we are free to free the IBTF channel, WQ and CQ resources, and
6679162SPeter.Dunlap@Sun.COM  * our own related resources.
6689162SPeter.Dunlap@Sun.COM  */
6699162SPeter.Dunlap@Sun.COM void
iser_ib_free_rc_channel(iser_chan_t * chan)6709162SPeter.Dunlap@Sun.COM iser_ib_free_rc_channel(iser_chan_t *chan)
6719162SPeter.Dunlap@Sun.COM {
6729162SPeter.Dunlap@Sun.COM 	iser_qp_t	*iser_qp;
6739162SPeter.Dunlap@Sun.COM 
6749162SPeter.Dunlap@Sun.COM 	iser_qp = &chan->ic_qp;
6759162SPeter.Dunlap@Sun.COM 
6769162SPeter.Dunlap@Sun.COM 	/* Ensure the SQ is empty */
6779162SPeter.Dunlap@Sun.COM 	while (chan->ic_sq_post_count != 0) {
6789162SPeter.Dunlap@Sun.COM 		mutex_exit(&chan->ic_conn->ic_lock);
6799162SPeter.Dunlap@Sun.COM 		delay(drv_usectohz(ISER_DELAY_HALF_SECOND));
6809162SPeter.Dunlap@Sun.COM 		mutex_enter(&chan->ic_conn->ic_lock);
6819162SPeter.Dunlap@Sun.COM 	}
6829162SPeter.Dunlap@Sun.COM 	mutex_destroy(&chan->ic_sq_post_lock);
6839162SPeter.Dunlap@Sun.COM 
6849162SPeter.Dunlap@Sun.COM 	/* Ensure the RQ is empty */
6859162SPeter.Dunlap@Sun.COM 	(void) ibt_flush_channel(chan->ic_chanhdl);
6869162SPeter.Dunlap@Sun.COM 	mutex_enter(&iser_qp->qp_lock);
6879162SPeter.Dunlap@Sun.COM 	while (iser_qp->rq_level != 0) {
6889162SPeter.Dunlap@Sun.COM 		mutex_exit(&iser_qp->qp_lock);
6899162SPeter.Dunlap@Sun.COM 		mutex_exit(&chan->ic_conn->ic_lock);
6909162SPeter.Dunlap@Sun.COM 		delay(drv_usectohz(ISER_DELAY_HALF_SECOND));
6919162SPeter.Dunlap@Sun.COM 		mutex_enter(&chan->ic_conn->ic_lock);
6929162SPeter.Dunlap@Sun.COM 		mutex_enter(&iser_qp->qp_lock);
6939162SPeter.Dunlap@Sun.COM 	}
6949162SPeter.Dunlap@Sun.COM 
6959162SPeter.Dunlap@Sun.COM 	/* Free our QP handle */
6969162SPeter.Dunlap@Sun.COM 	mutex_exit(&iser_qp->qp_lock);
6979162SPeter.Dunlap@Sun.COM 	(void) iser_ib_fini_qp(iser_qp);
6989162SPeter.Dunlap@Sun.COM 
6999162SPeter.Dunlap@Sun.COM 	/* Free the IBT channel resources */
7009162SPeter.Dunlap@Sun.COM 	(void) ibt_free_channel(chan->ic_chanhdl);
7019162SPeter.Dunlap@Sun.COM 	chan->ic_chanhdl = NULL;
7029162SPeter.Dunlap@Sun.COM 
7039162SPeter.Dunlap@Sun.COM 	/* Free the CQs */
70411093SSrivijitha.Dugganapalli@Sun.COM 	(void) ibt_free_cq(chan->ic_sendcq);
70511093SSrivijitha.Dugganapalli@Sun.COM 	(void) ibt_free_cq(chan->ic_recvcq);
7069162SPeter.Dunlap@Sun.COM 
7079162SPeter.Dunlap@Sun.COM 	/* Free the chan handle */
70811078SPeter.Cudhea@Sun.COM 	mutex_destroy(&chan->ic_chan_lock);
7099162SPeter.Dunlap@Sun.COM 	kmem_free(chan, sizeof (iser_chan_t));
7109162SPeter.Dunlap@Sun.COM }
7119162SPeter.Dunlap@Sun.COM 
7129162SPeter.Dunlap@Sun.COM /*
7139162SPeter.Dunlap@Sun.COM  * iser_ib_post_recv
7149162SPeter.Dunlap@Sun.COM  *
7159162SPeter.Dunlap@Sun.COM  * This function handles keeping the RQ full on a given channel.
7169162SPeter.Dunlap@Sun.COM  * This routine will mostly be run on a taskq, and will check the
7179162SPeter.Dunlap@Sun.COM  * current fill level of the RQ, and post as many WRs as necessary
7189162SPeter.Dunlap@Sun.COM  * to fill it again.
7199162SPeter.Dunlap@Sun.COM  */
7209247SPeter.Dunlap@Sun.COM 
7219247SPeter.Dunlap@Sun.COM int
iser_ib_post_recv_async(ibt_channel_hdl_t chanhdl)7229247SPeter.Dunlap@Sun.COM iser_ib_post_recv_async(ibt_channel_hdl_t chanhdl)
7239247SPeter.Dunlap@Sun.COM {
7249247SPeter.Dunlap@Sun.COM 	iser_chan_t	*chan;
7259247SPeter.Dunlap@Sun.COM 	int		status;
7269247SPeter.Dunlap@Sun.COM 
7279247SPeter.Dunlap@Sun.COM 	/* Pull our iSER channel handle from the private data */
7289247SPeter.Dunlap@Sun.COM 	chan = (iser_chan_t *)ibt_get_chan_private(chanhdl);
7299247SPeter.Dunlap@Sun.COM 
7309586SPeter.Dunlap@Sun.COM 	/*
7319586SPeter.Dunlap@Sun.COM 	 * Caller must check that chan->ic_conn->ic_stage indicates
7329586SPeter.Dunlap@Sun.COM 	 * the connection is active (not closing, not closed) and
7339586SPeter.Dunlap@Sun.COM 	 * it must hold the mutex cross the check and the call to this function
7349586SPeter.Dunlap@Sun.COM 	 */
7359586SPeter.Dunlap@Sun.COM 	ASSERT(mutex_owned(&chan->ic_conn->ic_lock));
736*12485SPeter.Gill@Sun.COM 	ASSERT((chan->ic_conn->ic_stage >= ISER_CONN_STAGE_ALLOCATED) &&
7379586SPeter.Dunlap@Sun.COM 	    (chan->ic_conn->ic_stage <= ISER_CONN_STAGE_LOGGED_IN));
7389247SPeter.Dunlap@Sun.COM 	idm_conn_hold(chan->ic_conn->ic_idmc);
7399247SPeter.Dunlap@Sun.COM 	status = ddi_taskq_dispatch(iser_taskq, iser_ib_post_recv_task,
7409247SPeter.Dunlap@Sun.COM 	    (void *)chanhdl, DDI_NOSLEEP);
7419247SPeter.Dunlap@Sun.COM 	if (status != DDI_SUCCESS) {
7429247SPeter.Dunlap@Sun.COM 		idm_conn_rele(chan->ic_conn->ic_idmc);
7439247SPeter.Dunlap@Sun.COM 	}
7449247SPeter.Dunlap@Sun.COM 
7459247SPeter.Dunlap@Sun.COM 	return (status);
7469247SPeter.Dunlap@Sun.COM }
7479247SPeter.Dunlap@Sun.COM 
7489247SPeter.Dunlap@Sun.COM static void
iser_ib_post_recv_task(void * arg)7499247SPeter.Dunlap@Sun.COM iser_ib_post_recv_task(void *arg)
7509247SPeter.Dunlap@Sun.COM {
7519247SPeter.Dunlap@Sun.COM 	ibt_channel_hdl_t	chanhdl = arg;
7529247SPeter.Dunlap@Sun.COM 	iser_chan_t		*chan;
7539247SPeter.Dunlap@Sun.COM 
7549247SPeter.Dunlap@Sun.COM 	/* Pull our iSER channel handle from the private data */
7559247SPeter.Dunlap@Sun.COM 	chan = (iser_chan_t *)ibt_get_chan_private(chanhdl);
7569247SPeter.Dunlap@Sun.COM 
7579247SPeter.Dunlap@Sun.COM 	iser_ib_post_recv(chanhdl);
7589247SPeter.Dunlap@Sun.COM 	idm_conn_rele(chan->ic_conn->ic_idmc);
7599247SPeter.Dunlap@Sun.COM }
7609247SPeter.Dunlap@Sun.COM 
7619162SPeter.Dunlap@Sun.COM void
iser_ib_post_recv(ibt_channel_hdl_t chanhdl)7629247SPeter.Dunlap@Sun.COM iser_ib_post_recv(ibt_channel_hdl_t chanhdl)
7639162SPeter.Dunlap@Sun.COM {
7649162SPeter.Dunlap@Sun.COM 	iser_chan_t	*chan;
7659162SPeter.Dunlap@Sun.COM 	iser_hca_t	*hca;
7669162SPeter.Dunlap@Sun.COM 	iser_msg_t	*msg;
7679162SPeter.Dunlap@Sun.COM 	ibt_recv_wr_t	*wrlist, wr[ISER_IB_RQ_POST_MAX];
7689162SPeter.Dunlap@Sun.COM 	int		rq_space, msg_ret;
7699162SPeter.Dunlap@Sun.COM 	int		total_num, npost;
7709162SPeter.Dunlap@Sun.COM 	uint_t		nposted;
7719162SPeter.Dunlap@Sun.COM 	int		status, i;
7729162SPeter.Dunlap@Sun.COM 	iser_qp_t	*iser_qp;
7739162SPeter.Dunlap@Sun.COM 
7749162SPeter.Dunlap@Sun.COM 	/* Pull our iSER channel handle from the private data */
7759162SPeter.Dunlap@Sun.COM 	chan = (iser_chan_t *)ibt_get_chan_private(chanhdl);
7769162SPeter.Dunlap@Sun.COM 
7779247SPeter.Dunlap@Sun.COM 	ASSERT(chan != NULL);
7789247SPeter.Dunlap@Sun.COM 
7799162SPeter.Dunlap@Sun.COM 	mutex_enter(&chan->ic_conn->ic_lock);
7809162SPeter.Dunlap@Sun.COM 
7819162SPeter.Dunlap@Sun.COM 	/* Bail out if the connection is closed; no need for more recv WRs */
7829162SPeter.Dunlap@Sun.COM 	if ((chan->ic_conn->ic_stage == ISER_CONN_STAGE_CLOSING) ||
7839162SPeter.Dunlap@Sun.COM 	    (chan->ic_conn->ic_stage == ISER_CONN_STAGE_CLOSED)) {
7849162SPeter.Dunlap@Sun.COM 		mutex_exit(&chan->ic_conn->ic_lock);
7859162SPeter.Dunlap@Sun.COM 		return;
7869162SPeter.Dunlap@Sun.COM 	}
7879162SPeter.Dunlap@Sun.COM 
7889162SPeter.Dunlap@Sun.COM 	/* get the QP handle from the iser_chan */
7899162SPeter.Dunlap@Sun.COM 	iser_qp = &chan->ic_qp;
7909162SPeter.Dunlap@Sun.COM 
79110322SPriya.Krishnan@Sun.COM 	hca = chan->ic_hca;
7929162SPeter.Dunlap@Sun.COM 
7939162SPeter.Dunlap@Sun.COM 	if (hca == NULL) {
7949162SPeter.Dunlap@Sun.COM 		ISER_LOG(CE_NOTE, "iser_ib_post_recv: unable to retrieve "
7959162SPeter.Dunlap@Sun.COM 		    "HCA handle");
7969162SPeter.Dunlap@Sun.COM 		mutex_exit(&chan->ic_conn->ic_lock);
7979162SPeter.Dunlap@Sun.COM 		return;
7989162SPeter.Dunlap@Sun.COM 	}
7999162SPeter.Dunlap@Sun.COM 
8009162SPeter.Dunlap@Sun.COM 	/* check for space to post on the RQ */
8019162SPeter.Dunlap@Sun.COM 	mutex_enter(&iser_qp->qp_lock);
8029162SPeter.Dunlap@Sun.COM 	rq_space = iser_qp->rq_depth - iser_qp->rq_level;
8039162SPeter.Dunlap@Sun.COM 	if (rq_space == 0) {
8049162SPeter.Dunlap@Sun.COM 		/* The RQ is full, clear the pending flag and return */
8059162SPeter.Dunlap@Sun.COM 		iser_qp->rq_taskqpending = B_FALSE;
8069162SPeter.Dunlap@Sun.COM 		mutex_exit(&iser_qp->qp_lock);
8079162SPeter.Dunlap@Sun.COM 		mutex_exit(&chan->ic_conn->ic_lock);
8089162SPeter.Dunlap@Sun.COM 		return;
8099162SPeter.Dunlap@Sun.COM 	}
8109162SPeter.Dunlap@Sun.COM 
8119162SPeter.Dunlap@Sun.COM 	/* Keep track of the lowest value for rq_min_post_level */
8129162SPeter.Dunlap@Sun.COM 	if (iser_qp->rq_level < iser_qp->rq_min_post_level)
8139162SPeter.Dunlap@Sun.COM 		iser_qp->rq_min_post_level = iser_qp->rq_level;
8149162SPeter.Dunlap@Sun.COM 
8159162SPeter.Dunlap@Sun.COM 	mutex_exit(&iser_qp->qp_lock);
8169162SPeter.Dunlap@Sun.COM 
8179162SPeter.Dunlap@Sun.COM 	/* we've room to post, so pull from the msg cache */
8189162SPeter.Dunlap@Sun.COM 	msg = iser_msg_get(hca, rq_space, &msg_ret);
8199162SPeter.Dunlap@Sun.COM 	if (msg == NULL) {
8209162SPeter.Dunlap@Sun.COM 		ISER_LOG(CE_NOTE, "iser_ib_post_recv: no message handles "
8219162SPeter.Dunlap@Sun.COM 		    "available in msg cache currently");
8229162SPeter.Dunlap@Sun.COM 		/*
8239162SPeter.Dunlap@Sun.COM 		 * There are no messages on the cache. Wait a half-
8249162SPeter.Dunlap@Sun.COM 		 * second, then try again.
8259162SPeter.Dunlap@Sun.COM 		 */
8269162SPeter.Dunlap@Sun.COM 		delay(drv_usectohz(ISER_DELAY_HALF_SECOND));
8279247SPeter.Dunlap@Sun.COM 		status = iser_ib_post_recv_async(chanhdl);
8289162SPeter.Dunlap@Sun.COM 		if (status != DDI_SUCCESS) {
8299162SPeter.Dunlap@Sun.COM 			ISER_LOG(CE_NOTE, "iser_ib_post_recv: failed to "
8309162SPeter.Dunlap@Sun.COM 			    "redispatch routine");
8319162SPeter.Dunlap@Sun.COM 			/* Failed to dispatch, clear pending flag */
8329162SPeter.Dunlap@Sun.COM 			mutex_enter(&iser_qp->qp_lock);
8339162SPeter.Dunlap@Sun.COM 			iser_qp->rq_taskqpending = B_FALSE;
8349162SPeter.Dunlap@Sun.COM 			mutex_exit(&iser_qp->qp_lock);
8359162SPeter.Dunlap@Sun.COM 		}
8369162SPeter.Dunlap@Sun.COM 		mutex_exit(&chan->ic_conn->ic_lock);
8379162SPeter.Dunlap@Sun.COM 		return;
8389162SPeter.Dunlap@Sun.COM 	}
8399162SPeter.Dunlap@Sun.COM 
8409162SPeter.Dunlap@Sun.COM 	if (msg_ret != rq_space) {
8419162SPeter.Dunlap@Sun.COM 		ISER_LOG(CE_NOTE, "iser_ib_post_recv: requested number of "
8429162SPeter.Dunlap@Sun.COM 		    "messages not allocated: requested (%d) allocated (%d)",
8439162SPeter.Dunlap@Sun.COM 		    rq_space, msg_ret);
8449162SPeter.Dunlap@Sun.COM 		/* We got some, but not all, of our requested depth */
8459162SPeter.Dunlap@Sun.COM 		rq_space = msg_ret;
8469162SPeter.Dunlap@Sun.COM 	}
8479162SPeter.Dunlap@Sun.COM 
8489162SPeter.Dunlap@Sun.COM 	/*
8499162SPeter.Dunlap@Sun.COM 	 * Now, walk through the allocated WRs and post them,
8509162SPeter.Dunlap@Sun.COM 	 * ISER_IB_RQ_POST_MAX (or less) at a time.
8519162SPeter.Dunlap@Sun.COM 	 */
8529162SPeter.Dunlap@Sun.COM 	wrlist = &wr[0];
8539162SPeter.Dunlap@Sun.COM 	total_num = rq_space;
8549162SPeter.Dunlap@Sun.COM 
8559162SPeter.Dunlap@Sun.COM 	while (total_num) {
8569162SPeter.Dunlap@Sun.COM 		/* determine the number to post on this iteration */
8579162SPeter.Dunlap@Sun.COM 		npost = (total_num > ISER_IB_RQ_POST_MAX) ?
8589162SPeter.Dunlap@Sun.COM 		    ISER_IB_RQ_POST_MAX : total_num;
8599162SPeter.Dunlap@Sun.COM 
8609162SPeter.Dunlap@Sun.COM 		/* build a list of WRs from the msg list */
8619162SPeter.Dunlap@Sun.COM 		for (i = 0; i < npost; i++) {
8629162SPeter.Dunlap@Sun.COM 			wrlist[i].wr_id		= (ibt_wrid_t)(uintptr_t)msg;
8639162SPeter.Dunlap@Sun.COM 			wrlist[i].wr_nds	= ISER_IB_SGLIST_SIZE;
8649162SPeter.Dunlap@Sun.COM 			wrlist[i].wr_sgl	= &msg->msg_ds;
8659162SPeter.Dunlap@Sun.COM 			msg = msg->nextp;
8669162SPeter.Dunlap@Sun.COM 		}
8679162SPeter.Dunlap@Sun.COM 
8689162SPeter.Dunlap@Sun.COM 		/* post the list to the RQ */
8699162SPeter.Dunlap@Sun.COM 		nposted = 0;
8709162SPeter.Dunlap@Sun.COM 		status = ibt_post_recv(chanhdl, wrlist, npost, &nposted);
8719162SPeter.Dunlap@Sun.COM 		if ((status != IBT_SUCCESS) || (nposted != npost)) {
8729162SPeter.Dunlap@Sun.COM 			ISER_LOG(CE_NOTE, "iser_ib_post_recv: ibt_post_recv "
8739162SPeter.Dunlap@Sun.COM 			    "failed: requested (%d) posted (%d) status (%d)",
8749162SPeter.Dunlap@Sun.COM 			    npost, nposted, status);
8759162SPeter.Dunlap@Sun.COM 			total_num -= nposted;
8769162SPeter.Dunlap@Sun.COM 			break;
8779162SPeter.Dunlap@Sun.COM 		}
8789162SPeter.Dunlap@Sun.COM 
8799162SPeter.Dunlap@Sun.COM 		/* decrement total number to post by the number posted */
8809162SPeter.Dunlap@Sun.COM 		total_num -= nposted;
8819162SPeter.Dunlap@Sun.COM 	}
8829162SPeter.Dunlap@Sun.COM 
8839162SPeter.Dunlap@Sun.COM 	mutex_enter(&iser_qp->qp_lock);
8849162SPeter.Dunlap@Sun.COM 	if (total_num != 0) {
8859162SPeter.Dunlap@Sun.COM 		ISER_LOG(CE_NOTE, "iser_ib_post_recv: unable to fill RQ, "
8869162SPeter.Dunlap@Sun.COM 		    "failed to post (%d) WRs", total_num);
8879162SPeter.Dunlap@Sun.COM 		iser_qp->rq_level += rq_space - total_num;
8889162SPeter.Dunlap@Sun.COM 	} else {
8899162SPeter.Dunlap@Sun.COM 		iser_qp->rq_level += rq_space;
8909162SPeter.Dunlap@Sun.COM 	}
8919162SPeter.Dunlap@Sun.COM 
8929162SPeter.Dunlap@Sun.COM 	/*
8939162SPeter.Dunlap@Sun.COM 	 * Now that we've filled the RQ, check that all of the recv WRs
8949162SPeter.Dunlap@Sun.COM 	 * haven't just been immediately consumed. If so, taskqpending is
8959162SPeter.Dunlap@Sun.COM 	 * still B_TRUE, so we need to fire off a taskq thread to post
8969162SPeter.Dunlap@Sun.COM 	 * more WRs.
8979162SPeter.Dunlap@Sun.COM 	 */
8989162SPeter.Dunlap@Sun.COM 	if (iser_qp->rq_level == 0) {
8999162SPeter.Dunlap@Sun.COM 		mutex_exit(&iser_qp->qp_lock);
9009247SPeter.Dunlap@Sun.COM 		status = iser_ib_post_recv_async(chanhdl);
9019162SPeter.Dunlap@Sun.COM 		if (status != DDI_SUCCESS) {
9029162SPeter.Dunlap@Sun.COM 			ISER_LOG(CE_NOTE, "iser_ib_post_recv: failed to "
9039162SPeter.Dunlap@Sun.COM 			    "dispatch followup routine");
9049162SPeter.Dunlap@Sun.COM 			/* Failed to dispatch, clear pending flag */
9059162SPeter.Dunlap@Sun.COM 			mutex_enter(&iser_qp->qp_lock);
9069162SPeter.Dunlap@Sun.COM 			iser_qp->rq_taskqpending = B_FALSE;
9079162SPeter.Dunlap@Sun.COM 			mutex_exit(&iser_qp->qp_lock);
9089162SPeter.Dunlap@Sun.COM 		}
9099162SPeter.Dunlap@Sun.COM 	} else {
9109162SPeter.Dunlap@Sun.COM 		/*
9119162SPeter.Dunlap@Sun.COM 		 * We're done, we've filled the RQ. Clear the taskq
9129162SPeter.Dunlap@Sun.COM 		 * flag so that we can run again.
9139162SPeter.Dunlap@Sun.COM 		 */
9149162SPeter.Dunlap@Sun.COM 		iser_qp->rq_taskqpending = B_FALSE;
9159162SPeter.Dunlap@Sun.COM 		mutex_exit(&iser_qp->qp_lock);
9169162SPeter.Dunlap@Sun.COM 	}
9179162SPeter.Dunlap@Sun.COM 
9189162SPeter.Dunlap@Sun.COM 	mutex_exit(&chan->ic_conn->ic_lock);
9199162SPeter.Dunlap@Sun.COM }
9209162SPeter.Dunlap@Sun.COM 
9219162SPeter.Dunlap@Sun.COM /*
9229162SPeter.Dunlap@Sun.COM  * iser_ib_handle_portup_event()
9239162SPeter.Dunlap@Sun.COM  * This handles the IBT_EVENT_PORT_UP unaffiliated asynchronous event.
9249162SPeter.Dunlap@Sun.COM  *
9259162SPeter.Dunlap@Sun.COM  * To facilitate a seamless bringover of the port and configure the CM service
9269162SPeter.Dunlap@Sun.COM  * for inbound iSER service requests on this newly active port, the existing
9279162SPeter.Dunlap@Sun.COM  * IDM services will be checked for iSER support.
9289162SPeter.Dunlap@Sun.COM  * If an iSER service was already created, then this service will simply be
9299162SPeter.Dunlap@Sun.COM  * bound to the gid of the newly active port. If on the other hand, the CM
9309162SPeter.Dunlap@Sun.COM  * service did not exist, i.e. only socket communication, then a new CM
9319162SPeter.Dunlap@Sun.COM  * service will be first registered with the saved service parameters and
9329162SPeter.Dunlap@Sun.COM  * then bound to the newly active port.
9339162SPeter.Dunlap@Sun.COM  *
9349162SPeter.Dunlap@Sun.COM  */
9359162SPeter.Dunlap@Sun.COM /* ARGSUSED */
9369162SPeter.Dunlap@Sun.COM static void
iser_ib_handle_portup_event(ibt_hca_hdl_t hdl,ibt_async_event_t * event)9379162SPeter.Dunlap@Sun.COM iser_ib_handle_portup_event(ibt_hca_hdl_t hdl, ibt_async_event_t *event)
9389162SPeter.Dunlap@Sun.COM {
9399162SPeter.Dunlap@Sun.COM 	iser_hca_t		*hca;
9409162SPeter.Dunlap@Sun.COM 	ib_gid_t		gid;
9419162SPeter.Dunlap@Sun.COM 	idm_svc_t		*idm_svc;
9429162SPeter.Dunlap@Sun.COM 	int			status;
9439162SPeter.Dunlap@Sun.COM 
9449162SPeter.Dunlap@Sun.COM 	ISER_LOG(CE_NOTE, "iser_ib_handle_portup_event: HCA(0x%llx) port(%d)",
9459162SPeter.Dunlap@Sun.COM 	    (longlong_t)event->ev_hca_guid, event->ev_port);
9469162SPeter.Dunlap@Sun.COM 
9479162SPeter.Dunlap@Sun.COM 	/*
9489162SPeter.Dunlap@Sun.COM 	 * Query all ports on the HCA and update the port information
9499162SPeter.Dunlap@Sun.COM 	 * maintainted in the iser_hca_t structure
9509162SPeter.Dunlap@Sun.COM 	 */
9519162SPeter.Dunlap@Sun.COM 	hca = iser_ib_guid2hca(event->ev_hca_guid);
9529162SPeter.Dunlap@Sun.COM 	if (hca == NULL) {
9539162SPeter.Dunlap@Sun.COM 
9549162SPeter.Dunlap@Sun.COM 		/* HCA is just made available, first port on that HCA */
9559162SPeter.Dunlap@Sun.COM 		hca = iser_ib_alloc_hca(event->ev_hca_guid);
95610775SPriya.Krishnan@Sun.COM 		if (hca == NULL) {
95710775SPriya.Krishnan@Sun.COM 			ISER_LOG(CE_NOTE, "iser_ib_handle_portup_event "
95810775SPriya.Krishnan@Sun.COM 			    "iser_ib_alloc_hca failed: HCA(0x%llx) port(%d)",
95910775SPriya.Krishnan@Sun.COM 			    (longlong_t)event->ev_hca_guid, event->ev_port);
96010775SPriya.Krishnan@Sun.COM 			return;
96110775SPriya.Krishnan@Sun.COM 		}
9629162SPeter.Dunlap@Sun.COM 		mutex_enter(&iser_state->is_hcalist_lock);
9639162SPeter.Dunlap@Sun.COM 		list_insert_tail(&iser_state->is_hcalist, hca);
9649162SPeter.Dunlap@Sun.COM 		iser_state->is_num_hcas++;
9659162SPeter.Dunlap@Sun.COM 		mutex_exit(&iser_state->is_hcalist_lock);
9669162SPeter.Dunlap@Sun.COM 
9679162SPeter.Dunlap@Sun.COM 	} else {
9689162SPeter.Dunlap@Sun.COM 
9699162SPeter.Dunlap@Sun.COM 		status = iser_ib_update_hcaports(hca);
9709162SPeter.Dunlap@Sun.COM 
9719162SPeter.Dunlap@Sun.COM 		if (status != IBT_SUCCESS) {
9729162SPeter.Dunlap@Sun.COM 			ISER_LOG(CE_NOTE, "iser_ib_handle_portup_event "
9739162SPeter.Dunlap@Sun.COM 			    "status(0x%x): iser_ib_update_hcaports failed: "
9749162SPeter.Dunlap@Sun.COM 			    "HCA(0x%llx) port(%d)", status,
9759162SPeter.Dunlap@Sun.COM 			    (longlong_t)event->ev_hca_guid, event->ev_port);
9769162SPeter.Dunlap@Sun.COM 			return;
9779162SPeter.Dunlap@Sun.COM 		}
9789162SPeter.Dunlap@Sun.COM 	}
9799162SPeter.Dunlap@Sun.COM 
9809162SPeter.Dunlap@Sun.COM 	gid = hca->hca_port_info[event->ev_port - 1].p_sgid_tbl[0];
9819162SPeter.Dunlap@Sun.COM 
9829162SPeter.Dunlap@Sun.COM 	/*
9839162SPeter.Dunlap@Sun.COM 	 * Iterate through the global list of IDM target services
9849162SPeter.Dunlap@Sun.COM 	 * and check for existing iSER CM service.
9859162SPeter.Dunlap@Sun.COM 	 */
9869162SPeter.Dunlap@Sun.COM 	mutex_enter(&idm.idm_global_mutex);
9879162SPeter.Dunlap@Sun.COM 	for (idm_svc = list_head(&idm.idm_tgt_svc_list);
9889162SPeter.Dunlap@Sun.COM 	    idm_svc != NULL;
9899162SPeter.Dunlap@Sun.COM 	    idm_svc = list_next(&idm.idm_tgt_svc_list, idm_svc)) {
9909162SPeter.Dunlap@Sun.COM 
9919162SPeter.Dunlap@Sun.COM 
9929162SPeter.Dunlap@Sun.COM 		if (idm_svc->is_iser_svc == NULL) {
9939162SPeter.Dunlap@Sun.COM 
9949162SPeter.Dunlap@Sun.COM 			/* Establish a new CM service for iSER requests */
9959162SPeter.Dunlap@Sun.COM 			status = iser_tgt_svc_create(
9969162SPeter.Dunlap@Sun.COM 			    &idm_svc->is_svc_req, idm_svc);
9979162SPeter.Dunlap@Sun.COM 
9989162SPeter.Dunlap@Sun.COM 			if (status != IBT_SUCCESS) {
9999162SPeter.Dunlap@Sun.COM 				ISER_LOG(CE_NOTE, "iser_ib_handle_portup_event "
10009162SPeter.Dunlap@Sun.COM 				    "status(0x%x): iser_tgt_svc_create failed: "
10019162SPeter.Dunlap@Sun.COM 				    "HCA(0x%llx) port(%d)", status,
10029162SPeter.Dunlap@Sun.COM 				    (longlong_t)event->ev_hca_guid,
10039162SPeter.Dunlap@Sun.COM 				    event->ev_port);
10049162SPeter.Dunlap@Sun.COM 
10059162SPeter.Dunlap@Sun.COM 				continue;
10069162SPeter.Dunlap@Sun.COM 			}
10079162SPeter.Dunlap@Sun.COM 		}
10089162SPeter.Dunlap@Sun.COM 
10099162SPeter.Dunlap@Sun.COM 		status = iser_ib_activate_port(
10109162SPeter.Dunlap@Sun.COM 		    idm_svc, event->ev_hca_guid, gid);
10119162SPeter.Dunlap@Sun.COM 		if (status != IBT_SUCCESS) {
10129162SPeter.Dunlap@Sun.COM 
10139162SPeter.Dunlap@Sun.COM 			ISER_LOG(CE_NOTE, "iser_ib_handle_portup_event "
10149162SPeter.Dunlap@Sun.COM 			    "status(0x%x): Bind service on port "
10159162SPeter.Dunlap@Sun.COM 			    "(%llx:%llx) failed",
10169162SPeter.Dunlap@Sun.COM 			    status, (longlong_t)gid.gid_prefix,
10179162SPeter.Dunlap@Sun.COM 			    (longlong_t)gid.gid_guid);
10189162SPeter.Dunlap@Sun.COM 
10199162SPeter.Dunlap@Sun.COM 			continue;
10209162SPeter.Dunlap@Sun.COM 		}
10219162SPeter.Dunlap@Sun.COM 		ISER_LOG(CE_NOTE, "iser_ib_handle_portup_event: service bound "
10229162SPeter.Dunlap@Sun.COM 		    "HCA(0x%llx) port(%d)", (longlong_t)event->ev_hca_guid,
10239162SPeter.Dunlap@Sun.COM 		    event->ev_port);
10249162SPeter.Dunlap@Sun.COM 	}
10259162SPeter.Dunlap@Sun.COM 	mutex_exit(&idm.idm_global_mutex);
10269162SPeter.Dunlap@Sun.COM 
10279162SPeter.Dunlap@Sun.COM 	ISER_LOG(CE_NOTE, "iser_ib_handle_portup_event success: "
10289162SPeter.Dunlap@Sun.COM 	    "HCA(0x%llx) port(%d)", (longlong_t)event->ev_hca_guid,
10299162SPeter.Dunlap@Sun.COM 	    event->ev_port);
10309162SPeter.Dunlap@Sun.COM }
10319162SPeter.Dunlap@Sun.COM 
10329162SPeter.Dunlap@Sun.COM /*
10339162SPeter.Dunlap@Sun.COM  * iser_ib_handle_portdown_event()
10349162SPeter.Dunlap@Sun.COM  * This handles the IBT_EVENT_PORT_DOWN unaffiliated asynchronous error.
10359162SPeter.Dunlap@Sun.COM  *
10369162SPeter.Dunlap@Sun.COM  * Unconfigure the CM service on the deactivated port and teardown the
10379162SPeter.Dunlap@Sun.COM  * connections that are using the CM service.
10389162SPeter.Dunlap@Sun.COM  */
10399162SPeter.Dunlap@Sun.COM /* ARGSUSED */
10409162SPeter.Dunlap@Sun.COM static void
iser_ib_handle_portdown_event(ibt_hca_hdl_t hdl,ibt_async_event_t * event)10419162SPeter.Dunlap@Sun.COM iser_ib_handle_portdown_event(ibt_hca_hdl_t hdl, ibt_async_event_t *event)
10429162SPeter.Dunlap@Sun.COM {
10439162SPeter.Dunlap@Sun.COM 	iser_hca_t		*hca;
10449162SPeter.Dunlap@Sun.COM 	ib_gid_t		gid;
10459162SPeter.Dunlap@Sun.COM 	int			status;
10469162SPeter.Dunlap@Sun.COM 
10479162SPeter.Dunlap@Sun.COM 	/*
10489162SPeter.Dunlap@Sun.COM 	 * Query all ports on the HCA and update the port information
10499162SPeter.Dunlap@Sun.COM 	 * maintainted in the iser_hca_t structure
10509162SPeter.Dunlap@Sun.COM 	 */
10519162SPeter.Dunlap@Sun.COM 	hca = iser_ib_guid2hca(event->ev_hca_guid);
10529162SPeter.Dunlap@Sun.COM 	ASSERT(hca != NULL);
10539162SPeter.Dunlap@Sun.COM 
10549162SPeter.Dunlap@Sun.COM 	status = iser_ib_update_hcaports(hca);
10559162SPeter.Dunlap@Sun.COM 	if (status != IBT_SUCCESS) {
10569162SPeter.Dunlap@Sun.COM 		ISER_LOG(CE_NOTE, "iser_ib_handle_portdown_event status(0x%x): "
10579162SPeter.Dunlap@Sun.COM 		    "ibt_ib_update_hcaports failed: HCA(0x%llx) port(%d)",
10589162SPeter.Dunlap@Sun.COM 		    status, (longlong_t)event->ev_hca_guid, event->ev_port);
10599162SPeter.Dunlap@Sun.COM 		return;
10609162SPeter.Dunlap@Sun.COM 	}
10619162SPeter.Dunlap@Sun.COM 
10629162SPeter.Dunlap@Sun.COM 	/* get the gid of the new port */
10639162SPeter.Dunlap@Sun.COM 	gid = hca->hca_port_info[event->ev_port - 1].p_sgid_tbl[0];
10649162SPeter.Dunlap@Sun.COM 	iser_ib_deactivate_port(event->ev_hca_guid, gid);
10659162SPeter.Dunlap@Sun.COM 
10669162SPeter.Dunlap@Sun.COM 	ISER_LOG(CE_NOTE, "iser_ib_handle_portdown_event success: "
10679162SPeter.Dunlap@Sun.COM 	    "HCA(0x%llx) port(%d)", (longlong_t)event->ev_hca_guid,
10689162SPeter.Dunlap@Sun.COM 	    event->ev_port);
10699162SPeter.Dunlap@Sun.COM }
10709162SPeter.Dunlap@Sun.COM 
10719162SPeter.Dunlap@Sun.COM /*
10729162SPeter.Dunlap@Sun.COM  * iser_ib_handle_hca_detach_event()
10739162SPeter.Dunlap@Sun.COM  * Quiesce all activity bound for the port, teardown the connection, unbind
10749162SPeter.Dunlap@Sun.COM  * iSER services on all ports and release the HCA handle.
10759162SPeter.Dunlap@Sun.COM  */
10769162SPeter.Dunlap@Sun.COM /* ARGSUSED */
10779162SPeter.Dunlap@Sun.COM static void
iser_ib_handle_hca_detach_event(ibt_hca_hdl_t hdl,ibt_async_event_t * event)10789162SPeter.Dunlap@Sun.COM iser_ib_handle_hca_detach_event(ibt_hca_hdl_t hdl, ibt_async_event_t *event)
10799162SPeter.Dunlap@Sun.COM {
10809162SPeter.Dunlap@Sun.COM 	iser_hca_t	*nexthca, *hca;
10819162SPeter.Dunlap@Sun.COM 	int		i, status;
10829162SPeter.Dunlap@Sun.COM 
10839162SPeter.Dunlap@Sun.COM 	ISER_LOG(CE_NOTE, "iser_ib_handle_hca_detach_event: HCA(0x%llx)",
10849162SPeter.Dunlap@Sun.COM 	    (longlong_t)event->ev_hca_guid);
10859162SPeter.Dunlap@Sun.COM 
10869162SPeter.Dunlap@Sun.COM 	hca = iser_ib_guid2hca(event->ev_hca_guid);
10879162SPeter.Dunlap@Sun.COM 	for (i = 0; i < hca->hca_num_ports; i++) {
10889162SPeter.Dunlap@Sun.COM 		iser_ib_deactivate_port(hca->hca_guid,
10899162SPeter.Dunlap@Sun.COM 		    hca->hca_port_info[i].p_sgid_tbl[0]);
10909162SPeter.Dunlap@Sun.COM 	}
10919162SPeter.Dunlap@Sun.COM 
10929162SPeter.Dunlap@Sun.COM 	/*
10939162SPeter.Dunlap@Sun.COM 	 * Update the HCA list maintained in the iser_state. Free the
10949162SPeter.Dunlap@Sun.COM 	 * resources allocated to the HCA, i.e. caches, protection domain
10959162SPeter.Dunlap@Sun.COM 	 */
10969162SPeter.Dunlap@Sun.COM 	mutex_enter(&iser_state->is_hcalist_lock);
10979162SPeter.Dunlap@Sun.COM 
10989162SPeter.Dunlap@Sun.COM 	for (hca = list_head(&iser_state->is_hcalist);
10999162SPeter.Dunlap@Sun.COM 	    hca != NULL;
11009162SPeter.Dunlap@Sun.COM 	    hca = nexthca) {
11019162SPeter.Dunlap@Sun.COM 
11029162SPeter.Dunlap@Sun.COM 		nexthca = list_next(&iser_state->is_hcalist, hca);
11039162SPeter.Dunlap@Sun.COM 
11049162SPeter.Dunlap@Sun.COM 		if (hca->hca_guid == event->ev_hca_guid) {
11059162SPeter.Dunlap@Sun.COM 
11069162SPeter.Dunlap@Sun.COM 			list_remove(&iser_state->is_hcalist, hca);
11079162SPeter.Dunlap@Sun.COM 			iser_state->is_num_hcas--;
11089162SPeter.Dunlap@Sun.COM 
11099162SPeter.Dunlap@Sun.COM 			status = iser_ib_free_hca(hca);
11109162SPeter.Dunlap@Sun.COM 			if (status != DDI_SUCCESS) {
11119162SPeter.Dunlap@Sun.COM 				ISER_LOG(CE_WARN, "iser_ib_handle_hca_detach: "
11129162SPeter.Dunlap@Sun.COM 				    "Failed to free hca(%p)", (void *)hca);
11139162SPeter.Dunlap@Sun.COM 				list_insert_tail(&iser_state->is_hcalist, hca);
11149162SPeter.Dunlap@Sun.COM 				iser_state->is_num_hcas++;
11159162SPeter.Dunlap@Sun.COM 			}
11169162SPeter.Dunlap@Sun.COM 			/* No way to return status to IBT if this fails */
11179162SPeter.Dunlap@Sun.COM 		}
11189162SPeter.Dunlap@Sun.COM 	}
11199162SPeter.Dunlap@Sun.COM 	mutex_exit(&iser_state->is_hcalist_lock);
11209162SPeter.Dunlap@Sun.COM 
11219162SPeter.Dunlap@Sun.COM }
11229162SPeter.Dunlap@Sun.COM 
11239162SPeter.Dunlap@Sun.COM /*
11249162SPeter.Dunlap@Sun.COM  * iser_ib_async_handler
11259162SPeter.Dunlap@Sun.COM  * An IBT Asynchronous Event handler is registered it with the framework and
11269162SPeter.Dunlap@Sun.COM  * passed via the ibt_attach() routine. This function handles the following
11279162SPeter.Dunlap@Sun.COM  * asynchronous events.
11289162SPeter.Dunlap@Sun.COM  * IBT_EVENT_PORT_UP
11299162SPeter.Dunlap@Sun.COM  * IBT_ERROR_PORT_DOWN
11309162SPeter.Dunlap@Sun.COM  * IBT_HCA_ATTACH_EVENT
11319162SPeter.Dunlap@Sun.COM  * IBT_HCA_DETACH_EVENT
11329162SPeter.Dunlap@Sun.COM  */
11339162SPeter.Dunlap@Sun.COM /* ARGSUSED */
11349162SPeter.Dunlap@Sun.COM void
iser_ib_async_handler(void * clntp,ibt_hca_hdl_t hdl,ibt_async_code_t code,ibt_async_event_t * event)11359162SPeter.Dunlap@Sun.COM iser_ib_async_handler(void *clntp, ibt_hca_hdl_t hdl, ibt_async_code_t code,
11369162SPeter.Dunlap@Sun.COM     ibt_async_event_t *event)
11379162SPeter.Dunlap@Sun.COM {
11389162SPeter.Dunlap@Sun.COM 	switch (code) {
11399162SPeter.Dunlap@Sun.COM 	case IBT_EVENT_PORT_UP:
11409162SPeter.Dunlap@Sun.COM 		iser_ib_handle_portup_event(hdl, event);
11419162SPeter.Dunlap@Sun.COM 		break;
11429162SPeter.Dunlap@Sun.COM 
11439162SPeter.Dunlap@Sun.COM 	case IBT_ERROR_PORT_DOWN:
11449162SPeter.Dunlap@Sun.COM 		iser_ib_handle_portdown_event(hdl, event);
11459162SPeter.Dunlap@Sun.COM 		break;
11469162SPeter.Dunlap@Sun.COM 
11479162SPeter.Dunlap@Sun.COM 	case IBT_HCA_ATTACH_EVENT:
11489162SPeter.Dunlap@Sun.COM 		/*
11499162SPeter.Dunlap@Sun.COM 		 * A new HCA device is available for use, ignore this
11509162SPeter.Dunlap@Sun.COM 		 * event because the corresponding IBT_EVENT_PORT_UP
11519162SPeter.Dunlap@Sun.COM 		 * events will get triggered and handled accordingly.
11529162SPeter.Dunlap@Sun.COM 		 */
11539162SPeter.Dunlap@Sun.COM 		break;
11549162SPeter.Dunlap@Sun.COM 
11559162SPeter.Dunlap@Sun.COM 	case IBT_HCA_DETACH_EVENT:
11569162SPeter.Dunlap@Sun.COM 		iser_ib_handle_hca_detach_event(hdl, event);
11579162SPeter.Dunlap@Sun.COM 		break;
11589162SPeter.Dunlap@Sun.COM 
11599162SPeter.Dunlap@Sun.COM 	default:
11609162SPeter.Dunlap@Sun.COM 		break;
11619162SPeter.Dunlap@Sun.COM 	}
11629162SPeter.Dunlap@Sun.COM }
11639162SPeter.Dunlap@Sun.COM 
11649162SPeter.Dunlap@Sun.COM /*
11659162SPeter.Dunlap@Sun.COM  * iser_ib_init_hcas
11669162SPeter.Dunlap@Sun.COM  *
11679162SPeter.Dunlap@Sun.COM  * This function opens all the HCA devices, gathers the HCA state information
11689162SPeter.Dunlap@Sun.COM  * and adds the HCA handle for each HCA found in the iser_soft_state.
11699162SPeter.Dunlap@Sun.COM  */
11709162SPeter.Dunlap@Sun.COM static int
iser_ib_init_hcas(void)11719162SPeter.Dunlap@Sun.COM iser_ib_init_hcas(void)
11729162SPeter.Dunlap@Sun.COM {
11739162SPeter.Dunlap@Sun.COM 	ib_guid_t	*guid;
11749162SPeter.Dunlap@Sun.COM 	int		num_hcas;
11759162SPeter.Dunlap@Sun.COM 	int		i;
11769162SPeter.Dunlap@Sun.COM 	iser_hca_t	*hca;
11779162SPeter.Dunlap@Sun.COM 
11789162SPeter.Dunlap@Sun.COM 	/* Retrieve the HCA list */
11799162SPeter.Dunlap@Sun.COM 	num_hcas = ibt_get_hca_list(&guid);
11809162SPeter.Dunlap@Sun.COM 	if (num_hcas == 0) {
11819162SPeter.Dunlap@Sun.COM 		/*
11829162SPeter.Dunlap@Sun.COM 		 * This shouldn't happen, but might if we have all HCAs
11839162SPeter.Dunlap@Sun.COM 		 * detach prior to initialization.
11849162SPeter.Dunlap@Sun.COM 		 */
11859162SPeter.Dunlap@Sun.COM 		return (DDI_FAILURE);
11869162SPeter.Dunlap@Sun.COM 	}
11879162SPeter.Dunlap@Sun.COM 
11889162SPeter.Dunlap@Sun.COM 	/* Initialize the hcalist lock */
11899162SPeter.Dunlap@Sun.COM 	mutex_init(&iser_state->is_hcalist_lock, NULL, MUTEX_DRIVER, NULL);
11909162SPeter.Dunlap@Sun.COM 
11919162SPeter.Dunlap@Sun.COM 	/* Create the HCA list */
11929162SPeter.Dunlap@Sun.COM 	list_create(&iser_state->is_hcalist, sizeof (iser_hca_t),
11939162SPeter.Dunlap@Sun.COM 	    offsetof(iser_hca_t, hca_node));
11949162SPeter.Dunlap@Sun.COM 
11959162SPeter.Dunlap@Sun.COM 	for (i = 0; i < num_hcas; i++) {
11969162SPeter.Dunlap@Sun.COM 
11979162SPeter.Dunlap@Sun.COM 		ISER_LOG(CE_NOTE, "iser_ib_init_hcas: initializing HCA "
11989162SPeter.Dunlap@Sun.COM 		    "(0x%llx)", (longlong_t)guid[i]);
11999162SPeter.Dunlap@Sun.COM 
12009162SPeter.Dunlap@Sun.COM 		hca = iser_ib_alloc_hca(guid[i]);
12019162SPeter.Dunlap@Sun.COM 		if (hca == NULL) {
12029162SPeter.Dunlap@Sun.COM 			/* This shouldn't happen, teardown and fail */
12039162SPeter.Dunlap@Sun.COM 			(void) iser_ib_fini_hcas();
12049162SPeter.Dunlap@Sun.COM 			(void) ibt_free_hca_list(guid, num_hcas);
12059162SPeter.Dunlap@Sun.COM 			return (DDI_FAILURE);
12069162SPeter.Dunlap@Sun.COM 		}
12079162SPeter.Dunlap@Sun.COM 
12089162SPeter.Dunlap@Sun.COM 		mutex_enter(&iser_state->is_hcalist_lock);
12099162SPeter.Dunlap@Sun.COM 		list_insert_tail(&iser_state->is_hcalist, hca);
12109162SPeter.Dunlap@Sun.COM 		iser_state->is_num_hcas++;
12119162SPeter.Dunlap@Sun.COM 		mutex_exit(&iser_state->is_hcalist_lock);
12129162SPeter.Dunlap@Sun.COM 
12139162SPeter.Dunlap@Sun.COM 	}
12149162SPeter.Dunlap@Sun.COM 
12159162SPeter.Dunlap@Sun.COM 	/* Free the IBT HCA list */
12169162SPeter.Dunlap@Sun.COM 	(void) ibt_free_hca_list(guid, num_hcas);
12179162SPeter.Dunlap@Sun.COM 
12189162SPeter.Dunlap@Sun.COM 	/* Check that we've initialized at least one HCA */
12199162SPeter.Dunlap@Sun.COM 	mutex_enter(&iser_state->is_hcalist_lock);
12209162SPeter.Dunlap@Sun.COM 	if (list_is_empty(&iser_state->is_hcalist)) {
12219162SPeter.Dunlap@Sun.COM 		ISER_LOG(CE_NOTE, "iser_ib_init_hcas: failed to initialize "
12229162SPeter.Dunlap@Sun.COM 		    "any HCAs");
12239162SPeter.Dunlap@Sun.COM 
12249162SPeter.Dunlap@Sun.COM 		mutex_exit(&iser_state->is_hcalist_lock);
12259162SPeter.Dunlap@Sun.COM 		(void) iser_ib_fini_hcas();
12269162SPeter.Dunlap@Sun.COM 		return (DDI_FAILURE);
12279162SPeter.Dunlap@Sun.COM 	}
12289162SPeter.Dunlap@Sun.COM 	mutex_exit(&iser_state->is_hcalist_lock);
12299162SPeter.Dunlap@Sun.COM 
12309162SPeter.Dunlap@Sun.COM 	return (DDI_SUCCESS);
12319162SPeter.Dunlap@Sun.COM }
12329162SPeter.Dunlap@Sun.COM 
12339162SPeter.Dunlap@Sun.COM /*
12349162SPeter.Dunlap@Sun.COM  * iser_ib_fini_hcas
12359162SPeter.Dunlap@Sun.COM  *
12369162SPeter.Dunlap@Sun.COM  * Teardown the iSER HCA list initialized above.
12379162SPeter.Dunlap@Sun.COM  */
12389162SPeter.Dunlap@Sun.COM static int
iser_ib_fini_hcas(void)12399162SPeter.Dunlap@Sun.COM iser_ib_fini_hcas(void)
12409162SPeter.Dunlap@Sun.COM {
12419162SPeter.Dunlap@Sun.COM 	iser_hca_t	*nexthca, *hca;
12429162SPeter.Dunlap@Sun.COM 	int		status;
12439162SPeter.Dunlap@Sun.COM 
12449162SPeter.Dunlap@Sun.COM 	mutex_enter(&iser_state->is_hcalist_lock);
12459162SPeter.Dunlap@Sun.COM 	for (hca = list_head(&iser_state->is_hcalist);
12469162SPeter.Dunlap@Sun.COM 	    hca != NULL;
12479162SPeter.Dunlap@Sun.COM 	    hca = nexthca) {
12489162SPeter.Dunlap@Sun.COM 
12499162SPeter.Dunlap@Sun.COM 		nexthca = list_next(&iser_state->is_hcalist, hca);
12509162SPeter.Dunlap@Sun.COM 
12519162SPeter.Dunlap@Sun.COM 		list_remove(&iser_state->is_hcalist, hca);
12529162SPeter.Dunlap@Sun.COM 
12539162SPeter.Dunlap@Sun.COM 		status = iser_ib_free_hca(hca);
12549162SPeter.Dunlap@Sun.COM 		if (status != IBT_SUCCESS) {
12559162SPeter.Dunlap@Sun.COM 			ISER_LOG(CE_NOTE, "iser_ib_fini_hcas: failed to free "
12569162SPeter.Dunlap@Sun.COM 			    "HCA during fini");
12579162SPeter.Dunlap@Sun.COM 			list_insert_tail(&iser_state->is_hcalist, hca);
12589162SPeter.Dunlap@Sun.COM 			return (DDI_FAILURE);
12599162SPeter.Dunlap@Sun.COM 		}
12609162SPeter.Dunlap@Sun.COM 
12619162SPeter.Dunlap@Sun.COM 		iser_state->is_num_hcas--;
12629162SPeter.Dunlap@Sun.COM 
12639162SPeter.Dunlap@Sun.COM 	}
12649162SPeter.Dunlap@Sun.COM 	mutex_exit(&iser_state->is_hcalist_lock);
12659162SPeter.Dunlap@Sun.COM 	list_destroy(&iser_state->is_hcalist);
12669162SPeter.Dunlap@Sun.COM 	mutex_destroy(&iser_state->is_hcalist_lock);
12679162SPeter.Dunlap@Sun.COM 
12689162SPeter.Dunlap@Sun.COM 	return (DDI_SUCCESS);
12699162SPeter.Dunlap@Sun.COM }
12709162SPeter.Dunlap@Sun.COM 
12719162SPeter.Dunlap@Sun.COM /*
12729162SPeter.Dunlap@Sun.COM  * iser_ib_alloc_hca
12739162SPeter.Dunlap@Sun.COM  *
12749162SPeter.Dunlap@Sun.COM  * This function opens the given HCA device, gathers the HCA state information
12759162SPeter.Dunlap@Sun.COM  * and adds the HCA handle
12769162SPeter.Dunlap@Sun.COM  */
12779162SPeter.Dunlap@Sun.COM static iser_hca_t *
iser_ib_alloc_hca(ib_guid_t guid)12789162SPeter.Dunlap@Sun.COM iser_ib_alloc_hca(ib_guid_t guid)
12799162SPeter.Dunlap@Sun.COM {
12809162SPeter.Dunlap@Sun.COM 	iser_hca_t	*hca;
12819162SPeter.Dunlap@Sun.COM 	int		status;
12829162SPeter.Dunlap@Sun.COM 
12839162SPeter.Dunlap@Sun.COM 	/* Allocate an iser_hca_t HCA handle */
12849162SPeter.Dunlap@Sun.COM 	hca = (iser_hca_t *)kmem_zalloc(sizeof (iser_hca_t), KM_SLEEP);
12859162SPeter.Dunlap@Sun.COM 
12869162SPeter.Dunlap@Sun.COM 	/* Open this HCA */
12879162SPeter.Dunlap@Sun.COM 	status = ibt_open_hca(iser_state->is_ibhdl, guid, &hca->hca_hdl);
12889162SPeter.Dunlap@Sun.COM 	if (status != IBT_SUCCESS) {
12899162SPeter.Dunlap@Sun.COM 		ISER_LOG(CE_NOTE, "iser_ib_alloc_hca: ibt_open_hca failed:"
12909162SPeter.Dunlap@Sun.COM 		    " guid (0x%llx) status (0x%x)", (longlong_t)guid, status);
12919162SPeter.Dunlap@Sun.COM 		kmem_free(hca, sizeof (iser_hca_t));
12929162SPeter.Dunlap@Sun.COM 		return (NULL);
12939162SPeter.Dunlap@Sun.COM 	}
12949162SPeter.Dunlap@Sun.COM 
12959162SPeter.Dunlap@Sun.COM 	hca->hca_guid		= guid;
12969162SPeter.Dunlap@Sun.COM 	hca->hca_clnt_hdl	= iser_state->is_ibhdl;
12979162SPeter.Dunlap@Sun.COM 
12989162SPeter.Dunlap@Sun.COM 	/* Query the HCA */
12999162SPeter.Dunlap@Sun.COM 	status = ibt_query_hca(hca->hca_hdl, &hca->hca_attr);
13009162SPeter.Dunlap@Sun.COM 	if (status != IBT_SUCCESS) {
13019162SPeter.Dunlap@Sun.COM 		ISER_LOG(CE_NOTE, "iser_ib_alloc_hca: ibt_query_hca "
13029162SPeter.Dunlap@Sun.COM 		    "failure: guid (0x%llx) status (0x%x)",
13039162SPeter.Dunlap@Sun.COM 		    (longlong_t)guid, status);
13049162SPeter.Dunlap@Sun.COM 		(void) ibt_close_hca(hca->hca_hdl);
13059162SPeter.Dunlap@Sun.COM 		kmem_free(hca, sizeof (iser_hca_t));
13069162SPeter.Dunlap@Sun.COM 		return (NULL);
13079162SPeter.Dunlap@Sun.COM 	}
13089162SPeter.Dunlap@Sun.COM 
13099162SPeter.Dunlap@Sun.COM 	/* Query all ports on the HCA */
13109162SPeter.Dunlap@Sun.COM 	status = ibt_query_hca_ports(hca->hca_hdl, 0,
13119162SPeter.Dunlap@Sun.COM 	    &hca->hca_port_info, &hca->hca_num_ports,
13129162SPeter.Dunlap@Sun.COM 	    &hca->hca_port_info_sz);
13139162SPeter.Dunlap@Sun.COM 	if (status != IBT_SUCCESS) {
13149162SPeter.Dunlap@Sun.COM 		ISER_LOG(CE_NOTE, "iser_ib_alloc_hca: "
13159162SPeter.Dunlap@Sun.COM 		    "ibt_query_hca_ports failure: guid (0x%llx) "
13169162SPeter.Dunlap@Sun.COM 		    "status (0x%x)", (longlong_t)guid, status);
13179162SPeter.Dunlap@Sun.COM 		(void) ibt_close_hca(hca->hca_hdl);
13189162SPeter.Dunlap@Sun.COM 		kmem_free(hca, sizeof (iser_hca_t));
13199162SPeter.Dunlap@Sun.COM 		return (NULL);
13209162SPeter.Dunlap@Sun.COM 	}
13219162SPeter.Dunlap@Sun.COM 
13229162SPeter.Dunlap@Sun.COM 	/* Allocate a single PD on this HCA */
13239162SPeter.Dunlap@Sun.COM 	status = ibt_alloc_pd(hca->hca_hdl, IBT_PD_NO_FLAGS,
13249162SPeter.Dunlap@Sun.COM 	    &hca->hca_pdhdl);
13259162SPeter.Dunlap@Sun.COM 	if (status != IBT_SUCCESS) {
13269162SPeter.Dunlap@Sun.COM 		ISER_LOG(CE_NOTE, "iser_ib_alloc_hca: ibt_alloc_pd "
13279162SPeter.Dunlap@Sun.COM 		    "failure: guid (0x%llx) status (0x%x)",
13289162SPeter.Dunlap@Sun.COM 		    (longlong_t)guid, status);
13299162SPeter.Dunlap@Sun.COM 		(void) ibt_close_hca(hca->hca_hdl);
13309162SPeter.Dunlap@Sun.COM 		ibt_free_portinfo(hca->hca_port_info, hca->hca_port_info_sz);
13319162SPeter.Dunlap@Sun.COM 		kmem_free(hca, sizeof (iser_hca_t));
13329162SPeter.Dunlap@Sun.COM 		return (NULL);
13339162SPeter.Dunlap@Sun.COM 	}
13349162SPeter.Dunlap@Sun.COM 
13359162SPeter.Dunlap@Sun.COM 	/* Initialize the message and data MR caches for this HCA */
13369162SPeter.Dunlap@Sun.COM 	iser_init_hca_caches(hca);
13379162SPeter.Dunlap@Sun.COM 
13389162SPeter.Dunlap@Sun.COM 	return (hca);
13399162SPeter.Dunlap@Sun.COM }
13409162SPeter.Dunlap@Sun.COM 
13419162SPeter.Dunlap@Sun.COM static int
iser_ib_free_hca(iser_hca_t * hca)13429162SPeter.Dunlap@Sun.COM iser_ib_free_hca(iser_hca_t *hca)
13439162SPeter.Dunlap@Sun.COM {
13449162SPeter.Dunlap@Sun.COM 	int			status;
13459162SPeter.Dunlap@Sun.COM 	ibt_hca_portinfo_t	*hca_port_info;
13469162SPeter.Dunlap@Sun.COM 	uint_t			hca_port_info_sz;
13479162SPeter.Dunlap@Sun.COM 
13489162SPeter.Dunlap@Sun.COM 	ASSERT(hca != NULL);
13499162SPeter.Dunlap@Sun.COM 	if (hca->hca_failed)
13509162SPeter.Dunlap@Sun.COM 		return (DDI_FAILURE);
13519162SPeter.Dunlap@Sun.COM 
13529162SPeter.Dunlap@Sun.COM 	hca_port_info = hca->hca_port_info;
13539162SPeter.Dunlap@Sun.COM 	hca_port_info_sz = hca->hca_port_info_sz;
13549162SPeter.Dunlap@Sun.COM 
13559162SPeter.Dunlap@Sun.COM 	/*
13569162SPeter.Dunlap@Sun.COM 	 * Free the memory regions before freeing
13579162SPeter.Dunlap@Sun.COM 	 * the associated protection domain
13589162SPeter.Dunlap@Sun.COM 	 */
13599162SPeter.Dunlap@Sun.COM 	iser_fini_hca_caches(hca);
13609162SPeter.Dunlap@Sun.COM 
13619162SPeter.Dunlap@Sun.COM 	status = ibt_free_pd(hca->hca_hdl, hca->hca_pdhdl);
13629162SPeter.Dunlap@Sun.COM 	if (status != IBT_SUCCESS) {
13639162SPeter.Dunlap@Sun.COM 		ISER_LOG(CE_NOTE, "iser_ib_free_hca: failed to free PD "
13649162SPeter.Dunlap@Sun.COM 		    "status=0x%x", status);
13659162SPeter.Dunlap@Sun.COM 		goto out_caches;
13669162SPeter.Dunlap@Sun.COM 	}
13679162SPeter.Dunlap@Sun.COM 
13689162SPeter.Dunlap@Sun.COM 	status = ibt_close_hca(hca->hca_hdl);
13699162SPeter.Dunlap@Sun.COM 	if (status != IBT_SUCCESS) {
13709162SPeter.Dunlap@Sun.COM 		ISER_LOG(CE_NOTE, "iser_ib_fini_hcas: failed to close HCA "
13719162SPeter.Dunlap@Sun.COM 		    "status=0x%x", status);
13729162SPeter.Dunlap@Sun.COM 		goto out_pd;
13739162SPeter.Dunlap@Sun.COM 	}
13749162SPeter.Dunlap@Sun.COM 
13759162SPeter.Dunlap@Sun.COM 	ibt_free_portinfo(hca_port_info, hca_port_info_sz);
13769162SPeter.Dunlap@Sun.COM 
13779162SPeter.Dunlap@Sun.COM 	kmem_free(hca, sizeof (iser_hca_t));
13789162SPeter.Dunlap@Sun.COM 	return (DDI_SUCCESS);
13799162SPeter.Dunlap@Sun.COM 
13809162SPeter.Dunlap@Sun.COM 	/*
13819162SPeter.Dunlap@Sun.COM 	 * We only managed to partially tear down the HCA, try to put it back
13829162SPeter.Dunlap@Sun.COM 	 * like it was before returning.
13839162SPeter.Dunlap@Sun.COM 	 */
13849162SPeter.Dunlap@Sun.COM out_pd:
13859162SPeter.Dunlap@Sun.COM 	status = ibt_alloc_pd(hca->hca_hdl, IBT_PD_NO_FLAGS, &hca->hca_pdhdl);
13869162SPeter.Dunlap@Sun.COM 	if (status != IBT_SUCCESS) {
13879162SPeter.Dunlap@Sun.COM 		hca->hca_failed = B_TRUE;
13889162SPeter.Dunlap@Sun.COM 		/* Report error and exit */
13899162SPeter.Dunlap@Sun.COM 		ISER_LOG(CE_NOTE, "iser_ib_free_hca: could not re-alloc PD "
13909162SPeter.Dunlap@Sun.COM 		    "status=0x%x", status);
13919162SPeter.Dunlap@Sun.COM 		return (DDI_FAILURE);
13929162SPeter.Dunlap@Sun.COM 	}
13939162SPeter.Dunlap@Sun.COM 
13949162SPeter.Dunlap@Sun.COM out_caches:
13959162SPeter.Dunlap@Sun.COM 	iser_init_hca_caches(hca);
13969162SPeter.Dunlap@Sun.COM 
13979162SPeter.Dunlap@Sun.COM 	return (DDI_FAILURE);
13989162SPeter.Dunlap@Sun.COM }
13999162SPeter.Dunlap@Sun.COM 
14009162SPeter.Dunlap@Sun.COM static int
iser_ib_update_hcaports(iser_hca_t * hca)14019162SPeter.Dunlap@Sun.COM iser_ib_update_hcaports(iser_hca_t *hca)
14029162SPeter.Dunlap@Sun.COM {
14039162SPeter.Dunlap@Sun.COM 	ibt_hca_portinfo_t	*pinfop, *oldpinfop;
14049162SPeter.Dunlap@Sun.COM 	uint_t			size, oldsize, nport;
14059162SPeter.Dunlap@Sun.COM 	int			status;
14069162SPeter.Dunlap@Sun.COM 
14079162SPeter.Dunlap@Sun.COM 	ASSERT(hca != NULL);
14089162SPeter.Dunlap@Sun.COM 
14099162SPeter.Dunlap@Sun.COM 	status = ibt_query_hca_ports(hca->hca_hdl, 0, &pinfop, &nport, &size);
14109162SPeter.Dunlap@Sun.COM 	if (status != IBT_SUCCESS) {
14119162SPeter.Dunlap@Sun.COM 		ISER_LOG(CE_NOTE, "ibt_query_hca_ports failed: %d", status);
14129162SPeter.Dunlap@Sun.COM 		return (status);
14139162SPeter.Dunlap@Sun.COM 	}
14149162SPeter.Dunlap@Sun.COM 
14159162SPeter.Dunlap@Sun.COM 	oldpinfop = hca->hca_port_info;
14169162SPeter.Dunlap@Sun.COM 	oldsize	= hca->hca_port_info_sz;
14179162SPeter.Dunlap@Sun.COM 	hca->hca_port_info = pinfop;
14189162SPeter.Dunlap@Sun.COM 	hca->hca_port_info_sz = size;
14199162SPeter.Dunlap@Sun.COM 
14209162SPeter.Dunlap@Sun.COM 	(void) ibt_free_portinfo(oldpinfop, oldsize);
14219162SPeter.Dunlap@Sun.COM 
14229162SPeter.Dunlap@Sun.COM 	return (IBT_SUCCESS);
14239162SPeter.Dunlap@Sun.COM }
14249162SPeter.Dunlap@Sun.COM 
14259162SPeter.Dunlap@Sun.COM /*
14269162SPeter.Dunlap@Sun.COM  * iser_ib_gid2hca
14279162SPeter.Dunlap@Sun.COM  * Given a gid, find the corresponding hca
14289162SPeter.Dunlap@Sun.COM  */
14299162SPeter.Dunlap@Sun.COM iser_hca_t *
iser_ib_gid2hca(ib_gid_t gid)14309162SPeter.Dunlap@Sun.COM iser_ib_gid2hca(ib_gid_t gid)
14319162SPeter.Dunlap@Sun.COM {
14329162SPeter.Dunlap@Sun.COM 
14339162SPeter.Dunlap@Sun.COM 	iser_hca_t	*hca;
14349162SPeter.Dunlap@Sun.COM 	int		i;
14359162SPeter.Dunlap@Sun.COM 
14369162SPeter.Dunlap@Sun.COM 	mutex_enter(&iser_state->is_hcalist_lock);
14379162SPeter.Dunlap@Sun.COM 	for (hca = list_head(&iser_state->is_hcalist);
14389162SPeter.Dunlap@Sun.COM 	    hca != NULL;
14399162SPeter.Dunlap@Sun.COM 	    hca = list_next(&iser_state->is_hcalist, hca)) {
14409162SPeter.Dunlap@Sun.COM 
14419162SPeter.Dunlap@Sun.COM 		for (i = 0; i < hca->hca_num_ports; i++) {
14429162SPeter.Dunlap@Sun.COM 			if ((hca->hca_port_info[i].p_sgid_tbl[0].gid_prefix ==
14439162SPeter.Dunlap@Sun.COM 			    gid.gid_prefix) &&
14449162SPeter.Dunlap@Sun.COM 			    (hca->hca_port_info[i].p_sgid_tbl[0].gid_guid ==
14459162SPeter.Dunlap@Sun.COM 			    gid.gid_guid)) {
14469162SPeter.Dunlap@Sun.COM 
14479162SPeter.Dunlap@Sun.COM 				mutex_exit(&iser_state->is_hcalist_lock);
14489162SPeter.Dunlap@Sun.COM 
14499162SPeter.Dunlap@Sun.COM 				return (hca);
14509162SPeter.Dunlap@Sun.COM 			}
14519162SPeter.Dunlap@Sun.COM 		}
14529162SPeter.Dunlap@Sun.COM 	}
14539162SPeter.Dunlap@Sun.COM 	mutex_exit(&iser_state->is_hcalist_lock);
14549162SPeter.Dunlap@Sun.COM 	return (NULL);
14559162SPeter.Dunlap@Sun.COM }
14569162SPeter.Dunlap@Sun.COM 
14579162SPeter.Dunlap@Sun.COM /*
14589162SPeter.Dunlap@Sun.COM  * iser_ib_guid2hca
14599162SPeter.Dunlap@Sun.COM  * Given a HCA guid, find the corresponding HCA
14609162SPeter.Dunlap@Sun.COM  */
14619162SPeter.Dunlap@Sun.COM iser_hca_t *
iser_ib_guid2hca(ib_guid_t guid)14629162SPeter.Dunlap@Sun.COM iser_ib_guid2hca(ib_guid_t guid)
14639162SPeter.Dunlap@Sun.COM {
14649162SPeter.Dunlap@Sun.COM 
14659162SPeter.Dunlap@Sun.COM 	iser_hca_t	*hca;
14669162SPeter.Dunlap@Sun.COM 
14679162SPeter.Dunlap@Sun.COM 	mutex_enter(&iser_state->is_hcalist_lock);
14689162SPeter.Dunlap@Sun.COM 	for (hca = list_head(&iser_state->is_hcalist);
14699162SPeter.Dunlap@Sun.COM 	    hca != NULL;
14709162SPeter.Dunlap@Sun.COM 	    hca = list_next(&iser_state->is_hcalist, hca)) {
14719162SPeter.Dunlap@Sun.COM 
14729162SPeter.Dunlap@Sun.COM 		if (hca->hca_guid == guid) {
14739162SPeter.Dunlap@Sun.COM 			mutex_exit(&iser_state->is_hcalist_lock);
14749162SPeter.Dunlap@Sun.COM 			return (hca);
14759162SPeter.Dunlap@Sun.COM 		}
14769162SPeter.Dunlap@Sun.COM 	}
14779162SPeter.Dunlap@Sun.COM 	mutex_exit(&iser_state->is_hcalist_lock);
14789162SPeter.Dunlap@Sun.COM 	return (NULL);
14799162SPeter.Dunlap@Sun.COM }
14809162SPeter.Dunlap@Sun.COM 
14819162SPeter.Dunlap@Sun.COM /*
14829162SPeter.Dunlap@Sun.COM  * iser_ib_conv_sockaddr2ibtaddr
14839162SPeter.Dunlap@Sun.COM  * This function converts a socket address into the IBT format
14849162SPeter.Dunlap@Sun.COM  */
iser_ib_conv_sockaddr2ibtaddr(idm_sockaddr_t * saddr,ibt_ip_addr_t * ibt_addr)14859162SPeter.Dunlap@Sun.COM void iser_ib_conv_sockaddr2ibtaddr(
14869162SPeter.Dunlap@Sun.COM     idm_sockaddr_t *saddr, ibt_ip_addr_t *ibt_addr)
14879162SPeter.Dunlap@Sun.COM {
14889162SPeter.Dunlap@Sun.COM 	if (saddr == NULL) {
14899162SPeter.Dunlap@Sun.COM 		ibt_addr->family = AF_UNSPEC;
14909162SPeter.Dunlap@Sun.COM 		ibt_addr->un.ip4addr = 0;
14919162SPeter.Dunlap@Sun.COM 	} else {
14929162SPeter.Dunlap@Sun.COM 		switch (saddr->sin.sa_family) {
14939162SPeter.Dunlap@Sun.COM 		case AF_INET:
14949162SPeter.Dunlap@Sun.COM 
14959162SPeter.Dunlap@Sun.COM 			ibt_addr->family	= saddr->sin4.sin_family;
14969162SPeter.Dunlap@Sun.COM 			ibt_addr->un.ip4addr	= saddr->sin4.sin_addr.s_addr;
14979162SPeter.Dunlap@Sun.COM 			break;
14989162SPeter.Dunlap@Sun.COM 
14999162SPeter.Dunlap@Sun.COM 		case AF_INET6:
15009162SPeter.Dunlap@Sun.COM 
15019162SPeter.Dunlap@Sun.COM 			ibt_addr->family	= saddr->sin6.sin6_family;
15029162SPeter.Dunlap@Sun.COM 			ibt_addr->un.ip6addr	= saddr->sin6.sin6_addr;
15039162SPeter.Dunlap@Sun.COM 			break;
15049162SPeter.Dunlap@Sun.COM 
15059162SPeter.Dunlap@Sun.COM 		default:
15069162SPeter.Dunlap@Sun.COM 			ibt_addr->family = AF_UNSPEC;
15079162SPeter.Dunlap@Sun.COM 		}
15089162SPeter.Dunlap@Sun.COM 
15099162SPeter.Dunlap@Sun.COM 	}
15109162SPeter.Dunlap@Sun.COM }
15119162SPeter.Dunlap@Sun.COM 
15129162SPeter.Dunlap@Sun.COM /*
15139162SPeter.Dunlap@Sun.COM  * iser_ib_conv_ibtaddr2sockaddr
15149162SPeter.Dunlap@Sun.COM  * This function converts an IBT ip address handle to a sockaddr
15159162SPeter.Dunlap@Sun.COM  */
iser_ib_conv_ibtaddr2sockaddr(struct sockaddr_storage * ss,ibt_ip_addr_t * ibt_addr,in_port_t port)15169162SPeter.Dunlap@Sun.COM void iser_ib_conv_ibtaddr2sockaddr(struct sockaddr_storage *ss,
15179162SPeter.Dunlap@Sun.COM     ibt_ip_addr_t *ibt_addr, in_port_t port)
15189162SPeter.Dunlap@Sun.COM {
15199162SPeter.Dunlap@Sun.COM 	struct sockaddr_in *sin;
15209162SPeter.Dunlap@Sun.COM 	struct sockaddr_in6 *sin6;
15219162SPeter.Dunlap@Sun.COM 
15229162SPeter.Dunlap@Sun.COM 	switch (ibt_addr->family) {
15239162SPeter.Dunlap@Sun.COM 	case AF_INET:
15249162SPeter.Dunlap@Sun.COM 	case AF_UNSPEC:
15259162SPeter.Dunlap@Sun.COM 
15269162SPeter.Dunlap@Sun.COM 		sin = (struct sockaddr_in *)ibt_addr;
15279162SPeter.Dunlap@Sun.COM 		sin->sin_port = ntohs(port);
15289162SPeter.Dunlap@Sun.COM 		bcopy(sin, ss, sizeof (struct sockaddr_in));
15299162SPeter.Dunlap@Sun.COM 		break;
15309162SPeter.Dunlap@Sun.COM 
15319162SPeter.Dunlap@Sun.COM 	case AF_INET6:
15329162SPeter.Dunlap@Sun.COM 
15339162SPeter.Dunlap@Sun.COM 		sin6 = (struct sockaddr_in6 *)ibt_addr;
15349162SPeter.Dunlap@Sun.COM 		sin6->sin6_port = ntohs(port);
15359162SPeter.Dunlap@Sun.COM 		bcopy(sin6, ss, sizeof (struct sockaddr_in6));
15369162SPeter.Dunlap@Sun.COM 		break;
15379162SPeter.Dunlap@Sun.COM 
15389162SPeter.Dunlap@Sun.COM 	default:
15399162SPeter.Dunlap@Sun.COM 		ISER_LOG(CE_NOTE, "iser_ib_conv_ibtaddr2sockaddr: "
15409162SPeter.Dunlap@Sun.COM 		    "unknown family type: 0x%x", ibt_addr->family);
15419162SPeter.Dunlap@Sun.COM 	}
15429162SPeter.Dunlap@Sun.COM }
15439162SPeter.Dunlap@Sun.COM 
15449162SPeter.Dunlap@Sun.COM /*
15459162SPeter.Dunlap@Sun.COM  * iser_ib_setup_cq
15469162SPeter.Dunlap@Sun.COM  * This function sets up the Completion Queue size and allocates the specified
15479162SPeter.Dunlap@Sun.COM  * Completion Queue
15489162SPeter.Dunlap@Sun.COM  */
15499162SPeter.Dunlap@Sun.COM static int
iser_ib_setup_cq(ibt_hca_hdl_t hca_hdl,uint_t cq_size,ibt_cq_hdl_t * cq_hdl)15509162SPeter.Dunlap@Sun.COM iser_ib_setup_cq(ibt_hca_hdl_t hca_hdl, uint_t cq_size, ibt_cq_hdl_t *cq_hdl)
15519162SPeter.Dunlap@Sun.COM {
15529162SPeter.Dunlap@Sun.COM 
15539162SPeter.Dunlap@Sun.COM 	ibt_cq_attr_t		cq_attr;
15549162SPeter.Dunlap@Sun.COM 	int			status;
15559162SPeter.Dunlap@Sun.COM 
15569162SPeter.Dunlap@Sun.COM 	cq_attr.cq_size		= cq_size;
15579162SPeter.Dunlap@Sun.COM 	cq_attr.cq_sched	= 0;
15589162SPeter.Dunlap@Sun.COM 	cq_attr.cq_flags	= IBT_CQ_NO_FLAGS;
15599162SPeter.Dunlap@Sun.COM 
15609162SPeter.Dunlap@Sun.COM 	/* Allocate a Completion Queue */
15619162SPeter.Dunlap@Sun.COM 	status = ibt_alloc_cq(hca_hdl, &cq_attr, cq_hdl, NULL);
15629162SPeter.Dunlap@Sun.COM 	if (status != IBT_SUCCESS) {
15639162SPeter.Dunlap@Sun.COM 		ISER_LOG(CE_NOTE, "iser_ib_setup_cq: ibt_alloc_cq failure (%d)",
15649162SPeter.Dunlap@Sun.COM 		    status);
15659162SPeter.Dunlap@Sun.COM 		return (status);
15669162SPeter.Dunlap@Sun.COM 	}
15679162SPeter.Dunlap@Sun.COM 
15689162SPeter.Dunlap@Sun.COM 	return (ISER_STATUS_SUCCESS);
15699162SPeter.Dunlap@Sun.COM }
15709162SPeter.Dunlap@Sun.COM 
15719162SPeter.Dunlap@Sun.COM /*
15729162SPeter.Dunlap@Sun.COM  * iser_ib_setup_chanargs
15739162SPeter.Dunlap@Sun.COM  *
15749162SPeter.Dunlap@Sun.COM  */
15759162SPeter.Dunlap@Sun.COM static void
iser_ib_setup_chanargs(uint8_t hca_port,ibt_cq_hdl_t scq_hdl,ibt_cq_hdl_t rcq_hdl,uint_t sq_size,uint_t rq_size,ibt_pd_hdl_t hca_pdhdl,ibt_rc_chan_alloc_args_t * cargs)15769162SPeter.Dunlap@Sun.COM iser_ib_setup_chanargs(uint8_t hca_port, ibt_cq_hdl_t scq_hdl,
15779162SPeter.Dunlap@Sun.COM     ibt_cq_hdl_t rcq_hdl, uint_t sq_size, uint_t rq_size,
15789162SPeter.Dunlap@Sun.COM     ibt_pd_hdl_t hca_pdhdl, ibt_rc_chan_alloc_args_t *cargs)
15799162SPeter.Dunlap@Sun.COM {
15809162SPeter.Dunlap@Sun.COM 
15819162SPeter.Dunlap@Sun.COM 	bzero(cargs, sizeof (ibt_rc_chan_alloc_args_t));
15829162SPeter.Dunlap@Sun.COM 
15839162SPeter.Dunlap@Sun.COM 	/*
15849162SPeter.Dunlap@Sun.COM 	 * Set up the size of the channels send queue, receive queue and the
15859162SPeter.Dunlap@Sun.COM 	 * maximum number of elements in a scatter gather list of work requests
15869162SPeter.Dunlap@Sun.COM 	 * posted to the send and receive queues.
15879162SPeter.Dunlap@Sun.COM 	 */
15889162SPeter.Dunlap@Sun.COM 	cargs->rc_sizes.cs_sq		= sq_size;
15899162SPeter.Dunlap@Sun.COM 	cargs->rc_sizes.cs_rq		= rq_size;
15909162SPeter.Dunlap@Sun.COM 	cargs->rc_sizes.cs_sq_sgl	= ISER_IB_SGLIST_SIZE;
15919162SPeter.Dunlap@Sun.COM 	cargs->rc_sizes.cs_rq_sgl	= ISER_IB_SGLIST_SIZE;
15929162SPeter.Dunlap@Sun.COM 
15939162SPeter.Dunlap@Sun.COM 	/*
15949162SPeter.Dunlap@Sun.COM 	 * All Work requests signaled on a WR basis will receive a send
15959162SPeter.Dunlap@Sun.COM 	 * request completion.
15969162SPeter.Dunlap@Sun.COM 	 */
15979162SPeter.Dunlap@Sun.COM 	cargs->rc_flags			= IBT_ALL_SIGNALED;
15989162SPeter.Dunlap@Sun.COM 
15999162SPeter.Dunlap@Sun.COM 	/* Enable RDMA read and RDMA write on the channel end points */
16009162SPeter.Dunlap@Sun.COM 	cargs->rc_control		= IBT_CEP_RDMA_RD | IBT_CEP_RDMA_WR;
16019162SPeter.Dunlap@Sun.COM 
16029162SPeter.Dunlap@Sun.COM 	/* Set the local hca port on which the channel is allocated */
16039162SPeter.Dunlap@Sun.COM 	cargs->rc_hca_port_num		= hca_port;
16049162SPeter.Dunlap@Sun.COM 
16059162SPeter.Dunlap@Sun.COM 	/* Set the Send and Receive Completion Queue handles */
16069162SPeter.Dunlap@Sun.COM 	cargs->rc_scq			= scq_hdl;
16079162SPeter.Dunlap@Sun.COM 	cargs->rc_rcq			= rcq_hdl;
16089162SPeter.Dunlap@Sun.COM 
16099162SPeter.Dunlap@Sun.COM 	/* Set the protection domain associated with the channel */
16109162SPeter.Dunlap@Sun.COM 	cargs->rc_pd			= hca_pdhdl;
16119162SPeter.Dunlap@Sun.COM 
16129162SPeter.Dunlap@Sun.COM 	/* No SRQ usage */
16139162SPeter.Dunlap@Sun.COM 	cargs->rc_srq			= NULL;
16149162SPeter.Dunlap@Sun.COM }
16159162SPeter.Dunlap@Sun.COM 
16169162SPeter.Dunlap@Sun.COM /*
16179162SPeter.Dunlap@Sun.COM  * iser_ib_init_qp
16189162SPeter.Dunlap@Sun.COM  * Initialize the QP handle
16199162SPeter.Dunlap@Sun.COM  */
16209162SPeter.Dunlap@Sun.COM void
iser_ib_init_qp(iser_chan_t * chan,uint_t sq_size,uint_t rq_size)16219162SPeter.Dunlap@Sun.COM iser_ib_init_qp(iser_chan_t *chan, uint_t sq_size, uint_t rq_size)
16229162SPeter.Dunlap@Sun.COM {
16239162SPeter.Dunlap@Sun.COM 	/* Initialize the handle lock */
16249162SPeter.Dunlap@Sun.COM 	mutex_init(&chan->ic_qp.qp_lock, NULL, MUTEX_DRIVER, NULL);
16259162SPeter.Dunlap@Sun.COM 
16269162SPeter.Dunlap@Sun.COM 	/* Record queue sizes */
16279162SPeter.Dunlap@Sun.COM 	chan->ic_qp.sq_size = sq_size;
16289162SPeter.Dunlap@Sun.COM 	chan->ic_qp.rq_size = rq_size;
16299162SPeter.Dunlap@Sun.COM 
16309162SPeter.Dunlap@Sun.COM 	/* Initialize the RQ monitoring data */
16319162SPeter.Dunlap@Sun.COM 	chan->ic_qp.rq_depth  = rq_size;
16329162SPeter.Dunlap@Sun.COM 	chan->ic_qp.rq_level  = 0;
16339162SPeter.Dunlap@Sun.COM 	chan->ic_qp.rq_lwm = (chan->ic_recvcq_sz * ISER_IB_RQ_LWM_PCT) / 100;
16349162SPeter.Dunlap@Sun.COM 
16359162SPeter.Dunlap@Sun.COM 	/* Initialize the taskq flag */
16369162SPeter.Dunlap@Sun.COM 	chan->ic_qp.rq_taskqpending = B_FALSE;
16379162SPeter.Dunlap@Sun.COM }
16389162SPeter.Dunlap@Sun.COM 
16399162SPeter.Dunlap@Sun.COM /*
16409162SPeter.Dunlap@Sun.COM  * iser_ib_fini_qp
16419162SPeter.Dunlap@Sun.COM  * Teardown the QP handle
16429162SPeter.Dunlap@Sun.COM  */
16439162SPeter.Dunlap@Sun.COM void
iser_ib_fini_qp(iser_qp_t * qp)16449162SPeter.Dunlap@Sun.COM iser_ib_fini_qp(iser_qp_t *qp)
16459162SPeter.Dunlap@Sun.COM {
16469162SPeter.Dunlap@Sun.COM 	/* Destroy the handle lock */
16479162SPeter.Dunlap@Sun.COM 	mutex_destroy(&qp->qp_lock);
16489162SPeter.Dunlap@Sun.COM }
16499162SPeter.Dunlap@Sun.COM 
16509162SPeter.Dunlap@Sun.COM static int
iser_ib_activate_port(idm_svc_t * idm_svc,ib_guid_t guid,ib_gid_t gid)16519162SPeter.Dunlap@Sun.COM iser_ib_activate_port(idm_svc_t *idm_svc, ib_guid_t guid, ib_gid_t gid)
16529162SPeter.Dunlap@Sun.COM {
16539162SPeter.Dunlap@Sun.COM 	iser_svc_t	*iser_svc;
16549162SPeter.Dunlap@Sun.COM 	iser_sbind_t	*is_sbind;
16559162SPeter.Dunlap@Sun.COM 	int		status;
16569162SPeter.Dunlap@Sun.COM 
16579162SPeter.Dunlap@Sun.COM 	iser_svc = idm_svc->is_iser_svc;
16589162SPeter.Dunlap@Sun.COM 
16599162SPeter.Dunlap@Sun.COM 	/*
16609162SPeter.Dunlap@Sun.COM 	 * Save the address of the service bind handle in the
16619162SPeter.Dunlap@Sun.COM 	 * iser_svc_t to undo the service binding at a later time
16629162SPeter.Dunlap@Sun.COM 	 */
16639162SPeter.Dunlap@Sun.COM 	is_sbind = kmem_zalloc(sizeof (iser_sbind_t), KM_SLEEP);
16649162SPeter.Dunlap@Sun.COM 	is_sbind->is_gid	= gid;
16659162SPeter.Dunlap@Sun.COM 	is_sbind->is_guid	= guid;
16669162SPeter.Dunlap@Sun.COM 
16679162SPeter.Dunlap@Sun.COM 	status  = ibt_bind_service(iser_svc->is_srvhdl, gid, NULL,
16689162SPeter.Dunlap@Sun.COM 	    idm_svc, &is_sbind->is_sbindhdl);
16699162SPeter.Dunlap@Sun.COM 
16709162SPeter.Dunlap@Sun.COM 	if (status != IBT_SUCCESS) {
16719162SPeter.Dunlap@Sun.COM 		ISER_LOG(CE_NOTE, "iser_ib_activate_port: status(0x%x): "
16729162SPeter.Dunlap@Sun.COM 		    "Bind service(%llx) on port(%llx:%llx) failed",
16739162SPeter.Dunlap@Sun.COM 		    status, (longlong_t)iser_svc->is_svcid,
16749162SPeter.Dunlap@Sun.COM 		    (longlong_t)gid.gid_prefix, (longlong_t)gid.gid_guid);
16759162SPeter.Dunlap@Sun.COM 
16769162SPeter.Dunlap@Sun.COM 		kmem_free(is_sbind, sizeof (iser_sbind_t));
16779162SPeter.Dunlap@Sun.COM 
16789162SPeter.Dunlap@Sun.COM 		return (status);
16799162SPeter.Dunlap@Sun.COM 	}
16809162SPeter.Dunlap@Sun.COM 
16819162SPeter.Dunlap@Sun.COM 	list_insert_tail(&iser_svc->is_sbindlist, is_sbind);
16829162SPeter.Dunlap@Sun.COM 
16839162SPeter.Dunlap@Sun.COM 	return (IBT_SUCCESS);
16849162SPeter.Dunlap@Sun.COM }
16859162SPeter.Dunlap@Sun.COM 
16869162SPeter.Dunlap@Sun.COM static void
iser_ib_deactivate_port(ib_guid_t hca_guid,ib_gid_t gid)16879162SPeter.Dunlap@Sun.COM iser_ib_deactivate_port(ib_guid_t hca_guid, ib_gid_t gid)
16889162SPeter.Dunlap@Sun.COM {
16899162SPeter.Dunlap@Sun.COM 	iser_svc_t	*iser_svc;
16909162SPeter.Dunlap@Sun.COM 	iser_conn_t	*iser_conn;
16919162SPeter.Dunlap@Sun.COM 	iser_sbind_t	*is_sbind;
16929162SPeter.Dunlap@Sun.COM 	idm_conn_t	*idm_conn;
16939162SPeter.Dunlap@Sun.COM 
16949162SPeter.Dunlap@Sun.COM 	/*
16959162SPeter.Dunlap@Sun.COM 	 * Iterate through the global list of IDM target connections.
16969162SPeter.Dunlap@Sun.COM 	 * Issue a TRANSPORT_FAIL for any connections on this port, and
16979162SPeter.Dunlap@Sun.COM 	 * if there is a bound service running on the port, tear it down.
16989162SPeter.Dunlap@Sun.COM 	 */
16999162SPeter.Dunlap@Sun.COM 	mutex_enter(&idm.idm_global_mutex);
17009162SPeter.Dunlap@Sun.COM 	for (idm_conn = list_head(&idm.idm_tgt_conn_list);
17019162SPeter.Dunlap@Sun.COM 	    idm_conn != NULL;
17029162SPeter.Dunlap@Sun.COM 	    idm_conn = list_next(&idm.idm_tgt_conn_list, idm_conn)) {
17039162SPeter.Dunlap@Sun.COM 
17049162SPeter.Dunlap@Sun.COM 		if (idm_conn->ic_transport_type != IDM_TRANSPORT_TYPE_ISER) {
17059162SPeter.Dunlap@Sun.COM 			/* this is not an iSER connection, skip it */
17069162SPeter.Dunlap@Sun.COM 			continue;
17079162SPeter.Dunlap@Sun.COM 		}
17089162SPeter.Dunlap@Sun.COM 
17099162SPeter.Dunlap@Sun.COM 		iser_conn = idm_conn->ic_transport_private;
17109162SPeter.Dunlap@Sun.COM 		if (iser_conn->ic_chan->ic_ibt_path.pi_hca_guid != hca_guid) {
17119162SPeter.Dunlap@Sun.COM 			/* this iSER connection is on a different port */
17129162SPeter.Dunlap@Sun.COM 			continue;
17139162SPeter.Dunlap@Sun.COM 		}
17149162SPeter.Dunlap@Sun.COM 
17159162SPeter.Dunlap@Sun.COM 		/* Fail the transport for this connection */
17169162SPeter.Dunlap@Sun.COM 		idm_conn_event(idm_conn, CE_TRANSPORT_FAIL, IDM_STATUS_FAIL);
17179162SPeter.Dunlap@Sun.COM 
17189162SPeter.Dunlap@Sun.COM 		if (idm_conn->ic_conn_type == CONN_TYPE_INI) {
17199162SPeter.Dunlap@Sun.COM 			/* initiator connection, nothing else to do */
17209162SPeter.Dunlap@Sun.COM 			continue;
17219162SPeter.Dunlap@Sun.COM 		}
17229162SPeter.Dunlap@Sun.COM 
17239162SPeter.Dunlap@Sun.COM 		/* Check for a service binding */
17249162SPeter.Dunlap@Sun.COM 		iser_svc = idm_conn->ic_svc_binding->is_iser_svc;
17259162SPeter.Dunlap@Sun.COM 		is_sbind = iser_ib_get_bind(iser_svc, hca_guid, gid);
17269162SPeter.Dunlap@Sun.COM 		if (is_sbind != NULL) {
17279162SPeter.Dunlap@Sun.COM 			/* This service is still bound, tear it down */
172811093SSrivijitha.Dugganapalli@Sun.COM 			(void) ibt_unbind_service(iser_svc->is_srvhdl,
17299162SPeter.Dunlap@Sun.COM 			    is_sbind->is_sbindhdl);
17309162SPeter.Dunlap@Sun.COM 			list_remove(&iser_svc->is_sbindlist, is_sbind);
17319162SPeter.Dunlap@Sun.COM 			kmem_free(is_sbind, sizeof (iser_sbind_t));
17329162SPeter.Dunlap@Sun.COM 		}
17339162SPeter.Dunlap@Sun.COM 	}
17349162SPeter.Dunlap@Sun.COM 	mutex_exit(&idm.idm_global_mutex);
17359162SPeter.Dunlap@Sun.COM }
17369162SPeter.Dunlap@Sun.COM 
17379162SPeter.Dunlap@Sun.COM static iser_sbind_t *
iser_ib_get_bind(iser_svc_t * iser_svc,ib_guid_t hca_guid,ib_gid_t gid)17389162SPeter.Dunlap@Sun.COM iser_ib_get_bind(iser_svc_t *iser_svc, ib_guid_t hca_guid, ib_gid_t gid)
17399162SPeter.Dunlap@Sun.COM {
17409162SPeter.Dunlap@Sun.COM 	iser_sbind_t	*is_sbind;
17419162SPeter.Dunlap@Sun.COM 
17429162SPeter.Dunlap@Sun.COM 	for (is_sbind = list_head(&iser_svc->is_sbindlist);
17439162SPeter.Dunlap@Sun.COM 	    is_sbind != NULL;
17449162SPeter.Dunlap@Sun.COM 	    is_sbind = list_next(&iser_svc->is_sbindlist, is_sbind)) {
17459162SPeter.Dunlap@Sun.COM 
17469162SPeter.Dunlap@Sun.COM 		if ((is_sbind->is_guid == hca_guid) &&
17479162SPeter.Dunlap@Sun.COM 		    (is_sbind->is_gid.gid_prefix == gid.gid_prefix) &&
17489162SPeter.Dunlap@Sun.COM 		    (is_sbind->is_gid.gid_guid == gid.gid_guid)) {
17499162SPeter.Dunlap@Sun.COM 			return (is_sbind);
17509162SPeter.Dunlap@Sun.COM 		}
17519162SPeter.Dunlap@Sun.COM 	}
17529162SPeter.Dunlap@Sun.COM 	return (NULL);
17539162SPeter.Dunlap@Sun.COM }
1754