11cfa752fSRamaswamy Tummala /*
21cfa752fSRamaswamy Tummala  * CDDL HEADER START
31cfa752fSRamaswamy Tummala  *
41cfa752fSRamaswamy Tummala  * The contents of this file are subject to the terms of the
51cfa752fSRamaswamy Tummala  * Common Development and Distribution License (the "License").
61cfa752fSRamaswamy Tummala  * You may not use this file except in compliance with the License.
71cfa752fSRamaswamy Tummala  *
81cfa752fSRamaswamy Tummala  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91cfa752fSRamaswamy Tummala  * or http://www.opensolaris.org/os/licensing.
101cfa752fSRamaswamy Tummala  * See the License for the specific language governing permissions
111cfa752fSRamaswamy Tummala  * and limitations under the License.
121cfa752fSRamaswamy Tummala  *
131cfa752fSRamaswamy Tummala  * When distributing Covered Code, include this CDDL HEADER in each
141cfa752fSRamaswamy Tummala  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151cfa752fSRamaswamy Tummala  * If applicable, add the following below this CDDL HEADER, with the
161cfa752fSRamaswamy Tummala  * fields enclosed by brackets "[]" replaced with your own identifying
171cfa752fSRamaswamy Tummala  * information: Portions Copyright [yyyy] [name of copyright owner]
181cfa752fSRamaswamy Tummala  *
191cfa752fSRamaswamy Tummala  * CDDL HEADER END
201cfa752fSRamaswamy Tummala  */
211cfa752fSRamaswamy Tummala /*
221cfa752fSRamaswamy Tummala  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
231cfa752fSRamaswamy Tummala  */
241cfa752fSRamaswamy Tummala 
253fe80ca4SDan Cross /*
263fe80ca4SDan Cross  * Copyright 2023 Oxide Computer Company
273fe80ca4SDan Cross  */
283fe80ca4SDan Cross 
291cfa752fSRamaswamy Tummala #include <sys/conf.h>
301cfa752fSRamaswamy Tummala #include <sys/stat.h>
311cfa752fSRamaswamy Tummala #include <sys/modctl.h>
321cfa752fSRamaswamy Tummala #include <sys/taskq.h>
331cfa752fSRamaswamy Tummala #include <sys/mdi_impldefs.h>
341cfa752fSRamaswamy Tummala #include <sys/sunmdi.h>
351cfa752fSRamaswamy Tummala #include <sys/sunpm.h>
361cfa752fSRamaswamy Tummala #include <sys/ib/mgt/ibdm/ibdm_impl.h>
371cfa752fSRamaswamy Tummala #include <sys/ib/ibnex/ibnex.h>
381cfa752fSRamaswamy Tummala #include <sys/ib/ibnex/ibnex_devctl.h>
391cfa752fSRamaswamy Tummala #include <sys/ib/ibtl/ibti.h>
401cfa752fSRamaswamy Tummala #include <sys/ib/ibtl/impl/ibtl_ibnex.h>
411cfa752fSRamaswamy Tummala #include <sys/file.h>
421cfa752fSRamaswamy Tummala #include <sys/hwconf.h>
431cfa752fSRamaswamy Tummala #include <sys/fs/dv_node.h>
441cfa752fSRamaswamy Tummala 
451cfa752fSRamaswamy Tummala void ibnex_handle_hca_attach(void *);
461cfa752fSRamaswamy Tummala static int ibnex_hca_bus_config_one(dev_info_t *, void *,
471cfa752fSRamaswamy Tummala 		ddi_bus_config_op_t, uint_t *, dev_info_t **);
481cfa752fSRamaswamy Tummala 
491cfa752fSRamaswamy Tummala static ibnex_node_data_t *ibnex_get_cdip_info(dev_info_t *, char *,
501cfa752fSRamaswamy Tummala 		dev_info_t **, ibnex_node_type_t *);
511cfa752fSRamaswamy Tummala static int ibnex_prom_devname_to_pkey_n_portnum(
521cfa752fSRamaswamy Tummala 		char *, ib_pkey_t *, uint8_t *);
531cfa752fSRamaswamy Tummala static dev_info_t *ibnex_config_obp_args(dev_info_t *, char *);
541cfa752fSRamaswamy Tummala 
551cfa752fSRamaswamy Tummala extern int	ibnex_busctl(dev_info_t *,
561cfa752fSRamaswamy Tummala 		    dev_info_t *, ddi_ctl_enum_t, void *, void *);
571cfa752fSRamaswamy Tummala extern int	ibnex_map_fault(dev_info_t *,
581cfa752fSRamaswamy Tummala 		    dev_info_t *, struct hat *, struct seg *,
591cfa752fSRamaswamy Tummala 			caddr_t, struct devpage *, pfn_t, uint_t, uint_t);
601cfa752fSRamaswamy Tummala static int	ibnex_hca_bus_config(dev_info_t *, uint_t,
611cfa752fSRamaswamy Tummala 		    ddi_bus_config_op_t, void *, dev_info_t **);
621cfa752fSRamaswamy Tummala static int	ibnex_hca_bus_unconfig(dev_info_t *,
631cfa752fSRamaswamy Tummala 		    uint_t, ddi_bus_config_op_t, void *);
641cfa752fSRamaswamy Tummala extern dev_info_t	*ibnex_config_port_node(dev_info_t *, char *);
651cfa752fSRamaswamy Tummala extern dev_info_t	*ibnex_config_obp_args(dev_info_t *, char *);
661cfa752fSRamaswamy Tummala extern int		ibnex_ioc_bus_config_one(dev_info_t **, uint_t,
671cfa752fSRamaswamy Tummala 			    ddi_bus_config_op_t, void *, dev_info_t **, int *);
681cfa752fSRamaswamy Tummala extern int		ibnex_pseudo_config_one(
691cfa752fSRamaswamy Tummala 		    ibnex_node_data_t *, char *, dev_info_t *);
701cfa752fSRamaswamy Tummala extern void		ibnex_config_all_children(dev_info_t *);
711cfa752fSRamaswamy Tummala extern void			ibnex_pseudo_initnodes(void);
721cfa752fSRamaswamy Tummala 
731cfa752fSRamaswamy Tummala extern int		ibnex_pseudo_mdi_config_one(int, void *, dev_info_t **,
741cfa752fSRamaswamy Tummala 			    char *, char *);
751cfa752fSRamaswamy Tummala extern int			ibnex_get_dip_from_guid(ib_guid_t, int,
761cfa752fSRamaswamy Tummala 			    ib_pkey_t, dev_info_t **);
771cfa752fSRamaswamy Tummala extern dev_info_t	*ibnex_commsvc_initnode(dev_info_t *,
781cfa752fSRamaswamy Tummala 			    ibdm_port_attr_t *, int, int, ib_pkey_t, int *,
791cfa752fSRamaswamy Tummala 			    int);
801cfa752fSRamaswamy Tummala extern uint64_t		ibnex_str2hex(char *, int, int *);
811cfa752fSRamaswamy Tummala extern int		ibnex_str2int(char *, int, int *);
821cfa752fSRamaswamy Tummala extern void		ibnex_create_hcasvc_nodes(
831cfa752fSRamaswamy Tummala 			    dev_info_t *, ibdm_port_attr_t *);
841cfa752fSRamaswamy Tummala extern void		ibnex_create_port_nodes(
851cfa752fSRamaswamy Tummala 			    dev_info_t *, ibdm_port_attr_t *);
861cfa752fSRamaswamy Tummala extern void		ibnex_create_vppa_nodes(
871cfa752fSRamaswamy Tummala 			    dev_info_t *, ibdm_port_attr_t *);
881cfa752fSRamaswamy Tummala extern int		ibnex_get_pkey_commsvc_index_portnum(
891cfa752fSRamaswamy Tummala 			    char *, int *, ib_pkey_t *, uint8_t *);
901cfa752fSRamaswamy Tummala 
911cfa752fSRamaswamy Tummala extern ibnex_t	ibnex;
921cfa752fSRamaswamy Tummala extern int	ibnex_port_settling_time;
931cfa752fSRamaswamy Tummala 
941cfa752fSRamaswamy Tummala /*
951cfa752fSRamaswamy Tummala  * The bus_ops structure defines the capabilities of HCA nexus driver.
961cfa752fSRamaswamy Tummala  */
971cfa752fSRamaswamy Tummala struct bus_ops ibnex_ci_busops = {
981cfa752fSRamaswamy Tummala 	BUSO_REV,
991cfa752fSRamaswamy Tummala 	nullbusmap,		/* bus_map */
1001cfa752fSRamaswamy Tummala 	NULL,			/* bus_get_intrspec */
1011cfa752fSRamaswamy Tummala 	NULL,			/* bus_add_intrspec */
1021cfa752fSRamaswamy Tummala 	NULL,			/* bus_remove_intrspec */
1031cfa752fSRamaswamy Tummala 	ibnex_map_fault,	/* Map Fault */
1041cfa752fSRamaswamy Tummala 	ddi_no_dma_map,		/* DMA related entry points */
1051cfa752fSRamaswamy Tummala 	NULL,
1061cfa752fSRamaswamy Tummala 	NULL,
1071cfa752fSRamaswamy Tummala 	NULL,
1081cfa752fSRamaswamy Tummala 	NULL,
1091cfa752fSRamaswamy Tummala 	NULL,
1101cfa752fSRamaswamy Tummala 	NULL,
1111cfa752fSRamaswamy Tummala 	NULL,
1121cfa752fSRamaswamy Tummala 	ibnex_busctl,		/* bus_ctl */
1131cfa752fSRamaswamy Tummala 	ddi_bus_prop_op,	/* bus_prop_op */
1141cfa752fSRamaswamy Tummala 	NULL,			/* bus_get_eventcookie	*/
1151cfa752fSRamaswamy Tummala 	NULL,			/* bus_add_eventcall	*/
1161cfa752fSRamaswamy Tummala 	NULL,			/* bus_remove_eventcall	*/
1171cfa752fSRamaswamy Tummala 	NULL,			/* bus_post_event	*/
1181cfa752fSRamaswamy Tummala 	NULL,
1191cfa752fSRamaswamy Tummala 	ibnex_hca_bus_config,	/* bus config */
1201cfa752fSRamaswamy Tummala 	ibnex_hca_bus_unconfig	/* bus unconfig */
1211cfa752fSRamaswamy Tummala };
1221cfa752fSRamaswamy Tummala 
1231cfa752fSRamaswamy Tummala /*
1241cfa752fSRamaswamy Tummala  * ibnex_hca_bus_config()
1251cfa752fSRamaswamy Tummala  *
1261cfa752fSRamaswamy Tummala  * BUS_CONFIG_ONE:
1271cfa752fSRamaswamy Tummala  *	Enumerate the exact instance of the driver. Use the device node name
1281cfa752fSRamaswamy Tummala  *	to locate the exact instance.
1291cfa752fSRamaswamy Tummala  *	Query IBDM to find whether the hardware exits for the instance of the
1301cfa752fSRamaswamy Tummala  *	driver. If exists, create a device node and return NDI_SUCCESS.
1311cfa752fSRamaswamy Tummala  *
1321cfa752fSRamaswamy Tummala  * BUS_CONFIG_ALL:
1331cfa752fSRamaswamy Tummala  *	Enumerate all the instances of all the possible children (seen before
1341cfa752fSRamaswamy Tummala  *	and never seen before).
1351cfa752fSRamaswamy Tummala  *
1361cfa752fSRamaswamy Tummala  * BUS_CONFIG_DRIVER:
1371cfa752fSRamaswamy Tummala  *	Enumerate all the instances of a particular driver.
1381cfa752fSRamaswamy Tummala  */
1391cfa752fSRamaswamy Tummala static int
ibnex_hca_bus_config(dev_info_t * parent,uint_t flag,ddi_bus_config_op_t op,void * devname,dev_info_t ** child)1401cfa752fSRamaswamy Tummala ibnex_hca_bus_config(dev_info_t *parent, uint_t flag,
1411cfa752fSRamaswamy Tummala     ddi_bus_config_op_t op, void *devname, dev_info_t **child)
1421cfa752fSRamaswamy Tummala {
1433fe80ca4SDan Cross 	int			ret = IBNEX_SUCCESS;
1443fe80ca4SDan Cross 	boolean_t		enteredv;
1451cfa752fSRamaswamy Tummala 	char			*srvname, nameaddr[MAXNAMELEN];
1461cfa752fSRamaswamy Tummala 	dev_info_t		*cdip;
1471cfa752fSRamaswamy Tummala 	ibnex_node_data_t	*node_data;
1481cfa752fSRamaswamy Tummala 	ibnex_port_node_t	*port_node;
1491cfa752fSRamaswamy Tummala 
1501cfa752fSRamaswamy Tummala 	/*
1511cfa752fSRamaswamy Tummala 	 * In a normal case HCA is setup as a phci.
1521cfa752fSRamaswamy Tummala 	 * If an HCA is in maintenance mode, its phci is not set up
1531cfa752fSRamaswamy Tummala 	 * but the driver is attached to update the firmware. In this
1541cfa752fSRamaswamy Tummala 	 * case, do not configure the MPxIO clients.
1551cfa752fSRamaswamy Tummala 	 */
1561cfa752fSRamaswamy Tummala 	if (mdi_component_is_phci(parent, NULL) == MDI_FAILURE) {
1571cfa752fSRamaswamy Tummala 		if (op == BUS_CONFIG_ALL || op == BUS_CONFIG_DRIVER)
1581cfa752fSRamaswamy Tummala 			return (NDI_SUCCESS);
1591cfa752fSRamaswamy Tummala 		else
1601cfa752fSRamaswamy Tummala 			return (NDI_FAILURE);
1611cfa752fSRamaswamy Tummala 	}
1621cfa752fSRamaswamy Tummala 
1631cfa752fSRamaswamy Tummala 	switch (op) {
1641cfa752fSRamaswamy Tummala 	case BUS_CONFIG_ONE:
1651cfa752fSRamaswamy Tummala 		IBTF_DPRINTF_L4("ibnex", "\thca_bus_config: CONFIG_ONE, "
1661cfa752fSRamaswamy Tummala 		    "parent %p", parent);
1671cfa752fSRamaswamy Tummala 		ret = ibnex_hca_bus_config_one(
1681cfa752fSRamaswamy Tummala 		    parent, devname, op, &flag, child);
1691cfa752fSRamaswamy Tummala 		break;
1701cfa752fSRamaswamy Tummala 
1711cfa752fSRamaswamy Tummala 	case BUS_CONFIG_OBP_ARGS:
1723fe80ca4SDan Cross 		mdi_devi_enter(parent, &enteredv);
1731cfa752fSRamaswamy Tummala 		cdip = ibnex_config_obp_args(parent, devname);
1741cfa752fSRamaswamy Tummala 		if (cdip) {
1751cfa752fSRamaswamy Tummala 			/*
1761cfa752fSRamaswamy Tummala 			 * Boot case.
1771cfa752fSRamaswamy Tummala 			 * Special handling because the "devname"
1781cfa752fSRamaswamy Tummala 			 * format for the enumerated device is
1791cfa752fSRamaswamy Tummala 			 * different.
1801cfa752fSRamaswamy Tummala 			 */
1811cfa752fSRamaswamy Tummala 			node_data = ddi_get_parent_data(cdip);
1821cfa752fSRamaswamy Tummala 			port_node = &node_data->node_data.port_node;
1831cfa752fSRamaswamy Tummala 			if (node_data->node_type ==
1841cfa752fSRamaswamy Tummala 			    IBNEX_VPPA_COMMSVC_NODE) {
1851cfa752fSRamaswamy Tummala 				srvname =
1861cfa752fSRamaswamy Tummala 				    ibnex.ibnex_vppa_comm_svc_names[
1871cfa752fSRamaswamy Tummala 				    port_node->port_commsvc_idx];
1881cfa752fSRamaswamy Tummala 				(void) snprintf(nameaddr, MAXNAMELEN,
1891cfa752fSRamaswamy Tummala 				    "ibport@%x,%x,%s",
1901cfa752fSRamaswamy Tummala 				    port_node->port_num,
1911cfa752fSRamaswamy Tummala 				    port_node->port_pkey, srvname);
1921cfa752fSRamaswamy Tummala 			}
1931cfa752fSRamaswamy Tummala 			devname = (void *)nameaddr;
1941cfa752fSRamaswamy Tummala 		} else {
1951cfa752fSRamaswamy Tummala 			IBTF_DPRINTF_L2("ibnex", "\thca_bus_config: "
1961cfa752fSRamaswamy Tummala 			    "CONFIG_OBP_ARGS : invalid state!!");
1971cfa752fSRamaswamy Tummala 
1981cfa752fSRamaswamy Tummala 			ret = IBNEX_FAILURE;
1991cfa752fSRamaswamy Tummala 		}
2003fe80ca4SDan Cross 		mdi_devi_exit(parent, enteredv);
2011cfa752fSRamaswamy Tummala 		break;
2021cfa752fSRamaswamy Tummala 
2031cfa752fSRamaswamy Tummala 	case BUS_CONFIG_ALL:
2041cfa752fSRamaswamy Tummala 		IBTF_DPRINTF_L4("ibnex",
2051cfa752fSRamaswamy Tummala 		    "\thca_bus_config: CONFIG_ALL parent %p", parent);
2061cfa752fSRamaswamy Tummala 		ibnex_config_all_children(parent);
2071cfa752fSRamaswamy Tummala 		break;
2081cfa752fSRamaswamy Tummala 
2091cfa752fSRamaswamy Tummala 	case BUS_CONFIG_DRIVER:
2101cfa752fSRamaswamy Tummala 		IBTF_DPRINTF_L4("ibnex", "\thca_bus_config: "
2111cfa752fSRamaswamy Tummala 		    "CONFIG_DRIVER parent %p", parent);
2121cfa752fSRamaswamy Tummala 		ibnex_config_all_children(parent);
2131cfa752fSRamaswamy Tummala 		break;
2141cfa752fSRamaswamy Tummala 
2151cfa752fSRamaswamy Tummala 	default:
2161cfa752fSRamaswamy Tummala 		IBTF_DPRINTF_L4("ibnex", "\thca_bus_config: error");
2171cfa752fSRamaswamy Tummala 		ret = IBNEX_FAILURE;
2181cfa752fSRamaswamy Tummala 		break;
2191cfa752fSRamaswamy Tummala 	}
2201cfa752fSRamaswamy Tummala 
2211cfa752fSRamaswamy Tummala 
2221cfa752fSRamaswamy Tummala 	if (ret == IBNEX_SUCCESS) {
2231cfa752fSRamaswamy Tummala 		if (op == BUS_CONFIG_OBP_ARGS)
2241cfa752fSRamaswamy Tummala 			op = BUS_CONFIG_ONE;
2251cfa752fSRamaswamy Tummala 
2261cfa752fSRamaswamy Tummala 		ret = ndi_busop_bus_config(
2271cfa752fSRamaswamy Tummala 		    parent, flag, op, devname, child, 0);
2281cfa752fSRamaswamy Tummala 		IBTF_DPRINTF_L4("ibnex", "\thca_bus_config:"
2291cfa752fSRamaswamy Tummala 		    "ndi_busop_bus_config : retval %d", ret);
2301cfa752fSRamaswamy Tummala 		return (ret);
2311cfa752fSRamaswamy Tummala 	}
2321cfa752fSRamaswamy Tummala 
2331cfa752fSRamaswamy Tummala 	return (NDI_FAILURE);
2341cfa752fSRamaswamy Tummala }
2351cfa752fSRamaswamy Tummala 
2361cfa752fSRamaswamy Tummala /*
2371cfa752fSRamaswamy Tummala  * ibnex_hca_bus_unconfig()
2381cfa752fSRamaswamy Tummala  *
2391cfa752fSRamaswamy Tummala  *	Unconfigure a particular device node or all instance of a device
2401cfa752fSRamaswamy Tummala  *	driver device or all children of IBnex
2411cfa752fSRamaswamy Tummala  */
2421cfa752fSRamaswamy Tummala static int
ibnex_hca_bus_unconfig(dev_info_t * parent,uint_t flag,ddi_bus_config_op_t op,void * device_name)2431cfa752fSRamaswamy Tummala ibnex_hca_bus_unconfig(dev_info_t *parent,
2441cfa752fSRamaswamy Tummala     uint_t flag, ddi_bus_config_op_t op, void *device_name)
2451cfa752fSRamaswamy Tummala {
2461cfa752fSRamaswamy Tummala 
2471cfa752fSRamaswamy Tummala 	if (ndi_busop_bus_unconfig(parent, flag, op, device_name) !=
2481cfa752fSRamaswamy Tummala 	    DDI_SUCCESS)
2491cfa752fSRamaswamy Tummala 		return (DDI_FAILURE);
2501cfa752fSRamaswamy Tummala 
2511cfa752fSRamaswamy Tummala 	if ((op == BUS_UNCONFIG_ALL || op == BUS_UNCONFIG_DRIVER) &&
2521cfa752fSRamaswamy Tummala 	    (flag & NDI_UNCONFIG)) {
2531cfa752fSRamaswamy Tummala 		ibnex_node_data_t	*ndp;
2541cfa752fSRamaswamy Tummala 		dev_info_t		*dip = NULL;
2551cfa752fSRamaswamy Tummala 		major_t			major = (major_t)(uintptr_t)device_name;
2561cfa752fSRamaswamy Tummala 
2571cfa752fSRamaswamy Tummala 		mutex_enter(&ibnex.ibnex_mutex);
2581cfa752fSRamaswamy Tummala 
2591cfa752fSRamaswamy Tummala 		if (major == -1) {
2601cfa752fSRamaswamy Tummala 			/*
2611cfa752fSRamaswamy Tummala 			 * HCA dip. When major number is -1 HCA is
2621cfa752fSRamaswamy Tummala 			 * going away cleanup all the port nodes.
2631cfa752fSRamaswamy Tummala 			 */
2641cfa752fSRamaswamy Tummala 			for (ndp = ibnex.ibnex_port_node_head;
2651cfa752fSRamaswamy Tummala 			    ndp; ndp = ndp->node_next) {
2661cfa752fSRamaswamy Tummala 				ibnex_port_node_t	*port_node;
2671cfa752fSRamaswamy Tummala 
2681cfa752fSRamaswamy Tummala 				port_node = &ndp->node_data.port_node;
2691cfa752fSRamaswamy Tummala 				if (port_node->port_pdip == parent) {
2701cfa752fSRamaswamy Tummala 					port_node->port_pdip = NULL;
2711cfa752fSRamaswamy Tummala 					ndp->node_dip = NULL;
2721cfa752fSRamaswamy Tummala 					ndp->node_state =
2731cfa752fSRamaswamy Tummala 					    IBNEX_CFGADM_UNCONFIGURED;
2741cfa752fSRamaswamy Tummala 				}
2751cfa752fSRamaswamy Tummala 			}
2761cfa752fSRamaswamy Tummala 		} else {
2771cfa752fSRamaswamy Tummala 			/*
2781cfa752fSRamaswamy Tummala 			 * HCA dip. Cleanup only the port nodes that
2791cfa752fSRamaswamy Tummala 			 * match the major number.
2801cfa752fSRamaswamy Tummala 			 */
2811cfa752fSRamaswamy Tummala 			for (ndp = ibnex.ibnex_port_node_head;
2821cfa752fSRamaswamy Tummala 			    ndp; ndp = ndp->node_next) {
2831cfa752fSRamaswamy Tummala 				ibnex_port_node_t	*port_node;
2841cfa752fSRamaswamy Tummala 
2851cfa752fSRamaswamy Tummala 				port_node = &ndp->node_data.port_node;
2861cfa752fSRamaswamy Tummala 				dip = ndp->node_dip;
2871cfa752fSRamaswamy Tummala 				if (dip && (ddi_driver_major(dip) ==
2881cfa752fSRamaswamy Tummala 				    major) && port_node->port_pdip ==
2891cfa752fSRamaswamy Tummala 				    parent) {
2901cfa752fSRamaswamy Tummala 					port_node->port_pdip = NULL;
2911cfa752fSRamaswamy Tummala 					ndp->node_dip = NULL;
2921cfa752fSRamaswamy Tummala 					ndp->node_state =
2931cfa752fSRamaswamy Tummala 					    IBNEX_CFGADM_UNCONFIGURED;
2941cfa752fSRamaswamy Tummala 				}
2951cfa752fSRamaswamy Tummala 			}
2961cfa752fSRamaswamy Tummala 		}
2971cfa752fSRamaswamy Tummala 		mutex_exit(&ibnex.ibnex_mutex);
2981cfa752fSRamaswamy Tummala 	}
2991cfa752fSRamaswamy Tummala 	return (DDI_SUCCESS);
3001cfa752fSRamaswamy Tummala }
3011cfa752fSRamaswamy Tummala 
3021cfa752fSRamaswamy Tummala /*
3031cfa752fSRamaswamy Tummala  * ibnex_config_obp_args()
3041cfa752fSRamaswamy Tummala  *	Configures a particular port node for a IP over IB communication
3051cfa752fSRamaswamy Tummala  *	service.
3061cfa752fSRamaswamy Tummala  *	The format of the input string "devname" is
307bf5d9f18SAndy Fiddaman  *		port=x,pkey=y,protocol=ip
3081cfa752fSRamaswamy Tummala  *	Thr format of the node name created here is
3091cfa752fSRamaswamy Tummala  *		ibport@<Port#>,<pkey>,<service name>
3101cfa752fSRamaswamy Tummala  *	where pkey = 0 for port communication service nodes
3111cfa752fSRamaswamy Tummala  *	Returns "dev_info_t" of the "child" node just created
3121cfa752fSRamaswamy Tummala  *	NULL when failed to enumerate the child node
3131cfa752fSRamaswamy Tummala  *
3141cfa752fSRamaswamy Tummala  */
3151cfa752fSRamaswamy Tummala static dev_info_t *
ibnex_config_obp_args(dev_info_t * parent,char * devname)3161cfa752fSRamaswamy Tummala ibnex_config_obp_args(dev_info_t *parent, char *devname)
3171cfa752fSRamaswamy Tummala {
3181cfa752fSRamaswamy Tummala 	int			ii, index;
3191cfa752fSRamaswamy Tummala 	int			rval, iter = 0;
3201cfa752fSRamaswamy Tummala 	char			*temp;
3211cfa752fSRamaswamy Tummala 	uint8_t			port_num;
3221cfa752fSRamaswamy Tummala 	ib_guid_t		hca_guid, port_guid;
3231cfa752fSRamaswamy Tummala 	ib_pkey_t		pkey;
3241cfa752fSRamaswamy Tummala 	dev_info_t		*cdip;
3251cfa752fSRamaswamy Tummala 	boolean_t		displayed = B_FALSE;
3261cfa752fSRamaswamy Tummala 	ibdm_port_attr_t	*port_attr;
3271cfa752fSRamaswamy Tummala 
3281cfa752fSRamaswamy Tummala 	IBTF_DPRINTF_L4("ibnex", "\tconfig_obp_args: %s", devname);
3291cfa752fSRamaswamy Tummala 
3301cfa752fSRamaswamy Tummala 	/* Is this OBP node for IPoIB ? */
3311cfa752fSRamaswamy Tummala 	temp = devname;
3321cfa752fSRamaswamy Tummala 	do {
3331cfa752fSRamaswamy Tummala 		temp = strstr(temp, ",protocol=ip");
3341cfa752fSRamaswamy Tummala 		if (temp == NULL)
3351cfa752fSRamaswamy Tummala 			break;
3361cfa752fSRamaswamy Tummala 
3371cfa752fSRamaswamy Tummala 		if (strlen(devname) > (int)((temp - devname) + 12)) {
3381cfa752fSRamaswamy Tummala 			if (temp[12] == ',')
3391cfa752fSRamaswamy Tummala 				break;
3401cfa752fSRamaswamy Tummala 		} else {
3411cfa752fSRamaswamy Tummala 			break;
3421cfa752fSRamaswamy Tummala 		}
3431cfa752fSRamaswamy Tummala 		temp++;
3441cfa752fSRamaswamy Tummala 	} while (temp);
3451cfa752fSRamaswamy Tummala 
3461cfa752fSRamaswamy Tummala 	if (temp == NULL)
3471cfa752fSRamaswamy Tummala 		return (NULL);
3481cfa752fSRamaswamy Tummala 	if (ibnex_prom_devname_to_pkey_n_portnum(
3491cfa752fSRamaswamy Tummala 	    devname, &pkey, &port_num) != IBNEX_SUCCESS) {
3501cfa752fSRamaswamy Tummala 		return (NULL);
3511cfa752fSRamaswamy Tummala 	}
3521cfa752fSRamaswamy Tummala 	for (index = 0; index < ibnex.ibnex_nvppa_comm_svcs; index++) {
3531cfa752fSRamaswamy Tummala 		if (strcmp(ibnex.ibnex_vppa_comm_svc_names[index],
3541cfa752fSRamaswamy Tummala 		    "ipib") == 0) {
3551cfa752fSRamaswamy Tummala 			break;
3561cfa752fSRamaswamy Tummala 		}
3571cfa752fSRamaswamy Tummala 	}
3581cfa752fSRamaswamy Tummala 
3591cfa752fSRamaswamy Tummala 	hca_guid = ibtl_ibnex_hcadip2guid(parent);
3601cfa752fSRamaswamy Tummala 	if ((port_attr = ibdm_ibnex_probe_hcaport(
3611cfa752fSRamaswamy Tummala 	    hca_guid, port_num)) == NULL) {
3621cfa752fSRamaswamy Tummala 		IBTF_DPRINTF_L2("ibnex",
3631cfa752fSRamaswamy Tummala 		    "\tconfig_port_node: Port does not exist");
3641cfa752fSRamaswamy Tummala 		return (NULL);
3651cfa752fSRamaswamy Tummala 	}
3661cfa752fSRamaswamy Tummala 
3671cfa752fSRamaswamy Tummala 	/* Wait until "port is up" */
3681cfa752fSRamaswamy Tummala 	while (port_attr->pa_state != IBT_PORT_ACTIVE) {
3691cfa752fSRamaswamy Tummala 		ibdm_ibnex_free_port_attr(port_attr);
3701cfa752fSRamaswamy Tummala 		delay(drv_usectohz(10000));
3711cfa752fSRamaswamy Tummala 		if ((port_attr = ibdm_ibnex_probe_hcaport(
3721cfa752fSRamaswamy Tummala 		    hca_guid, port_num)) == NULL) {
3731cfa752fSRamaswamy Tummala 			return (NULL);
3741cfa752fSRamaswamy Tummala 		}
3751cfa752fSRamaswamy Tummala 		if (iter++ == 400) {
3761cfa752fSRamaswamy Tummala 			if (displayed == B_FALSE) {
3771cfa752fSRamaswamy Tummala 				cmn_err(CE_NOTE, "\tWaiting for Port %d "
3781cfa752fSRamaswamy Tummala 				    "initialization", port_attr->pa_port_num);
3791cfa752fSRamaswamy Tummala 				displayed = B_TRUE;
3801cfa752fSRamaswamy Tummala 			}
3811cfa752fSRamaswamy Tummala 		}
3821cfa752fSRamaswamy Tummala 	}
3831cfa752fSRamaswamy Tummala 	IBTF_DPRINTF_L4("ibnex", "\tPort is initialized");
3841cfa752fSRamaswamy Tummala 
3851cfa752fSRamaswamy Tummala 	mutex_enter(&ibnex.ibnex_mutex);
3861cfa752fSRamaswamy Tummala 	port_guid = port_attr->pa_port_guid;
3871cfa752fSRamaswamy Tummala 	rval = ibnex_get_dip_from_guid(port_guid, index, pkey, &cdip);
3881cfa752fSRamaswamy Tummala 	if (rval == IBNEX_SUCCESS && cdip != NULL) {
3891cfa752fSRamaswamy Tummala 		IBTF_DPRINTF_L4("ibnex", "\tconfig_port_node: Node exists");
3901cfa752fSRamaswamy Tummala 		mutex_exit(&ibnex.ibnex_mutex);
3911cfa752fSRamaswamy Tummala 		ibdm_ibnex_free_port_attr(port_attr);
3921cfa752fSRamaswamy Tummala 		return (cdip);
3931cfa752fSRamaswamy Tummala 	}
3941cfa752fSRamaswamy Tummala 	for (ii = 0; ii < port_attr->pa_npkeys; ii++) {
3951cfa752fSRamaswamy Tummala 		if (pkey == port_attr->pa_pkey_tbl[ii].pt_pkey) {
3961cfa752fSRamaswamy Tummala 			cdip = ibnex_commsvc_initnode(parent, port_attr,
3971cfa752fSRamaswamy Tummala 			    index, IBNEX_VPPA_COMMSVC_NODE, pkey, &rval,
3981cfa752fSRamaswamy Tummala 			    IBNEX_CFGADM_ENUMERATE);
3991cfa752fSRamaswamy Tummala 			IBTF_DPRINTF_L5("ibnex",
4001cfa752fSRamaswamy Tummala 			    "\t ibnex_commsvc_initnode rval %x", rval);
4011cfa752fSRamaswamy Tummala 			break;
4021cfa752fSRamaswamy Tummala 		}
4031cfa752fSRamaswamy Tummala 	}
4041cfa752fSRamaswamy Tummala 	mutex_exit(&ibnex.ibnex_mutex);
4051cfa752fSRamaswamy Tummala 
4061cfa752fSRamaswamy Tummala 	ibdm_ibnex_free_port_attr(port_attr);
4071cfa752fSRamaswamy Tummala 	return (cdip);
4081cfa752fSRamaswamy Tummala }
4091cfa752fSRamaswamy Tummala 
4101cfa752fSRamaswamy Tummala 
4111cfa752fSRamaswamy Tummala /*
4121cfa752fSRamaswamy Tummala  * ibnex_prom_devname_to_pkey_n_portnum()
4131cfa752fSRamaswamy Tummala  *	Parses the device node name and extracts "PKEY" and "port#"
4141cfa752fSRamaswamy Tummala  *	Returns IBNEX_SUCCESS/IBNEX_FAILURE
4151cfa752fSRamaswamy Tummala  */
4161cfa752fSRamaswamy Tummala static int
ibnex_prom_devname_to_pkey_n_portnum(char * devname,ib_pkey_t * pkey,uint8_t * port)4171cfa752fSRamaswamy Tummala ibnex_prom_devname_to_pkey_n_portnum(
4181cfa752fSRamaswamy Tummala     char *devname, ib_pkey_t *pkey, uint8_t *port)
4191cfa752fSRamaswamy Tummala {
4201cfa752fSRamaswamy Tummala 	int	ret = IBNEX_SUCCESS;
4211cfa752fSRamaswamy Tummala 	char	*tmp, *tmp1;
4221cfa752fSRamaswamy Tummala 
4231cfa752fSRamaswamy Tummala 	if ((tmp = strstr(devname, "port=")) != NULL) {
4241cfa752fSRamaswamy Tummala 		if ((tmp = strchr(++tmp, '=')) != NULL)
4251cfa752fSRamaswamy Tummala 			if ((tmp1 = strchr(++tmp, ',')) != NULL)
4261cfa752fSRamaswamy Tummala 				*port = ibnex_str2int(tmp, (tmp1 - tmp), &ret);
4271cfa752fSRamaswamy Tummala 	} else
4281cfa752fSRamaswamy Tummala 		ret = IBNEX_FAILURE;
4291cfa752fSRamaswamy Tummala 
4301cfa752fSRamaswamy Tummala 	if ((ret == IBNEX_SUCCESS) &&
4311cfa752fSRamaswamy Tummala 	    (tmp = strstr(devname, "pkey=")) != NULL) {
4321cfa752fSRamaswamy Tummala 		if ((tmp = strchr(++tmp, '=')) != NULL)
4331cfa752fSRamaswamy Tummala 			if ((tmp1 = strchr(++tmp, ',')) != NULL)
4341cfa752fSRamaswamy Tummala 				*pkey = ibnex_str2hex(tmp, (tmp1 - tmp), &ret);
4351cfa752fSRamaswamy Tummala 	} else
4361cfa752fSRamaswamy Tummala 		ret = IBNEX_FAILURE;
4371cfa752fSRamaswamy Tummala 
4381cfa752fSRamaswamy Tummala 	return (ret);
4391cfa752fSRamaswamy Tummala }
4401cfa752fSRamaswamy Tummala 
4411cfa752fSRamaswamy Tummala static ibnex_node_data_t *
ibnex_get_cdip_info(dev_info_t * parent,char * devname,dev_info_t ** cdip,ibnex_node_type_t * type)4421cfa752fSRamaswamy Tummala ibnex_get_cdip_info(dev_info_t *parent,
4431cfa752fSRamaswamy Tummala     char *devname, dev_info_t **cdip, ibnex_node_type_t *type)
4441cfa752fSRamaswamy Tummala {
445*d5ebc493SDan Cross 	char			*device_name, *cname = NULL, *caddr = NULL;
4461cfa752fSRamaswamy Tummala 	int			len;
4471cfa752fSRamaswamy Tummala 	ibnex_node_data_t	*node_data = NULL;
4481cfa752fSRamaswamy Tummala 
4491cfa752fSRamaswamy Tummala 	len = strlen((char *)devname) + 1;
4501cfa752fSRamaswamy Tummala 	device_name = i_ddi_strdup(devname, KM_SLEEP);
4511cfa752fSRamaswamy Tummala 	i_ddi_parse_name(device_name, &cname, &caddr, NULL);
4521cfa752fSRamaswamy Tummala 
4531cfa752fSRamaswamy Tummala 	IBTF_DPRINTF_L4("ibnex",
4541cfa752fSRamaswamy Tummala 	    "\tfind_child_dip: cname %s addr %s", cname, caddr);
4551cfa752fSRamaswamy Tummala 
4561cfa752fSRamaswamy Tummala 	if (strncmp(cname, IBNEX_IOC_CNAME, 3) ==  0)
4571cfa752fSRamaswamy Tummala 		*type = IBNEX_IOC_NODE;
4581cfa752fSRamaswamy Tummala 	else if (strncmp(cname, IBNEX_IBPORT_CNAME, 3) ==  0)
4591cfa752fSRamaswamy Tummala 		*type = IBNEX_HCA_CHILD_NODE;
4601cfa752fSRamaswamy Tummala 	else
4611cfa752fSRamaswamy Tummala 		*type = IBNEX_PSEUDO_NODE;
4621cfa752fSRamaswamy Tummala 
4631cfa752fSRamaswamy Tummala 	*cdip = ndi_devi_findchild(parent, devname);
4641cfa752fSRamaswamy Tummala 
4651cfa752fSRamaswamy Tummala 	IBTF_DPRINTF_L4("ibnex",
4661cfa752fSRamaswamy Tummala 	    "\tfind_child_dip: cdip %p type %x", *cdip, *type);
4671cfa752fSRamaswamy Tummala 
4681cfa752fSRamaswamy Tummala 	if (*cdip)
4691cfa752fSRamaswamy Tummala 		node_data = ddi_get_parent_data(*cdip);
4701cfa752fSRamaswamy Tummala 	kmem_free(device_name, len);
4711cfa752fSRamaswamy Tummala 
4721cfa752fSRamaswamy Tummala 	return (node_data);
4731cfa752fSRamaswamy Tummala }
4741cfa752fSRamaswamy Tummala 
4751cfa752fSRamaswamy Tummala static int
ibnex_hca_bus_config_one(dev_info_t * parent,void * devname,ddi_bus_config_op_t op,uint_t * flag,dev_info_t ** child)4761cfa752fSRamaswamy Tummala ibnex_hca_bus_config_one(dev_info_t *parent, void *devname,
477bf5d9f18SAndy Fiddaman     ddi_bus_config_op_t op, uint_t *flag, dev_info_t **child)
4781cfa752fSRamaswamy Tummala {
4793fe80ca4SDan Cross 	int			ret = IBNEX_SUCCESS, len, need_bus_config;
480*d5ebc493SDan Cross 	char			*device_name, *caddr, *cname;
4811cfa752fSRamaswamy Tummala 	dev_info_t		*cdip;
4821cfa752fSRamaswamy Tummala 	ibnex_node_data_t	*node_data;
4831cfa752fSRamaswamy Tummala 	ibnex_node_type_t	node_type;
4841cfa752fSRamaswamy Tummala 	int			index;
4851cfa752fSRamaswamy Tummala 	uint8_t			port_num;
4861cfa752fSRamaswamy Tummala 	ib_pkey_t		pkey;
4873fe80ca4SDan Cross 	boolean_t		enteredv;
4881cfa752fSRamaswamy Tummala 
4891cfa752fSRamaswamy Tummala 	len = strlen((char *)devname) + 1;
4901cfa752fSRamaswamy Tummala 	device_name = i_ddi_strdup(devname, KM_SLEEP);
4911cfa752fSRamaswamy Tummala 	i_ddi_parse_name(device_name, &cname, &caddr, NULL);
4921cfa752fSRamaswamy Tummala 
4931cfa752fSRamaswamy Tummala 	if (caddr == NULL || (strlen(caddr) == 0)) {
4941cfa752fSRamaswamy Tummala 		IBTF_DPRINTF_L2("ibnex",
4951cfa752fSRamaswamy Tummala 		    "\thca_bus_config: Invalid device node address");
4961cfa752fSRamaswamy Tummala 		kmem_free(device_name, len);
4971cfa752fSRamaswamy Tummala 		return (IBNEX_FAILURE);
4981cfa752fSRamaswamy Tummala 	}
4991cfa752fSRamaswamy Tummala 
5003fe80ca4SDan Cross 	ndi_devi_enter(parent);
5011cfa752fSRamaswamy Tummala 	node_data = ibnex_get_cdip_info(
5021cfa752fSRamaswamy Tummala 	    parent, devname, &cdip, &node_type);
5033fe80ca4SDan Cross 	ndi_devi_exit(parent);
5041cfa752fSRamaswamy Tummala 
5051cfa752fSRamaswamy Tummala 	if (cdip) {
5061cfa752fSRamaswamy Tummala 		if ((node_data) && (node_data->node_type ==
5071cfa752fSRamaswamy Tummala 		    IBNEX_PORT_COMMSVC_NODE)) {
5081cfa752fSRamaswamy Tummala 			if (node_data->node_dip == NULL) {
5091cfa752fSRamaswamy Tummala 				node_data->node_dip = cdip;
5101cfa752fSRamaswamy Tummala 				node_data->node_data.port_node.port_pdip =
5111cfa752fSRamaswamy Tummala 				    parent;
5121cfa752fSRamaswamy Tummala 			}
5131cfa752fSRamaswamy Tummala 		}
5141cfa752fSRamaswamy Tummala 	}
5151cfa752fSRamaswamy Tummala 
5161cfa752fSRamaswamy Tummala 	/*
5171cfa752fSRamaswamy Tummala 	 * If child dip is present, just return
5181cfa752fSRamaswamy Tummala 	 * from here.
5191cfa752fSRamaswamy Tummala 	 */
5201cfa752fSRamaswamy Tummala 	if (cdip != NULL || (node_data != NULL &&
5211cfa752fSRamaswamy Tummala 	    node_data->node_dip != NULL)) {
5221cfa752fSRamaswamy Tummala 		goto end;
5231cfa752fSRamaswamy Tummala 	}
5241cfa752fSRamaswamy Tummala 
5251cfa752fSRamaswamy Tummala 	switch (node_type) {
5261cfa752fSRamaswamy Tummala 
5271cfa752fSRamaswamy Tummala 	case IBNEX_IOC_NODE:
5281cfa752fSRamaswamy Tummala 		ret = ibnex_ioc_bus_config_one(&parent, *flag,
5291cfa752fSRamaswamy Tummala 		    op, devname, child, &need_bus_config);
5301cfa752fSRamaswamy Tummala 		if (!need_bus_config) {
5311cfa752fSRamaswamy Tummala 			kmem_free(device_name, len);
5321cfa752fSRamaswamy Tummala 			return (ret);
5331cfa752fSRamaswamy Tummala 		}
5341cfa752fSRamaswamy Tummala 		break;
5351cfa752fSRamaswamy Tummala 
5361cfa752fSRamaswamy Tummala 	case IBNEX_PSEUDO_NODE:
5371cfa752fSRamaswamy Tummala 		ret = IBNEX_SUCCESS;
5383fe80ca4SDan Cross 		mdi_devi_enter(parent, &enteredv);
5391cfa752fSRamaswamy Tummala 		ibnex_pseudo_initnodes();
5401cfa752fSRamaswamy Tummala 		mutex_enter(&ibnex.ibnex_mutex);
5411cfa752fSRamaswamy Tummala 		ret = ibnex_pseudo_config_one(NULL,
5421cfa752fSRamaswamy Tummala 		    caddr, parent);
5431cfa752fSRamaswamy Tummala 		mutex_exit(&ibnex.ibnex_mutex);
5443fe80ca4SDan Cross 		mdi_devi_exit(parent, enteredv);
5451cfa752fSRamaswamy Tummala 		break;
5461cfa752fSRamaswamy Tummala 
5471cfa752fSRamaswamy Tummala 	default:
5481cfa752fSRamaswamy Tummala 		if (ibnex_get_pkey_commsvc_index_portnum(devname,
5491cfa752fSRamaswamy Tummala 		    &index, &pkey, &port_num) != IBNEX_SUCCESS) {
5501cfa752fSRamaswamy Tummala 			IBTF_DPRINTF_L2("ibnex",
5511cfa752fSRamaswamy Tummala 			    "\tconfig_port_node: Invalid Service Name");
55203c76a6eSRajkumar Sivaprakasam 			kmem_free(device_name, len);
5531cfa752fSRamaswamy Tummala 			return (IBNEX_FAILURE);
5541cfa752fSRamaswamy Tummala 		}
5551cfa752fSRamaswamy Tummala 
5561cfa752fSRamaswamy Tummala 		if ((pkey != 0) && (port_num != 0)) {
5571cfa752fSRamaswamy Tummala 			if (strcmp("ipib",
5581cfa752fSRamaswamy Tummala 			    ibnex.ibnex_vppa_comm_svc_names[index]) == 0) {
5591cfa752fSRamaswamy Tummala 				IBTF_DPRINTF_L2("ibnex",
5601cfa752fSRamaswamy Tummala 				    "Skipping IBD devices... ");
5611cfa752fSRamaswamy Tummala 				break;
5621cfa752fSRamaswamy Tummala 			}
5631cfa752fSRamaswamy Tummala 		}
5641cfa752fSRamaswamy Tummala 
5653fe80ca4SDan Cross 		ndi_devi_enter(parent);
5661cfa752fSRamaswamy Tummala 		cdip = ibnex_config_port_node(parent, devname);
5671cfa752fSRamaswamy Tummala 		if (cdip)
5681cfa752fSRamaswamy Tummala 			ret = IBNEX_SUCCESS;
5691cfa752fSRamaswamy Tummala 		else
5701cfa752fSRamaswamy Tummala 			ret = IBNEX_FAILURE;
5713fe80ca4SDan Cross 		ndi_devi_exit(parent);
5721cfa752fSRamaswamy Tummala 		break;
5731cfa752fSRamaswamy Tummala 	}
5741cfa752fSRamaswamy Tummala end:
5751cfa752fSRamaswamy Tummala 	if (node_type == IBNEX_HCA_CHILD_NODE) {
5761cfa752fSRamaswamy Tummala 		/* Allows enumeration under PHCI */
5771cfa752fSRamaswamy Tummala 		*flag |= NDI_MDI_FALLBACK;
5781cfa752fSRamaswamy Tummala 	}
5791cfa752fSRamaswamy Tummala 	kmem_free(device_name, len);
5801cfa752fSRamaswamy Tummala 	return (ret);
5811cfa752fSRamaswamy Tummala }
5821cfa752fSRamaswamy Tummala 
5831cfa752fSRamaswamy Tummala void
ibnex_handle_hca_attach(void * cb_arg)5841cfa752fSRamaswamy Tummala ibnex_handle_hca_attach(void *cb_arg)
5851cfa752fSRamaswamy Tummala {
5861aae5cd0SRajkumar Sivaprakasam 	ib_guid_t hca_guid	= *((ib_guid_t *)cb_arg);
5871aae5cd0SRajkumar Sivaprakasam 	dev_info_t		*phci;
5883fe80ca4SDan Cross 	int			ii;
5891cfa752fSRamaswamy Tummala 	ibdm_hca_list_t		*hca_list;
5901cfa752fSRamaswamy Tummala 
5911cfa752fSRamaswamy Tummala 	IBTF_DPRINTF_L4("ibnex", "handle_hca_attach(%llx)", hca_guid);
5921cfa752fSRamaswamy Tummala 
5931cfa752fSRamaswamy Tummala 	phci = ibtl_ibnex_hcaguid2dip(hca_guid);
5941cfa752fSRamaswamy Tummala 
5951cfa752fSRamaswamy Tummala 	/*
5961cfa752fSRamaswamy Tummala 	 * Enumerate children of this HCA, port nodes,
5971cfa752fSRamaswamy Tummala 	 * VPPA & HCA_SVC nodes. Use ndi_devi_enter() for
5981cfa752fSRamaswamy Tummala 	 * locking. IB Nexus is enumerating the children
5991cfa752fSRamaswamy Tummala 	 * of HCA, not MPXIO clients.
6001cfa752fSRamaswamy Tummala 	 */
6013fe80ca4SDan Cross 	ndi_devi_enter(phci);
6021cfa752fSRamaswamy Tummala 	ibdm_ibnex_port_settle_wait(hca_guid, ibnex_port_settling_time);
6031cfa752fSRamaswamy Tummala 	hca_list = ibdm_ibnex_get_hca_info_by_guid(hca_guid);
6041cfa752fSRamaswamy Tummala 	if (hca_list == NULL) {
6053fe80ca4SDan Cross 		ndi_devi_exit(phci);
60603c76a6eSRajkumar Sivaprakasam 		kmem_free(cb_arg, sizeof (ib_guid_t));
6071cfa752fSRamaswamy Tummala 		return;
6081cfa752fSRamaswamy Tummala 	}
6091cfa752fSRamaswamy Tummala 	ibnex_create_hcasvc_nodes(phci, hca_list->hl_hca_port_attr);
6101cfa752fSRamaswamy Tummala 	for (ii = 0; ii < hca_list->hl_nports; ii++) {
6111aae5cd0SRajkumar Sivaprakasam 		ibnex_create_port_nodes(phci, &hca_list->hl_port_attr[ii]);
6121aae5cd0SRajkumar Sivaprakasam 		ibnex_create_vppa_nodes(phci, &hca_list->hl_port_attr[ii]);
6131cfa752fSRamaswamy Tummala 	}
6141cfa752fSRamaswamy Tummala 	ibdm_ibnex_free_hca_list(hca_list);
6153fe80ca4SDan Cross 	ndi_devi_exit(phci);
61603c76a6eSRajkumar Sivaprakasam 	kmem_free(cb_arg, sizeof (ib_guid_t));
6171cfa752fSRamaswamy Tummala }
618