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 (c) 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 
25 /*
26  * Copyright 2023 Oxide Computer Company
27  */
28 
29 #include <sys/conf.h>
30 #include <sys/stat.h>
31 #include <sys/modctl.h>
32 #include <sys/taskq.h>
33 #include <sys/mdi_impldefs.h>
34 #include <sys/sunmdi.h>
35 #include <sys/sunpm.h>
36 #include <sys/ib/mgt/ibdm/ibdm_impl.h>
37 #include <sys/ib/ibnex/ibnex.h>
38 #include <sys/ib/ibnex/ibnex_devctl.h>
39 #include <sys/ib/ibtl/ibti.h>
40 #include <sys/ib/ibtl/impl/ibtl_ibnex.h>
41 #include <sys/file.h>
42 #include <sys/hwconf.h>
43 #include <sys/fs/dv_node.h>
44 
45 void ibnex_handle_hca_attach(void *);
46 static int ibnex_hca_bus_config_one(dev_info_t *, void *,
47 		ddi_bus_config_op_t, uint_t *, dev_info_t **);
48 
49 static ibnex_node_data_t *ibnex_get_cdip_info(dev_info_t *, char *,
50 		dev_info_t **, ibnex_node_type_t *);
51 static int ibnex_prom_devname_to_pkey_n_portnum(
52 		char *, ib_pkey_t *, uint8_t *);
53 static dev_info_t *ibnex_config_obp_args(dev_info_t *, char *);
54 
55 extern int	ibnex_busctl(dev_info_t *,
56 		    dev_info_t *, ddi_ctl_enum_t, void *, void *);
57 extern int	ibnex_map_fault(dev_info_t *,
58 		    dev_info_t *, struct hat *, struct seg *,
59 			caddr_t, struct devpage *, pfn_t, uint_t, uint_t);
60 static int	ibnex_hca_bus_config(dev_info_t *, uint_t,
61 		    ddi_bus_config_op_t, void *, dev_info_t **);
62 static int	ibnex_hca_bus_unconfig(dev_info_t *,
63 		    uint_t, ddi_bus_config_op_t, void *);
64 extern dev_info_t	*ibnex_config_port_node(dev_info_t *, char *);
65 extern dev_info_t	*ibnex_config_obp_args(dev_info_t *, char *);
66 extern int		ibnex_ioc_bus_config_one(dev_info_t **, uint_t,
67 			    ddi_bus_config_op_t, void *, dev_info_t **, int *);
68 extern int		ibnex_pseudo_config_one(
69 		    ibnex_node_data_t *, char *, dev_info_t *);
70 extern void		ibnex_config_all_children(dev_info_t *);
71 extern void			ibnex_pseudo_initnodes(void);
72 
73 extern int		ibnex_pseudo_mdi_config_one(int, void *, dev_info_t **,
74 			    char *, char *);
75 extern int			ibnex_get_dip_from_guid(ib_guid_t, int,
76 			    ib_pkey_t, dev_info_t **);
77 extern dev_info_t	*ibnex_commsvc_initnode(dev_info_t *,
78 			    ibdm_port_attr_t *, int, int, ib_pkey_t, int *,
79 			    int);
80 extern uint64_t		ibnex_str2hex(char *, int, int *);
81 extern int		ibnex_str2int(char *, int, int *);
82 extern void		ibnex_create_hcasvc_nodes(
83 			    dev_info_t *, ibdm_port_attr_t *);
84 extern void		ibnex_create_port_nodes(
85 			    dev_info_t *, ibdm_port_attr_t *);
86 extern void		ibnex_create_vppa_nodes(
87 			    dev_info_t *, ibdm_port_attr_t *);
88 extern int		ibnex_get_pkey_commsvc_index_portnum(
89 			    char *, int *, ib_pkey_t *, uint8_t *);
90 
91 extern ibnex_t	ibnex;
92 extern int	ibnex_port_settling_time;
93 
94 /*
95  * The bus_ops structure defines the capabilities of HCA nexus driver.
96  */
97 struct bus_ops ibnex_ci_busops = {
98 	BUSO_REV,
99 	nullbusmap,		/* bus_map */
100 	NULL,			/* bus_get_intrspec */
101 	NULL,			/* bus_add_intrspec */
102 	NULL,			/* bus_remove_intrspec */
103 	ibnex_map_fault,	/* Map Fault */
104 	ddi_no_dma_map,		/* DMA related entry points */
105 	NULL,
106 	NULL,
107 	NULL,
108 	NULL,
109 	NULL,
110 	NULL,
111 	NULL,
112 	ibnex_busctl,		/* bus_ctl */
113 	ddi_bus_prop_op,	/* bus_prop_op */
114 	NULL,			/* bus_get_eventcookie	*/
115 	NULL,			/* bus_add_eventcall	*/
116 	NULL,			/* bus_remove_eventcall	*/
117 	NULL,			/* bus_post_event	*/
118 	NULL,
119 	ibnex_hca_bus_config,	/* bus config */
120 	ibnex_hca_bus_unconfig	/* bus unconfig */
121 };
122 
123 /*
124  * ibnex_hca_bus_config()
125  *
126  * BUS_CONFIG_ONE:
127  *	Enumerate the exact instance of the driver. Use the device node name
128  *	to locate the exact instance.
129  *	Query IBDM to find whether the hardware exits for the instance of the
130  *	driver. If exists, create a device node and return NDI_SUCCESS.
131  *
132  * BUS_CONFIG_ALL:
133  *	Enumerate all the instances of all the possible children (seen before
134  *	and never seen before).
135  *
136  * BUS_CONFIG_DRIVER:
137  *	Enumerate all the instances of a particular driver.
138  */
139 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)140 ibnex_hca_bus_config(dev_info_t *parent, uint_t flag,
141     ddi_bus_config_op_t op, void *devname, dev_info_t **child)
142 {
143 	int			ret = IBNEX_SUCCESS;
144 	boolean_t		enteredv;
145 	char			*srvname, nameaddr[MAXNAMELEN];
146 	dev_info_t		*cdip;
147 	ibnex_node_data_t	*node_data;
148 	ibnex_port_node_t	*port_node;
149 
150 	/*
151 	 * In a normal case HCA is setup as a phci.
152 	 * If an HCA is in maintenance mode, its phci is not set up
153 	 * but the driver is attached to update the firmware. In this
154 	 * case, do not configure the MPxIO clients.
155 	 */
156 	if (mdi_component_is_phci(parent, NULL) == MDI_FAILURE) {
157 		if (op == BUS_CONFIG_ALL || op == BUS_CONFIG_DRIVER)
158 			return (NDI_SUCCESS);
159 		else
160 			return (NDI_FAILURE);
161 	}
162 
163 	switch (op) {
164 	case BUS_CONFIG_ONE:
165 		IBTF_DPRINTF_L4("ibnex", "\thca_bus_config: CONFIG_ONE, "
166 		    "parent %p", parent);
167 		ret = ibnex_hca_bus_config_one(
168 		    parent, devname, op, &flag, child);
169 		break;
170 
171 	case BUS_CONFIG_OBP_ARGS:
172 		mdi_devi_enter(parent, &enteredv);
173 		cdip = ibnex_config_obp_args(parent, devname);
174 		if (cdip) {
175 			/*
176 			 * Boot case.
177 			 * Special handling because the "devname"
178 			 * format for the enumerated device is
179 			 * different.
180 			 */
181 			node_data = ddi_get_parent_data(cdip);
182 			port_node = &node_data->node_data.port_node;
183 			if (node_data->node_type ==
184 			    IBNEX_VPPA_COMMSVC_NODE) {
185 				srvname =
186 				    ibnex.ibnex_vppa_comm_svc_names[
187 				    port_node->port_commsvc_idx];
188 				(void) snprintf(nameaddr, MAXNAMELEN,
189 				    "ibport@%x,%x,%s",
190 				    port_node->port_num,
191 				    port_node->port_pkey, srvname);
192 			}
193 			devname = (void *)nameaddr;
194 		} else {
195 			IBTF_DPRINTF_L2("ibnex", "\thca_bus_config: "
196 			    "CONFIG_OBP_ARGS : invalid state!!");
197 
198 			ret = IBNEX_FAILURE;
199 		}
200 		mdi_devi_exit(parent, enteredv);
201 		break;
202 
203 	case BUS_CONFIG_ALL:
204 		IBTF_DPRINTF_L4("ibnex",
205 		    "\thca_bus_config: CONFIG_ALL parent %p", parent);
206 		ibnex_config_all_children(parent);
207 		break;
208 
209 	case BUS_CONFIG_DRIVER:
210 		IBTF_DPRINTF_L4("ibnex", "\thca_bus_config: "
211 		    "CONFIG_DRIVER parent %p", parent);
212 		ibnex_config_all_children(parent);
213 		break;
214 
215 	default:
216 		IBTF_DPRINTF_L4("ibnex", "\thca_bus_config: error");
217 		ret = IBNEX_FAILURE;
218 		break;
219 	}
220 
221 
222 	if (ret == IBNEX_SUCCESS) {
223 		if (op == BUS_CONFIG_OBP_ARGS)
224 			op = BUS_CONFIG_ONE;
225 
226 		ret = ndi_busop_bus_config(
227 		    parent, flag, op, devname, child, 0);
228 		IBTF_DPRINTF_L4("ibnex", "\thca_bus_config:"
229 		    "ndi_busop_bus_config : retval %d", ret);
230 		return (ret);
231 	}
232 
233 	return (NDI_FAILURE);
234 }
235 
236 /*
237  * ibnex_hca_bus_unconfig()
238  *
239  *	Unconfigure a particular device node or all instance of a device
240  *	driver device or all children of IBnex
241  */
242 static int
ibnex_hca_bus_unconfig(dev_info_t * parent,uint_t flag,ddi_bus_config_op_t op,void * device_name)243 ibnex_hca_bus_unconfig(dev_info_t *parent,
244     uint_t flag, ddi_bus_config_op_t op, void *device_name)
245 {
246 
247 	if (ndi_busop_bus_unconfig(parent, flag, op, device_name) !=
248 	    DDI_SUCCESS)
249 		return (DDI_FAILURE);
250 
251 	if ((op == BUS_UNCONFIG_ALL || op == BUS_UNCONFIG_DRIVER) &&
252 	    (flag & NDI_UNCONFIG)) {
253 		ibnex_node_data_t	*ndp;
254 		dev_info_t		*dip = NULL;
255 		major_t			major = (major_t)(uintptr_t)device_name;
256 
257 		mutex_enter(&ibnex.ibnex_mutex);
258 
259 		if (major == -1) {
260 			/*
261 			 * HCA dip. When major number is -1 HCA is
262 			 * going away cleanup all the port nodes.
263 			 */
264 			for (ndp = ibnex.ibnex_port_node_head;
265 			    ndp; ndp = ndp->node_next) {
266 				ibnex_port_node_t	*port_node;
267 
268 				port_node = &ndp->node_data.port_node;
269 				if (port_node->port_pdip == parent) {
270 					port_node->port_pdip = NULL;
271 					ndp->node_dip = NULL;
272 					ndp->node_state =
273 					    IBNEX_CFGADM_UNCONFIGURED;
274 				}
275 			}
276 		} else {
277 			/*
278 			 * HCA dip. Cleanup only the port nodes that
279 			 * match the major number.
280 			 */
281 			for (ndp = ibnex.ibnex_port_node_head;
282 			    ndp; ndp = ndp->node_next) {
283 				ibnex_port_node_t	*port_node;
284 
285 				port_node = &ndp->node_data.port_node;
286 				dip = ndp->node_dip;
287 				if (dip && (ddi_driver_major(dip) ==
288 				    major) && port_node->port_pdip ==
289 				    parent) {
290 					port_node->port_pdip = NULL;
291 					ndp->node_dip = NULL;
292 					ndp->node_state =
293 					    IBNEX_CFGADM_UNCONFIGURED;
294 				}
295 			}
296 		}
297 		mutex_exit(&ibnex.ibnex_mutex);
298 	}
299 	return (DDI_SUCCESS);
300 }
301 
302 /*
303  * ibnex_config_obp_args()
304  *	Configures a particular port node for a IP over IB communication
305  *	service.
306  *	The format of the input string "devname" is
307  *		port=x,pkey=y,protocol=ip
308  *	Thr format of the node name created here is
309  *		ibport@<Port#>,<pkey>,<service name>
310  *	where pkey = 0 for port communication service nodes
311  *	Returns "dev_info_t" of the "child" node just created
312  *	NULL when failed to enumerate the child node
313  *
314  */
315 static dev_info_t *
ibnex_config_obp_args(dev_info_t * parent,char * devname)316 ibnex_config_obp_args(dev_info_t *parent, char *devname)
317 {
318 	int			ii, index;
319 	int			rval, iter = 0;
320 	char			*temp;
321 	uint8_t			port_num;
322 	ib_guid_t		hca_guid, port_guid;
323 	ib_pkey_t		pkey;
324 	dev_info_t		*cdip;
325 	boolean_t		displayed = B_FALSE;
326 	ibdm_port_attr_t	*port_attr;
327 
328 	IBTF_DPRINTF_L4("ibnex", "\tconfig_obp_args: %s", devname);
329 
330 	/* Is this OBP node for IPoIB ? */
331 	temp = devname;
332 	do {
333 		temp = strstr(temp, ",protocol=ip");
334 		if (temp == NULL)
335 			break;
336 
337 		if (strlen(devname) > (int)((temp - devname) + 12)) {
338 			if (temp[12] == ',')
339 				break;
340 		} else {
341 			break;
342 		}
343 		temp++;
344 	} while (temp);
345 
346 	if (temp == NULL)
347 		return (NULL);
348 	if (ibnex_prom_devname_to_pkey_n_portnum(
349 	    devname, &pkey, &port_num) != IBNEX_SUCCESS) {
350 		return (NULL);
351 	}
352 	for (index = 0; index < ibnex.ibnex_nvppa_comm_svcs; index++) {
353 		if (strcmp(ibnex.ibnex_vppa_comm_svc_names[index],
354 		    "ipib") == 0) {
355 			break;
356 		}
357 	}
358 
359 	hca_guid = ibtl_ibnex_hcadip2guid(parent);
360 	if ((port_attr = ibdm_ibnex_probe_hcaport(
361 	    hca_guid, port_num)) == NULL) {
362 		IBTF_DPRINTF_L2("ibnex",
363 		    "\tconfig_port_node: Port does not exist");
364 		return (NULL);
365 	}
366 
367 	/* Wait until "port is up" */
368 	while (port_attr->pa_state != IBT_PORT_ACTIVE) {
369 		ibdm_ibnex_free_port_attr(port_attr);
370 		delay(drv_usectohz(10000));
371 		if ((port_attr = ibdm_ibnex_probe_hcaport(
372 		    hca_guid, port_num)) == NULL) {
373 			return (NULL);
374 		}
375 		if (iter++ == 400) {
376 			if (displayed == B_FALSE) {
377 				cmn_err(CE_NOTE, "\tWaiting for Port %d "
378 				    "initialization", port_attr->pa_port_num);
379 				displayed = B_TRUE;
380 			}
381 		}
382 	}
383 	IBTF_DPRINTF_L4("ibnex", "\tPort is initialized");
384 
385 	mutex_enter(&ibnex.ibnex_mutex);
386 	port_guid = port_attr->pa_port_guid;
387 	rval = ibnex_get_dip_from_guid(port_guid, index, pkey, &cdip);
388 	if (rval == IBNEX_SUCCESS && cdip != NULL) {
389 		IBTF_DPRINTF_L4("ibnex", "\tconfig_port_node: Node exists");
390 		mutex_exit(&ibnex.ibnex_mutex);
391 		ibdm_ibnex_free_port_attr(port_attr);
392 		return (cdip);
393 	}
394 	for (ii = 0; ii < port_attr->pa_npkeys; ii++) {
395 		if (pkey == port_attr->pa_pkey_tbl[ii].pt_pkey) {
396 			cdip = ibnex_commsvc_initnode(parent, port_attr,
397 			    index, IBNEX_VPPA_COMMSVC_NODE, pkey, &rval,
398 			    IBNEX_CFGADM_ENUMERATE);
399 			IBTF_DPRINTF_L5("ibnex",
400 			    "\t ibnex_commsvc_initnode rval %x", rval);
401 			break;
402 		}
403 	}
404 	mutex_exit(&ibnex.ibnex_mutex);
405 
406 	ibdm_ibnex_free_port_attr(port_attr);
407 	return (cdip);
408 }
409 
410 
411 /*
412  * ibnex_prom_devname_to_pkey_n_portnum()
413  *	Parses the device node name and extracts "PKEY" and "port#"
414  *	Returns IBNEX_SUCCESS/IBNEX_FAILURE
415  */
416 static int
ibnex_prom_devname_to_pkey_n_portnum(char * devname,ib_pkey_t * pkey,uint8_t * port)417 ibnex_prom_devname_to_pkey_n_portnum(
418     char *devname, ib_pkey_t *pkey, uint8_t *port)
419 {
420 	int	ret = IBNEX_SUCCESS;
421 	char	*tmp, *tmp1;
422 
423 	if ((tmp = strstr(devname, "port=")) != NULL) {
424 		if ((tmp = strchr(++tmp, '=')) != NULL)
425 			if ((tmp1 = strchr(++tmp, ',')) != NULL)
426 				*port = ibnex_str2int(tmp, (tmp1 - tmp), &ret);
427 	} else
428 		ret = IBNEX_FAILURE;
429 
430 	if ((ret == IBNEX_SUCCESS) &&
431 	    (tmp = strstr(devname, "pkey=")) != NULL) {
432 		if ((tmp = strchr(++tmp, '=')) != NULL)
433 			if ((tmp1 = strchr(++tmp, ',')) != NULL)
434 				*pkey = ibnex_str2hex(tmp, (tmp1 - tmp), &ret);
435 	} else
436 		ret = IBNEX_FAILURE;
437 
438 	return (ret);
439 }
440 
441 static ibnex_node_data_t *
ibnex_get_cdip_info(dev_info_t * parent,char * devname,dev_info_t ** cdip,ibnex_node_type_t * type)442 ibnex_get_cdip_info(dev_info_t *parent,
443     char *devname, dev_info_t **cdip, ibnex_node_type_t *type)
444 {
445 	char			*device_name, *cname = NULL, *caddr = NULL;
446 	int			len;
447 	ibnex_node_data_t	*node_data = NULL;
448 
449 	len = strlen((char *)devname) + 1;
450 	device_name = i_ddi_strdup(devname, KM_SLEEP);
451 	i_ddi_parse_name(device_name, &cname, &caddr, NULL);
452 
453 	IBTF_DPRINTF_L4("ibnex",
454 	    "\tfind_child_dip: cname %s addr %s", cname, caddr);
455 
456 	if (strncmp(cname, IBNEX_IOC_CNAME, 3) ==  0)
457 		*type = IBNEX_IOC_NODE;
458 	else if (strncmp(cname, IBNEX_IBPORT_CNAME, 3) ==  0)
459 		*type = IBNEX_HCA_CHILD_NODE;
460 	else
461 		*type = IBNEX_PSEUDO_NODE;
462 
463 	*cdip = ndi_devi_findchild(parent, devname);
464 
465 	IBTF_DPRINTF_L4("ibnex",
466 	    "\tfind_child_dip: cdip %p type %x", *cdip, *type);
467 
468 	if (*cdip)
469 		node_data = ddi_get_parent_data(*cdip);
470 	kmem_free(device_name, len);
471 
472 	return (node_data);
473 }
474 
475 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)476 ibnex_hca_bus_config_one(dev_info_t *parent, void *devname,
477     ddi_bus_config_op_t op, uint_t *flag, dev_info_t **child)
478 {
479 	int			ret = IBNEX_SUCCESS, len, need_bus_config;
480 	char			*device_name, *caddr, *cname;
481 	dev_info_t		*cdip;
482 	ibnex_node_data_t	*node_data;
483 	ibnex_node_type_t	node_type;
484 	int			index;
485 	uint8_t			port_num;
486 	ib_pkey_t		pkey;
487 	boolean_t		enteredv;
488 
489 	len = strlen((char *)devname) + 1;
490 	device_name = i_ddi_strdup(devname, KM_SLEEP);
491 	i_ddi_parse_name(device_name, &cname, &caddr, NULL);
492 
493 	if (caddr == NULL || (strlen(caddr) == 0)) {
494 		IBTF_DPRINTF_L2("ibnex",
495 		    "\thca_bus_config: Invalid device node address");
496 		kmem_free(device_name, len);
497 		return (IBNEX_FAILURE);
498 	}
499 
500 	ndi_devi_enter(parent);
501 	node_data = ibnex_get_cdip_info(
502 	    parent, devname, &cdip, &node_type);
503 	ndi_devi_exit(parent);
504 
505 	if (cdip) {
506 		if ((node_data) && (node_data->node_type ==
507 		    IBNEX_PORT_COMMSVC_NODE)) {
508 			if (node_data->node_dip == NULL) {
509 				node_data->node_dip = cdip;
510 				node_data->node_data.port_node.port_pdip =
511 				    parent;
512 			}
513 		}
514 	}
515 
516 	/*
517 	 * If child dip is present, just return
518 	 * from here.
519 	 */
520 	if (cdip != NULL || (node_data != NULL &&
521 	    node_data->node_dip != NULL)) {
522 		goto end;
523 	}
524 
525 	switch (node_type) {
526 
527 	case IBNEX_IOC_NODE:
528 		ret = ibnex_ioc_bus_config_one(&parent, *flag,
529 		    op, devname, child, &need_bus_config);
530 		if (!need_bus_config) {
531 			kmem_free(device_name, len);
532 			return (ret);
533 		}
534 		break;
535 
536 	case IBNEX_PSEUDO_NODE:
537 		ret = IBNEX_SUCCESS;
538 		mdi_devi_enter(parent, &enteredv);
539 		ibnex_pseudo_initnodes();
540 		mutex_enter(&ibnex.ibnex_mutex);
541 		ret = ibnex_pseudo_config_one(NULL,
542 		    caddr, parent);
543 		mutex_exit(&ibnex.ibnex_mutex);
544 		mdi_devi_exit(parent, enteredv);
545 		break;
546 
547 	default:
548 		if (ibnex_get_pkey_commsvc_index_portnum(devname,
549 		    &index, &pkey, &port_num) != IBNEX_SUCCESS) {
550 			IBTF_DPRINTF_L2("ibnex",
551 			    "\tconfig_port_node: Invalid Service Name");
552 			kmem_free(device_name, len);
553 			return (IBNEX_FAILURE);
554 		}
555 
556 		if ((pkey != 0) && (port_num != 0)) {
557 			if (strcmp("ipib",
558 			    ibnex.ibnex_vppa_comm_svc_names[index]) == 0) {
559 				IBTF_DPRINTF_L2("ibnex",
560 				    "Skipping IBD devices... ");
561 				break;
562 			}
563 		}
564 
565 		ndi_devi_enter(parent);
566 		cdip = ibnex_config_port_node(parent, devname);
567 		if (cdip)
568 			ret = IBNEX_SUCCESS;
569 		else
570 			ret = IBNEX_FAILURE;
571 		ndi_devi_exit(parent);
572 		break;
573 	}
574 end:
575 	if (node_type == IBNEX_HCA_CHILD_NODE) {
576 		/* Allows enumeration under PHCI */
577 		*flag |= NDI_MDI_FALLBACK;
578 	}
579 	kmem_free(device_name, len);
580 	return (ret);
581 }
582 
583 void
ibnex_handle_hca_attach(void * cb_arg)584 ibnex_handle_hca_attach(void *cb_arg)
585 {
586 	ib_guid_t hca_guid	= *((ib_guid_t *)cb_arg);
587 	dev_info_t		*phci;
588 	int			ii;
589 	ibdm_hca_list_t		*hca_list;
590 
591 	IBTF_DPRINTF_L4("ibnex", "handle_hca_attach(%llx)", hca_guid);
592 
593 	phci = ibtl_ibnex_hcaguid2dip(hca_guid);
594 
595 	/*
596 	 * Enumerate children of this HCA, port nodes,
597 	 * VPPA & HCA_SVC nodes. Use ndi_devi_enter() for
598 	 * locking. IB Nexus is enumerating the children
599 	 * of HCA, not MPXIO clients.
600 	 */
601 	ndi_devi_enter(phci);
602 	ibdm_ibnex_port_settle_wait(hca_guid, ibnex_port_settling_time);
603 	hca_list = ibdm_ibnex_get_hca_info_by_guid(hca_guid);
604 	if (hca_list == NULL) {
605 		ndi_devi_exit(phci);
606 		kmem_free(cb_arg, sizeof (ib_guid_t));
607 		return;
608 	}
609 	ibnex_create_hcasvc_nodes(phci, hca_list->hl_hca_port_attr);
610 	for (ii = 0; ii < hca_list->hl_nports; ii++) {
611 		ibnex_create_port_nodes(phci, &hca_list->hl_port_attr[ii]);
612 		ibnex_create_vppa_nodes(phci, &hca_list->hl_port_attr[ii]);
613 	}
614 	ibdm_ibnex_free_hca_list(hca_list);
615 	ndi_devi_exit(phci);
616 	kmem_free(cb_arg, sizeof (ib_guid_t));
617 }
618