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