Home | History | Annotate | Download | only in ibtl
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #include <sys/systm.h>
     27 #include <sys/sunndi.h>
     28 #include <sys/sunmdi.h>
     29 #include <sys/ib/ibtl/impl/ibtl.h>
     30 #include <sys/ib/ibtl/impl/ibtl_ibnex.h>
     31 
     32 /*
     33  * ibtl_ibnex.c
     34  *    These routines tie the Device Manager into IBTL.
     35  *
     36  *    ibt_reprobe_dev which can be called by IBTF clients.
     37  *    This results in calls to IBnexus callback.
     38  */
     39 
     40 /*
     41  * Globals.
     42  */
     43 static char		ibtl_ibnex[] = "ibtl_ibnex";
     44 ibtl_ibnex_callback_t	ibtl_ibnex_callback_routine = NULL;
     45 
     46 /*
     47  * Function:
     48  *	ibtl_ibnex_get_hca_info
     49  * Input:
     50  *	hca_guid	- The HCA's node GUID.
     51  *	flag		- Tells what to do
     52  *			IBTL_IBNEX_LIST_CLNTS_FLAG - Build a NVLIST containing
     53  *						client's names, their AP_IDs and
     54  *						alternate_HCA information.
     55  *						(-x list_clients option)
     56  *			IBTL_IBNEX_UNCFG_CLNTS_FLAG - Build a NVLIST containing
     57  *						clients' devpaths and their
     58  *						AP_IDs. (-x unconfig_clients)
     59  *	callback	- Callback function to get ap_id from ib(7d)
     60  * Output:
     61  *	buffer		- The information is returned in this buffer
     62  *      bufsiz		- The size of the information buffer
     63  * Returns:
     64  *	IBT_SUCCESS/IBT_HCA_INVALID/IBT_INVALID_PARAM
     65  * Description:
     66  *      For a given HCA node GUID it figures out the registered clients
     67  *	(ie. ones who called ibt_open_hca(9f) on this GUID) and creates
     68  *	a NVL packed buffer (of client names/ap_ids or devpaths) and returns
     69  *	it. If flag is not specified, then an error is returned.
     70  */
     71 ibt_status_t
     72 ibtl_ibnex_get_hca_info(ib_guid_t hca_guid, int flag, char **buffer,
     73     size_t *bufsiz, void (*callback)(dev_info_t *, char **))
     74 {
     75 	char			*node_name;
     76 	char			*ret_apid;
     77 	nvlist_t		*nvl;
     78 	ibtl_hca_t		*ibt_hca;
     79 	ibtl_clnt_t		*clntp;
     80 	dev_info_t		*child;
     81 	dev_info_t		*parent;
     82 	ibtl_hca_devinfo_t	*hca_devp;
     83 
     84 	IBTF_DPRINTF_L3(ibtl_ibnex, "ibtl_ibnex_get_hca_info: "
     85 	    "GUID  0x%llX, flag = 0x%x", hca_guid, flag);
     86 
     87 	*buffer = NULL;
     88 	*bufsiz = 0;
     89 
     90 	/* verify that valid "flag" is passed */
     91 	if (flag != IBTL_IBNEX_LIST_CLNTS_FLAG &&
     92 	    flag != IBTL_IBNEX_UNCFG_CLNTS_FLAG) {
     93 		return (IBT_INVALID_PARAM);
     94 	}
     95 
     96 	mutex_enter(&ibtl_clnt_list_mutex);
     97 
     98 	if ((hca_devp = ibtl_get_hcadevinfo(hca_guid)) == NULL) {
     99 		mutex_exit(&ibtl_clnt_list_mutex);
    100 
    101 		/*
    102 		 * If we are here, then the requested HCA device is not
    103 		 * present. Return the status as Invalid HCA GUID.
    104 		 */
    105 		IBTF_DPRINTF_L2(ibtl_ibnex, "ibtl_ibnex_get_hca_info: "
    106 		    "HCA Not Found, Invalid HCA GUID 0x%llX", hca_guid);
    107 		return (IBT_HCA_INVALID);
    108 	}
    109 
    110 	/* Walk the client list */
    111 	ibt_hca = hca_devp->hd_clnt_list;
    112 	(void) nvlist_alloc(&nvl, 0, KM_SLEEP);
    113 
    114 	/* Allocate memory for ret_apid, instead of using stack */
    115 	ret_apid = kmem_alloc(IBTL_IBNEX_APID_LEN, KM_SLEEP);
    116 
    117 	while (ibt_hca != NULL) {
    118 		clntp = ibt_hca->ha_clnt_devp;
    119 		child = clntp->clnt_dip;
    120 		IBTF_DPRINTF_L4(ibtl_ibnex, "ibtl_ibnex_get_hca_info: "
    121 		    "Client = %s", clntp->clnt_modinfop->mi_clnt_name);
    122 
    123 		if (flag == IBTL_IBNEX_LIST_CLNTS_FLAG) {
    124 			(void) nvlist_add_string(nvl, "Client",
    125 			    clntp->clnt_modinfop->mi_clnt_name);
    126 
    127 			/*
    128 			 * Always check, first, if this client exists
    129 			 * under this HCA anymore? If not, continue.
    130 			 */
    131 			if (clntp->clnt_hca_list == NULL) {
    132 				(void) nvlist_add_string(nvl, "Alt_HCA", "no");
    133 				(void) nvlist_add_string(nvl, "ApID", "-");
    134 				ibt_hca = ibt_hca->ha_clnt_link;
    135 				continue;
    136 			}
    137 
    138 			/* Check if this client has more than one HCAs */
    139 			if (clntp->clnt_hca_list->ha_hca_link == NULL)
    140 				(void) nvlist_add_string(nvl, "Alt_HCA", "no");
    141 			else
    142 				(void) nvlist_add_string(nvl, "Alt_HCA", "yes");
    143 
    144 			if (child == NULL) {
    145 				(void) nvlist_add_string(nvl, "ApID", "-");
    146 				ibt_hca = ibt_hca->ha_clnt_link;
    147 				continue;
    148 			}
    149 
    150 			/*
    151 			 * All IB clients (IOC, VPPA, Port, Pseudo etc.)
    152 			 * need to be looked at. The parent of IOC nodes
    153 			 * is "ib" nexus and node-name is "ioc". "VPPA/Port"s
    154 			 * should have HCA as parent and node-name is "ibport".
    155 			 * HCA validity is checked by looking at parent's "dip"
    156 			 * and the dip saved in the ibtl_hca_devinfo_t.
    157 			 * NOTE: We only want to list this HCA's IB clients.
    158 			 * All others clients are ignored.
    159 			 */
    160 			parent = ddi_get_parent(child);
    161 			if (parent == NULL || /* No parent? */
    162 			    ddi_get_parent_data(child) == NULL) {
    163 				(void) nvlist_add_string(nvl, "ApID", "-");
    164 				ibt_hca = ibt_hca->ha_clnt_link;
    165 				continue;
    166 			}
    167 
    168 			node_name = ddi_node_name(child);
    169 			if ((strcmp(ddi_node_name(parent), "ib") == 0) ||
    170 			    ((hca_devp->hd_hca_dip == parent) &&
    171 			    (strncmp(node_name, IBNEX_IBPORT_CNAME, 6) == 0))) {
    172 				ASSERT(callback != NULL);
    173 				/*
    174 				 * Callback is invoked to figure out the
    175 				 * ap_id string.
    176 				 */
    177 				callback(child, &ret_apid);
    178 				(void) nvlist_add_string(nvl, "ApID", ret_apid);
    179 			} else {
    180 				(void) nvlist_add_string(nvl, "ApID", "-");
    181 			}
    182 
    183 		} else if (flag == IBTL_IBNEX_UNCFG_CLNTS_FLAG) {
    184 			char		path[MAXPATHLEN];
    185 
    186 			if (child == NULL) {
    187 				IBTF_DPRINTF_L4(ibtl_ibnex,
    188 				    "ibtl_ibnex_get_hca_info: No dip exists");
    189 				ibt_hca = ibt_hca->ha_clnt_link;
    190 				continue;
    191 			}
    192 
    193 			/*
    194 			 * if the child has a alternate HCA then skip it
    195 			 */
    196 			if (clntp->clnt_hca_list->ha_hca_link) {
    197 				IBTF_DPRINTF_L4(ibtl_ibnex,
    198 				    "ibtl_ibnex_get_hca_info: Alt HCA exists");
    199 				ibt_hca = ibt_hca->ha_clnt_link;
    200 				continue;
    201 			}
    202 
    203 			/*
    204 			 * See earlier comments on how to check if a client
    205 			 * is IOC, VPPA, Port or a Pseudo node.
    206 			 */
    207 			parent = ddi_get_parent(child);
    208 			if (parent == NULL || /* No parent? */
    209 			    ddi_get_parent_data(child) == NULL) {
    210 				IBTF_DPRINTF_L4(ibtl_ibnex,
    211 				    "ibtl_ibnex_get_hca_info: no parent");
    212 				ibt_hca = ibt_hca->ha_clnt_link;
    213 				continue;
    214 			}
    215 
    216 			node_name = ddi_node_name(child);
    217 			if ((strcmp(ddi_node_name(parent), "ib") == 0) ||
    218 			    ((hca_devp->hd_hca_dip == parent) &&
    219 			    (strncmp(node_name, IBNEX_IBPORT_CNAME, 6) == 0))) {
    220 				ASSERT(callback != NULL);
    221 				/*
    222 				 * Callback is invoked to figure out the
    223 				 * ap_id string.
    224 				 */
    225 				callback(child, &ret_apid);
    226 				(void) nvlist_add_string(nvl, "ApID", ret_apid);
    227 
    228 				/*
    229 				 * ddi_pathname() doesn't supply /devices,
    230 				 * so we do
    231 				 */
    232 				(void) strcpy(path, "/devices");
    233 				(void) ddi_pathname(child, path + strlen(path));
    234 				IBTF_DPRINTF_L4(ibtl_ibnex,
    235 				    "ibtl_ibnex_get_hca_info: "
    236 				    "device path = %s", path);
    237 
    238 				if (nvlist_add_string(nvl, "devpath", path)) {
    239 					IBTF_DPRINTF_L2(ibtl_ibnex,
    240 					    "ibtl_ibnex_get_hca_info: "
    241 					    "failed to fill in path %s", path);
    242 					mutex_exit(&ibtl_clnt_list_mutex);
    243 					nvlist_free(nvl);
    244 					kmem_free(ret_apid,
    245 					    IBTL_IBNEX_APID_LEN);
    246 					return (ibt_get_module_failure(
    247 					    IBT_FAILURE_IBTL, 0));
    248 				}
    249 			} /* end of if */
    250 		} /* end of while */
    251 
    252 		ibt_hca = ibt_hca->ha_clnt_link;
    253 	} /* End of while */
    254 	mutex_exit(&ibtl_clnt_list_mutex);
    255 
    256 	kmem_free(ret_apid, IBTL_IBNEX_APID_LEN);
    257 
    258 	/* Pack all data into "buffer" */
    259 	if (nvlist_pack(nvl, buffer, bufsiz, NV_ENCODE_NATIVE, KM_SLEEP)) {
    260 		IBTF_DPRINTF_L2(ibtl_ibnex, "ibtl_ibnex_get_hca_info: "
    261 		    "nvlist_pack failed");
    262 		nvlist_free(nvl);
    263 		return (ibt_get_module_failure(IBT_FAILURE_IBTL, 0));
    264 	}
    265 
    266 	IBTF_DPRINTF_L4(ibtl_ibnex, "ibtl_ibnex_get_hca_info: size = %x",
    267 	    *bufsiz);
    268 	nvlist_free(nvl);
    269 	return (IBT_SUCCESS);
    270 }
    271 
    272 
    273 /*
    274  * Function:
    275  *      ibtl_ibnex_register_callback()
    276  * Input:
    277  *	ibnex_cb	- IB nexus driver callback routine
    278  * Output:
    279  *      none
    280  * Returns:
    281  *      none
    282  * Description:
    283  *     	Register a callback routine for IB nexus driver
    284  */
    285 void
    286 ibtl_ibnex_register_callback(ibtl_ibnex_callback_t ibnex_cb)
    287 {
    288 	IBTF_DPRINTF_L5(ibtl_ibnex, "ibtl_ibnex_register_callback:");
    289 
    290 	mutex_enter(&ibtl_clnt_list_mutex);
    291 	ibtl_ibnex_callback_routine = ibnex_cb;
    292 	mutex_exit(&ibtl_clnt_list_mutex);
    293 }
    294 
    295 /*
    296  * Function:
    297  *      ibtl_ibnex_unregister_callback()
    298  * Input:
    299  *      none
    300  * Output:
    301  *      none
    302  * Returns:
    303  *      none
    304  * Description:
    305  *     	Un-register a callback routine for IB nexus driver
    306  */
    307 void
    308 ibtl_ibnex_unregister_callback()
    309 {
    310 	IBTF_DPRINTF_L5(ibtl_ibnex, "ibtl_ibnex_unregister_callback: ibnex cb");
    311 
    312 	mutex_enter(&ibtl_clnt_list_mutex);
    313 	ibtl_ibnex_callback_routine = NULL;
    314 	mutex_exit(&ibtl_clnt_list_mutex);
    315 }
    316 
    317 
    318 /*
    319  * Function:
    320  *	ibtl_ibnex_hcadip2guid
    321  * Input:
    322  *	dev_info_t	- The "dip" of this HCA
    323  * Output:
    324  *	hca_guid	- The HCA's node GUID.
    325  * Returns:
    326  *	"HCA GUID" on SUCCESS, NULL on FAILURE
    327  * Description:
    328  *      For a given HCA node GUID it figures out the HCA GUID
    329  *	and returns it. If not found, NULL is returned.
    330  */
    331 ib_guid_t
    332 ibtl_ibnex_hcadip2guid(dev_info_t *hca_dip)
    333 {
    334 	ib_guid_t		hca_guid = 0LL;
    335 	ibtl_hca_devinfo_t	*hca_devp;
    336 
    337 	mutex_enter(&ibtl_clnt_list_mutex);
    338 	hca_devp = ibtl_hca_list;
    339 
    340 	while (hca_devp) {
    341 		if (hca_devp->hd_hca_dip == hca_dip) {
    342 			hca_guid = hca_devp->hd_hca_attr->hca_node_guid;
    343 			break;
    344 		}
    345 		hca_devp = hca_devp->hd_hca_dev_link;
    346 	}
    347 	mutex_exit(&ibtl_clnt_list_mutex);
    348 	IBTF_DPRINTF_L4(ibtl_ibnex, "ibtl_ibnex_hcadip_guid: hca_guid 0x%llX",
    349 	    hca_guid);
    350 	return (hca_guid);
    351 }
    352 
    353 
    354 /*
    355  * Function:
    356  *	ibtl_ibnex_hcaguid2dip
    357  * Input:
    358  *	hca_guid	- The HCA's node GUID.
    359  * Output:
    360  *	dev_info_t	- The "dip" of this HCA
    361  * Returns:
    362  *	"dip" on SUCCESS, NULL on FAILURE
    363  * Description:
    364  *      For a given HCA node GUID it figures out the "dip"
    365  *	and returns it. If not found, NULL is returned.
    366  */
    367 dev_info_t *
    368 ibtl_ibnex_hcaguid2dip(ib_guid_t hca_guid)
    369 {
    370 	dev_info_t		*dip = NULL;
    371 	ibtl_hca_devinfo_t	*hca_devp;
    372 
    373 	IBTF_DPRINTF_L4(ibtl_ibnex, "ibtl_ibnex_hcaguid2dip:");
    374 
    375 	mutex_enter(&ibtl_clnt_list_mutex);
    376 	hca_devp = ibtl_hca_list;
    377 
    378 	while (hca_devp) {
    379 		if (hca_devp->hd_hca_attr->hca_node_guid == hca_guid) {
    380 			dip = hca_devp->hd_hca_dip;
    381 			break;
    382 		}
    383 		hca_devp = hca_devp->hd_hca_dev_link;
    384 	}
    385 	mutex_exit(&ibtl_clnt_list_mutex);
    386 	return (dip);
    387 }
    388 
    389 
    390 /*
    391  * Function:
    392  *	ibtl_ibnex_get_hca_verbose_data
    393  * Input:
    394  *	hca_guid	- The HCA's node GUID.
    395  * Output:
    396  *	buffer		- The information is returned in this buffer
    397  *      bufsiz		- The size of the information buffer
    398  * Returns:
    399  *	IBT_SUCCESS/IBT_HCA_INVALID
    400  * Description:
    401  *      For a given HCA node GUID it figures out the verbose listing display.
    402  */
    403 ibt_status_t
    404 ibtl_ibnex_get_hca_verbose_data(ib_guid_t hca_guid, char **buffer,
    405     size_t *bufsiz)
    406 {
    407 	char			path[IBTL_IBNEX_STR_LEN];
    408 	char			tmp[MAXPATHLEN];
    409 	uint_t			ii;
    410 	ibt_hca_portinfo_t	*pinfop;
    411 	ibtl_hca_devinfo_t	*hca_devp;
    412 
    413 	IBTF_DPRINTF_L3(ibtl_ibnex, "ibtl_ibnex_get_hca_verbose_data: "
    414 	    "HCA GUID 0x%llX", hca_guid);
    415 
    416 	*buffer = NULL;
    417 	*bufsiz = 0;
    418 
    419 	mutex_enter(&ibtl_clnt_list_mutex);
    420 	if ((hca_devp = ibtl_get_hcadevinfo(hca_guid)) == NULL) {
    421 		mutex_exit(&ibtl_clnt_list_mutex);
    422 
    423 		/*
    424 		 * If we are here, then the requested HCA device is not
    425 		 * present. Return the status as Invalid HCA GUID.
    426 		 */
    427 		IBTF_DPRINTF_L2(ibtl_ibnex, "ibtl_ibnex_get_hca_verbose_data: "
    428 		    "HCA Not Found, Invalid HCA GUID");
    429 		return (IBT_HCA_INVALID);
    430 	}
    431 
    432 	(void) snprintf(tmp, MAXPATHLEN, "VID: 0x%x, PID: 0x%x, #ports: 0x%x",
    433 	    hca_devp->hd_hca_attr->hca_vendor_id,
    434 	    hca_devp->hd_hca_attr->hca_device_id,
    435 	    hca_devp->hd_hca_attr->hca_nports);
    436 
    437 	pinfop = hca_devp->hd_portinfop;
    438 	for (ii = 0; ii < hca_devp->hd_hca_attr->hca_nports; ii++) {
    439 		(void) snprintf(path, IBTL_IBNEX_STR_LEN,
    440 		    ", port%d GUID: 0x%llX", ii + 1,
    441 		    (longlong_t)pinfop[ii].p_sgid_tbl->gid_guid);
    442 		(void) strcat(tmp, path);
    443 	}
    444 	mutex_exit(&ibtl_clnt_list_mutex);
    445 
    446 	*bufsiz =  strlen(tmp);
    447 	*buffer = kmem_alloc(*bufsiz, KM_SLEEP);
    448 	(void) strncpy(*buffer, tmp, *bufsiz);
    449 
    450 	IBTF_DPRINTF_L4(ibtl_ibnex, "ibtl_ibnex_get_hca_verbose_data: "
    451 	    "data = %s, size = 0x%x", *buffer, *bufsiz);
    452 	return (IBT_SUCCESS);
    453 }
    454 
    455 /*
    456  * Function:
    457  *      ibt_reprobe_dev()
    458  * Input:
    459  *      dev_info_t	*dip
    460  * Output:
    461  *      none
    462  * Returns:
    463  *      Return value from IBnexus callback handler
    464  *		IBT_ILLEGAL_OP if IBnexus callback is not installed.
    465  * Description:
    466  *     	This function passes the IBTF client's "reprobe device
    467  *		properties" request to IBnexus. See ibt_reprobe_dev(9f)
    468  *		for details.
    469  */
    470 ibt_status_t
    471 ibt_reprobe_dev(dev_info_t *dip)
    472 {
    473 	ibt_status_t		rv;
    474 	ibtl_ibnex_cb_args_t	cb_args;
    475 
    476 	if (dip == NULL)
    477 		return (IBT_NOT_SUPPORTED);
    478 
    479 	/*
    480 	 * Restricting the reprobe request to the children of
    481 	 * ibnexus. Note the IB_CONF_UPDATE_EVENT DDI event can
    482 	 * be subscribed by any device on the IBnexus device tree.
    483 	 */
    484 	if (strcmp(ddi_node_name(ddi_get_parent(dip)), "ib") != 0)
    485 		return (IBT_NOT_SUPPORTED);
    486 
    487 	/* Reprobe for IOC nodes only */
    488 	if (strncmp(ddi_node_name(dip), IBNEX_IBPORT_CNAME, 6) == 0)
    489 		return (IBT_NOT_SUPPORTED);
    490 
    491 	cb_args.cb_flag = IBTL_IBNEX_REPROBE_DEV_REQ;
    492 	cb_args.cb_dip = dip;
    493 	mutex_enter(&ibtl_clnt_list_mutex);
    494 	if (ibtl_ibnex_callback_routine) {
    495 		rv = (*ibtl_ibnex_callback_routine)(&cb_args);
    496 		mutex_exit(&ibtl_clnt_list_mutex);
    497 		return (rv);
    498 	}
    499 	mutex_exit(&ibtl_clnt_list_mutex);
    500 
    501 	/* Should -not- come here */
    502 	IBTF_DPRINTF_L2("ibtl", "ibt_reprobe_dev: ibnex not registered!!");
    503 	return (IBT_ILLEGAL_OP);
    504 }
    505 
    506 
    507 /*
    508  * Function:
    509  *	ibtl_ibnex_valid_hca_parent
    510  * Input:
    511  *	pdip		- The parent dip from client's child dev_info_t
    512  * Output:
    513  *	NONE
    514  * Returns:
    515  *	IBT_SUCCESS/IBT_NO_HCAS_AVAILABLE
    516  * Description:
    517  *	For a given pdip, of Port/VPPA devices, match it against all the
    518  *	registered HCAs's dip.  If match found return IBT_SUCCESS,
    519  *	else IBT_NO_HCAS_AVAILABLE.
    520  *	For IOC/Pseudo devices check if the given pdip is that of
    521  *	the ib(7d) nexus. If yes return IBT_SUCCESS,
    522  *	else IBT_NO_HCAS_AVAILABLE.
    523  */
    524 ibt_status_t
    525 ibtl_ibnex_valid_hca_parent(dev_info_t *pdip)
    526 {
    527 	ibtl_hca_devinfo_t	*hca_devp;
    528 
    529 	IBTF_DPRINTF_L4(ibtl_ibnex, "ibtl_ibnex_valid_hca_parent: pdip %p",
    530 	    pdip);
    531 
    532 	/* For Pseudo devices and IOCs */
    533 	if (strncmp(ddi_node_name(pdip), "ib", 2) == 0)
    534 		return (IBT_SUCCESS);
    535 	else {
    536 		/* For Port devices and VPPAs */
    537 		mutex_enter(&ibtl_clnt_list_mutex);
    538 		hca_devp = ibtl_hca_list;
    539 		while (hca_devp) {
    540 			if (hca_devp->hd_hca_dip == pdip) {
    541 				mutex_exit(&ibtl_clnt_list_mutex);
    542 				return (IBT_SUCCESS);
    543 			}
    544 			hca_devp = hca_devp->hd_hca_dev_link;
    545 		}
    546 		mutex_exit(&ibtl_clnt_list_mutex);
    547 		return (IBT_NO_HCAS_AVAILABLE);
    548 	}
    549 }
    550 
    551 /*
    552  * Function:
    553  *	ibtl_ibnex_phci_register
    554  * Input:
    555  *	hca_dip		- The HCA dip
    556  * Output:
    557  *	NONE
    558  * Returns:
    559  *	IBT_SUCCESS/IBT_FAILURE
    560  * Description:
    561  * 	Register the HCA dip as the MPxIO PCHI.
    562  */
    563 ibt_status_t
    564 ibtl_ibnex_phci_register(dev_info_t *hca_dip)
    565 {
    566 	/* Register the with MPxIO as PHCI */
    567 	if (mdi_phci_register(MDI_HCI_CLASS_IB, hca_dip, 0) !=
    568 	    MDI_SUCCESS) {
    569 		return (IBT_FAILURE);
    570 	}
    571 	return (IBT_SUCCESS);
    572 }
    573 
    574 /*
    575  * Function:
    576  *	ibtl_ibnex_phci_unregister
    577  * Input:
    578  *	hca_dip		- The HCA dip
    579  * Output:
    580  *	NONE
    581  * Returns:
    582  *	IBT_SUCCESS/IBT_FAILURE
    583  * Description:
    584  * 	Free up any pending MPxIO Pathinfos and unregister the HCA dip as the
    585  * 	MPxIO PCHI.
    586  */
    587 ibt_status_t
    588 ibtl_ibnex_phci_unregister(dev_info_t *hca_dip)
    589 {
    590 	mdi_pathinfo_t *pip = NULL;
    591 	dev_info_t *vdip = 0;
    592 	int circ = 0, circ1 = 0;
    593 
    594 	/*
    595 	 * Should free all the Pathinfos associated with the HCA pdip before
    596 	 * unregistering the PHCI.
    597 	 *
    598 	 * mdi_pi_free will call ib_vhci_pi_uninit() callbackfor each PI where
    599 	 * the ibnex internal datastructures (ibnex_node_data) will have to be
    600 	 * cleaned up if needed.
    601 	 */
    602 	vdip = mdi_devi_get_vdip(hca_dip);
    603 	ndi_devi_enter(vdip, &circ1);
    604 	ndi_devi_enter(hca_dip, &circ);
    605 	while (pip = mdi_get_next_client_path(hca_dip, NULL)) {
    606 		if (mdi_pi_free(pip, 0) == MDI_SUCCESS) {
    607 			continue;
    608 		}
    609 		ndi_devi_exit(hca_dip, circ);
    610 		ndi_devi_exit(vdip, circ1);
    611 		IBTF_DPRINTF_L1(ibtl_ibnex, "ibtl_ibnex_phci_unregister: "
    612 		    "mdi_pi_free failed");
    613 		return (IBT_FAILURE);
    614 	}
    615 	ndi_devi_exit(hca_dip, circ);
    616 	ndi_devi_exit(vdip, circ1);
    617 
    618 	if (mdi_phci_unregister(hca_dip, 0) != MDI_SUCCESS) {
    619 		IBTF_DPRINTF_L1(ibtl_ibnex, "ibtl_ibnex_phci_unregister: PHCI "
    620 		    "unregister failed");
    621 		return (IBT_FAILURE);
    622 	}
    623 	return (IBT_SUCCESS);
    624 }
    625 
    626 /*
    627  * Function:
    628  *	ibtl_ibnex_query_hca_byguid
    629  * Input:
    630  *	hca_guid	- The HCA's node GUID.
    631  *	driver_name_size- size of the caller allocated driver_name buffer
    632  * Output:
    633  *	hca_attrs	- caller allocated buffer which will contain
    634  *			  HCA attributes upon success
    635  *	driver_name	- caller allocated buffer which will contain
    636  *			  HCA driver name upon success
    637  *	driver_instance - HCA driver instance
    638  *	hca_device_path	- caller allocated buffer of size MAXPATHLEN which
    639  *			  will contain hca device path upon success.
    640  * Returns:
    641  *	IBT_SUCCESS/IBT_FAILURE
    642  * Description:
    643  *	Get the HCA attributes, driver name and instance number of the
    644  *	specified HCA.
    645  */
    646 ibt_status_t
    647 ibtl_ibnex_query_hca_byguid(ib_guid_t hca_guid, ibt_hca_attr_t *hca_attrs,
    648     char *driver_name, size_t driver_name_size, int *driver_instance,
    649     char *hca_device_path)
    650 {
    651 	ibtl_hca_devinfo_t	*hca_devp;
    652 
    653 	IBTF_DPRINTF_L4(ibtl_ibnex, "ibtl_ibnex_query_hca_byguid("
    654 	    "hca_guid = 0x%llx, hca_attrs = 0x%p, driver_name = 0x%p, "
    655 	    "driver_name_size = 0x%d, driver_instancep = 0x%p)", hca_guid,
    656 	    hca_attrs, driver_name, (int)driver_name_size, driver_instance);
    657 
    658 	mutex_enter(&ibtl_clnt_list_mutex);
    659 
    660 	hca_devp = ibtl_get_hcadevinfo(hca_guid);
    661 	if (hca_devp == NULL) {
    662 		mutex_exit(&ibtl_clnt_list_mutex);
    663 		return (IBT_HCA_INVALID);
    664 	}
    665 
    666 	if (strlcpy(driver_name,
    667 	    ddi_driver_name(hca_devp->hd_hca_dip), driver_name_size) >=
    668 	    driver_name_size) {
    669 		mutex_exit(&ibtl_clnt_list_mutex);
    670 		return (IBT_INSUFF_KERNEL_RESOURCE);
    671 	}
    672 
    673 	(void) ddi_pathname(hca_devp->hd_hca_dip, hca_device_path);
    674 	*driver_instance = ddi_get_instance(hca_devp->hd_hca_dip);
    675 	bcopy(hca_devp->hd_hca_attr, hca_attrs, sizeof (ibt_hca_attr_t));
    676 
    677 	mutex_exit(&ibtl_clnt_list_mutex);
    678 	return (IBT_SUCCESS);
    679 }
    680