xref: /illumos-gate/usr/src/uts/common/io/ib/mgt/ibdma/ibdma.c (revision b1d7ec75953cd517f5b7c3d9cb427ff8ec5d7d07)
11bdd6c0eSSue Gleeson /*
21bdd6c0eSSue Gleeson  * CDDL HEADER START
31bdd6c0eSSue Gleeson  *
41bdd6c0eSSue Gleeson  * The contents of this file are subject to the terms of the
51bdd6c0eSSue Gleeson  * Common Development and Distribution License (the "License").
61bdd6c0eSSue Gleeson  * You may not use this file except in compliance with the License.
71bdd6c0eSSue Gleeson  *
81bdd6c0eSSue Gleeson  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91bdd6c0eSSue Gleeson  * or http://www.opensolaris.org/os/licensing.
101bdd6c0eSSue Gleeson  * See the License for the specific language governing permissions
111bdd6c0eSSue Gleeson  * and limitations under the License.
121bdd6c0eSSue Gleeson  *
131bdd6c0eSSue Gleeson  * When distributing Covered Code, include this CDDL HEADER in each
141bdd6c0eSSue Gleeson  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151bdd6c0eSSue Gleeson  * If applicable, add the following below this CDDL HEADER, with the
161bdd6c0eSSue Gleeson  * fields enclosed by brackets "[]" replaced with your own identifying
171bdd6c0eSSue Gleeson  * information: Portions Copyright [yyyy] [name of copyright owner]
181bdd6c0eSSue Gleeson  *
191bdd6c0eSSue Gleeson  * CDDL HEADER END
201bdd6c0eSSue Gleeson  */
211bdd6c0eSSue Gleeson 
221bdd6c0eSSue Gleeson /*
23*b1d7ec75SPeter Cudhea - Oracle Corporation - Burlington, MA United States  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
241bdd6c0eSSue Gleeson  */
251bdd6c0eSSue Gleeson 
261bdd6c0eSSue Gleeson /*
271bdd6c0eSSue Gleeson  * Infiniband Device Management Agent for IB storage.
281bdd6c0eSSue Gleeson  */
291bdd6c0eSSue Gleeson 
301bdd6c0eSSue Gleeson #include <sys/conf.h>
311bdd6c0eSSue Gleeson #include <sys/file.h>
321bdd6c0eSSue Gleeson #include <sys/ddi.h>
331bdd6c0eSSue Gleeson #include <sys/sunddi.h>
341bdd6c0eSSue Gleeson #include <sys/modctl.h>
351bdd6c0eSSue Gleeson #include <sys/priv.h>
361bdd6c0eSSue Gleeson #include <sys/sysmacros.h>
371bdd6c0eSSue Gleeson 
381bdd6c0eSSue Gleeson #include <sys/ib/ibtl/ibti.h>		/* IB public interfaces */
391bdd6c0eSSue Gleeson 
401bdd6c0eSSue Gleeson #include <sys/ib/mgt/ibdma/ibdma.h>
411bdd6c0eSSue Gleeson #include <sys/ib/mgt/ibdma/ibdma_impl.h>
421bdd6c0eSSue Gleeson 
431bdd6c0eSSue Gleeson /*
441bdd6c0eSSue Gleeson  * NOTE: The IB Device Management Agent function, like other IB
451bdd6c0eSSue Gleeson  * managers and agents is best implemented as a kernel misc.
461bdd6c0eSSue Gleeson  * module.
471bdd6c0eSSue Gleeson  * Eventually we could modify IBT_DM_AGENT so that we don't need to
481bdd6c0eSSue Gleeson  * open each HCA to receive asynchronous events.
491bdd6c0eSSue Gleeson  */
501bdd6c0eSSue Gleeson 
511bdd6c0eSSue Gleeson #define	IBDMA_NAME_VERSION	"IB Device Management Agent"
521bdd6c0eSSue Gleeson 
531bdd6c0eSSue Gleeson extern struct mod_ops mod_miscops;
541bdd6c0eSSue Gleeson 
551bdd6c0eSSue Gleeson static void ibdma_ibt_async_handler(void *clnt, ibt_hca_hdl_t hdl,
561bdd6c0eSSue Gleeson 	ibt_async_code_t code, ibt_async_event_t *event);
571bdd6c0eSSue Gleeson 
581bdd6c0eSSue Gleeson static void ibdma_mad_recv_cb(ibmf_handle_t ibmf_hdl,
591bdd6c0eSSue Gleeson 	ibmf_msg_t *msgp, void *args);
601bdd6c0eSSue Gleeson static void ibdma_create_resp_mad(ibmf_msg_t *msgp);
611bdd6c0eSSue Gleeson 
621bdd6c0eSSue Gleeson /*
631bdd6c0eSSue Gleeson  * Misc. kernel module for now.
641bdd6c0eSSue Gleeson  */
651bdd6c0eSSue Gleeson static struct modlmisc modlmisc = {
661bdd6c0eSSue Gleeson 	&mod_miscops,
671bdd6c0eSSue Gleeson 	IBDMA_NAME_VERSION
681bdd6c0eSSue Gleeson };
691bdd6c0eSSue Gleeson 
701bdd6c0eSSue Gleeson static struct modlinkage modlinkage = {
711bdd6c0eSSue Gleeson 	MODREV_1, (void *)&modlmisc, NULL
721bdd6c0eSSue Gleeson };
731bdd6c0eSSue Gleeson 
741bdd6c0eSSue Gleeson static ibt_clnt_modinfo_t ibdma_ibt_modinfo = {
751bdd6c0eSSue Gleeson 	IBTI_V_CURR,
761bdd6c0eSSue Gleeson 	IBT_DM_AGENT,
771bdd6c0eSSue Gleeson 	ibdma_ibt_async_handler,
781bdd6c0eSSue Gleeson 	NULL,
791bdd6c0eSSue Gleeson 	"ibdma"
801bdd6c0eSSue Gleeson };
811bdd6c0eSSue Gleeson 
821bdd6c0eSSue Gleeson /*
831bdd6c0eSSue Gleeson  * Module global state allocated at init().
841bdd6c0eSSue Gleeson  */
851bdd6c0eSSue Gleeson static ibdma_mod_state_t	*ibdma = NULL;
861bdd6c0eSSue Gleeson 
871bdd6c0eSSue Gleeson /*
881bdd6c0eSSue Gleeson  * Init/Fini handlers and IBTL HCA management prototypes.
891bdd6c0eSSue Gleeson  */
901bdd6c0eSSue Gleeson static int ibdma_init();
911bdd6c0eSSue Gleeson static int ibdma_fini();
921bdd6c0eSSue Gleeson static int ibdma_ibt_init();
931bdd6c0eSSue Gleeson static void ibdma_ibt_fini();
941bdd6c0eSSue Gleeson static ibdma_hca_t *ibdma_hca_init(ib_guid_t guid);
951bdd6c0eSSue Gleeson static void ibdma_hca_fini(ibdma_hca_t *hca);
961bdd6c0eSSue Gleeson static ibdma_hca_t *ibdma_find_hca(ib_guid_t guid);
971bdd6c0eSSue Gleeson 
981bdd6c0eSSue Gleeson /*
991bdd6c0eSSue Gleeson  * DevMgmt Agent MAD attribute handlers prototypes.
1001bdd6c0eSSue Gleeson  */
1011bdd6c0eSSue Gleeson static void ibdma_get_class_portinfo(ibmf_msg_t *msg);
1021bdd6c0eSSue Gleeson static void ibdma_get_io_unitinfo(ibdma_hca_t *hca, ibmf_msg_t *msg);
1031bdd6c0eSSue Gleeson static void ibdma_get_ioc_profile(ibdma_hca_t *hca, ibmf_msg_t *msg);
1041bdd6c0eSSue Gleeson static void ibdma_get_ioc_services(ibdma_hca_t *hca, ibmf_msg_t *msg);
1051bdd6c0eSSue Gleeson 
1061bdd6c0eSSue Gleeson /*
1071bdd6c0eSSue Gleeson  * _init()
1081bdd6c0eSSue Gleeson  */
1091bdd6c0eSSue Gleeson int
_init(void)1101bdd6c0eSSue Gleeson _init(void)
1111bdd6c0eSSue Gleeson {
1121bdd6c0eSSue Gleeson 	int status;
1131bdd6c0eSSue Gleeson 
1141bdd6c0eSSue Gleeson 	ASSERT(ibdma == NULL);
1151bdd6c0eSSue Gleeson 
1161bdd6c0eSSue Gleeson 	ibdma = kmem_zalloc(sizeof (*ibdma), KM_SLEEP);
1171bdd6c0eSSue Gleeson 	ASSERT(ibdma != NULL);
1181bdd6c0eSSue Gleeson 
1191bdd6c0eSSue Gleeson 	status = ibdma_init();
1201bdd6c0eSSue Gleeson 	if (status != DDI_SUCCESS) {
1211bdd6c0eSSue Gleeson 		kmem_free(ibdma, sizeof (*ibdma));
1221bdd6c0eSSue Gleeson 		ibdma = NULL;
1231bdd6c0eSSue Gleeson 		return (status);
1241bdd6c0eSSue Gleeson 	}
1251bdd6c0eSSue Gleeson 
1261bdd6c0eSSue Gleeson 	status = mod_install(&modlinkage);
1271bdd6c0eSSue Gleeson 	if (status != DDI_SUCCESS) {
1281bdd6c0eSSue Gleeson 		cmn_err(CE_NOTE, "_init, mod_install error (%d)", status);
1291bdd6c0eSSue Gleeson 		(void) ibdma_fini();
1301bdd6c0eSSue Gleeson 		kmem_free(ibdma, sizeof (*ibdma));
1311bdd6c0eSSue Gleeson 		ibdma = NULL;
1321bdd6c0eSSue Gleeson 	}
1331bdd6c0eSSue Gleeson 	return (status);
1341bdd6c0eSSue Gleeson }
1351bdd6c0eSSue Gleeson 
1361bdd6c0eSSue Gleeson /*
1371bdd6c0eSSue Gleeson  * _info()
1381bdd6c0eSSue Gleeson  */
1391bdd6c0eSSue Gleeson int
_info(struct modinfo * modinfop)1401bdd6c0eSSue Gleeson _info(struct modinfo *modinfop)
1411bdd6c0eSSue Gleeson {
1421bdd6c0eSSue Gleeson 	return (mod_info(&modlinkage, modinfop));
1431bdd6c0eSSue Gleeson }
1441bdd6c0eSSue Gleeson 
1451bdd6c0eSSue Gleeson /*
1461bdd6c0eSSue Gleeson  * _fini()
1471bdd6c0eSSue Gleeson  */
1481bdd6c0eSSue Gleeson int
_fini(void)1491bdd6c0eSSue Gleeson _fini(void)
1501bdd6c0eSSue Gleeson {
1511bdd6c0eSSue Gleeson 	int		status;
1521bdd6c0eSSue Gleeson 	int		slot;
1531bdd6c0eSSue Gleeson 	ibdma_hca_t	*hca;
1541bdd6c0eSSue Gleeson 
1551bdd6c0eSSue Gleeson 	status = mod_remove(&modlinkage);
1561bdd6c0eSSue Gleeson 	if (status != DDI_SUCCESS) {
1571bdd6c0eSSue Gleeson 		cmn_err(CE_NOTE, "_fini, mod_remove error (%d)", status);
1581bdd6c0eSSue Gleeson 		return (status);
1591bdd6c0eSSue Gleeson 	}
1601bdd6c0eSSue Gleeson 
1611bdd6c0eSSue Gleeson 	/*
1621bdd6c0eSSue Gleeson 	 * Sanity check to see if anyone is not cleaning
1631bdd6c0eSSue Gleeson 	 * up appropriately.
1641bdd6c0eSSue Gleeson 	 */
1651bdd6c0eSSue Gleeson 	mutex_enter(&ibdma->ms_hca_list_lock);
1661bdd6c0eSSue Gleeson 	hca = list_head(&ibdma->ms_hca_list);
1671bdd6c0eSSue Gleeson 	while (hca != NULL) {
1681bdd6c0eSSue Gleeson 		for (slot = 0; slot < IBDMA_MAX_IOC; slot++) {
1691bdd6c0eSSue Gleeson 			if (hca->ih_ioc[slot].ii_inuse) {
1701bdd6c0eSSue Gleeson 				cmn_err(CE_NOTE, "_fini, IOC %d still attached"
1711bdd6c0eSSue Gleeson 				    " for (0x%0llx)", slot+1,
1721bdd6c0eSSue Gleeson 				    (u_longlong_t)hca->ih_iou_guid);
1731bdd6c0eSSue Gleeson 			}
1741bdd6c0eSSue Gleeson 		}
1751bdd6c0eSSue Gleeson 		hca = list_next(&ibdma->ms_hca_list, hca);
1761bdd6c0eSSue Gleeson 	}
1771bdd6c0eSSue Gleeson 	mutex_exit(&ibdma->ms_hca_list_lock);
1781bdd6c0eSSue Gleeson 
1791bdd6c0eSSue Gleeson 	(void) ibdma_fini();
1801bdd6c0eSSue Gleeson 	kmem_free(ibdma, sizeof (*ibdma));
1811bdd6c0eSSue Gleeson 	return (status);
1821bdd6c0eSSue Gleeson }
1831bdd6c0eSSue Gleeson 
1841bdd6c0eSSue Gleeson /*
1851bdd6c0eSSue Gleeson  * ibdma_init()
1861bdd6c0eSSue Gleeson  *
1871bdd6c0eSSue Gleeson  * Initialize I/O Unit structure, generate initial HCA list and register
1881bdd6c0eSSue Gleeson  * it port with the IBMF.
1891bdd6c0eSSue Gleeson  */
1901bdd6c0eSSue Gleeson static int
ibdma_init()1911bdd6c0eSSue Gleeson ibdma_init()
1921bdd6c0eSSue Gleeson {
1931bdd6c0eSSue Gleeson 	int		status;
1941bdd6c0eSSue Gleeson 
1951bdd6c0eSSue Gleeson 	/*
1961bdd6c0eSSue Gleeson 	 * Global lock and I/O Unit initialization.
1971bdd6c0eSSue Gleeson 	 */
1981bdd6c0eSSue Gleeson 	mutex_init(&ibdma->ms_hca_list_lock, NULL, MUTEX_DRIVER, NULL);
1991bdd6c0eSSue Gleeson 
2001bdd6c0eSSue Gleeson 	/*
2011bdd6c0eSSue Gleeson 	 * Discover IB hardware and setup for device management agent
2021bdd6c0eSSue Gleeson 	 * support.
2031bdd6c0eSSue Gleeson 	 */
2041bdd6c0eSSue Gleeson 	status = ibdma_ibt_init();
2051bdd6c0eSSue Gleeson 	if (status != DDI_SUCCESS) {
2061bdd6c0eSSue Gleeson 		cmn_err(CE_NOTE, "ibdma_init, ibt_attach failed (%d)",
2071bdd6c0eSSue Gleeson 		    status);
2081bdd6c0eSSue Gleeson 		mutex_destroy(&ibdma->ms_hca_list_lock);
2091bdd6c0eSSue Gleeson 		return (status);
2101bdd6c0eSSue Gleeson 	}
2111bdd6c0eSSue Gleeson 
2121bdd6c0eSSue Gleeson 	return (status);
2131bdd6c0eSSue Gleeson }
2141bdd6c0eSSue Gleeson 
2151bdd6c0eSSue Gleeson /*
2161bdd6c0eSSue Gleeson  * ibdma_fini()
2171bdd6c0eSSue Gleeson  *
2181bdd6c0eSSue Gleeson  * Release resource if we are no longer in use.
2191bdd6c0eSSue Gleeson  */
2201bdd6c0eSSue Gleeson static int
ibdma_fini()2211bdd6c0eSSue Gleeson ibdma_fini()
2221bdd6c0eSSue Gleeson {
2231bdd6c0eSSue Gleeson 	ibdma_ibt_fini();
2241bdd6c0eSSue Gleeson 	mutex_destroy(&ibdma->ms_hca_list_lock);
2251bdd6c0eSSue Gleeson 	return (DDI_SUCCESS);
2261bdd6c0eSSue Gleeson }
2271bdd6c0eSSue Gleeson 
2281bdd6c0eSSue Gleeson /*
2291bdd6c0eSSue Gleeson  * ibdma_ibt_async_handler()
2301bdd6c0eSSue Gleeson  */
2311bdd6c0eSSue Gleeson /* ARGSUSED */
2321bdd6c0eSSue Gleeson static void
ibdma_ibt_async_handler(void * clnt,ibt_hca_hdl_t hdl,ibt_async_code_t code,ibt_async_event_t * event)2331bdd6c0eSSue Gleeson ibdma_ibt_async_handler(void *clnt, ibt_hca_hdl_t hdl,
2341bdd6c0eSSue Gleeson 	ibt_async_code_t code, ibt_async_event_t *event)
2351bdd6c0eSSue Gleeson {
2361bdd6c0eSSue Gleeson 	ibdma_hca_t	*hca;
2371bdd6c0eSSue Gleeson 
2381bdd6c0eSSue Gleeson 	switch (code) {
2391bdd6c0eSSue Gleeson 
2401bdd6c0eSSue Gleeson 	case IBT_EVENT_PORT_UP:
2411bdd6c0eSSue Gleeson 	case IBT_ERROR_PORT_DOWN:
242*b1d7ec75SPeter Cudhea - Oracle Corporation - Burlington, MA United States 	case IBT_PORT_CHANGE_EVENT:
243*b1d7ec75SPeter Cudhea - Oracle Corporation - Burlington, MA United States 	case IBT_CLNT_REREG_EVENT:
2441bdd6c0eSSue Gleeson 		break;
2451bdd6c0eSSue Gleeson 
2461bdd6c0eSSue Gleeson 	case IBT_HCA_ATTACH_EVENT:
2471bdd6c0eSSue Gleeson 		mutex_enter(&ibdma->ms_hca_list_lock);
2481bdd6c0eSSue Gleeson 		hca = ibdma_hca_init(event->ev_hca_guid);
2491bdd6c0eSSue Gleeson 		if (hca != NULL) {
2501bdd6c0eSSue Gleeson 			list_insert_tail(&ibdma->ms_hca_list, hca);
2511bdd6c0eSSue Gleeson 			cmn_err(CE_NOTE, "hca ibt hdl (%p)",
2521bdd6c0eSSue Gleeson 			    (void *)hca->ih_ibt_hdl);
2531bdd6c0eSSue Gleeson 			ibdma->ms_num_hcas++;
2541bdd6c0eSSue Gleeson 		}
2551bdd6c0eSSue Gleeson 		mutex_exit(&ibdma->ms_hca_list_lock);
2561bdd6c0eSSue Gleeson 		break;
2571bdd6c0eSSue Gleeson 
2581bdd6c0eSSue Gleeson 	case IBT_HCA_DETACH_EVENT:
2591bdd6c0eSSue Gleeson 		mutex_enter(&ibdma->ms_hca_list_lock);
2601bdd6c0eSSue Gleeson 		hca = ibdma_find_hca(event->ev_hca_guid);
2611bdd6c0eSSue Gleeson 		if (hca != NULL) {
2621bdd6c0eSSue Gleeson 			list_remove(&ibdma->ms_hca_list, hca);
2631bdd6c0eSSue Gleeson 			cmn_err(CE_NOTE, "removing hca (%p) (0x%llx)",
2641bdd6c0eSSue Gleeson 			    (void *)hca, hca ?
2651bdd6c0eSSue Gleeson 			    (u_longlong_t)hca->ih_iou_guid : 0x0ll);
2661bdd6c0eSSue Gleeson 			ibdma_hca_fini(hca);
2671bdd6c0eSSue Gleeson 		}
2681bdd6c0eSSue Gleeson 		mutex_exit(&ibdma->ms_hca_list_lock);
2691bdd6c0eSSue Gleeson 		break;
2701bdd6c0eSSue Gleeson 
2711bdd6c0eSSue Gleeson 	default:
272*b1d7ec75SPeter Cudhea - Oracle Corporation - Burlington, MA United States #ifdef	DEBUG
2731bdd6c0eSSue Gleeson 		cmn_err(CE_NOTE, "ibt_async_handler, unhandled event(%d)",
2741bdd6c0eSSue Gleeson 		    code);
275*b1d7ec75SPeter Cudhea - Oracle Corporation - Burlington, MA United States #endif
2761bdd6c0eSSue Gleeson 		break;
2771bdd6c0eSSue Gleeson 	}
2781bdd6c0eSSue Gleeson 
2791bdd6c0eSSue Gleeson }
2801bdd6c0eSSue Gleeson 
2811bdd6c0eSSue Gleeson /*
2821bdd6c0eSSue Gleeson  * ibdma_ibt_init()
2831bdd6c0eSSue Gleeson  */
2841bdd6c0eSSue Gleeson static int
ibdma_ibt_init()2851bdd6c0eSSue Gleeson ibdma_ibt_init()
2861bdd6c0eSSue Gleeson {
2871bdd6c0eSSue Gleeson 	int		status;
2881bdd6c0eSSue Gleeson 	int		hca_cnt;
2891bdd6c0eSSue Gleeson 	int		hca_ndx;
2901bdd6c0eSSue Gleeson 	ib_guid_t	*guid;
2911bdd6c0eSSue Gleeson 	ibdma_hca_t	*hca;
2921bdd6c0eSSue Gleeson 
2931bdd6c0eSSue Gleeson 	/*
2941bdd6c0eSSue Gleeson 	 * Attach to IBTF and get HCA list.
2951bdd6c0eSSue Gleeson 	 */
2961bdd6c0eSSue Gleeson 	status = ibt_attach(&ibdma_ibt_modinfo, NULL,
2971bdd6c0eSSue Gleeson 	    ibdma, &ibdma->ms_ibt_hdl);
2981bdd6c0eSSue Gleeson 	if (status != DDI_SUCCESS) {
2991bdd6c0eSSue Gleeson 		cmn_err(CE_NOTE, "ibt_init, ibt_attach failed (%d)",
3001bdd6c0eSSue Gleeson 		    status);
3011bdd6c0eSSue Gleeson 		return (status);
3021bdd6c0eSSue Gleeson 	}
3031bdd6c0eSSue Gleeson 
304168665f7SSue Gleeson 	list_create(&ibdma->ms_hca_list, sizeof (ibdma_hca_t),
305168665f7SSue Gleeson 	    offsetof(ibdma_hca_t, ih_node));
306168665f7SSue Gleeson 
3071bdd6c0eSSue Gleeson 	hca_cnt = ibt_get_hca_list(&guid);
3081bdd6c0eSSue Gleeson 	if (hca_cnt < 1) {
3091bdd6c0eSSue Gleeson #ifdef	DEBUG_IBDMA
3101bdd6c0eSSue Gleeson 		cmn_err(CE_NOTE, "ibt_init, no HCA(s) found");
3111bdd6c0eSSue Gleeson #endif
312168665f7SSue Gleeson 		/* not an error if no HCAs, but nothing more to do here */
313168665f7SSue Gleeson 		return (DDI_SUCCESS);
3141bdd6c0eSSue Gleeson 	}
3151bdd6c0eSSue Gleeson 
3161bdd6c0eSSue Gleeson 	mutex_enter(&ibdma->ms_hca_list_lock);
3171bdd6c0eSSue Gleeson 
3181bdd6c0eSSue Gleeson 	for (hca_ndx = 0; hca_ndx < hca_cnt; hca_ndx++) {
3191bdd6c0eSSue Gleeson #ifdef	DEBUG_IBDMA
3201bdd6c0eSSue Gleeson 		cmn_err(CE_NOTE, "adding hca GUID(0x%llx)",
3211bdd6c0eSSue Gleeson 		    (u_longlong_t)guid[hca_ndx]);
3221bdd6c0eSSue Gleeson #endif
3231bdd6c0eSSue Gleeson 
3241bdd6c0eSSue Gleeson 		hca = ibdma_hca_init(guid[hca_ndx]);
3251bdd6c0eSSue Gleeson 		if (hca == NULL) {
3261bdd6c0eSSue Gleeson 			cmn_err(CE_NOTE, "ibt_init, hca_init GUID(0x%llx)"
3271bdd6c0eSSue Gleeson 			    " failed", (u_longlong_t)guid[hca_ndx]);
3281bdd6c0eSSue Gleeson 			continue;
3291bdd6c0eSSue Gleeson 		}
3301bdd6c0eSSue Gleeson 		list_insert_tail(&ibdma->ms_hca_list, hca);
3311bdd6c0eSSue Gleeson 		ibdma->ms_num_hcas++;
3321bdd6c0eSSue Gleeson 	}
3331bdd6c0eSSue Gleeson 
3341bdd6c0eSSue Gleeson 	mutex_exit(&ibdma->ms_hca_list_lock);
3351bdd6c0eSSue Gleeson 
3361bdd6c0eSSue Gleeson 	ibt_free_hca_list(guid, hca_cnt);
3371bdd6c0eSSue Gleeson #ifdef	DEBUG_IBDMA
3381bdd6c0eSSue Gleeson 	cmn_err(CE_NOTE, "Added %d HCA(s)",
3391bdd6c0eSSue Gleeson 	    ibdma->ms_num_hcas);
3401bdd6c0eSSue Gleeson #endif
3411bdd6c0eSSue Gleeson 	return (DDI_SUCCESS);
3421bdd6c0eSSue Gleeson }
3431bdd6c0eSSue Gleeson 
3441bdd6c0eSSue Gleeson /*
3451bdd6c0eSSue Gleeson  * ibdma_ibt_fini()
3461bdd6c0eSSue Gleeson  */
3471bdd6c0eSSue Gleeson static void
ibdma_ibt_fini()3481bdd6c0eSSue Gleeson ibdma_ibt_fini()
3491bdd6c0eSSue Gleeson {
3501bdd6c0eSSue Gleeson 	ibdma_hca_t		*hca;
3511bdd6c0eSSue Gleeson 	ibdma_hca_t		*next;
3521bdd6c0eSSue Gleeson 
3531bdd6c0eSSue Gleeson 	mutex_enter(&ibdma->ms_hca_list_lock);
3541bdd6c0eSSue Gleeson 	hca = list_head(&ibdma->ms_hca_list);
3551bdd6c0eSSue Gleeson 	while (hca != NULL) {
3561bdd6c0eSSue Gleeson 		next = list_next(&ibdma->ms_hca_list, hca);
3571bdd6c0eSSue Gleeson 		list_remove(&ibdma->ms_hca_list, hca);
3581bdd6c0eSSue Gleeson #ifdef	DEBUG_IBDMA
3591bdd6c0eSSue Gleeson 		cmn_err(CE_NOTE, "removing hca (%p) (0x%llx)",
3601bdd6c0eSSue Gleeson 		    (void *)hca, hca ?
3611bdd6c0eSSue Gleeson 		    (u_longlong_t)hca->ih_iou_guid : 0x0ll);
3621bdd6c0eSSue Gleeson 		cmn_err(CE_NOTE, "hca ibt hdl (%p)",
3631bdd6c0eSSue Gleeson 		    (void *)hca->ih_ibt_hdl);
3641bdd6c0eSSue Gleeson #endif
3651bdd6c0eSSue Gleeson 		ibdma_hca_fini(hca);
3661bdd6c0eSSue Gleeson 		hca = next;
3671bdd6c0eSSue Gleeson 	}
3681bdd6c0eSSue Gleeson 	list_destroy(&ibdma->ms_hca_list);
3691bdd6c0eSSue Gleeson 
370168665f7SSue Gleeson 	(void) ibt_detach(ibdma->ms_ibt_hdl);
3711bdd6c0eSSue Gleeson 	ibdma->ms_ibt_hdl   = NULL;
3721bdd6c0eSSue Gleeson 	ibdma->ms_num_hcas  = 0;
3731bdd6c0eSSue Gleeson 	mutex_exit(&ibdma->ms_hca_list_lock);
3741bdd6c0eSSue Gleeson }
3751bdd6c0eSSue Gleeson 
3761bdd6c0eSSue Gleeson /*
3771bdd6c0eSSue Gleeson  * ibdma_find_hca()
3781bdd6c0eSSue Gleeson  */
3791bdd6c0eSSue Gleeson static ibdma_hca_t *
ibdma_find_hca(ib_guid_t guid)3801bdd6c0eSSue Gleeson ibdma_find_hca(ib_guid_t guid)
3811bdd6c0eSSue Gleeson {
3821bdd6c0eSSue Gleeson 	ibdma_hca_t	*hca;
3831bdd6c0eSSue Gleeson 
3841bdd6c0eSSue Gleeson 	ASSERT(mutex_owned(&ibdma->ms_hca_list_lock));
3851bdd6c0eSSue Gleeson 
3861bdd6c0eSSue Gleeson 	hca = list_head(&ibdma->ms_hca_list);
3871bdd6c0eSSue Gleeson 	while (hca != NULL) {
3881bdd6c0eSSue Gleeson 		if (hca->ih_iou_guid == guid) {
3891bdd6c0eSSue Gleeson 			break;
3901bdd6c0eSSue Gleeson 		}
3911bdd6c0eSSue Gleeson 		hca = list_next(&ibdma->ms_hca_list, hca);
3921bdd6c0eSSue Gleeson 	}
3931bdd6c0eSSue Gleeson 	return (hca);
3941bdd6c0eSSue Gleeson }
3951bdd6c0eSSue Gleeson 
3961bdd6c0eSSue Gleeson /*
3971bdd6c0eSSue Gleeson  * ibdma_hca_init()
3981bdd6c0eSSue Gleeson  */
3991bdd6c0eSSue Gleeson static ibdma_hca_t *
ibdma_hca_init(ib_guid_t guid)4001bdd6c0eSSue Gleeson ibdma_hca_init(ib_guid_t guid)
4011bdd6c0eSSue Gleeson {
4021bdd6c0eSSue Gleeson 	ibt_status_t		status;
4031bdd6c0eSSue Gleeson 	ibdma_hca_t		*hca;
4041bdd6c0eSSue Gleeson 	ibdma_port_t		*port;
4051bdd6c0eSSue Gleeson 	ibt_hca_attr_t		hca_attr;
4061bdd6c0eSSue Gleeson 	int			ndx;
4071bdd6c0eSSue Gleeson 
4081bdd6c0eSSue Gleeson 	ASSERT(mutex_owned(&ibdma->ms_hca_list_lock));
4091bdd6c0eSSue Gleeson 
4101bdd6c0eSSue Gleeson 	status = ibt_query_hca_byguid(guid, &hca_attr);
4111bdd6c0eSSue Gleeson 	if (status != IBT_SUCCESS) {
4121bdd6c0eSSue Gleeson 		cmn_err(CE_NOTE, "hca_init HCA query error (%d)",
4131bdd6c0eSSue Gleeson 		    status);
4141bdd6c0eSSue Gleeson 		return (NULL);
4151bdd6c0eSSue Gleeson 	}
4161bdd6c0eSSue Gleeson 
4171bdd6c0eSSue Gleeson 	if (ibdma_find_hca(guid) != NULL) {
4181bdd6c0eSSue Gleeson #ifdef	DEBUG_IBDMA
4191bdd6c0eSSue Gleeson 		cmn_err(CE_NOTE, "hca_init HCA already exists");
4201bdd6c0eSSue Gleeson #endif
4211bdd6c0eSSue Gleeson 		return (NULL);
4221bdd6c0eSSue Gleeson 	}
4231bdd6c0eSSue Gleeson 
4241bdd6c0eSSue Gleeson 	hca = kmem_zalloc(sizeof (ibdma_hca_t) +
4251bdd6c0eSSue Gleeson 	    (hca_attr.hca_nports-1)*sizeof (ibdma_port_t), KM_SLEEP);
4261bdd6c0eSSue Gleeson 	ASSERT(hca != NULL);
4271bdd6c0eSSue Gleeson 
4281bdd6c0eSSue Gleeson 	hca->ih_nports   = hca_attr.hca_nports;
4291bdd6c0eSSue Gleeson 
4301bdd6c0eSSue Gleeson 	rw_init(&hca->ih_iou_rwlock, NULL, RW_DRIVER, NULL);
4311bdd6c0eSSue Gleeson 	rw_enter(&hca->ih_iou_rwlock, RW_WRITER);
4321bdd6c0eSSue Gleeson 	hca->ih_iou_guid		= guid;
4331bdd6c0eSSue Gleeson 	hca->ih_iou.iou_changeid	= h2b16(1);
4341bdd6c0eSSue Gleeson 	hca->ih_iou.iou_num_ctrl_slots	= IBDMA_MAX_IOC;
4351bdd6c0eSSue Gleeson 	hca->ih_iou.iou_flag		= IB_DM_IOU_OPTIONROM_ABSENT;
4361bdd6c0eSSue Gleeson 
4371bdd6c0eSSue Gleeson 	list_create(&hca->ih_hdl_list, sizeof (ibdma_hdl_impl_t),
4381bdd6c0eSSue Gleeson 	    offsetof(ibdma_hdl_impl_t, ih_node));
4391bdd6c0eSSue Gleeson 	rw_exit(&hca->ih_iou_rwlock);
4401bdd6c0eSSue Gleeson 
4411bdd6c0eSSue Gleeson 	/*
4421bdd6c0eSSue Gleeson 	 * It would be better to not open, but IBTL is setup to only allow
4431bdd6c0eSSue Gleeson 	 * certain managers to get async call backs if not open.
4441bdd6c0eSSue Gleeson 	 */
4451bdd6c0eSSue Gleeson 	status = ibt_open_hca(ibdma->ms_ibt_hdl, guid, &hca->ih_ibt_hdl);
4461bdd6c0eSSue Gleeson 	if (status != IBT_SUCCESS) {
4471bdd6c0eSSue Gleeson 		cmn_err(CE_NOTE, "hca_init() IBT open failed (%d)",
4481bdd6c0eSSue Gleeson 		    status);
4491bdd6c0eSSue Gleeson 
4501bdd6c0eSSue Gleeson 		list_destroy(&hca->ih_hdl_list);
4511bdd6c0eSSue Gleeson 		rw_destroy(&hca->ih_iou_rwlock);
4521bdd6c0eSSue Gleeson 		kmem_free(hca, sizeof (ibdma_hca_t) +
4531bdd6c0eSSue Gleeson 		    (hca_attr.hca_nports-1)*sizeof (ibdma_port_t));
4541bdd6c0eSSue Gleeson 		return (NULL);
4551bdd6c0eSSue Gleeson 	}
4561bdd6c0eSSue Gleeson 
4571bdd6c0eSSue Gleeson 	/*
4581bdd6c0eSSue Gleeson 	 * Register with the IB Management Framework and setup MAD call-back.
4591bdd6c0eSSue Gleeson 	 */
4601bdd6c0eSSue Gleeson 	for (ndx = 0; ndx < hca->ih_nports; ndx++) {
4611bdd6c0eSSue Gleeson 		port = &hca->ih_port[ndx];
4621bdd6c0eSSue Gleeson 		port->ip_hcap = hca;
4631bdd6c0eSSue Gleeson 		port->ip_ibmf_reg.ir_ci_guid	= hca->ih_iou_guid;
4641bdd6c0eSSue Gleeson 		port->ip_ibmf_reg.ir_port_num	= ndx + 1;
4651bdd6c0eSSue Gleeson 		port->ip_ibmf_reg.ir_client_class = DEV_MGT_AGENT;
4661bdd6c0eSSue Gleeson 
4671bdd6c0eSSue Gleeson 		status = ibmf_register(&port->ip_ibmf_reg, IBMF_VERSION,
4681bdd6c0eSSue Gleeson 		    0, NULL, NULL, &port->ip_ibmf_hdl, &port->ip_ibmf_caps);
4691bdd6c0eSSue Gleeson 		if (status != IBMF_SUCCESS) {
4701bdd6c0eSSue Gleeson 			cmn_err(CE_NOTE, "hca_init, IBMF register failed (%d)",
4711bdd6c0eSSue Gleeson 			    status);
4721bdd6c0eSSue Gleeson 			port->ip_ibmf_hdl = NULL;
4731bdd6c0eSSue Gleeson 			ibdma_hca_fini(hca);
4741bdd6c0eSSue Gleeson 			return (NULL);
4751bdd6c0eSSue Gleeson 		}
4761bdd6c0eSSue Gleeson 
4771bdd6c0eSSue Gleeson 		status = ibmf_setup_async_cb(port->ip_ibmf_hdl,
4781bdd6c0eSSue Gleeson 		    IBMF_QP_HANDLE_DEFAULT, ibdma_mad_recv_cb, port, 0);
4791bdd6c0eSSue Gleeson 		if (status != IBMF_SUCCESS) {
4801bdd6c0eSSue Gleeson 			cmn_err(CE_NOTE, "hca_init, IBMF cb setup failed (%d)",
4811bdd6c0eSSue Gleeson 			    status);
4821bdd6c0eSSue Gleeson 			ibdma_hca_fini(hca);
4831bdd6c0eSSue Gleeson 			return (NULL);
4841bdd6c0eSSue Gleeson 		}
4851bdd6c0eSSue Gleeson 
4861bdd6c0eSSue Gleeson 		status = ibt_modify_port_byguid(hca->ih_iou_guid,
4871bdd6c0eSSue Gleeson 		    ndx+1, IBT_PORT_SET_DEVMGT, 0);
4881bdd6c0eSSue Gleeson 		if (status != IBT_SUCCESS) {
4891bdd6c0eSSue Gleeson 			cmn_err(CE_NOTE, "hca_init, IBT modify port caps"
4901bdd6c0eSSue Gleeson 			    " error (%d)", status);
4911bdd6c0eSSue Gleeson 			ibdma_hca_fini(hca);
4921bdd6c0eSSue Gleeson 			return (NULL);
4931bdd6c0eSSue Gleeson 		}
4941bdd6c0eSSue Gleeson 	}
4951bdd6c0eSSue Gleeson 	return (hca);
4961bdd6c0eSSue Gleeson }
4971bdd6c0eSSue Gleeson 
4981bdd6c0eSSue Gleeson /*
4991bdd6c0eSSue Gleeson  * ibdma_hca_fini()
5001bdd6c0eSSue Gleeson  */
5011bdd6c0eSSue Gleeson static void
ibdma_hca_fini(ibdma_hca_t * hca)5021bdd6c0eSSue Gleeson ibdma_hca_fini(ibdma_hca_t *hca)
5031bdd6c0eSSue Gleeson {
5041bdd6c0eSSue Gleeson 	int			status;
5051bdd6c0eSSue Gleeson 	int			ndx;
5061bdd6c0eSSue Gleeson 	ibdma_port_t		*port;
5071bdd6c0eSSue Gleeson 	ibdma_hdl_impl_t	*hdl;
5081bdd6c0eSSue Gleeson 	ibdma_hdl_impl_t	*hdl_next;
5091bdd6c0eSSue Gleeson 
5101bdd6c0eSSue Gleeson 	ASSERT(mutex_owned(&ibdma->ms_hca_list_lock));
5111bdd6c0eSSue Gleeson 	ASSERT(hca != NULL);
5121bdd6c0eSSue Gleeson 
5131bdd6c0eSSue Gleeson 	rw_enter(&hca->ih_iou_rwlock, RW_WRITER);
5141bdd6c0eSSue Gleeson 
5151bdd6c0eSSue Gleeson 	/*
5161bdd6c0eSSue Gleeson 	 * All handles should have been de-registered, but release
5171bdd6c0eSSue Gleeson 	 * any that are outstanding.
5181bdd6c0eSSue Gleeson 	 */
5191bdd6c0eSSue Gleeson 	hdl = list_head(&hca->ih_hdl_list);
5201bdd6c0eSSue Gleeson 	while (hdl != NULL) {
5211bdd6c0eSSue Gleeson 		hdl_next = list_next(&hca->ih_hdl_list, hdl);
5221bdd6c0eSSue Gleeson 		list_remove(&hca->ih_hdl_list, hdl);
5231bdd6c0eSSue Gleeson 		cmn_err(CE_NOTE, "hca_fini, unexpected ibdma user handle"
5241bdd6c0eSSue Gleeson 		    " exists");
5251bdd6c0eSSue Gleeson 		kmem_free(hdl, sizeof (*hdl));
5261bdd6c0eSSue Gleeson 		hdl = hdl_next;
5271bdd6c0eSSue Gleeson 	}
5281bdd6c0eSSue Gleeson 	list_destroy(&hca->ih_hdl_list);
5291bdd6c0eSSue Gleeson 
5301bdd6c0eSSue Gleeson 	/*
5311bdd6c0eSSue Gleeson 	 * Un-register with the IBMF.
5321bdd6c0eSSue Gleeson 	 */
5331bdd6c0eSSue Gleeson 	for (ndx = 0; ndx < hca->ih_nports; ndx++) {
5341bdd6c0eSSue Gleeson 		port = &hca->ih_port[ndx];
5351bdd6c0eSSue Gleeson 		port->ip_hcap = NULL;
5361bdd6c0eSSue Gleeson 
5371bdd6c0eSSue Gleeson 		status = ibt_modify_port_byguid(hca->ih_iou_guid,
5381bdd6c0eSSue Gleeson 		    ndx+1, IBT_PORT_RESET_DEVMGT, 0);
5391bdd6c0eSSue Gleeson 		if (status != IBT_SUCCESS)
5401bdd6c0eSSue Gleeson 			cmn_err(CE_NOTE, "hca_fini, IBT modify port caps"
5411bdd6c0eSSue Gleeson 			    " error (%d)", status);
5421bdd6c0eSSue Gleeson 
5431bdd6c0eSSue Gleeson 		if (port->ip_ibmf_hdl == NULL)
5441bdd6c0eSSue Gleeson 			continue;
5451bdd6c0eSSue Gleeson 
5461bdd6c0eSSue Gleeson 		status = ibmf_tear_down_async_cb(port->ip_ibmf_hdl,
5471bdd6c0eSSue Gleeson 		    IBMF_QP_HANDLE_DEFAULT, 0);
5481bdd6c0eSSue Gleeson 		if (status != IBMF_SUCCESS)
5491bdd6c0eSSue Gleeson 			cmn_err(CE_NOTE, "hca_fini, IBMF tear down cb"
5501bdd6c0eSSue Gleeson 			    " error (%d)", status);
5511bdd6c0eSSue Gleeson 
5521bdd6c0eSSue Gleeson 		status = ibmf_unregister(&port->ip_ibmf_hdl, 0);
5531bdd6c0eSSue Gleeson 		if (status != IBMF_SUCCESS)
5541bdd6c0eSSue Gleeson 			cmn_err(CE_NOTE, "hca_fini, IBMF un-register"
5551bdd6c0eSSue Gleeson 			    " error (%d)", status);
5561bdd6c0eSSue Gleeson 		port->ip_ibmf_hdl = NULL;
5571bdd6c0eSSue Gleeson 	}
5581bdd6c0eSSue Gleeson 
5591bdd6c0eSSue Gleeson 	status = ibt_close_hca(hca->ih_ibt_hdl);
5601bdd6c0eSSue Gleeson 	if (status != IBT_SUCCESS)
5611bdd6c0eSSue Gleeson 		cmn_err(CE_NOTE, "hca_fini close error (%d)", status);
5621bdd6c0eSSue Gleeson 
5631bdd6c0eSSue Gleeson 	rw_exit(&hca->ih_iou_rwlock);
5641bdd6c0eSSue Gleeson 	rw_destroy(&hca->ih_iou_rwlock);
5651bdd6c0eSSue Gleeson 	kmem_free(hca, sizeof (ibdma_hca_t) +
5661bdd6c0eSSue Gleeson 	    (hca->ih_nports-1) * sizeof (ibdma_port_t));
5671bdd6c0eSSue Gleeson }
5681bdd6c0eSSue Gleeson 
5691bdd6c0eSSue Gleeson /* DM IBMF MAD handlers */
5701bdd6c0eSSue Gleeson /*
5711bdd6c0eSSue Gleeson  * ibdma_create_resp_mad()
5721bdd6c0eSSue Gleeson  */
5731bdd6c0eSSue Gleeson static void
ibdma_create_resp_mad(ibmf_msg_t * msgp)5741bdd6c0eSSue Gleeson ibdma_create_resp_mad(ibmf_msg_t *msgp)
5751bdd6c0eSSue Gleeson {
5761bdd6c0eSSue Gleeson 	/*
5771bdd6c0eSSue Gleeson 	 * Allocate send buffer fix up hdr for response.
5781bdd6c0eSSue Gleeson 	 */
5791bdd6c0eSSue Gleeson 	msgp->im_msgbufs_send.im_bufs_mad_hdr =
5801bdd6c0eSSue Gleeson 	    kmem_zalloc(IBDMA_MAD_SIZE, KM_SLEEP);
5811bdd6c0eSSue Gleeson 
5821bdd6c0eSSue Gleeson 	msgp->im_msgbufs_send.im_bufs_cl_hdr = (uchar_t *)
5831bdd6c0eSSue Gleeson 	    msgp->im_msgbufs_send.im_bufs_mad_hdr + sizeof (ib_mad_hdr_t);
5841bdd6c0eSSue Gleeson 	msgp->im_msgbufs_send.im_bufs_cl_hdr_len = IBDMA_DM_MAD_HDR_SIZE;
5851bdd6c0eSSue Gleeson 	msgp->im_msgbufs_send.im_bufs_cl_data =
5861bdd6c0eSSue Gleeson 	    ((char *)msgp->im_msgbufs_send.im_bufs_cl_hdr +
5871bdd6c0eSSue Gleeson 	    IBDMA_DM_MAD_HDR_SIZE);
5881bdd6c0eSSue Gleeson 	msgp->im_msgbufs_send.im_bufs_cl_data_len =
5891bdd6c0eSSue Gleeson 	    IBDMA_MAD_SIZE - sizeof (ib_mad_hdr_t) - IBDMA_DM_MAD_HDR_SIZE;
5901bdd6c0eSSue Gleeson 	(void) memcpy(msgp->im_msgbufs_send.im_bufs_mad_hdr,
5911bdd6c0eSSue Gleeson 	    msgp->im_msgbufs_recv.im_bufs_mad_hdr, IBDMA_MAD_SIZE);
5921bdd6c0eSSue Gleeson 
5931bdd6c0eSSue Gleeson 	/*
5941bdd6c0eSSue Gleeson 	 * We may want to support a GRH since this is a GMP; not
5951bdd6c0eSSue Gleeson 	 * required for current SRP device manager platforms.
5961bdd6c0eSSue Gleeson 	 */
5971bdd6c0eSSue Gleeson #if 0
5981bdd6c0eSSue Gleeson 	if (msgp->im_msg_flags & IBMF_MSG_FLAGS_GLOBAL_ADDRESS) {
5991bdd6c0eSSue Gleeson 		ib_gid_t	temp = msgp->im_global_addr.ig_recver_gid;
6001bdd6c0eSSue Gleeson 
6011bdd6c0eSSue Gleeson 		msgp->im_global_addr.ig_recver_gid =
6021bdd6c0eSSue Gleeson 		    msgp->im_global_addr.ig_sender_gid;
6031bdd6c0eSSue Gleeson 		msgp->im_global_addr.ig_sender_gid = temp;
6041bdd6c0eSSue Gleeson 	}
6051bdd6c0eSSue Gleeson #endif
6061bdd6c0eSSue Gleeson }
6071bdd6c0eSSue Gleeson 
6081bdd6c0eSSue Gleeson /*
6091bdd6c0eSSue Gleeson  * ibdma_mad_send_cb()
6101bdd6c0eSSue Gleeson  */
6111bdd6c0eSSue Gleeson /* ARGSUSED */
6121bdd6c0eSSue Gleeson static void
ibdma_mad_send_cb(ibmf_handle_t ibmf_hdl,ibmf_msg_t * msgp,void * arg)6131bdd6c0eSSue Gleeson ibdma_mad_send_cb(ibmf_handle_t ibmf_hdl, ibmf_msg_t *msgp, void *arg)
6141bdd6c0eSSue Gleeson {
6151bdd6c0eSSue Gleeson 	/*
6161bdd6c0eSSue Gleeson 	 * Just free the buffers and release the message.
6171bdd6c0eSSue Gleeson 	 */
6181bdd6c0eSSue Gleeson 	if (msgp->im_msgbufs_send.im_bufs_mad_hdr != NULL) {
6191bdd6c0eSSue Gleeson 		kmem_free(msgp->im_msgbufs_send.im_bufs_mad_hdr,
6201bdd6c0eSSue Gleeson 		    IBDMA_MAD_SIZE);
6211bdd6c0eSSue Gleeson 		msgp->im_msgbufs_send.im_bufs_mad_hdr = NULL;
6221bdd6c0eSSue Gleeson 	}
6231bdd6c0eSSue Gleeson 	if (ibmf_free_msg(ibmf_hdl, &msgp) != IBMF_SUCCESS) {
6241bdd6c0eSSue Gleeson 		cmn_err(CE_NOTE, "mad_send_cb, IBMF message free error");
6251bdd6c0eSSue Gleeson 	}
6261bdd6c0eSSue Gleeson }
6271bdd6c0eSSue Gleeson 
6281bdd6c0eSSue Gleeson /*
6291bdd6c0eSSue Gleeson  * ibdma_mad_recv_cb()
6301bdd6c0eSSue Gleeson  */
6311bdd6c0eSSue Gleeson static void
ibdma_mad_recv_cb(ibmf_handle_t ibmf_hdl,ibmf_msg_t * msgp,void * args)6321bdd6c0eSSue Gleeson ibdma_mad_recv_cb(ibmf_handle_t ibmf_hdl, ibmf_msg_t *msgp, void *args)
6331bdd6c0eSSue Gleeson {
6341bdd6c0eSSue Gleeson 	int		status;
6351bdd6c0eSSue Gleeson 	ib_mad_hdr_t	*in_mad;
6361bdd6c0eSSue Gleeson 	ib_mad_hdr_t	*out_mad;
6371bdd6c0eSSue Gleeson 	ibdma_port_t	*port = args;
6381bdd6c0eSSue Gleeson 
6391bdd6c0eSSue Gleeson 	ASSERT(msgp != NULL);
6401bdd6c0eSSue Gleeson 	ASSERT(port != NULL);
6411bdd6c0eSSue Gleeson 
6421bdd6c0eSSue Gleeson 	if (msgp->im_msg_status != IBMF_SUCCESS) {
6431bdd6c0eSSue Gleeson 		cmn_err(CE_NOTE, "mad_recv_cb, bad MAD receive status (%d)",
6441bdd6c0eSSue Gleeson 		    msgp->im_msg_status);
6451bdd6c0eSSue Gleeson 		goto drop;
6461bdd6c0eSSue Gleeson 	}
6471bdd6c0eSSue Gleeson 
6481bdd6c0eSSue Gleeson 	in_mad = msgp->im_msgbufs_recv.im_bufs_mad_hdr;
6491bdd6c0eSSue Gleeson 
6501bdd6c0eSSue Gleeson 	if (in_mad->MgmtClass != MAD_MGMT_CLASS_DEV_MGT) {
6511bdd6c0eSSue Gleeson #ifdef	DEBUG_IBDMA
6521bdd6c0eSSue Gleeson 		cmn_err(CE_NOTE, "mad_recv_cb, MAD not of Dev Mgmt Class");
6531bdd6c0eSSue Gleeson #endif
6541bdd6c0eSSue Gleeson 		goto drop;
6551bdd6c0eSSue Gleeson 	}
6561bdd6c0eSSue Gleeson 
6571bdd6c0eSSue Gleeson 	ibdma_create_resp_mad(msgp);
6581bdd6c0eSSue Gleeson 	out_mad = msgp->im_msgbufs_send.im_bufs_mad_hdr;
6591bdd6c0eSSue Gleeson 
6601bdd6c0eSSue Gleeson 	out_mad->R_Method = IB_DM_DEVMGT_METHOD_GET_RESP;
6611bdd6c0eSSue Gleeson 	out_mad->Status   = 0;
6621bdd6c0eSSue Gleeson 
6631bdd6c0eSSue Gleeson 	if (in_mad->R_Method == MAD_METHOD_SET) {
6641bdd6c0eSSue Gleeson #ifdef	DEBUG_IBDMA
6651bdd6c0eSSue Gleeson 		cmn_err(CE_NOTE, "mad_recv_cb, no attributes supported"
6661bdd6c0eSSue Gleeson 		    " for set");
6671bdd6c0eSSue Gleeson #endif
6681bdd6c0eSSue Gleeson 		out_mad->Status = MAD_STATUS_UNSUPP_METHOD_ATTR;
6691bdd6c0eSSue Gleeson 		goto send_resp;
6701bdd6c0eSSue Gleeson 	}
6711bdd6c0eSSue Gleeson 
6721bdd6c0eSSue Gleeson 	if (in_mad->R_Method != MAD_METHOD_GET) {
6731bdd6c0eSSue Gleeson #ifdef	DEBUG_IBDMA
6741bdd6c0eSSue Gleeson 		cmn_err(CE_NOTE, "mad_recv_cb, no attributes supported"
6751bdd6c0eSSue Gleeson 		    " for set");
6761bdd6c0eSSue Gleeson #endif
6771bdd6c0eSSue Gleeson 		out_mad->Status = MAD_STATUS_UNSUPP_METHOD;
6781bdd6c0eSSue Gleeson 		goto send_resp;
6791bdd6c0eSSue Gleeson 	}
6801bdd6c0eSSue Gleeson 
6811bdd6c0eSSue Gleeson 	/*
6821bdd6c0eSSue Gleeson 	 * Process a GET method.
6831bdd6c0eSSue Gleeson 	 */
6841bdd6c0eSSue Gleeson 	switch (b2h16(in_mad->AttributeID)) {
6851bdd6c0eSSue Gleeson 
6861bdd6c0eSSue Gleeson 	case IB_DM_ATTR_CLASSPORTINFO:
6871bdd6c0eSSue Gleeson 		ibdma_get_class_portinfo(msgp);
6881bdd6c0eSSue Gleeson 		break;
6891bdd6c0eSSue Gleeson 
6901bdd6c0eSSue Gleeson 	case IB_DM_ATTR_IO_UNITINFO:
6911bdd6c0eSSue Gleeson 		ibdma_get_io_unitinfo(port->ip_hcap, msgp);
6921bdd6c0eSSue Gleeson 		break;
6931bdd6c0eSSue Gleeson 
6941bdd6c0eSSue Gleeson 	case IB_DM_ATTR_IOC_CTRL_PROFILE:
6951bdd6c0eSSue Gleeson 		ibdma_get_ioc_profile(port->ip_hcap, msgp);
6961bdd6c0eSSue Gleeson 		break;
6971bdd6c0eSSue Gleeson 
6981bdd6c0eSSue Gleeson 	case IB_DM_ATTR_SERVICE_ENTRIES:
6991bdd6c0eSSue Gleeson 		ibdma_get_ioc_services(port->ip_hcap, msgp);
7001bdd6c0eSSue Gleeson 		break;
7011bdd6c0eSSue Gleeson 
7021bdd6c0eSSue Gleeson 	default:
7031bdd6c0eSSue Gleeson 		out_mad->Status = MAD_STATUS_UNSUPP_METHOD_ATTR;
7041bdd6c0eSSue Gleeson 		break;
7051bdd6c0eSSue Gleeson 	}
7061bdd6c0eSSue Gleeson 
7071bdd6c0eSSue Gleeson send_resp:
7081bdd6c0eSSue Gleeson 	status = ibmf_msg_transport(ibmf_hdl, IBMF_QP_HANDLE_DEFAULT,
7091bdd6c0eSSue Gleeson 	    msgp, NULL, ibdma_mad_send_cb, NULL, 0);
7101bdd6c0eSSue Gleeson 	if (status != IBMF_SUCCESS) {
7111bdd6c0eSSue Gleeson 		cmn_err(CE_NOTE, "mad_recv_cb, send error (%d)", status);
7121bdd6c0eSSue Gleeson 		ibdma_mad_send_cb(ibmf_hdl, msgp, NULL);
7131bdd6c0eSSue Gleeson 	}
7141bdd6c0eSSue Gleeson 	return;
7151bdd6c0eSSue Gleeson 
7161bdd6c0eSSue Gleeson drop:
7171bdd6c0eSSue Gleeson 	status = ibmf_free_msg(ibmf_hdl, &msgp);
7181bdd6c0eSSue Gleeson 	if (status != IBMF_SUCCESS) {
7191bdd6c0eSSue Gleeson 		cmn_err(CE_NOTE, "mad_recv_cb, error dropping (%d)",
7201bdd6c0eSSue Gleeson 		    status);
7211bdd6c0eSSue Gleeson 	}
7221bdd6c0eSSue Gleeson }
7231bdd6c0eSSue Gleeson 
7241bdd6c0eSSue Gleeson /*
7251bdd6c0eSSue Gleeson  * ibdma_get_class_portinfo()
7261bdd6c0eSSue Gleeson  */
7271bdd6c0eSSue Gleeson static void
ibdma_get_class_portinfo(ibmf_msg_t * msg)7281bdd6c0eSSue Gleeson ibdma_get_class_portinfo(ibmf_msg_t *msg)
7291bdd6c0eSSue Gleeson {
7301bdd6c0eSSue Gleeson 	ib_mad_classportinfo_t	*cpip;
7311bdd6c0eSSue Gleeson 
7321bdd6c0eSSue Gleeson 	cpip = (ib_mad_classportinfo_t *)msg->im_msgbufs_send.im_bufs_cl_data;
7331bdd6c0eSSue Gleeson 	bzero(cpip, sizeof (*cpip));
7341bdd6c0eSSue Gleeson 	cpip->BaseVersion   = MAD_CLASS_BASE_VERS_1;
7351bdd6c0eSSue Gleeson 	cpip->ClassVersion  = IB_DM_CLASS_VERSION_1;
7361bdd6c0eSSue Gleeson 	cpip->RespTimeValue = h2b32(IBDMA_DM_RESP_TIME);
7371bdd6c0eSSue Gleeson }
7381bdd6c0eSSue Gleeson 
7391bdd6c0eSSue Gleeson /*
7401bdd6c0eSSue Gleeson  * ibdma_get_io_unitinfo()
7411bdd6c0eSSue Gleeson  */
7421bdd6c0eSSue Gleeson static void
ibdma_get_io_unitinfo(ibdma_hca_t * hca,ibmf_msg_t * msg)7431bdd6c0eSSue Gleeson ibdma_get_io_unitinfo(ibdma_hca_t *hca, ibmf_msg_t *msg)
7441bdd6c0eSSue Gleeson {
7451bdd6c0eSSue Gleeson 	ib_dm_io_unitinfo_t	*uip;
7461bdd6c0eSSue Gleeson 
7471bdd6c0eSSue Gleeson 	uip = (ib_dm_io_unitinfo_t *)msg->im_msgbufs_send.im_bufs_cl_data;
7481bdd6c0eSSue Gleeson 	rw_enter(&hca->ih_iou_rwlock, RW_READER);
7491bdd6c0eSSue Gleeson 	bcopy(&hca->ih_iou, uip, sizeof (ib_dm_io_unitinfo_t));
7501bdd6c0eSSue Gleeson 	rw_exit(&hca->ih_iou_rwlock);
7511bdd6c0eSSue Gleeson }
7521bdd6c0eSSue Gleeson 
7531bdd6c0eSSue Gleeson /*
7541bdd6c0eSSue Gleeson  * ibdma_get_ioc_profile()
7551bdd6c0eSSue Gleeson  */
7561bdd6c0eSSue Gleeson static void
ibdma_get_ioc_profile(ibdma_hca_t * hca,ibmf_msg_t * msg)7571bdd6c0eSSue Gleeson ibdma_get_ioc_profile(ibdma_hca_t *hca, ibmf_msg_t *msg)
7581bdd6c0eSSue Gleeson {
7591bdd6c0eSSue Gleeson 	ib_dm_ioc_ctrl_profile_t	*iocp;
7601bdd6c0eSSue Gleeson 	uint32_t			slot;
7611bdd6c0eSSue Gleeson 
7621bdd6c0eSSue Gleeson 	ASSERT(msg != NULL);
7631bdd6c0eSSue Gleeson 
7641bdd6c0eSSue Gleeson 	slot = b2h32(msg->im_msgbufs_recv.im_bufs_mad_hdr->AttributeModifier);
7651bdd6c0eSSue Gleeson 	iocp = (ib_dm_ioc_ctrl_profile_t *)
7661bdd6c0eSSue Gleeson 	    msg->im_msgbufs_send.im_bufs_cl_data;
7671bdd6c0eSSue Gleeson 	if (slot == 0 || slot > IBDMA_MAX_IOC) {
7681bdd6c0eSSue Gleeson 		msg->im_msgbufs_send.im_bufs_mad_hdr->Status =
7691bdd6c0eSSue Gleeson 		    MAD_STATUS_INVALID_FIELD;
7701bdd6c0eSSue Gleeson 		return;
7711bdd6c0eSSue Gleeson 	}
7721bdd6c0eSSue Gleeson 
7731bdd6c0eSSue Gleeson 	slot--;
7741bdd6c0eSSue Gleeson 	rw_enter(&hca->ih_iou_rwlock, RW_READER);
7751bdd6c0eSSue Gleeson 	if (ibdma_get_ioc_state(hca, slot) == IBDMA_IOC_PRESENT) {
7761bdd6c0eSSue Gleeson 		bcopy(&hca->ih_ioc[slot].ii_profile, iocp,
7771bdd6c0eSSue Gleeson 		    sizeof (ib_dm_ioc_ctrl_profile_t));
7781bdd6c0eSSue Gleeson 	} else {
7791bdd6c0eSSue Gleeson 		msg->im_msgbufs_send.im_bufs_mad_hdr->Status =
7801bdd6c0eSSue Gleeson 		    IB_DM_DEVMGT_MAD_STAT_NORESP;
7811bdd6c0eSSue Gleeson 	}
7821bdd6c0eSSue Gleeson 	rw_exit(&hca->ih_iou_rwlock);
7831bdd6c0eSSue Gleeson }
7841bdd6c0eSSue Gleeson 
7851bdd6c0eSSue Gleeson /*
7861bdd6c0eSSue Gleeson  * ibdma_get_ioc_services()
7871bdd6c0eSSue Gleeson  */
7881bdd6c0eSSue Gleeson static void
ibdma_get_ioc_services(ibdma_hca_t * hca,ibmf_msg_t * msg)7891bdd6c0eSSue Gleeson ibdma_get_ioc_services(ibdma_hca_t *hca, ibmf_msg_t *msg)
7901bdd6c0eSSue Gleeson {
7911bdd6c0eSSue Gleeson 	ib_dm_srv_t	*to_svcp;
7921bdd6c0eSSue Gleeson 	ib_dm_srv_t	*from_svcp;
7931bdd6c0eSSue Gleeson 	uint32_t	slot;
7941bdd6c0eSSue Gleeson 	uint8_t		hi;
7951bdd6c0eSSue Gleeson 	uint8_t		low;
7961bdd6c0eSSue Gleeson 
7971bdd6c0eSSue Gleeson 	ASSERT(msg != NULL);
7981bdd6c0eSSue Gleeson 
7991bdd6c0eSSue Gleeson 	slot = b2h32(msg->im_msgbufs_recv.im_bufs_mad_hdr->AttributeModifier);
8001bdd6c0eSSue Gleeson 	hi   = (slot >> 8) & 0x00FF;
8011bdd6c0eSSue Gleeson 	low  = slot  & 0x00FF;
8021bdd6c0eSSue Gleeson 	slot = (slot >> 16) & 0x0FFFF;
8031bdd6c0eSSue Gleeson 	if (slot == 0 || slot > IBDMA_MAX_IOC) {
8041bdd6c0eSSue Gleeson 		msg->im_msgbufs_send.im_bufs_mad_hdr->Status =
8051bdd6c0eSSue Gleeson 		    MAD_STATUS_INVALID_FIELD;
8061bdd6c0eSSue Gleeson 		return;
8071bdd6c0eSSue Gleeson 	}
8081bdd6c0eSSue Gleeson 
8091bdd6c0eSSue Gleeson 	slot--;
8101bdd6c0eSSue Gleeson 
8111bdd6c0eSSue Gleeson 	rw_enter(&hca->ih_iou_rwlock, RW_READER);
8121bdd6c0eSSue Gleeson 	if (ibdma_get_ioc_state(hca, slot) != IBDMA_IOC_PRESENT) {
8131bdd6c0eSSue Gleeson 		msg->im_msgbufs_send.im_bufs_mad_hdr->Status =
8141bdd6c0eSSue Gleeson 		    IB_DM_DEVMGT_MAD_STAT_NORESP;
8151bdd6c0eSSue Gleeson 		rw_exit(&hca->ih_iou_rwlock);
8161bdd6c0eSSue Gleeson 		return;
8171bdd6c0eSSue Gleeson 	}
8181bdd6c0eSSue Gleeson 
8191bdd6c0eSSue Gleeson 	if ((low > hi) || (hi - low > 4)) {
8201bdd6c0eSSue Gleeson 		msg->im_msgbufs_send.im_bufs_mad_hdr->Status =
8211bdd6c0eSSue Gleeson 		    MAD_STATUS_INVALID_FIELD;
8221bdd6c0eSSue Gleeson 		rw_exit(&hca->ih_iou_rwlock);
8231bdd6c0eSSue Gleeson 		return;
8241bdd6c0eSSue Gleeson 	}
8251bdd6c0eSSue Gleeson 
8261bdd6c0eSSue Gleeson 	if (hi > hca->ih_ioc[slot].ii_profile.ioc_service_entries) {
8271bdd6c0eSSue Gleeson 		msg->im_msgbufs_send.im_bufs_mad_hdr->Status =
8281bdd6c0eSSue Gleeson 		    MAD_STATUS_INVALID_FIELD;
8291bdd6c0eSSue Gleeson 		rw_exit(&hca->ih_iou_rwlock);
8301bdd6c0eSSue Gleeson 		return;
8311bdd6c0eSSue Gleeson 	}
8321bdd6c0eSSue Gleeson 
8331bdd6c0eSSue Gleeson 	to_svcp = (ib_dm_srv_t *)msg->im_msgbufs_send.im_bufs_cl_data;
8341bdd6c0eSSue Gleeson 	from_svcp = hca->ih_ioc[slot].ii_srvcs + low;
8351bdd6c0eSSue Gleeson 	bcopy(from_svcp, to_svcp, sizeof (ib_dm_srv_t) * (hi - low + 1));
8361bdd6c0eSSue Gleeson 	rw_exit(&hca->ih_iou_rwlock);
8371bdd6c0eSSue Gleeson }
8381bdd6c0eSSue Gleeson 
8391bdd6c0eSSue Gleeson 
8401bdd6c0eSSue Gleeson /*
8411bdd6c0eSSue Gleeson  * Client API internal helpers
8421bdd6c0eSSue Gleeson  */
8431bdd6c0eSSue Gleeson 
8441bdd6c0eSSue Gleeson /*
8451bdd6c0eSSue Gleeson  * ibdma_hdl_to_ioc()
8461bdd6c0eSSue Gleeson  */
8471bdd6c0eSSue Gleeson ibdma_hdl_impl_t *
ibdma_get_hdl_impl(ibdma_hdl_t hdl)8481bdd6c0eSSue Gleeson ibdma_get_hdl_impl(ibdma_hdl_t hdl)
8491bdd6c0eSSue Gleeson {
8501bdd6c0eSSue Gleeson 	ibdma_hca_t		*hca;
8511bdd6c0eSSue Gleeson 	ibdma_hdl_impl_t	*hdl_tmp = hdl;
8521bdd6c0eSSue Gleeson 	ibdma_hdl_impl_t	*hdl_impl;
8531bdd6c0eSSue Gleeson 
8541bdd6c0eSSue Gleeson 	ASSERT(mutex_owned(&ibdma->ms_hca_list_lock));
8551bdd6c0eSSue Gleeson 
8561bdd6c0eSSue Gleeson 	if (hdl_tmp == NULL) {
8571bdd6c0eSSue Gleeson 		cmn_err(CE_NOTE, "get_hdl_impl, NULL handle");
8581bdd6c0eSSue Gleeson 		return (NULL);
8591bdd6c0eSSue Gleeson 	}
8601bdd6c0eSSue Gleeson 
8611bdd6c0eSSue Gleeson 	hca = ibdma_find_hca(hdl_tmp->ih_iou_guid);
8621bdd6c0eSSue Gleeson 	if (hca == NULL) {
8631bdd6c0eSSue Gleeson 		cmn_err(CE_NOTE, "get_hdl_impl, invalid handle, bad IOU");
8641bdd6c0eSSue Gleeson 		return (NULL);
8651bdd6c0eSSue Gleeson 	}
8661bdd6c0eSSue Gleeson 
8671bdd6c0eSSue Gleeson 	hdl_impl = list_head(&hca->ih_hdl_list);
8681bdd6c0eSSue Gleeson 	while (hdl_impl != NULL) {
8691bdd6c0eSSue Gleeson 		if (hdl_impl == hdl_tmp) {
8701bdd6c0eSSue Gleeson 			break;
8711bdd6c0eSSue Gleeson 		}
8721bdd6c0eSSue Gleeson 		hdl_impl = list_next(&hca->ih_hdl_list, hdl_impl);
8731bdd6c0eSSue Gleeson 	}
8741bdd6c0eSSue Gleeson 	return (hdl_impl);
8751bdd6c0eSSue Gleeson }
8761bdd6c0eSSue Gleeson 
8771bdd6c0eSSue Gleeson /*
8781bdd6c0eSSue Gleeson  * ibdma_set_ioc_state()
8791bdd6c0eSSue Gleeson  *
8801bdd6c0eSSue Gleeson  * slot should be 0 based (not DM 1 based slot).
8811bdd6c0eSSue Gleeson  *
8821bdd6c0eSSue Gleeson  * I/O Unit write lock should be held outside of this function.
8831bdd6c0eSSue Gleeson  */
8841bdd6c0eSSue Gleeson static void
ibdma_set_ioc_state(ibdma_hca_t * hca,int slot,ibdma_ioc_state_t state)8851bdd6c0eSSue Gleeson ibdma_set_ioc_state(ibdma_hca_t *hca, int slot, ibdma_ioc_state_t state)
8861bdd6c0eSSue Gleeson {
8871bdd6c0eSSue Gleeson 	uint8_t		cur;
8881bdd6c0eSSue Gleeson 	uint16_t	id;
8891bdd6c0eSSue Gleeson 
8901bdd6c0eSSue Gleeson 	cur = hca->ih_iou.iou_ctrl_list[slot >> 1];
8911bdd6c0eSSue Gleeson 	if (slot & 1) {
8921bdd6c0eSSue Gleeson 		cur = (cur & 0xF0) | state;
8931bdd6c0eSSue Gleeson 	} else {
8941bdd6c0eSSue Gleeson 		cur = (cur & 0x0F) | (state << 4);
8951bdd6c0eSSue Gleeson 	}
8961bdd6c0eSSue Gleeson 	hca->ih_iou.iou_ctrl_list[slot >> 1] = cur;
8971bdd6c0eSSue Gleeson 	id = b2h16(hca->ih_iou.iou_changeid);
8981bdd6c0eSSue Gleeson 	id++;
8991bdd6c0eSSue Gleeson 	hca->ih_iou.iou_changeid = h2b16(id);
9001bdd6c0eSSue Gleeson #ifdef	DEBUG_IBDMA
9011bdd6c0eSSue Gleeson 	cmn_err(CE_NOTE, "set_ioc_state, slot offset(%d), value(%d)",
9021bdd6c0eSSue Gleeson 	    slot, hca->ih_iou.iou_ctrl_list[slot >> 1]);
9031bdd6c0eSSue Gleeson #endif
9041bdd6c0eSSue Gleeson }
9051bdd6c0eSSue Gleeson 
9061bdd6c0eSSue Gleeson /*
9071bdd6c0eSSue Gleeson  * ibdma_get_ioc_state()
9081bdd6c0eSSue Gleeson  *
9091bdd6c0eSSue Gleeson  * slot should be 0 based (not DM 1 based slot).
9101bdd6c0eSSue Gleeson  *
9111bdd6c0eSSue Gleeson  * I/O Unit read lock should be held outside of this function.
9121bdd6c0eSSue Gleeson  */
9131bdd6c0eSSue Gleeson static ibdma_ioc_state_t
ibdma_get_ioc_state(ibdma_hca_t * hca,int slot)9141bdd6c0eSSue Gleeson ibdma_get_ioc_state(ibdma_hca_t *hca, int slot)
9151bdd6c0eSSue Gleeson {
9161bdd6c0eSSue Gleeson 	uint8_t		cur;
9171bdd6c0eSSue Gleeson 
9181bdd6c0eSSue Gleeson 	if (slot >= IBDMA_MAX_IOC)
9191bdd6c0eSSue Gleeson 		return (0xFF);
9201bdd6c0eSSue Gleeson 
9211bdd6c0eSSue Gleeson 	cur = hca->ih_iou.iou_ctrl_list[slot >> 1];
9221bdd6c0eSSue Gleeson 	cur = slot & 1 ?  cur & 0x0F : cur >> 4;
9231bdd6c0eSSue Gleeson 	return (cur);
9241bdd6c0eSSue Gleeson }
9251bdd6c0eSSue Gleeson 
9261bdd6c0eSSue Gleeson /* CLIENT API Implementation */
9271bdd6c0eSSue Gleeson /*
9281bdd6c0eSSue Gleeson  * ibdma_ioc_register()
9291bdd6c0eSSue Gleeson  *
9301bdd6c0eSSue Gleeson  */
9311bdd6c0eSSue Gleeson ibdma_hdl_t
ibdma_ioc_register(ib_guid_t iou_guid,ib_dm_ioc_ctrl_profile_t * profile,ib_dm_srv_t * services)9321bdd6c0eSSue Gleeson ibdma_ioc_register(ib_guid_t iou_guid, ib_dm_ioc_ctrl_profile_t *profile,
9331bdd6c0eSSue Gleeson 	ib_dm_srv_t *services)
9341bdd6c0eSSue Gleeson {
9351bdd6c0eSSue Gleeson 	int			free_slot = -1;
9361bdd6c0eSSue Gleeson 	int			svc_entries;
9371bdd6c0eSSue Gleeson 	int			slot;
9381bdd6c0eSSue Gleeson 	ibdma_hca_t		*hca;
9391bdd6c0eSSue Gleeson 	ibdma_hdl_impl_t	*hdl;
9401bdd6c0eSSue Gleeson 
9411bdd6c0eSSue Gleeson 	if (profile == NULL || services == NULL) {
9421bdd6c0eSSue Gleeson 		cmn_err(CE_NOTE, "ioc_register, bad parameter");
9431bdd6c0eSSue Gleeson 		return (NULL);
9441bdd6c0eSSue Gleeson 	}
9451bdd6c0eSSue Gleeson 
9461bdd6c0eSSue Gleeson 	svc_entries = profile->ioc_service_entries;
9471bdd6c0eSSue Gleeson 	if (svc_entries == 0) {
9481bdd6c0eSSue Gleeson 		cmn_err(CE_NOTE, "ioc_register, bad profile no service");
9491bdd6c0eSSue Gleeson 		return (NULL);
9501bdd6c0eSSue Gleeson 	}
9511bdd6c0eSSue Gleeson 
9521bdd6c0eSSue Gleeson 	/*
9531bdd6c0eSSue Gleeson 	 * Find the associated I/O Unit.
9541bdd6c0eSSue Gleeson 	 */
9551bdd6c0eSSue Gleeson 	mutex_enter(&ibdma->ms_hca_list_lock);
9561bdd6c0eSSue Gleeson 	hca = ibdma_find_hca(iou_guid);
9571bdd6c0eSSue Gleeson 	if (hca == NULL) {
9581bdd6c0eSSue Gleeson 		mutex_exit(&ibdma->ms_hca_list_lock);
9591bdd6c0eSSue Gleeson 		cmn_err(CE_NOTE, "ioc_register, bad I/O Unit GUID (0x%llx)",
9601bdd6c0eSSue Gleeson 		    (u_longlong_t)iou_guid);
9611bdd6c0eSSue Gleeson 		return (NULL);
9621bdd6c0eSSue Gleeson 	}
9631bdd6c0eSSue Gleeson 
9641bdd6c0eSSue Gleeson 	rw_enter(&hca->ih_iou_rwlock, RW_WRITER);
9651bdd6c0eSSue Gleeson 	for (slot = 0; slot < IBDMA_MAX_IOC; slot++) {
9661bdd6c0eSSue Gleeson 		if (hca->ih_ioc[slot].ii_inuse == 0) {
9671bdd6c0eSSue Gleeson 			if (free_slot == -1) {
9681bdd6c0eSSue Gleeson 				free_slot = slot;
9691bdd6c0eSSue Gleeson 			}
9701bdd6c0eSSue Gleeson 			continue;
9711bdd6c0eSSue Gleeson 		}
9721bdd6c0eSSue Gleeson 
9731bdd6c0eSSue Gleeson 		if (profile->ioc_guid ==
9741bdd6c0eSSue Gleeson 		    hca->ih_ioc[slot].ii_profile.ioc_guid) {
9751bdd6c0eSSue Gleeson 			rw_exit(&hca->ih_iou_rwlock);
9761bdd6c0eSSue Gleeson 			mutex_exit(&ibdma->ms_hca_list_lock);
9771bdd6c0eSSue Gleeson #ifdef	DEBUG_IBDMA
9781bdd6c0eSSue Gleeson 			cmn_err(CE_NOTE, "ioc_register, IOC previously"
9791bdd6c0eSSue Gleeson 			    " registered");
9801bdd6c0eSSue Gleeson #endif
9811bdd6c0eSSue Gleeson 			return (NULL);
9821bdd6c0eSSue Gleeson 		}
9831bdd6c0eSSue Gleeson 	}
9841bdd6c0eSSue Gleeson 
9851bdd6c0eSSue Gleeson 	if (free_slot < 0) {
9861bdd6c0eSSue Gleeson 		rw_exit(&hca->ih_iou_rwlock);
9871bdd6c0eSSue Gleeson 		cmn_err(CE_NOTE, "ioc_register, error - I/O Unit full");
9881bdd6c0eSSue Gleeson 		return (NULL);
9891bdd6c0eSSue Gleeson 	}
9901bdd6c0eSSue Gleeson #ifdef	DEBUG_IBDMA
9911bdd6c0eSSue Gleeson 	cmn_err(CE_NOTE, "ibdma_ioc_register, assigned to 0 based slot (%d)",
9921bdd6c0eSSue Gleeson 	    free_slot);
9931bdd6c0eSSue Gleeson #endif
9941bdd6c0eSSue Gleeson 
9951bdd6c0eSSue Gleeson 	hca->ih_ioc[free_slot].ii_inuse = 1;
9961bdd6c0eSSue Gleeson 	hca->ih_ioc[free_slot].ii_slot  = free_slot;
9971bdd6c0eSSue Gleeson 	hca->ih_ioc[free_slot].ii_hcap  = hca;
9981bdd6c0eSSue Gleeson 
9991bdd6c0eSSue Gleeson 	/*
10001bdd6c0eSSue Gleeson 	 * Allocate local copy of profile and services.
10011bdd6c0eSSue Gleeson 	 */
10021bdd6c0eSSue Gleeson 	hca->ih_ioc[free_slot].ii_srvcs =
10031bdd6c0eSSue Gleeson 	    kmem_zalloc(sizeof (ib_dm_srv_t) * svc_entries, KM_SLEEP);
10041bdd6c0eSSue Gleeson 	bcopy(profile, &hca->ih_ioc[free_slot].ii_profile,
10051bdd6c0eSSue Gleeson 	    sizeof (ib_dm_ioc_ctrl_profile_t));
10061bdd6c0eSSue Gleeson 	bcopy(services, hca->ih_ioc[free_slot].ii_srvcs,
10071bdd6c0eSSue Gleeson 	    sizeof (ib_dm_srv_t) * svc_entries);
10081bdd6c0eSSue Gleeson 
10091bdd6c0eSSue Gleeson 	/*
10101bdd6c0eSSue Gleeson 	 * Update the profile copy with the I/O controller slot assigned.
10111bdd6c0eSSue Gleeson 	 * The slot occupies the lower 8 biths of the vendor ID/slot 32bit
10121bdd6c0eSSue Gleeson 	 * field.
10131bdd6c0eSSue Gleeson 	 */
10141bdd6c0eSSue Gleeson 	profile->ioc_vendorid |= h2b32(free_slot);
10151bdd6c0eSSue Gleeson 
10161bdd6c0eSSue Gleeson 	ibdma_set_ioc_state(hca, free_slot, IBDMA_IOC_PRESENT);
10171bdd6c0eSSue Gleeson 
10181bdd6c0eSSue Gleeson 	hdl = kmem_alloc(sizeof (*hdl), KM_SLEEP);
10191bdd6c0eSSue Gleeson 	hdl->ih_iou_guid = hca->ih_iou_guid;
10201bdd6c0eSSue Gleeson 	hdl->ih_ioc_ndx = (uint8_t)free_slot;
10211bdd6c0eSSue Gleeson 	list_insert_tail(&hca->ih_hdl_list, hdl);
10221bdd6c0eSSue Gleeson 
10231bdd6c0eSSue Gleeson 	rw_exit(&hca->ih_iou_rwlock);
10241bdd6c0eSSue Gleeson 	mutex_exit(&ibdma->ms_hca_list_lock);
10251bdd6c0eSSue Gleeson 
10261bdd6c0eSSue Gleeson 	return ((ibdma_hdl_t)hdl);
10271bdd6c0eSSue Gleeson }
10281bdd6c0eSSue Gleeson 
10291bdd6c0eSSue Gleeson /*
10301bdd6c0eSSue Gleeson  * ibdma_ioc_unregister()
10311bdd6c0eSSue Gleeson  *
10321bdd6c0eSSue Gleeson  */
10331bdd6c0eSSue Gleeson ibdma_status_t
ibdma_ioc_unregister(ibdma_hdl_t hdl)10341bdd6c0eSSue Gleeson ibdma_ioc_unregister(ibdma_hdl_t hdl)
10351bdd6c0eSSue Gleeson {
10361bdd6c0eSSue Gleeson 	ibdma_ioc_t		*ioc;
10371bdd6c0eSSue Gleeson 	ibdma_hca_t		*hca;
10381bdd6c0eSSue Gleeson 	int			slot;
10391bdd6c0eSSue Gleeson 	ibdma_hdl_impl_t	*hdl_tmp = hdl;
10401bdd6c0eSSue Gleeson 	ibdma_hdl_impl_t	*hdl_impl;
10411bdd6c0eSSue Gleeson 
10421bdd6c0eSSue Gleeson 	if (hdl == NULL) {
10431bdd6c0eSSue Gleeson 		cmn_err(CE_NOTE, "ioc_unregister, NULL handle");
10441bdd6c0eSSue Gleeson 		return (IBDMA_BAD_PARAM);
10451bdd6c0eSSue Gleeson 	}
10461bdd6c0eSSue Gleeson 
10471bdd6c0eSSue Gleeson 	mutex_enter(&ibdma->ms_hca_list_lock);
10481bdd6c0eSSue Gleeson 	hca = ibdma_find_hca(hdl_tmp->ih_iou_guid);
10491bdd6c0eSSue Gleeson 	if (hca == NULL) {
10501bdd6c0eSSue Gleeson 		cmn_err(CE_NOTE, "ioc_unregsiter, invalid handle, IOU"
10511bdd6c0eSSue Gleeson 		    " not found");
10521bdd6c0eSSue Gleeson 		mutex_exit(&ibdma->ms_hca_list_lock);
10531bdd6c0eSSue Gleeson 		return (IBDMA_BAD_PARAM);
10541bdd6c0eSSue Gleeson 	}
10551bdd6c0eSSue Gleeson 
10561bdd6c0eSSue Gleeson 	hdl_impl = list_head(&hca->ih_hdl_list);
10571bdd6c0eSSue Gleeson 	while (hdl_impl != NULL) {
10581bdd6c0eSSue Gleeson 		if (hdl_impl == hdl_tmp) {
10591bdd6c0eSSue Gleeson 			break;
10601bdd6c0eSSue Gleeson 		}
10611bdd6c0eSSue Gleeson 		hdl_impl = list_next(&hca->ih_hdl_list, hdl_impl);
10621bdd6c0eSSue Gleeson 	}
10631bdd6c0eSSue Gleeson 
10641bdd6c0eSSue Gleeson 	if (hdl_impl == NULL) {
10651bdd6c0eSSue Gleeson 		cmn_err(CE_NOTE, "ioc_unregsiter, invalid handle, not found");
10661bdd6c0eSSue Gleeson 		mutex_exit(&ibdma->ms_hca_list_lock);
10671bdd6c0eSSue Gleeson 		return (IBDMA_BAD_PARAM);
10681bdd6c0eSSue Gleeson 	}
10691bdd6c0eSSue Gleeson 
10701bdd6c0eSSue Gleeson 	list_remove(&hca->ih_hdl_list, hdl_impl);
10711bdd6c0eSSue Gleeson 
10721bdd6c0eSSue Gleeson 	if (hdl_impl->ih_ioc_ndx >= IBDMA_MAX_IOC) {
10731bdd6c0eSSue Gleeson 		cmn_err(CE_NOTE, "ioc_unregister, corrupted handle");
10741bdd6c0eSSue Gleeson 		kmem_free(hdl_impl, sizeof (*hdl_impl));
10751bdd6c0eSSue Gleeson 		mutex_exit(&ibdma->ms_hca_list_lock);
10761bdd6c0eSSue Gleeson 		return (IBDMA_BAD_PARAM);
10771bdd6c0eSSue Gleeson 	}
10781bdd6c0eSSue Gleeson 	ioc = &hca->ih_ioc[hdl_impl->ih_ioc_ndx];
10791bdd6c0eSSue Gleeson 	kmem_free(hdl_impl, sizeof (*hdl_impl));
10801bdd6c0eSSue Gleeson 
10811bdd6c0eSSue Gleeson 	if (ioc->ii_slot > IBDMA_MAX_IOC) {
10821bdd6c0eSSue Gleeson 		cmn_err(CE_NOTE, "ioc_unregister, IOC corrupted, bad"
10831bdd6c0eSSue Gleeson 		    " slot in IOC");
10841bdd6c0eSSue Gleeson 		mutex_exit(&ibdma->ms_hca_list_lock);
10851bdd6c0eSSue Gleeson 		return (IBDMA_BAD_PARAM);
10861bdd6c0eSSue Gleeson 	}
10871bdd6c0eSSue Gleeson 
10881bdd6c0eSSue Gleeson 	rw_enter(&ioc->ii_hcap->ih_iou_rwlock, RW_WRITER);
10891bdd6c0eSSue Gleeson 	if (ioc->ii_inuse == 0) {
10901bdd6c0eSSue Gleeson 		rw_exit(&ioc->ii_hcap->ih_iou_rwlock);
10911bdd6c0eSSue Gleeson 		mutex_exit(&ibdma->ms_hca_list_lock);
10921bdd6c0eSSue Gleeson 		cmn_err(CE_NOTE, "ioc_unregister, slot not in use (%d)",
10931bdd6c0eSSue Gleeson 		    ioc->ii_slot+1);
10941bdd6c0eSSue Gleeson 		return (IBDMA_BAD_PARAM);
10951bdd6c0eSSue Gleeson 	}
10961bdd6c0eSSue Gleeson 
10971bdd6c0eSSue Gleeson 	ASSERT(ioc->ii_srvcs != NULL);
10981bdd6c0eSSue Gleeson 
10991bdd6c0eSSue Gleeson 	slot = ioc->ii_slot;
11001bdd6c0eSSue Gleeson 	hca  = ioc->ii_hcap;
11011bdd6c0eSSue Gleeson 	kmem_free(ioc->ii_srvcs, sizeof (ib_dm_srv_t) *
11021bdd6c0eSSue Gleeson 	    ioc->ii_profile.ioc_service_entries);
11031bdd6c0eSSue Gleeson 	bzero(ioc, sizeof (ibdma_ioc_t));
11041bdd6c0eSSue Gleeson 	ibdma_set_ioc_state(hca, slot, IBDMA_IOC_NOT_INSTALLED);
11051bdd6c0eSSue Gleeson 
11061bdd6c0eSSue Gleeson 	rw_exit(&hca->ih_iou_rwlock);
11071bdd6c0eSSue Gleeson 	mutex_exit(&ibdma->ms_hca_list_lock);
11081bdd6c0eSSue Gleeson 
11091bdd6c0eSSue Gleeson 	return (IBDMA_SUCCESS);
11101bdd6c0eSSue Gleeson }
11111bdd6c0eSSue Gleeson 
11121bdd6c0eSSue Gleeson /*
11131bdd6c0eSSue Gleeson  * ibdma_ioc_update()
11141bdd6c0eSSue Gleeson  *
11151bdd6c0eSSue Gleeson  */
11161bdd6c0eSSue Gleeson ibdma_status_t
ibdma_ioc_update(ibdma_hdl_t hdl,ib_dm_ioc_ctrl_profile_t * profile,ib_dm_srv_t * services)11171bdd6c0eSSue Gleeson ibdma_ioc_update(ibdma_hdl_t hdl, ib_dm_ioc_ctrl_profile_t *profile,
11181bdd6c0eSSue Gleeson 	ib_dm_srv_t *services)
11191bdd6c0eSSue Gleeson {
11201bdd6c0eSSue Gleeson 	ibdma_ioc_t		*ioc;
11211bdd6c0eSSue Gleeson 	ibdma_hca_t		*hca;
11221bdd6c0eSSue Gleeson 	ibdma_hdl_impl_t	*hdl_tmp = hdl;
11231bdd6c0eSSue Gleeson 	ibdma_hdl_impl_t	*hdl_impl;
11241bdd6c0eSSue Gleeson 
11251bdd6c0eSSue Gleeson 	if (hdl == NULL) {
11261bdd6c0eSSue Gleeson 		cmn_err(CE_NOTE, "ioc_update, NULL handle");
11271bdd6c0eSSue Gleeson 		return (IBDMA_BAD_PARAM);
11281bdd6c0eSSue Gleeson 	}
11291bdd6c0eSSue Gleeson 
11301bdd6c0eSSue Gleeson 	if (profile == NULL || services == NULL) {
11311bdd6c0eSSue Gleeson 		cmn_err(CE_NOTE, "ioc_update, NULL parameter");
11321bdd6c0eSSue Gleeson 		return (IBDMA_BAD_PARAM);
11331bdd6c0eSSue Gleeson 	}
11341bdd6c0eSSue Gleeson 
11351bdd6c0eSSue Gleeson 	mutex_enter(&ibdma->ms_hca_list_lock);
11361bdd6c0eSSue Gleeson 	hca = ibdma_find_hca(hdl_tmp->ih_iou_guid);
11371bdd6c0eSSue Gleeson 	if (hca == NULL) {
11381bdd6c0eSSue Gleeson 		cmn_err(CE_NOTE, "ioc_update, invalid handle, IOU not found");
11391bdd6c0eSSue Gleeson 		mutex_exit(&ibdma->ms_hca_list_lock);
11401bdd6c0eSSue Gleeson 		return (IBDMA_BAD_PARAM);
11411bdd6c0eSSue Gleeson 	}
11421bdd6c0eSSue Gleeson 
11431bdd6c0eSSue Gleeson 	hdl_impl = list_head(&hca->ih_hdl_list);
11441bdd6c0eSSue Gleeson 	while (hdl_impl != NULL) {
11451bdd6c0eSSue Gleeson 		if (hdl_impl == hdl_tmp) {
11461bdd6c0eSSue Gleeson 			break;
11471bdd6c0eSSue Gleeson 		}
11481bdd6c0eSSue Gleeson 		hdl_impl = list_next(&hca->ih_hdl_list, hdl_impl);
11491bdd6c0eSSue Gleeson 	}
11501bdd6c0eSSue Gleeson 
11511bdd6c0eSSue Gleeson 	if (hdl_impl == NULL) {
11521bdd6c0eSSue Gleeson 		cmn_err(CE_NOTE, "ioc_update, invalid handle, not found");
11531bdd6c0eSSue Gleeson 		mutex_exit(&ibdma->ms_hca_list_lock);
11541bdd6c0eSSue Gleeson 		return (IBDMA_BAD_PARAM);
11551bdd6c0eSSue Gleeson 	}
11561bdd6c0eSSue Gleeson 
11571bdd6c0eSSue Gleeson 	if (hdl_impl->ih_ioc_ndx >= IBDMA_MAX_IOC) {
11581bdd6c0eSSue Gleeson 		cmn_err(CE_NOTE, "ioc_update, corrupted handle");
11591bdd6c0eSSue Gleeson 		mutex_exit(&ibdma->ms_hca_list_lock);
11601bdd6c0eSSue Gleeson 		return (IBDMA_BAD_PARAM);
11611bdd6c0eSSue Gleeson 	}
11621bdd6c0eSSue Gleeson 	ioc = &hca->ih_ioc[hdl_impl->ih_ioc_ndx];
11631bdd6c0eSSue Gleeson 
11641bdd6c0eSSue Gleeson 	if (ioc->ii_slot >= IBDMA_MAX_IOC || ioc->ii_hcap == NULL) {
11651bdd6c0eSSue Gleeson 		cmn_err(CE_NOTE, "ioc_update, bad handle (%p)",
11661bdd6c0eSSue Gleeson 		    (void *)hdl);
11671bdd6c0eSSue Gleeson 		mutex_exit(&ibdma->ms_hca_list_lock);
11681bdd6c0eSSue Gleeson 		return (IBDMA_BAD_PARAM);
11691bdd6c0eSSue Gleeson 	}
11701bdd6c0eSSue Gleeson 
11711bdd6c0eSSue Gleeson 	rw_enter(&ioc->ii_hcap->ih_iou_rwlock, RW_WRITER);
11721bdd6c0eSSue Gleeson 	if (ioc->ii_inuse == 0) {
11731bdd6c0eSSue Gleeson 		rw_exit(&ioc->ii_hcap->ih_iou_rwlock);
11741bdd6c0eSSue Gleeson 		mutex_exit(&ibdma->ms_hca_list_lock);
11751bdd6c0eSSue Gleeson 		cmn_err(CE_NOTE, "ioc_udate slot not in use (%d)",
11761bdd6c0eSSue Gleeson 		    ioc->ii_slot+1);
11771bdd6c0eSSue Gleeson 		return (IBDMA_BAD_PARAM);
11781bdd6c0eSSue Gleeson 	}
11791bdd6c0eSSue Gleeson 
11801bdd6c0eSSue Gleeson 	ASSERT(ioc->ii_srvcs != NULL);
11811bdd6c0eSSue Gleeson 
11821bdd6c0eSSue Gleeson 	kmem_free(ioc->ii_srvcs, ioc->ii_profile.ioc_service_entries *
11831bdd6c0eSSue Gleeson 	    sizeof (ib_dm_srv_t));
11841bdd6c0eSSue Gleeson 	ioc->ii_srvcs = kmem_zalloc(profile->ioc_service_entries  *
11851bdd6c0eSSue Gleeson 	    sizeof (ib_dm_srv_t), KM_SLEEP);
11861bdd6c0eSSue Gleeson 
11871bdd6c0eSSue Gleeson 	bcopy(profile, &ioc->ii_profile, sizeof (ib_dm_ioc_ctrl_profile_t));
11881bdd6c0eSSue Gleeson 	bcopy(services, ioc->ii_srvcs, sizeof (ib_dm_srv_t) *
11891bdd6c0eSSue Gleeson 	    profile->ioc_service_entries);
11901bdd6c0eSSue Gleeson 	/*
11911bdd6c0eSSue Gleeson 	 * Update the profile copy with the I/O controller slot assigned.
11921bdd6c0eSSue Gleeson 	 * The slot occupies the lower 8 biths of the vendor ID/slot 32bit
11931bdd6c0eSSue Gleeson 	 * field.
11941bdd6c0eSSue Gleeson 	 */
11951bdd6c0eSSue Gleeson 	profile->ioc_vendorid |= h2b32(ioc->ii_slot);
11961bdd6c0eSSue Gleeson 	ibdma_set_ioc_state(ioc->ii_hcap, ioc->ii_slot, IBDMA_IOC_PRESENT);
11971bdd6c0eSSue Gleeson 	rw_exit(&ioc->ii_hcap->ih_iou_rwlock);
11981bdd6c0eSSue Gleeson 	mutex_exit(&ibdma->ms_hca_list_lock);
11991bdd6c0eSSue Gleeson 
12001bdd6c0eSSue Gleeson 	return (IBDMA_SUCCESS);
12011bdd6c0eSSue Gleeson }
1202