Merge illumos-gate
[unleashed.git] / usr / src / uts / common / io / ib / ibnex / ibnex.c
blob4dbea53bc72b38c953abe8a7a4c92c9dcf51df82
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
26 * Copyright (c) 2018, Joyent, Inc.
30 * The InfiniBand Nexus driver (IB nexus) is a bus nexus driver for IB bus.
31 * It supports Port nodes, Virtual Physical Point of Attachment nodes (VPPA)
32 * for HCAs registered with IBTL and IOC nodes for all the IOCs present in
33 * the IB fabric (that are accessible to the host). It also supports Pseudo
34 * device children to be enumerated using their .conf file(s). All Port nodes
35 * and VPPA nodes are children of HCA drivers. All the IOC nodes and the Pseudo
36 * device nodes are children of the IB nexus driver.
38 * IB nexus driver provides bus nexus entry points to all the HCA drivers.
40 * IB nexus driver registers with InfiniBand Device Manager (IBDM) to get
41 * information about all the HCA ports and I/O Controllers (IOCs) connected
42 * to the IB fabric. Based on that information, IB nexus will create all the
43 * device tree nodes.
46 #include <sys/conf.h>
47 #include <sys/stat.h>
48 #include <sys/modctl.h>
49 #include <sys/taskq.h>
50 #include <sys/mdi_impldefs.h>
51 #include <sys/sunmdi.h>
52 #include <sys/sunpm.h>
53 #include <sys/ib/mgt/ibdm/ibdm_impl.h>
54 #include <sys/ib/ibnex/ibnex.h>
55 #include <sys/ib/ibnex/ibnex_devctl.h>
56 #include <sys/ib/ibtl/ibti.h>
57 #include <sys/ib/ibtl/impl/ibtl_ibnex.h>
58 #include <sys/file.h>
59 #include <sys/hwconf.h>
60 #include <sys/fs/dv_node.h>
62 /* Function prototypes */
63 static int ibnex_attach(dev_info_t *, ddi_attach_cmd_t);
64 static int ibnex_getinfo(dev_info_t *, ddi_info_cmd_t,
65 void *, void **);
66 static int ibnex_detach(dev_info_t *, ddi_detach_cmd_t);
67 int ibnex_busctl(dev_info_t *,
68 dev_info_t *, ddi_ctl_enum_t, void *, void *);
69 int ibnex_map_fault(dev_info_t *,
70 dev_info_t *, struct hat *, struct seg *,
71 caddr_t, struct devpage *, pfn_t, uint_t, uint_t);
72 static int ibnex_init_child(dev_info_t *);
73 static ibnex_rval_t ibnex_comm_svc_init(char *, ibnex_node_type_t);
74 static void ibnex_comm_svc_fini();
75 dev_info_t *ibnex_commsvc_initnode(dev_info_t *,
76 ibdm_port_attr_t *, int, int, ib_pkey_t, int *,
77 int);
78 static void ibnex_delete_port_node_data(ibnex_node_data_t *);
79 int ibnex_get_dip_from_guid(ib_guid_t, int,
80 ib_pkey_t, dev_info_t **);
81 int ibnex_get_node_and_dip_from_guid(ib_guid_t, int,
82 ib_pkey_t, ibnex_node_data_t **, dev_info_t **);
83 static ibnex_node_data_t *ibnex_is_node_data_present(ibnex_node_type_t,
84 void *, int, ib_pkey_t);
85 static ibnex_node_data_t *ibnex_init_child_nodedata(ibnex_node_type_t, void *,
86 int, ib_pkey_t);
87 static int ibnex_create_port_node_prop(ibdm_port_attr_t *,
88 dev_info_t *, char *, ib_pkey_t);
89 void ibnex_dm_callback(void *, ibdm_events_t);
90 static int ibnex_create_port_compatible_prop(dev_info_t *,
91 char *, ibdm_port_attr_t *);
92 static int ibnex_create_ioc_srv_props(
93 dev_info_t *, ibdm_ioc_info_t *);
94 static int ibnex_get_eventcookie(dev_info_t *,
95 dev_info_t *, char *, ddi_eventcookie_t *);
96 static int ibnex_add_eventcall(dev_info_t *, dev_info_t *,
97 ddi_eventcookie_t, void (*)(dev_info_t *,
98 ddi_eventcookie_t, void *, void *),
99 void *arg, ddi_callback_id_t *cb_id);
100 static int ibnex_remove_eventcall(dev_info_t *,
101 ddi_callback_id_t);
102 static int ibnex_post_event(dev_info_t *, dev_info_t *,
103 ddi_eventcookie_t, void *);
104 static int ibnex_bus_config(dev_info_t *, uint_t,
105 ddi_bus_config_op_t, void *, dev_info_t **);
106 static int ibnex_bus_unconfig(dev_info_t *,
107 uint_t, ddi_bus_config_op_t, void *);
108 dev_info_t *ibnex_config_port_node(dev_info_t *, char *);
109 int ibnex_get_pkey_commsvc_index_portnum(
110 char *, int *, ib_pkey_t *, uint8_t *);
111 void ibnex_config_all_children(dev_info_t *);
112 static int ibnex_devname_to_portnum(char *, uint8_t *);
113 void ibnex_create_vppa_nodes(dev_info_t *, ibdm_port_attr_t *);
114 void ibnex_create_port_nodes(
115 dev_info_t *, ibdm_port_attr_t *);
116 void ibnex_create_hcasvc_nodes(
117 dev_info_t *, ibdm_port_attr_t *);
118 static int ibnex_config_root_iocnode(dev_info_t *, char *);
119 static int ibnex_devname2port(char *, int *);
120 static int ibnex_config_ioc_node(char *, dev_info_t *);
121 static int ibnex_devname_to_node_n_ioc_guids(
122 char *, ib_guid_t *, ib_guid_t *, char **);
123 static void ibnex_ioc_node_cleanup();
124 static void ibnex_delete_ioc_node_data(ibnex_node_data_t *);
125 int ibnex_ioc_initnode_all_pi(ibdm_ioc_info_t *);
126 static int ibnex_ioc_initnode_pdip(ibnex_node_data_t *,
127 ibdm_ioc_info_t *, dev_info_t *);
128 static int ibnex_create_ioc_node_prop(
129 ibdm_ioc_info_t *, dev_info_t *);
130 static int ibnex_create_ioc_compatible_prop(
131 dev_info_t *, ib_dm_ioc_ctrl_profile_t *);
132 uint64_t ibnex_str2hex(char *, int, int *);
133 int ibnex_str2int(char *, int, int *);
134 static int ibnex_create_ioc_portgid_prop(
135 dev_info_t *, ibdm_ioc_info_t *);
136 static void ibnex_wakeup_reprobe_ioc(ibnex_node_data_t *, int);
137 static void ibnex_wakeup_reprobe_all();
138 ibt_status_t ibnex_ibtl_callback(ibtl_ibnex_cb_args_t *);
139 void ibnex_pseudo_initnodes(void);
140 static char *ibnex_lookup_named_prop(ddi_prop_t *, char *);
141 static void ibnex_pseudo_node_cleanup(void);
142 static int ibnex_name_child(dev_info_t *, char *, int);
143 static int ibnex_name_pseudo_child(dev_info_t *, char *);
145 void ibnex_reprobe_ioc_dev(void *);
146 void ibnex_reprobe_ioc_all();
147 static void ibnex_update_prop(ibnex_node_data_t *,
148 ibdm_ioc_info_t *);
149 static ibnex_rval_t ibnex_unique_svcname(char *);
150 static void ibnex_handle_reprobe_dev(void *arg);
152 extern int ibnex_open(dev_t *, int, int, cred_t *);
153 extern int ibnex_close(dev_t, int, int, cred_t *);
154 extern int ibnex_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
155 extern int ibnex_offline_childdip(dev_info_t *);
157 static int ibnex_ioc_create_pi(
158 ibdm_ioc_info_t *, ibnex_node_data_t *,
159 dev_info_t *, int *);
160 static int ibnex_bus_power(dev_info_t *, void *,
161 pm_bus_power_op_t, void *, void *);
162 int ibnex_pseudo_create_all_pi(ibnex_node_data_t *);
163 static int ibnex_pseudo_create_pi_pdip(ibnex_node_data_t *,
164 dev_info_t *);
165 int ibnex_pseudo_config_one(
166 ibnex_node_data_t *, char *, dev_info_t *);
167 int ibnex_pseudo_mdi_config_one(int, void *, dev_info_t **,
168 char *, char *);
169 static void ibnex_config_pseudo_all(dev_info_t *);
170 int ibnex_ioc_bus_config_one(dev_info_t **, uint_t,
171 ddi_bus_config_op_t, void *, dev_info_t **, int *);
172 static int ibnex_is_merge_node(dev_info_t *);
173 static void ibnex_hw_in_dev_tree(char *);
174 static int ibnex_ioc_config_from_pdip(ibdm_ioc_info_t *,
175 dev_info_t *, int);
176 static int ibnex_ioc_pi_exists(ibnex_node_data_t *, dev_info_t *);
177 static int ibnex_ioc_pi_reachable(ibdm_ioc_info_t *,
178 dev_info_t *);
180 extern void ibnex_handle_hca_attach(void *);
182 extern struct bus_ops ibnex_ci_busops;
184 * Prototype declarations for the VHCI options
187 * Functions registered with the mpxio framework
189 static int ib_vhci_pi_init(dev_info_t *, mdi_pathinfo_t *, int);
190 static int ib_vhci_pi_uninit(dev_info_t *, mdi_pathinfo_t *, int);
191 static int ib_vhci_pi_state_change(dev_info_t *, mdi_pathinfo_t *,
192 mdi_pathinfo_state_t, uint32_t, int);
193 static int ib_vhci_failover(dev_info_t *, dev_info_t *, int);
196 static mdi_vhci_ops_t ibnex_vhci_ops = {
197 MDI_VHCI_OPS_REV,
198 ib_vhci_pi_init,
199 ib_vhci_pi_uninit,
200 ib_vhci_pi_state_change,
201 ib_vhci_failover
206 * The bus_ops structure defines the capabilities of IB nexus driver.
207 * IB nexus drivers does not support any DMA operations for its children
208 * as there is no such concept in Infiniband. All the memory operations
209 * and DMA operations required by the child drivers can be performed using
210 * the IBTF API.
212 struct bus_ops ibnex_bus_ops = {
213 BUSO_REV,
214 nullbusmap, /* bus_map */
215 NULL, /* bus_get_intrspec */
216 NULL, /* bus_add_intrspec */
217 NULL, /* bus_remove_intrspec */
218 ibnex_map_fault, /* Map Fault */
219 ddi_no_dma_map, /* DMA related entry points */
220 ddi_no_dma_allochdl,
221 NULL,
222 NULL,
223 NULL,
224 NULL,
225 NULL,
226 NULL,
227 ibnex_busctl, /* bus_ctl */
228 ddi_bus_prop_op, /* bus_prop_op */
229 ibnex_get_eventcookie, /* bus_get_eventcookie */
230 ibnex_add_eventcall, /* bus_add_eventcall */
231 ibnex_remove_eventcall, /* bus_remove_eventcall */
232 ibnex_post_event, /* bus_post_event */
233 NULL,
234 ibnex_bus_config, /* bus config */
235 ibnex_bus_unconfig, /* bus unconfig */
236 NULL, /* bus fm init */
237 NULL, /* bus fm fini */
238 NULL, /* bus fm access enter */
239 NULL, /* bus fm access exit */
240 ibnex_bus_power /* bus power */
243 /* ibnex cb_ops */
244 static struct cb_ops ibnex_cbops = {
245 ibnex_open, /* open */
246 ibnex_close, /* close */
247 nodev, /* strategy */
248 nodev, /* print */
249 nodev, /* dump */
250 nodev, /* read */
251 nodev, /* write */
252 ibnex_ioctl, /* ioctl */
253 nodev, /* devmap */
254 nodev, /* mmap */
255 nodev, /* segmap */
256 nochpoll, /* poll */
257 ddi_prop_op, /* prop_op */
258 NULL, /* stream */
259 D_MP, /* cb_flag */
260 CB_REV, /* rev */
261 nodev, /* int (*cb_aread)() */
262 nodev /* int (*cb_awrite)() */
266 * Device options
267 * Note: ddi_no_info needs to change during devfs time frame. The drivers
268 * with 1 to 1 mapping between minor node and instance should use
269 * ddi_1to1_info. (See bug id 4424752)
271 static struct dev_ops ibnex_ops = {
272 DEVO_REV, /* devo_rev, */
273 0, /* refcnt */
274 ibnex_getinfo, /* info */
275 nulldev, /* identify */
276 nulldev, /* probe */
277 ibnex_attach, /* attach */
278 ibnex_detach, /* detach */
279 nodev, /* reset */
280 &ibnex_cbops, /* driver ops - devctl interfaces */
281 &ibnex_bus_ops, /* bus operations */
282 nulldev, /* power */
283 ddi_quiesce_not_needed, /* quiesce */
286 /* Module linkage information for the kernel. */
287 static struct modldrv modldrv = {
288 &mod_driverops, /* Driver module */
289 "IB nexus", /* Driver name and version */
290 &ibnex_ops, /* driver ops */
293 static struct modlinkage modlinkage = {
294 MODREV_1, (void *)&modldrv, NULL
298 * Global per-instance IB Nexus data.
299 * There is only one instance of IB Nexus supported.
301 ibnex_t ibnex;
302 #ifdef __lock_lint
303 extern ibdm_t ibdm;
304 #endif
305 _NOTE(MUTEX_PROTECTS_DATA(ibnex.ibnex_mutex, ibnex_s))
306 _NOTE(DATA_READABLE_WITHOUT_LOCK(ibnex.ibnex_num_comm_svcs
307 ibnex.ibnex_comm_svc_names ibnex.ibnex_nvppa_comm_svcs
308 ibnex.ibnex_vppa_comm_svc_names ibnex.ibnex_nhcasvc_comm_svcs
309 ibnex.ibnex_hcasvc_comm_svc_names ibnex.ibnex_ioc_list))
310 _NOTE(MUTEX_PROTECTS_DATA(ibnex.ibnex_mutex, ibnex_node_data_s))
311 _NOTE(LOCK_ORDER(ibdm.ibdm_hl_mutex ibnex.ibnex_mutex))
313 /* The port settling time in seconds */
314 int ibnex_port_settling_time = 8;
316 /* create an array of properties supported, easier to add new ones here */
317 static struct ibnex_property {
318 char *name;
319 ibnex_node_type_t type;
320 } ibnex_properties[] = {
321 { "port-svc-list", IBNEX_PORT_COMMSVC_NODE},
322 { "vppa-svc-list", IBNEX_VPPA_COMMSVC_NODE},
323 { "hca-svc-list", IBNEX_HCASVC_COMMSVC_NODE}
326 #define N_IBNEX_PROPS (sizeof (ibnex_properties))/ \
327 (sizeof (struct ibnex_property))
330 * Event Definition
331 * Single event, event name defined in ibti_common.h.
332 * Event posted to specific child handler. Event posted
333 * at kernel priority.
335 static ndi_event_definition_t ibnex_ndi_event_defs[] = {
336 {IB_EVENT_TAG_PROP_UPDATE, IB_PROP_UPDATE_EVENT, EPL_KERNEL,
337 NDI_EVENT_POST_TO_TGT}
340 #define IB_N_NDI_EVENTS \
341 (sizeof (ibnex_ndi_event_defs) / sizeof (ndi_event_definition_t))
343 static ndi_event_set_t ib_ndi_events = {
344 NDI_EVENTS_REV1, IB_N_NDI_EVENTS, ibnex_ndi_event_defs};
345 static int ibnex_hw_status = IBNEX_DEVTREE_NOT_CHECKED;
349 * _init
350 * Loadable module init, called before any other module.
353 _init(void)
355 int error;
356 char **hca_driver_list;
357 int i, ndrivers;
359 if (ibnex_hw_status == IBNEX_DEVTREE_NOT_CHECKED) {
360 ibnex_hw_status = IBNEX_HW_NOT_IN_DEVTREE;
361 hca_driver_list = mdi_get_phci_driver_list("ib", &ndrivers);
362 for (i = 0; i < ndrivers; i++) {
363 ibnex_hw_in_dev_tree(hca_driver_list[i]);
364 if (ibnex_hw_status == IBNEX_HW_IN_DEVTREE)
365 break;
367 mdi_free_phci_driver_list(hca_driver_list, ndrivers);
371 * IB Nexus _init can be called while force attaching
372 * IB Nexus driver or when a HCA is hotplugged.
374 * If IB HW is not in device tree or if no HCA driver
375 * has been attached, fail IB Nexus _init().
377 if (ibnex_hw_status == IBNEX_HW_NOT_IN_DEVTREE &&
378 ibt_hw_is_present() == 0) {
379 IBTF_DPRINTF_L4("ibnex", "\t_init: NO IB HW");
380 return (DDI_FAILURE);
383 IBTF_DPRINTF_L4("ibnex", "\t_init");
384 mutex_init(&ibnex.ibnex_mutex, NULL, MUTEX_DRIVER, NULL);
385 cv_init(&ibnex.ibnex_reprobe_cv, NULL, CV_DRIVER, NULL);
386 cv_init(&ibnex.ibnex_ioc_list_cv, NULL, CV_DRIVER, NULL);
387 if ((error = mod_install(&modlinkage)) != 0) {
388 IBTF_DPRINTF_L2("ibnex", "\t_init: mod_install failed");
389 mutex_destroy(&ibnex.ibnex_mutex);
390 cv_destroy(&ibnex.ibnex_reprobe_cv);
391 cv_destroy(&ibnex.ibnex_ioc_list_cv);
392 } else {
393 ibdm_ibnex_register_callback(ibnex_dm_callback);
394 ibtl_ibnex_register_callback(ibnex_ibtl_callback);
396 return (error);
401 * _fini
402 * Prepares a module for unloading.
405 _fini(void)
407 int error;
409 IBTF_DPRINTF_L4("ibnex", "\t_fini");
410 if ((error = mod_remove(&modlinkage)) != 0) {
411 return (error);
413 ibdm_ibnex_unregister_callback();
414 ibtl_ibnex_unregister_callback();
415 mutex_destroy(&ibnex.ibnex_mutex);
416 cv_destroy(&ibnex.ibnex_reprobe_cv);
417 cv_destroy(&ibnex.ibnex_ioc_list_cv);
418 return (0);
423 * _info
424 * Returns information about loadable module.
427 _info(struct modinfo *modinfop)
429 IBTF_DPRINTF_L4("ibnex", "\t_info");
430 return (mod_info(&modlinkage, modinfop));
435 * ibnex_attach
436 * Configure and attach an instance of the IB Nexus driver
437 * Only one instance of IB Nexus is supported
438 * Create a minor node for cfgadm purpose
439 * Initialize communication services
440 * Register callback with IBDM
441 * Register callback with IBTL
443 static int
444 ibnex_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
446 int i;
447 int instance = ddi_get_instance(dip);
449 IBTF_DPRINTF_L4("ibnex", "\tattach: device = %p cmd = %x)", dip, cmd);
451 switch (cmd) {
452 case DDI_ATTACH:
453 break;
454 case DDI_RESUME:
455 IBTF_DPRINTF_L4("ibnex", "\tattach: RESUME");
456 return (DDI_SUCCESS);
457 default:
458 return (DDI_FAILURE);
461 /* Fail attach for more than one instance */
462 mutex_enter(&ibnex.ibnex_mutex);
463 if (ibnex.ibnex_dip != NULL) {
464 mutex_exit(&ibnex.ibnex_mutex);
465 return (DDI_FAILURE);
467 mutex_exit(&ibnex.ibnex_mutex);
470 * Create a IB nexus taskq
473 ibnex.ibnex_taskq_id = ddi_taskq_create(dip,
474 "ibnex-enum-taskq", 1, TASKQ_DEFAULTPRI, 0);
475 if (ibnex.ibnex_taskq_id == NULL) {
476 IBTF_DPRINTF_L2("ibnex",
477 "\tattach: ddi_taskq_create() failed");
478 return (DDI_FAILURE);
482 /* Register with MPxIO framework */
484 if (mdi_vhci_register(MDI_HCI_CLASS_IB, dip, &ibnex_vhci_ops, 0)
485 != MDI_SUCCESS) {
486 IBTF_DPRINTF_L2("ibnex",
487 "\tattach: mdi_vhci_register() failed");
488 (void) ddi_taskq_destroy(ibnex.ibnex_taskq_id);
489 ibnex.ibnex_taskq_id = NULL;
490 return (DDI_FAILURE);
495 * Create the "fabric" devctl minor-node for IB DR support.
496 * The minor number for the "devctl" node is in the same format
497 * as the AP minor nodes.
499 if (ddi_create_minor_node(dip, IBNEX_FABRIC, S_IFCHR, instance,
500 DDI_NT_IB_ATTACHMENT_POINT, 0) != DDI_SUCCESS) {
501 IBTF_DPRINTF_L2("ibnex",
502 "\tattach: failed to create fabric minornode");
503 (void) ddi_taskq_destroy(ibnex.ibnex_taskq_id);
504 ibnex.ibnex_taskq_id = NULL;
505 (void) mdi_vhci_unregister(dip, 0);
506 return (DDI_FAILURE);
510 * Create "devctl" minor node for general ioctl interface to the
511 * ib nexus.
513 if (ddi_create_minor_node(dip, "devctl", S_IFCHR, instance,
514 DDI_NT_IB_NEXUS, 0) != DDI_SUCCESS) {
515 IBTF_DPRINTF_L2("ibnex",
516 "\tattach: failed to create devctl minornode");
517 (void) ddi_remove_minor_node(dip, NULL);
518 (void) ddi_taskq_destroy(ibnex.ibnex_taskq_id);
519 ibnex.ibnex_taskq_id = NULL;
520 (void) mdi_vhci_unregister(dip, 0);
521 return (DDI_FAILURE);
525 * Set pm-want-child-notification property for
526 * power management of the phci and client
528 if (ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
529 "pm-want-child-notification?", NULL, 0) != DDI_PROP_SUCCESS) {
530 IBTF_DPRINTF_L2("ibnex",
531 "_attach: create pm-want-child-notification failed");
532 (void) ddi_remove_minor_node(dip, NULL);
533 (void) ddi_taskq_destroy(ibnex.ibnex_taskq_id);
534 ibnex.ibnex_taskq_id = NULL;
535 (void) mdi_vhci_unregister(dip, 0);
536 return (DDI_FAILURE);
539 mutex_enter(&ibnex.ibnex_mutex);
540 ibnex.ibnex_dip = dip;
541 mutex_exit(&ibnex.ibnex_mutex);
544 * Event Handling: Definition and Binding.
546 if (ndi_event_alloc_hdl(dip, 0, &ibnex.ibnex_ndi_event_hdl,
547 NDI_SLEEP) != NDI_SUCCESS) {
548 IBTF_DPRINTF_L2("ibnex",
549 "_attach: ndi_event_alloc_hdl failed");
550 (void) ddi_remove_minor_node(dip, NULL);
551 (void) ddi_taskq_destroy(ibnex.ibnex_taskq_id);
552 ibnex.ibnex_taskq_id = NULL;
553 (void) mdi_vhci_unregister(dip, 0);
554 return (DDI_FAILURE);
556 if (ndi_event_bind_set(ibnex.ibnex_ndi_event_hdl, &ib_ndi_events,
557 NDI_SLEEP) != NDI_SUCCESS) {
558 (void) ddi_remove_minor_node(dip, NULL);
559 (void) ndi_event_free_hdl(ibnex.ibnex_ndi_event_hdl);
560 IBTF_DPRINTF_L2("ibnex",
561 "_attach: ndi_event_bind_set failed");
562 (void) ddi_taskq_destroy(ibnex.ibnex_taskq_id);
563 ibnex.ibnex_taskq_id = NULL;
564 (void) mdi_vhci_unregister(dip, 0);
565 return (DDI_FAILURE);
568 for (i = 0; i < N_IBNEX_PROPS; i++) {
569 if (ibnex_comm_svc_init(ibnex_properties[i].name,
570 ibnex_properties[i].type) != IBNEX_SUCCESS) {
571 ibnex_comm_svc_fini();
572 (void) ndi_event_unbind_set(ibnex.ibnex_ndi_event_hdl,
573 &ib_ndi_events, NDI_SLEEP);
574 (void) ddi_remove_minor_node(dip, NULL);
575 (void) ndi_event_free_hdl(
576 ibnex.ibnex_ndi_event_hdl);
577 ibnex.ibnex_ndi_event_hdl = NULL;
578 IBTF_DPRINTF_L2("ibnex", "_attach: ibnex_comm_svc_init"
579 " failed %s", ibnex_properties[i].name);
580 (void) ddi_taskq_destroy(ibnex.ibnex_taskq_id);
581 ibnex.ibnex_taskq_id = NULL;
582 (void) mdi_vhci_unregister(dip, 0);
583 return (DDI_FAILURE);
588 * before anything else comes up:
589 * Initialize the internal list of pseudo device nodes by
590 * getting all pseudo children of "ib" and processing them.
592 ibnex_pseudo_initnodes();
594 return (DDI_SUCCESS);
599 * ibnex_getinfo()
600 * Given the device number, return the devinfo pointer or the
601 * instance number.
602 * Note: always succeed DDI_INFO_DEVT2INSTANCE, even before attach.
605 /*ARGSUSED*/
606 static int
607 ibnex_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
609 int ret = DDI_SUCCESS;
611 IBTF_DPRINTF_L4("ibnex", "\tgetinfo: Begin");
612 switch (cmd) {
613 case DDI_INFO_DEVT2DEVINFO:
614 if (ibnex.ibnex_dip != NULL)
615 *result = ibnex.ibnex_dip;
616 else {
617 *result = NULL;
618 ret = DDI_FAILURE;
620 break;
622 case DDI_INFO_DEVT2INSTANCE:
623 *result = 0;
624 break;
626 default:
627 ret = DDI_FAILURE;
629 return (ret);
634 * ibnex_detach
635 * Unregister callback with the IBDM
636 * Unregister callback with the IBTL
637 * Uninitialize the communication entries
638 * Remove all the minor nodes created by this instance
640 static int
641 ibnex_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
644 IBTF_DPRINTF_L4("ibnex", "\tdetach: dip = %p cmd = %x)", dip, cmd);
646 switch (cmd) {
648 case DDI_DETACH:
649 break;
650 case DDI_SUSPEND:
651 IBTF_DPRINTF_L4("ibnex", "\t_detach: Suspend");
652 return (DDI_SUCCESS);
653 default:
654 return (DDI_FAILURE);
657 mutex_enter(&ibnex.ibnex_mutex);
658 if (ibt_hw_is_present()) {
659 IBTF_DPRINTF_L2("ibnex",
660 "\tdetach: IB HW is present ");
661 mutex_exit(&ibnex.ibnex_mutex);
662 return (DDI_FAILURE);
664 if (ndi_event_free_hdl(ibnex.ibnex_ndi_event_hdl)) {
665 IBTF_DPRINTF_L2("ibnex",
666 "\tdetach: ndi_event_free_hdl() failed");
667 mutex_exit(&ibnex.ibnex_mutex);
668 return (DDI_FAILURE);
670 ibnex.ibnex_ndi_event_hdl = NULL;
671 ibnex.ibnex_prop_update_evt_cookie = NULL;
673 ibnex_pseudo_node_cleanup();
674 ibnex_comm_svc_fini();
675 ibnex_ioc_node_cleanup();
677 (void) ddi_remove_minor_node(dip, NULL);
678 ibnex.ibnex_dip = NULL;
679 mutex_exit(&ibnex.ibnex_mutex);
680 (void) mdi_vhci_unregister(dip, 0);
682 if (ibnex.ibnex_taskq_id != NULL) {
683 ddi_taskq_destroy(ibnex.ibnex_taskq_id);
684 ibnex.ibnex_taskq_id = NULL;
687 return (DDI_SUCCESS);
692 * ibnex_pseudo_node_cleanup()
693 * This checks if all the "dips" have been deallocated (implying
694 * that all the children have been unconfigured) first.
695 * If not, it just returns.
696 * If yes, then it frees up memory allocated for devi_name,
697 * node_addr, and property list.
699 static void
700 ibnex_pseudo_node_cleanup(void)
702 ibnex_node_data_t *nodep = ibnex.ibnex_pseudo_node_head;
703 ibnex_pseudo_node_t *pseudo;
705 IBTF_DPRINTF_L4("ibnex", "\tpseudo_node_cleanup:");
706 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
708 for (; nodep; nodep = nodep->node_next)
709 if (nodep->node_dip)
710 return;
712 IBTF_DPRINTF_L4("ibnex", "\tpseudo_node_cleanup: freeing up memory");
713 for (nodep = ibnex.ibnex_pseudo_node_head; nodep;
714 nodep = nodep->node_next) {
716 pseudo = &nodep->node_data.pseudo_node;
717 if (pseudo->pseudo_node_addr) {
718 kmem_free(pseudo->pseudo_node_addr,
719 strlen(pseudo-> pseudo_node_addr) + 1);
720 pseudo->pseudo_node_addr = NULL;
723 if (pseudo->pseudo_devi_name) {
724 kmem_free(pseudo->pseudo_devi_name,
725 strlen(pseudo-> pseudo_devi_name) + 1);
726 pseudo->pseudo_devi_name = NULL;
729 if (pseudo->pseudo_unit_addr) {
730 kmem_free(pseudo->pseudo_unit_addr,
731 pseudo->pseudo_unit_addr_len);
738 * This functions wakes up any reprobe requests waiting for completion
739 * of reprobe of this IOC. It also send an NDI event, if :
741 * notify_flag is set. This is set if :
742 * ibt_reprobe_ioc has returned with SUCCESS
743 * IBTF client has not been notified for this node.
744 * node_data->node_dip != NULL
745 * node_state has IBNEX_NODE_REPROBE_NOTIFY_ALWAYS set
746 * An NDI event cookie has been registered.
748 static void
749 ibnex_wakeup_reprobe_ioc(ibnex_node_data_t *node_data, int notify_flag)
751 ddi_eventcookie_t evt_cookie;
753 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
754 evt_cookie = ibnex.ibnex_prop_update_evt_cookie;
756 if ((ibnex.ibnex_reprobe_state == IBNEX_REPROBE_IOC_WAIT) ||
757 (node_data->node_reprobe_state != 0)) {
758 if (notify_flag && (node_data->node_dip != NULL) &&
759 (node_data->node_state &
760 IBNEX_NODE_REPROBE_NOTIFY_ALWAYS) &&
761 (evt_cookie != NULL)) {
762 ibt_prop_update_payload_t evt_data;
764 mutex_exit(&ibnex.ibnex_mutex);
766 bzero(&evt_data, sizeof (evt_data));
767 if (ndi_post_event(ibnex.ibnex_dip,
768 node_data->node_dip,
769 evt_cookie, &evt_data) != NDI_SUCCESS)
770 IBTF_DPRINTF_L2("ibnex",
771 "\tndi_post_event failed\n");
773 mutex_enter(&ibnex.ibnex_mutex);
776 node_data->node_reprobe_state = 0;
777 cv_broadcast(&ibnex.ibnex_reprobe_cv);
779 node_data->node_reprobe_state = 0;
783 * This function wakes up any reprobe request waiting for completion
784 * of reprobe of all IOCs.
786 static void
787 ibnex_wakeup_reprobe_all()
789 ibnex_node_data_t *ioc_node;
791 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
793 /* Notify if another reprobe_all is pending */
794 if (ibnex.ibnex_reprobe_state == IBNEX_REPROBE_ALL_WAIT) {
795 ibnex.ibnex_reprobe_state = 0;
796 cv_broadcast(&ibnex.ibnex_reprobe_cv);
798 ibnex.ibnex_reprobe_state = 0;
801 * The IOC may be hot-removed after the reprobe request.
802 * Reset the reprobe states for such IOCs.
804 for (ioc_node = ibnex.ibnex_ioc_node_head; ioc_node;
805 ioc_node = ioc_node->node_next) {
806 if (ioc_node->node_reprobe_state != 0) {
807 ibnex_wakeup_reprobe_ioc(ioc_node, 1);
813 * ibnex_ibnex_callback:
814 * IBTL_IBNEX_IBC_INIT:
815 * Called from ibc_init() which is called from
816 * HCA driver _init entry point
817 * Initializes the HCA dev_ops structure with default
818 * IB nexus structure.
819 * IBTL_IBNEX_IBC_FINI:
820 * Called from ibc_fini() which is called from
821 * HCA driver _fini entry point
822 * Un-Initializes the HCA dev_ops structure with default
823 * IB nexus strucuture.
824 * Returns IBT_SUCCESS
826 ibt_status_t
827 ibnex_ibtl_callback(ibtl_ibnex_cb_args_t *cb_args)
829 int retval = IBT_SUCCESS;
830 struct dev_ops *hca_dev_ops;
831 dev_info_t *clnt_dip;
832 ibnex_node_data_t *node_data;
834 IBTF_DPRINTF_L5("ibnex", "\tibtl_callback");
836 switch (cb_args->cb_flag) {
837 case IBTL_IBNEX_IBC_INIT:
839 * Get the devops structure of the HCA,
840 * and put IB nexus default busops vector in its place.
842 hca_dev_ops = ((struct modldrv *)
843 (cb_args->cb_modlp->ml_linkage[0]))->drv_dev_ops;
844 ASSERT((hca_dev_ops) && (hca_dev_ops->devo_bus_ops == NULL));
845 hca_dev_ops->devo_bus_ops = &ibnex_ci_busops;
846 break;
848 case IBTL_IBNEX_IBC_FINI:
849 hca_dev_ops = ((struct modldrv *)
850 (cb_args->cb_modlp->ml_linkage[0]))->drv_dev_ops;
851 hca_dev_ops->devo_bus_ops = NULL;
852 break;
854 case IBTL_IBNEX_REPROBE_DEV_REQ:
855 /* IBTL pass down request for ibt_reprobe_dev */
856 clnt_dip = cb_args->cb_dip;
857 ASSERT(clnt_dip);
859 node_data = ddi_get_parent_data(clnt_dip);
860 ASSERT(node_data);
862 /* Reprobe for IOC nodes only */
863 ASSERT(node_data->node_type == IBNEX_IOC_NODE);
866 * Start the reprobe. This could sleep as it is not
867 * from interrupt context.
869 if (taskq_dispatch(system_taskq, ibnex_handle_reprobe_dev,
870 clnt_dip, TQ_SLEEP) == 0) {
871 IBTF_DPRINTF_L2("ibnex",
872 "ibnex_ibtl_callback: taskq_dispatch failed");
873 mutex_enter(&ibnex.ibnex_mutex);
874 ibnex_wakeup_reprobe_ioc(node_data, 0);
875 mutex_exit(&ibnex.ibnex_mutex);
876 return (IBT_INSUFF_KERNEL_RESOURCE);
878 return (IBT_SUCCESS);
881 return (retval);
886 * Bus-ops entry points
890 * ibnex_map_fault
891 * IOC drivers need not map memory. Return failure to fail any
892 * such calls.
894 /*ARGSUSED*/
896 ibnex_map_fault(dev_info_t *dip, dev_info_t *rdip, struct hat *hat,
897 struct seg *seg, caddr_t addr, struct devpage *dp, pfn_t pfn,
898 uint_t prot, uint_t lock)
900 return (DDI_FAILURE);
905 * ibnex_busctl
906 * bus_ctl bus_ops entry point
908 /*ARGSUSED*/
910 ibnex_busctl(dev_info_t *dip, dev_info_t *rdip,
911 ddi_ctl_enum_t ctlop, void *arg, void *result)
913 dev_info_t *child_dip;
915 IBTF_DPRINTF_L4("ibnex",
916 "\tbusctl: dip = %p, rdip = %p, ctlop = %x,", dip, rdip, ctlop);
917 IBTF_DPRINTF_L4("ibnex", "\tbusctl: targ = %p, result %p", arg, result);
919 switch (ctlop) {
920 case DDI_CTLOPS_REPORTDEV:
921 if (rdip == NULL) {
922 return (DDI_FAILURE);
925 /* Log the relevant details of dip to sysbuf */
926 cmn_err(CE_CONT, "?IB device: %s@%s, %s%d\n",
927 ddi_node_name(rdip), ddi_get_name_addr(rdip),
928 ddi_driver_name(rdip), ddi_get_instance(rdip));
930 return (DDI_SUCCESS);
932 case DDI_CTLOPS_INITCHILD:
933 child_dip = (dev_info_t *)arg;
934 return (ibnex_init_child(child_dip));
936 case DDI_CTLOPS_UNINITCHILD:
937 child_dip = (dev_info_t *)arg;
938 ddi_set_name_addr(child_dip, NULL);
939 return (DDI_SUCCESS);
941 case DDI_CTLOPS_ATTACH:
942 case DDI_CTLOPS_DETACH:
943 case DDI_CTLOPS_POWER :
944 return (DDI_SUCCESS);
946 case DDI_CTLOPS_SIDDEV:
948 * Return DDI_SUCCESS for IOC/PORT/VPPA nodes and
949 * DDI_FAILURE for the nodes enumerated by a Pseudo file.
951 return (ndi_dev_is_persistent_node(rdip) ?
952 DDI_SUCCESS : DDI_FAILURE);
955 case DDI_CTLOPS_IOMIN:
957 * Return DDI_SUCCESS, so that consistent buf alloc
958 * gets the default DMA IO minimum for the platform
960 return (DDI_SUCCESS);
963 * These ops correspond to functions that "shouldn't" be
964 * called by IB Nexus driver.
966 case DDI_CTLOPS_DMAPMAPC:
967 case DDI_CTLOPS_REPORTINT:
968 case DDI_CTLOPS_REGSIZE:
969 case DDI_CTLOPS_NREGS:
970 case DDI_CTLOPS_SLAVEONLY:
971 case DDI_CTLOPS_AFFINITY:
972 case DDI_CTLOPS_POKE:
973 case DDI_CTLOPS_PEEK:
974 IBTF_DPRINTF_L2("ibnex",
975 "%s%d: invalid op (%d) from %s inst%d",
976 ddi_get_name(dip), ddi_get_instance(dip),
977 ctlop, ddi_get_name(rdip), ddi_get_instance(rdip));
978 return (DDI_FAILURE);
981 * Everything else (PTOB/BTOP/BTOPR/DVMAPAGESIZE requests) we
982 * pass up
984 default:
985 return (ddi_ctlops(dip, rdip, ctlop, arg, result));
991 * ibnex_init_child()
993 * Initialize a child device node. This is called for the DDI_CTLOPS_INITCHILD
994 * entry. Function returns DDI_SUCCESS, DDI_FAILURE or DDI_NOT_WELL_FORMED.
996 static int
997 ibnex_init_child(dev_info_t *child)
999 int ret;
1000 char name[MAXNAMELEN];
1002 IBTF_DPRINTF_L4("ibnex", "\tinit_child: child = %p", child);
1004 /* Handle Pseudo nodes of client children */
1005 if (ndi_dev_is_persistent_node(child) == 0) {
1006 /* Skip nodes without ib-node-type="merge" */
1007 if (ibnex_is_merge_node(child) != IBNEX_SUCCESS)
1008 return (DDI_FAILURE);
1010 if (ibnex_name_pseudo_child(child, name) != DDI_SUCCESS)
1011 return (DDI_FAILURE);
1013 ddi_set_name_addr(child, name);
1015 * Merge the .conf node
1017 if (ndi_merge_node(child,
1018 ibnex_name_child) == DDI_SUCCESS) {
1019 ddi_set_name_addr(child, NULL);
1020 return (DDI_FAILURE);
1022 return (DDI_NOT_WELL_FORMED);
1026 if ((ret = ibnex_name_child(child, name, 0)) != DDI_SUCCESS)
1027 return (ret);
1029 ddi_set_name_addr(child, name);
1031 return (DDI_SUCCESS);
1036 ibnex_name_pseudo_child(dev_info_t *child, char *name)
1038 char **unit_addr;
1039 uint_t n;
1040 if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child,
1041 DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) !=
1042 DDI_PROP_SUCCESS) {
1043 IBTF_DPRINTF_L4("ibnex",
1044 "\tname_pseudo_child: cannot find unit-address in %s.conf",
1045 ddi_get_name(child));
1046 return (DDI_FAILURE);
1048 if (n != 1 || *unit_addr == NULL || **unit_addr == 0) {
1049 cmn_err(CE_WARN, "unit-address property in %s.conf"
1050 " not well-formed", ddi_get_name(child));
1051 ddi_prop_free(unit_addr);
1052 return (DDI_FAILURE);
1054 (void) snprintf(name, MAXNAMELEN, "%s", *unit_addr);
1055 ddi_prop_free(unit_addr);
1056 return (DDI_SUCCESS);
1060 /*ARGSUSED*/
1062 ibnex_name_child(dev_info_t *child, char *name, int flag)
1064 ibnex_pseudo_node_t *pseudo;
1065 ibnex_node_data_t *node_datap;
1066 ibnex_port_node_t *port_node;
1067 ibnex_ioc_node_t *ioc;
1069 node_datap = ddi_get_parent_data(child);
1070 if (node_datap == NULL) {
1071 IBTF_DPRINTF_L2("ibnex", "\tname_child: Node data is NULL");
1072 return (DDI_NOT_WELL_FORMED);
1074 IBTF_DPRINTF_L4("ibnex", "\tname_sid_child: Node data %p"
1075 "Node type %x", node_datap, node_datap->node_type);
1076 switch (node_datap->node_type) {
1077 case IBNEX_PORT_COMMSVC_NODE:
1078 port_node = &node_datap->node_data.port_node;
1079 (void) snprintf(name, IBNEX_MAX_NODEADDR_SZ, "%x,0,%s",
1080 port_node->port_num,
1081 ibnex.ibnex_comm_svc_names[port_node->port_commsvc_idx]);
1082 break;
1083 case IBNEX_VPPA_COMMSVC_NODE:
1084 port_node = &node_datap->node_data.port_node;
1085 (void) snprintf(name, IBNEX_MAX_NODEADDR_SZ, "%x,%x,%s",
1086 port_node->port_num, port_node->port_pkey, ibnex.
1087 ibnex_vppa_comm_svc_names[port_node->port_commsvc_idx]);
1088 break;
1089 case IBNEX_HCASVC_COMMSVC_NODE:
1090 port_node = &node_datap->node_data.port_node;
1091 (void) snprintf(name, IBNEX_MAX_NODEADDR_SZ, "%x,0,%s",
1092 port_node->port_num,
1093 ibnex.ibnex_hcasvc_comm_svc_names[port_node->
1094 port_commsvc_idx]);
1095 break;
1096 case IBNEX_IOC_NODE:
1097 ioc = &node_datap->node_data.ioc_node;
1098 (void) snprintf(name, IBNEX_MAX_NODEADDR_SZ, "%llX,%llX",
1099 (longlong_t)ioc->ioc_guid, (longlong_t)ioc->iou_guid);
1100 break;
1101 case IBNEX_PSEUDO_NODE:
1102 pseudo = &node_datap->node_data.pseudo_node;
1103 (void) snprintf(name,
1104 IBNEX_MAX_NODEADDR_SZ, pseudo->pseudo_unit_addr);
1105 break;
1106 default:
1107 IBTF_DPRINTF_L2("ibnex", "\name_child: Not well formed");
1108 return (DDI_NOT_WELL_FORMED);
1111 return (DDI_SUCCESS);
1116 * ibnex_bus_config()
1118 * BUS_CONFIG_ONE:
1119 * Enumerate the exact instance of the driver. Use the device node name
1120 * to locate the exact instance.
1121 * Query IBDM to find whether the hardware exits for the instance of the
1122 * driver. If exists, create a device node and return NDI_SUCCESS.
1124 * BUS_CONFIG_ALL:
1125 * Enumerate all the instances of all the possible children (seen before
1126 * and never seen before).
1128 * BUS_CONFIG_DRIVER:
1129 * Enumerate all the instances of a particular driver.
1132 static int
1133 ibnex_bus_config(dev_info_t *parent, uint_t flag,
1134 ddi_bus_config_op_t op, void *devname, dev_info_t **child)
1136 int ret = IBNEX_SUCCESS, len, circ, need_bus_config;
1137 char *device_name, *cname = NULL, *caddr = NULL;
1138 dev_info_t *cdip;
1139 ibnex_node_data_t *node_data;
1141 switch (op) {
1142 case BUS_CONFIG_ONE:
1143 IBTF_DPRINTF_L4("ibnex", "\tbus_config: CONFIG_ONE, "
1144 "parent %p", parent);
1146 ndi_devi_enter(parent, &circ);
1148 len = strlen((char *)devname) + 1;
1149 device_name = i_ddi_strdup(devname, KM_SLEEP);
1150 i_ddi_parse_name(device_name, &cname, &caddr, NULL);
1152 if (caddr == NULL || (strlen(caddr) == 0)) {
1153 kmem_free(device_name, len);
1154 ndi_devi_exit(parent, circ);
1155 return (NDI_FAILURE);
1158 cdip = ndi_devi_findchild(parent, devname);
1159 if (cdip)
1160 node_data = ddi_get_parent_data(cdip);
1162 ndi_devi_exit(parent, circ);
1164 if (cdip == NULL || (node_data != NULL &&
1165 node_data->node_dip == NULL)) {
1166 /* Node is not present */
1167 if (strncmp(cname, IBNEX_IOC_CNAME, 3) == 0) {
1168 ret = ibnex_ioc_bus_config_one(&parent, flag,
1169 op, devname, child, &need_bus_config);
1170 if (!need_bus_config) {
1171 kmem_free(device_name, len);
1172 return (ret);
1174 } else {
1176 * if IB Nexus is the parent, call MDI. Bus
1177 * config with HCA as the parent would have
1178 * enumerated the Pseudo node.
1180 ret = IBNEX_SUCCESS;
1181 ibnex_pseudo_initnodes();
1182 mutex_enter(&ibnex.ibnex_mutex);
1183 ret = ibnex_pseudo_mdi_config_one(flag, devname,
1184 child, cname, caddr);
1185 mutex_exit(&ibnex.ibnex_mutex);
1186 kmem_free(device_name, len);
1187 return (ret);
1190 kmem_free(device_name, len);
1191 break;
1193 case BUS_CONFIG_ALL:
1194 /*FALLTHRU*/
1195 case BUS_CONFIG_DRIVER:
1196 if (op == BUS_CONFIG_ALL)
1197 IBTF_DPRINTF_L4("ibnex", "\tbus_config: CONFIG_ALL, "
1198 "parent %p", parent);
1199 else
1200 IBTF_DPRINTF_L4("ibnex", "\tbus_config: CONFIG_DRIVER"
1201 ", parent %p", parent);
1204 * Drive CONFIG requests for IB Nexus parent through
1205 * MDI. This is needed to load the HCA drivers in x86 SRP
1206 * boot case.
1208 * CONFIG Requests with HCA parent will probe devices using
1209 * ibdm and configure all children.
1211 ibdm_ioc_info_t *ioc_list, *new_ioc_list;
1213 mutex_enter(&ibnex.ibnex_mutex);
1214 while (ibnex.ibnex_ioc_list_state !=
1215 IBNEX_IOC_LIST_READY) {
1216 cv_wait(&ibnex.ibnex_ioc_list_cv,
1217 &ibnex.ibnex_mutex);
1219 ibnex.ibnex_ioc_list_state = IBNEX_IOC_LIST_RENEW;
1220 mutex_exit(&ibnex.ibnex_mutex);
1221 /* Enumerate all the IOC's */
1222 ibdm_ibnex_port_settle_wait(0, ibnex_port_settling_time);
1224 new_ioc_list = ibdm_ibnex_get_ioc_list(
1225 IBDM_IBNEX_NORMAL_PROBE);
1226 IBTF_DPRINTF_L4("ibnex",
1227 "\tbus_config: alloc ioc_list %p", new_ioc_list);
1229 * Optimize the calls for each BUS_CONFIG_ALL request
1230 * to the IB Nexus dip. This is currently done for
1231 * each PDIP.
1233 mutex_enter(&ibnex.ibnex_mutex);
1234 ioc_list = ibnex.ibnex_ioc_list;
1235 ibnex.ibnex_ioc_list = new_ioc_list;
1236 ibnex.ibnex_ioc_list_state = IBNEX_IOC_LIST_READY;
1237 cv_broadcast(&ibnex.ibnex_ioc_list_cv);
1238 mutex_exit(&ibnex.ibnex_mutex);
1240 if (ioc_list) {
1241 IBTF_DPRINTF_L4("ibnex",
1242 "\tbus_config: freeing ioc_list %p",
1243 ioc_list);
1244 ibdm_ibnex_free_ioc_list(ioc_list);
1248 ret = mdi_vhci_bus_config(parent,
1249 flag, op, devname, child, NULL);
1250 return (ret);
1251 default:
1252 IBTF_DPRINTF_L4("ibnex", "\tbus_config: error");
1253 ret = IBNEX_FAILURE;
1254 break;
1257 if (ret == IBNEX_SUCCESS) {
1258 ret = ndi_busop_bus_config(
1259 parent, flag, op, devname, child, 0);
1260 IBTF_DPRINTF_L4("ibnex", "\tbus_config:"
1261 "ndi_busop_bus_config : retval %d", ret);
1262 return (ret);
1265 return (NDI_FAILURE);
1270 * ibnex_config_root_iocnode()
1271 * Configures one particular instance of the IOC driver.
1272 * Returns IBNEX_SUCCESS/IBNEX_FAILURE
1274 static int
1275 ibnex_config_root_iocnode(dev_info_t *parent, char *device_name)
1277 int ret, port = 0, iter = 0;
1278 boolean_t displayed = B_FALSE;
1279 char *portstr;
1280 ib_guid_t hca_guid, iou_guid, ioc_guid;
1281 ibdm_ioc_info_t *ioc_info;
1282 ibdm_port_attr_t *port_attr;
1284 IBTF_DPRINTF_L4("ibnex",
1285 "\tconfig_root_iocnode: name %s", device_name);
1287 portstr = strstr(device_name, ":port=");
1288 if (portstr == NULL) {
1289 return (IBNEX_FAILURE);
1292 portstr[0] = 0; portstr++;
1293 if (ibnex_devname2port(portstr, &port)) {
1294 IBTF_DPRINTF_L4("ibnex", "\tconfig_root_iocnode: invalid port");
1295 return (IBNEX_FAILURE);
1298 if (ibnex_devname_to_node_n_ioc_guids(
1299 device_name, &iou_guid, &ioc_guid, NULL) != IBNEX_SUCCESS) {
1300 return (IBNEX_FAILURE);
1303 (void) snprintf(device_name, (IBNEX_MAX_NODEADDR_SZ + 4),
1304 "ioc@%llX,%llX", (longlong_t)ioc_guid, (longlong_t)iou_guid);
1306 hca_guid = ibtl_ibnex_hcadip2guid(parent);
1307 if ((port_attr = ibdm_ibnex_probe_hcaport(hca_guid, port)) == NULL) {
1308 IBTF_DPRINTF_L2("ibnex",
1309 "\tconfig_root_iocnode: Port does not exist");
1310 return (IBNEX_FAILURE);
1313 /* Wait until "port is up" */
1314 while (port_attr->pa_state != IBT_PORT_ACTIVE) {
1315 ibdm_ibnex_free_port_attr(port_attr);
1316 delay(drv_usectohz(10000));
1317 if ((port_attr = ibdm_ibnex_probe_hcaport(
1318 hca_guid, port)) == NULL) {
1319 return (IBNEX_FAILURE);
1322 if (iter++ == 400) {
1323 if (displayed == B_FALSE) {
1324 cmn_err(CE_NOTE, "\tWaiting for Port %d "
1325 "initialization", port_attr->pa_port_num);
1326 displayed = B_TRUE;
1330 ibdm_ibnex_free_port_attr(port_attr);
1331 IBTF_DPRINTF_L4("ibnex", "\tconfig_rootioc_node:"
1332 "Port is initialized");
1334 if ((ioc_info = ibdm_ibnex_probe_ioc(iou_guid, ioc_guid, 0)) == NULL) {
1335 ibdm_ibnex_free_ioc_list(ioc_info);
1336 return (IBNEX_FAILURE);
1338 mutex_enter(&ibnex.ibnex_mutex);
1339 if ((ret = ibnex_ioc_config_from_pdip(ioc_info, parent, 0)) !=
1340 IBNEX_SUCCESS) {
1341 IBTF_DPRINTF_L2("ibnex",
1342 "\tconfig_root_ioc_node failed for pdip %p", parent);
1344 mutex_exit(&ibnex.ibnex_mutex);
1345 ibdm_ibnex_free_ioc_list(ioc_info);
1346 return (ret);
1350 static int
1351 ibnex_devname2port(char *portstr, int *port)
1353 char *temp;
1354 int ret = IBNEX_FAILURE;
1356 IBTF_DPRINTF_L4("ibnex", "\tdevname2port: Begin");
1358 temp = strchr(portstr, '=');
1359 if (temp != NULL) {
1360 temp++;
1361 *port = ibnex_str2int(temp, strlen(temp), &ret);
1363 return (ret);
1368 * ibnex_config_all_children()
1369 * Wait for lata SM initialization case before enumerating the nodes
1370 * Get list of HCA's and HCA port information
1371 * Create device device nodes and its node properties
1372 * for port nodes and VPPA nodes
1373 * Get list of all the IOC node information
1374 * Create device nodes and its properties for all the IOCs
1375 * if not created already
1376 * Bind drivers for all the newly created device nodes
1377 * Support Pseudo nodes enumerated using their .conf file
1379 void
1380 ibnex_config_all_children(dev_info_t *parent)
1382 int ii;
1383 ibdm_ioc_info_t *ioc_list;
1384 ibdm_hca_list_t *hca_list;
1385 ib_guid_t hca_guid;
1386 int circ;
1388 IBTF_DPRINTF_L4("ibnex", "\tconfig_all_children: Begin");
1392 * Enumerate children of this HCA, port nodes,
1393 * VPPA & HCA_SVC nodes. Use ndi_devi_enter() for
1394 * locking. IB Nexus is enumerating the children
1395 * of HCA, not MPXIO clients.
1397 ndi_devi_enter(parent, &circ);
1398 hca_guid = ibtl_ibnex_hcadip2guid(parent);
1399 ibdm_ibnex_port_settle_wait(hca_guid, ibnex_port_settling_time);
1400 hca_list = ibdm_ibnex_get_hca_info_by_guid(hca_guid);
1401 if (hca_list == NULL) {
1402 ndi_devi_exit(parent, circ);
1403 return;
1405 ibnex_create_hcasvc_nodes(parent, hca_list->hl_hca_port_attr);
1406 for (ii = 0; ii < hca_list->hl_nports; ii++) {
1407 ibnex_create_port_nodes(
1408 parent, &hca_list->hl_port_attr[ii]);
1409 ibnex_create_vppa_nodes(parent, &hca_list->hl_port_attr[ii]);
1411 ibdm_ibnex_free_hca_list(hca_list);
1412 ndi_devi_exit(parent, circ);
1415 * Use mdi_devi_enter() for locking. IB Nexus is
1416 * enumerating MPxIO clients.
1418 mdi_devi_enter(parent, &circ);
1420 ibnex_pseudo_initnodes();
1422 mutex_enter(&ibnex.ibnex_mutex);
1423 while (ibnex.ibnex_ioc_list_state != IBNEX_IOC_LIST_READY) {
1424 cv_wait(&ibnex.ibnex_ioc_list_cv, &ibnex.ibnex_mutex);
1426 ibnex.ibnex_ioc_list_state = IBNEX_IOC_LIST_ACCESS;
1427 ioc_list = ibnex.ibnex_ioc_list;
1428 while (ioc_list) {
1429 (void) ibnex_ioc_config_from_pdip(ioc_list, parent, 0);
1430 ioc_list = ioc_list->ioc_next;
1432 ibnex.ibnex_ioc_list_state = IBNEX_IOC_LIST_READY;
1433 cv_broadcast(&ibnex.ibnex_ioc_list_cv);
1435 /* Config IBTF Pseudo clients */
1436 ibnex_config_pseudo_all(parent);
1438 mutex_exit(&ibnex.ibnex_mutex);
1439 mdi_devi_exit(parent, circ);
1441 IBTF_DPRINTF_L4("ibnex", "\tconfig_all_children: End");
1446 * ibnex_create_port_nodes:
1447 * Creates a device node per each communication service defined
1448 * in the "port-commsvc-list" property per HCA port
1450 void
1451 ibnex_create_port_nodes(dev_info_t *parent, ibdm_port_attr_t *port_attr)
1453 int idx;
1454 dev_info_t *dip;
1455 int rval;
1457 mutex_enter(&ibnex.ibnex_mutex);
1458 for (idx = 0; idx < ibnex.ibnex_num_comm_svcs; idx++) {
1459 rval = ibnex_get_dip_from_guid(port_attr->pa_port_guid,
1460 idx, 0, &dip);
1461 if (rval != IBNEX_SUCCESS || dip == NULL) {
1462 (void) ibnex_commsvc_initnode(parent, port_attr, idx,
1463 IBNEX_PORT_COMMSVC_NODE, 0, &rval,
1464 IBNEX_DEVFS_ENUMERATE);
1467 mutex_exit(&ibnex.ibnex_mutex);
1472 * ibnex_create_vppa_nodes:
1473 * Creates a device node per each communication service defined
1474 * in the "vppa-commsvc-list" property and per each PKEY that
1475 * this particular port supports and per HCA port
1477 void
1478 ibnex_create_vppa_nodes(
1479 dev_info_t *parent, ibdm_port_attr_t *port_attr)
1481 int idx, ii;
1482 int rval;
1483 ib_pkey_t pkey;
1484 dev_info_t *dip;
1486 IBTF_DPRINTF_L4("ibnex", "\tcreate_vppa_nodes: Begin");
1488 mutex_enter(&ibnex.ibnex_mutex);
1489 if (port_attr->pa_state != IBT_PORT_ACTIVE) {
1490 IBTF_DPRINTF_L4("ibnex", "\tcreate_vppa_nodes: "
1491 "Port %d is down", port_attr->pa_port_num);
1492 mutex_exit(&ibnex.ibnex_mutex);
1493 return;
1495 for (idx = 0; idx < ibnex.ibnex_nvppa_comm_svcs; idx++) {
1496 if (strcmp("ipib", ibnex.ibnex_vppa_comm_svc_names[idx]) == 0) {
1497 IBTF_DPRINTF_L2("ibnex", "Skipping IBD devices...");
1498 continue;
1500 for (ii = 0; ii < port_attr->pa_npkeys; ii++) {
1501 pkey = port_attr->pa_pkey_tbl[ii].pt_pkey;
1503 if (IBNEX_INVALID_PKEY(pkey)) {
1504 continue;
1506 rval = ibnex_get_dip_from_guid(
1507 port_attr->pa_port_guid, idx, pkey, &dip);
1508 if ((rval != IBNEX_SUCCESS) || (dip == NULL)) {
1509 (void) ibnex_commsvc_initnode(parent, port_attr,
1510 idx, IBNEX_VPPA_COMMSVC_NODE,
1511 pkey, &rval, IBNEX_CFGADM_ENUMERATE);
1515 mutex_exit(&ibnex.ibnex_mutex);
1520 * ibnex_create_hcasvc_nodes:
1521 * Creates a device node per each communication service defined
1522 * in the "port-commsvc-list" property per HCA port
1524 void
1525 ibnex_create_hcasvc_nodes(dev_info_t *parent, ibdm_port_attr_t *port_attr)
1527 int idx;
1528 dev_info_t *dip;
1529 int rval;
1531 mutex_enter(&ibnex.ibnex_mutex);
1532 for (idx = 0; idx < ibnex.ibnex_nhcasvc_comm_svcs; idx++) {
1533 rval = ibnex_get_dip_from_guid(port_attr->pa_port_guid,
1534 idx, 0, &dip);
1535 if (rval != IBNEX_SUCCESS || dip == NULL) {
1536 (void) ibnex_commsvc_initnode(parent, port_attr, idx,
1537 IBNEX_HCASVC_COMMSVC_NODE, 0, &rval,
1538 IBNEX_DEVFS_ENUMERATE);
1539 IBTF_DPRINTF_L5("ibnex", "create_hcasvc_nodes: "
1540 "commsvc_initnode failed, rval %x", rval);
1543 mutex_exit(&ibnex.ibnex_mutex);
1548 * ibnex_bus_unconfig()
1550 * Unconfigure a particular device node or all instance of a device
1551 * driver device or all children of IBnex
1553 static int
1554 ibnex_bus_unconfig(dev_info_t *parent,
1555 uint_t flag, ddi_bus_config_op_t op, void *device_name)
1557 ibnex_node_data_t *ndp;
1558 major_t major = (major_t)(uintptr_t)device_name;
1559 dev_info_t *dip = NULL;
1561 if (ndi_busop_bus_unconfig(parent, flag, op, device_name) !=
1562 DDI_SUCCESS)
1563 return (DDI_FAILURE);
1565 if ((op == BUS_UNCONFIG_ALL || op == BUS_UNCONFIG_DRIVER) &&
1566 (flag & (NDI_UNCONFIG | NDI_DETACH_DRIVER))) {
1567 mutex_enter(&ibnex.ibnex_mutex);
1569 * IB dip. here we handle IOC and pseudo nodes which
1570 * are the children of IB nexus. Cleanup only the nodes
1571 * with matching major number. We also need to cleanup
1572 * the PathInfo links to the PHCI here.
1574 for (ndp = ibnex.ibnex_ioc_node_head;
1575 ndp; ndp = ndp->node_next) {
1576 dip = ndp->node_dip;
1577 if (dip && (ddi_driver_major(dip) == major)) {
1578 (void) ibnex_offline_childdip(dip);
1581 for (ndp = ibnex.ibnex_pseudo_node_head;
1582 ndp; ndp = ndp->node_next) {
1583 dip = ndp->node_dip;
1584 if (dip && (ddi_driver_major(dip) == major)) {
1585 (void) ibnex_offline_childdip(dip);
1588 mutex_exit(&ibnex.ibnex_mutex);
1590 return (DDI_SUCCESS);
1595 * ibnex_config_port_node()
1597 * Configures a particular port / HCA node for a particular
1598 * communication service.
1599 * The format of the device_name is
1600 * ibport@<Port#>,<pkey>,<service name>
1601 * where pkey = 0 for port communication service nodes
1602 * Port# = 0 for HCA_SVC communication service nodes
1603 * Returns "dev_info_t" of the "child" node just created
1604 * NULL when failed to enumerate the child node
1606 dev_info_t *
1607 ibnex_config_port_node(dev_info_t *parent, char *devname)
1609 int ii, index;
1610 int rval;
1611 uint8_t port_num;
1612 ib_guid_t hca_guid, port_guid;
1613 ib_pkey_t pkey;
1614 dev_info_t *cdip;
1615 ibdm_port_attr_t *port_attr;
1616 ibdm_hca_list_t *hca_list;
1618 IBTF_DPRINTF_L4("ibnex", "\tconfig_port_node: %s", devname);
1620 if (ibnex_get_pkey_commsvc_index_portnum(devname,
1621 &index, &pkey, &port_num) != IBNEX_SUCCESS) {
1622 IBTF_DPRINTF_L2("ibnex",
1623 "\tconfig_port_node: Invalid Service Name");
1624 return (NULL);
1627 hca_guid = ibtl_ibnex_hcadip2guid(parent);
1628 if (port_num == 0) {
1630 * Use the dummy port attribute for HCA node in hca_list
1631 * Note : pa_state is always IBT_PORT_ACTIVE.
1633 hca_list = ibdm_ibnex_get_hca_info_by_guid(hca_guid);
1634 ASSERT(hca_list != NULL);
1635 port_attr = hca_list->hl_hca_port_attr;
1636 } else {
1637 if ((port_attr = ibdm_ibnex_probe_hcaport(
1638 hca_guid, port_num)) == NULL) {
1639 IBTF_DPRINTF_L2("ibnex",
1640 "\tconfig_port_node: Port does not exist");
1641 return (NULL);
1644 if (port_attr->pa_state != IBT_PORT_ACTIVE) {
1645 ibdm_ibnex_port_settle_wait(
1646 hca_guid, ibnex_port_settling_time);
1647 ibdm_ibnex_free_port_attr(port_attr);
1648 if ((port_attr = ibdm_ibnex_probe_hcaport(
1649 hca_guid, port_num)) == NULL) {
1650 return (NULL);
1655 port_guid = port_attr->pa_port_guid;
1656 mutex_enter(&ibnex.ibnex_mutex);
1657 rval = ibnex_get_dip_from_guid(port_guid, index, pkey, &cdip);
1658 if ((rval == IBNEX_SUCCESS) && cdip != NULL) {
1659 IBTF_DPRINTF_L4("ibnex", "\tconfig_port_node: Node exists");
1660 mutex_exit(&ibnex.ibnex_mutex);
1661 if (port_num != 0)
1662 ibdm_ibnex_free_port_attr(port_attr);
1663 else
1664 ibdm_ibnex_free_hca_list(hca_list);
1665 return (cdip);
1668 if (pkey == 0 && port_num != 0) {
1669 cdip = ibnex_commsvc_initnode(parent,
1670 port_attr, index, IBNEX_PORT_COMMSVC_NODE, pkey, &rval,
1671 IBNEX_DEVFS_ENUMERATE);
1672 IBTF_DPRINTF_L5("ibnex",
1673 "\t ibnex_commsvc_initnode rval %x", rval);
1674 } else if (pkey == 0 && port_num == 0) {
1675 cdip = ibnex_commsvc_initnode(parent,
1676 port_attr, index, IBNEX_HCASVC_COMMSVC_NODE, pkey, &rval,
1677 IBNEX_DEVFS_ENUMERATE);
1678 IBTF_DPRINTF_L5("ibnex",
1679 "\t ibnex_commsvc_initnode rval %x", rval);
1680 } else {
1681 if (port_attr->pa_state != IBT_PORT_ACTIVE) {
1682 IBTF_DPRINTF_L4("ibnex", "\tconfig_port_nodes: "
1683 "Port %d is down", port_attr->pa_port_num);
1684 ibdm_ibnex_free_port_attr(port_attr);
1685 mutex_exit(&ibnex.ibnex_mutex);
1686 return (NULL);
1688 for (ii = 0; ii < port_attr->pa_npkeys; ii++) {
1689 if (pkey == port_attr->pa_pkey_tbl[ii].pt_pkey) {
1690 cdip = ibnex_commsvc_initnode(parent, port_attr,
1691 index, IBNEX_VPPA_COMMSVC_NODE,
1692 pkey, &rval, IBNEX_CFGADM_ENUMERATE);
1693 IBTF_DPRINTF_L5("ibnex",
1694 "\t ibnex_commsvc_initnode rval %x", rval);
1695 break;
1699 mutex_exit(&ibnex.ibnex_mutex);
1700 if (port_num != 0)
1701 ibdm_ibnex_free_port_attr(port_attr);
1702 else
1703 ibdm_ibnex_free_hca_list(hca_list);
1704 return (cdip);
1709 * ibnex_get_pkey_commsvc_index_portnum()
1710 * Parses the device node name and extracts PKEY, communication
1711 * service index & Port #.
1712 * Returns IBNEX_SUCCESS/IBNEX_FAILURE
1715 ibnex_get_pkey_commsvc_index_portnum(char *device_name, int *index,
1716 ib_pkey_t *pkey, uint8_t *port_num)
1718 char *srv, **service_name, *temp;
1719 int ii, ncommsvcs, ret;
1721 if (ibnex_devname_to_portnum(device_name, port_num) !=
1722 IBNEX_SUCCESS) {
1723 IBTF_DPRINTF_L2("ibnex",
1724 "\tget_pkey_commsvc_index_portnum: Invalid Service Name");
1725 return (IBNEX_FAILURE);
1727 srv = strchr(device_name, ',');
1728 if (srv == 0)
1729 return (IBNEX_FAILURE);
1731 srv++;
1732 temp = strchr(srv, ',');
1733 if (temp == 0)
1734 return (IBNEX_FAILURE);
1735 temp++;
1736 *pkey = ibnex_str2hex(srv, (temp - srv - 1), &ret);
1737 if (ret != IBNEX_SUCCESS)
1738 return (ret);
1740 if (*pkey == 0 && *port_num != 0) {
1741 service_name = ibnex.ibnex_comm_svc_names;
1742 ncommsvcs = ibnex.ibnex_num_comm_svcs;
1743 } else if (*pkey == 0 && *port_num == 0) {
1744 service_name = ibnex.ibnex_hcasvc_comm_svc_names;
1745 ncommsvcs = ibnex.ibnex_nhcasvc_comm_svcs;
1746 } else {
1747 service_name = ibnex.ibnex_vppa_comm_svc_names;
1748 ncommsvcs = ibnex.ibnex_nvppa_comm_svcs;
1751 for (ii = 0; ii < ncommsvcs; ii++) {
1752 if (strcmp(service_name[ii], temp) == 0) {
1753 break;
1756 if (ii == ncommsvcs)
1757 return (IBNEX_FAILURE);
1759 *index = ii;
1760 return (IBNEX_SUCCESS);
1765 * ibnex_devname_to_portnum()
1766 * Get portguid from device name
1767 * Returns IBNEX_SUCCESS/IBNEX_FAILURE
1769 static int
1770 ibnex_devname_to_portnum(char *device_name, uint8_t *portnum)
1772 int ret;
1773 char *temp1, *temp2;
1775 temp1 = strchr(device_name, '@');
1776 if (temp1 == NULL) {
1777 return (IBNEX_FAILURE);
1779 temp2 = strchr(temp1, ',');
1780 if (temp2 == NULL)
1781 return (IBNEX_FAILURE);
1782 temp1++;
1783 *portnum = ibnex_str2hex(temp1, (temp2 - temp1), &ret);
1784 return (ret);
1789 * ibnex_config_ioc_node()
1790 * Configures one particular instance of the IOC driver.
1791 * Returns IBNEX_SUCCESS/IBNEX_FAILURE
1793 static int
1794 ibnex_config_ioc_node(char *device_name, dev_info_t *pdip)
1796 int ret;
1797 ib_guid_t iou_guid, ioc_guid;
1798 ibdm_ioc_info_t *ioc_info;
1800 IBTF_DPRINTF_L4("ibnex", "\tconfig_ioc_node: Begin");
1802 if (ibnex_devname_to_node_n_ioc_guids(
1803 device_name, &iou_guid, &ioc_guid, NULL) != IBNEX_SUCCESS) {
1804 return (IBNEX_FAILURE);
1807 ibdm_ibnex_port_settle_wait(0, ibnex_port_settling_time);
1809 if ((ioc_info = ibdm_ibnex_probe_ioc(iou_guid, ioc_guid, 0)) ==
1810 NULL) {
1811 ibdm_ibnex_free_ioc_list(ioc_info);
1812 return (IBNEX_FAILURE);
1814 mutex_enter(&ibnex.ibnex_mutex);
1815 ret = ibnex_ioc_config_from_pdip(ioc_info, pdip, 0);
1816 mutex_exit(&ibnex.ibnex_mutex);
1817 ibdm_ibnex_free_ioc_list(ioc_info);
1818 IBTF_DPRINTF_L4("ibnex", "\tconfig_ioc_node: ret %x",
1819 ret);
1820 return (ret);
1825 * ibnex_devname_to_node_n_ioc_guids()
1826 * Get node guid and ioc guid from the device name
1827 * Format of the device node name is:
1828 * ioc@<IOC GUID>,<IOU GUID>
1829 * Returns IBNEX_SUCCESS/IBNEX_FAILURE
1831 static int
1832 ibnex_devname_to_node_n_ioc_guids(
1833 char *device_name, ib_guid_t *iou_guid, ib_guid_t *ioc_guid,
1834 char **ioc_guid_strp)
1836 char *temp1, *temp;
1837 int len, ret;
1838 char *ioc_guid_str;
1840 IBTF_DPRINTF_L4("ibnex", "\tdevname_to_node_n_ioc_guids:"
1841 "Device Name %s", device_name);
1843 if ((temp = strchr(device_name, '@')) == NULL) {
1844 return (IBNEX_FAILURE);
1846 if ((temp1 = strchr(++temp, ',')) == NULL) {
1847 return (IBNEX_FAILURE);
1849 *ioc_guid = ibnex_str2hex(temp, (temp1 - temp), &ret);
1850 if (ret == IBNEX_SUCCESS) {
1851 if (ioc_guid_strp) {
1852 ioc_guid_str = *ioc_guid_strp = kmem_zalloc((temp1
1853 - temp) + 1, KM_SLEEP);
1854 (void) strncpy(ioc_guid_str, temp, temp1 - temp + 1);
1855 ioc_guid_str[temp1 - temp] = '\0';
1857 len = device_name + strlen(device_name) - ++temp1;
1858 *iou_guid = ibnex_str2hex(temp1, len, &ret);
1860 return (ret);
1865 * ibnex_ioc_initnode()
1866 * Allocate a pathinfo node for the IOC
1867 * Initialize the device node
1868 * Bind driver to the node
1869 * Update IBnex global data
1870 * Returns IBNEX_SUCCESS/IBNEX_FAILURE/IBNEX_BUSY
1872 static int
1873 ibnex_ioc_initnode_pdip(ibnex_node_data_t *node_data,
1874 ibdm_ioc_info_t *ioc_info, dev_info_t *pdip)
1876 int rval, node_valid;
1877 ibnex_node_state_t prev_state;
1879 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
1880 ASSERT(node_data);
1884 * Return EBUSY if another configure/unconfigure
1885 * operation is in progress
1887 if (node_data->node_state == IBNEX_CFGADM_UNCONFIGURING) {
1888 IBTF_DPRINTF_L4("ibnex",
1889 "\tioc_initnode_pdip : BUSY");
1890 return (IBNEX_BUSY);
1893 prev_state = node_data->node_state;
1894 node_data->node_state = IBNEX_CFGADM_CONFIGURING;
1895 mutex_exit(&ibnex.ibnex_mutex);
1897 rval = ibnex_ioc_create_pi(ioc_info, node_data, pdip, &node_valid);
1899 mutex_enter(&ibnex.ibnex_mutex);
1900 if (rval == IBNEX_SUCCESS)
1901 node_data->node_state = IBNEX_CFGADM_CONFIGURED;
1902 else if (node_valid)
1903 node_data->node_state = prev_state;
1905 return (rval);
1909 * ibnex_config_pseudo_all()
1910 * Configure all the pseudo nodes
1912 static void
1913 ibnex_config_pseudo_all(dev_info_t *pdip)
1915 ibnex_node_data_t *nodep;
1917 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
1919 for (nodep = ibnex.ibnex_pseudo_node_head;
1920 nodep; nodep = nodep->node_next) {
1921 (void) ibnex_pseudo_config_one(nodep, NULL, pdip);
1927 * ibnex_pseudo_config_one()
1930 ibnex_pseudo_config_one(ibnex_node_data_t *node_data, char *caddr,
1931 dev_info_t *pdip)
1933 int rval;
1934 ibnex_pseudo_node_t *pseudo;
1935 ibnex_node_state_t prev_state;
1937 IBTF_DPRINTF_L4("ibnex", "\tpseudo_config_one(%p, %p, %p)",
1938 node_data, caddr, pdip);
1940 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
1942 if (node_data == NULL) {
1943 IBTF_DPRINTF_L4("ibnex",
1944 "\tpseudo_config_one: caddr = %s", caddr);
1947 * This function is now called with PHCI / HCA driver
1948 * as parent. The format of devicename is :
1949 * <driver_name>@<driver_name>,<unit_address>
1950 * The "caddr" part of the devicename matches the
1951 * format of pseudo_node_addr.
1953 * Use "caddr" to find a matching Pseudo node entry.
1955 node_data = ibnex_is_node_data_present(IBNEX_PSEUDO_NODE,
1956 (void *)caddr, 0, 0);
1959 if (node_data == NULL) {
1960 IBTF_DPRINTF_L2("ibnex",
1961 "\tpseudo_config_one: Invalid node");
1962 return (IBNEX_FAILURE);
1965 if (node_data->node_ap_state == IBNEX_NODE_AP_UNCONFIGURED) {
1966 IBTF_DPRINTF_L4("ibnex",
1967 "\tpseudo_config_one: Unconfigured node");
1968 return (IBNEX_FAILURE);
1971 pseudo = &node_data->node_data.pseudo_node;
1974 * Do not enumerate nodes with ib-node-type set as "merge"
1976 if (pseudo->pseudo_merge_node == 1) {
1977 IBTF_DPRINTF_L4("ibnex",
1978 "\tpseudo_config_one: merge_node");
1979 return (IBNEX_FAILURE);
1983 * Check if a PI has already been created for the PDIP.
1984 * If so, return SUCCESS.
1986 if (node_data->node_dip != NULL && mdi_pi_find(pdip,
1987 pseudo->pseudo_node_addr, pseudo->pseudo_node_addr) != NULL) {
1988 IBTF_DPRINTF_L4("ibnex",
1989 "\tpseudo_config_one: PI created,"
1990 " pdip %p, addr %s", pdip, pseudo->pseudo_node_addr);
1991 return (IBNEX_SUCCESS);
1995 * Return EBUSY if another unconfigure
1996 * operation is in progress
1998 if (node_data->node_state == IBNEX_CFGADM_UNCONFIGURING) {
1999 IBTF_DPRINTF_L4("ibnex",
2000 "\tpseudo_config_one: BUSY");
2001 return (IBNEX_BUSY);
2005 prev_state = node_data->node_state;
2006 node_data->node_state = IBNEX_CFGADM_CONFIGURING;
2008 mutex_exit(&ibnex.ibnex_mutex);
2009 rval = ibnex_pseudo_create_pi_pdip(node_data, pdip);
2010 mutex_enter(&ibnex.ibnex_mutex);
2012 if (rval == IBNEX_SUCCESS) {
2013 node_data->node_state = IBNEX_CFGADM_CONFIGURED;
2014 } else {
2015 node_data->node_state = prev_state;
2018 IBTF_DPRINTF_L4("ibnex", "\tpseudo_config_one: ret %x",
2019 rval);
2020 return (rval);
2025 * ibnex_pseudo_mdi_config_one()
2026 * This is similar to ibnex_pseudo_config_one. Few
2027 * differences :
2028 * 1. parent device lock not held(no ndi_devi_enter)
2029 * 2. Called for IB Nexus as parent, not IB HCA as
2030 * parent.
2031 * 3. Calls mdi_vhci_bus_config()
2032 * This function skips checks for node_state, initializing
2033 * node_state, node_dip, etc. These checks and initializations
2034 * are done when BUS_CONFIG is called with PHCI as the parent.
2037 ibnex_pseudo_mdi_config_one(int flag, void *devname, dev_info_t **child,
2038 char *cname, char *caddr)
2040 int rval, len;
2041 char *node_addr;
2042 ibnex_node_data_t *node_data;
2044 IBTF_DPRINTF_L4("ibnex", "\tpseudo_mdi_config_one:"
2045 "cname = %s caddr = %s", cname, caddr);
2047 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
2049 len = strlen(cname) + strlen(caddr) + 2;
2050 node_addr = kmem_alloc(len, KM_SLEEP);
2052 (void) snprintf(node_addr, len, "%s,%s", cname, caddr);
2053 node_data = ibnex_is_node_data_present(IBNEX_PSEUDO_NODE,
2054 (void *)node_addr, 0, 0);
2055 kmem_free(node_addr, len);
2057 if (node_data == NULL) {
2058 IBTF_DPRINTF_L2("ibnex",
2059 "\tpseudo_mdi_config_one: Invalid node");
2060 return (IBNEX_FAILURE);
2063 mutex_exit(&ibnex.ibnex_mutex);
2064 rval = mdi_vhci_bus_config(ibnex.ibnex_dip, flag, BUS_CONFIG_ONE,
2065 devname, child, node_data->node_data.pseudo_node.pseudo_node_addr);
2066 mutex_enter(&ibnex.ibnex_mutex);
2068 return (rval);
2073 * ibnex_pseudo_create_all_pi()
2074 * Create all path infos node for a pseudo entry
2077 ibnex_pseudo_create_all_pi(ibnex_node_data_t *nodep)
2079 int hcacnt, rc;
2080 int hcafailcnt = 0;
2081 dev_info_t *hca_dip;
2082 ibdm_hca_list_t *hca_list, *head;
2084 IBTF_DPRINTF_L4("ibnex", "\tpseudo_create_all_pi(%p)",
2085 nodep);
2086 ibdm_ibnex_get_hca_list(&hca_list, &hcacnt);
2088 head = hca_list;
2091 * We return failure even if we fail for all HCAs.
2093 for (; hca_list != NULL; hca_list = hca_list->hl_next) {
2094 hca_dip = ibtl_ibnex_hcaguid2dip(hca_list->hl_hca_guid);
2095 rc = ibnex_pseudo_create_pi_pdip(nodep, hca_dip);
2096 if (rc != IBNEX_SUCCESS)
2097 hcafailcnt++;
2099 if (head)
2100 ibdm_ibnex_free_hca_list(head);
2102 if (hcafailcnt == hcacnt)
2103 rc = IBNEX_FAILURE;
2104 else
2105 rc = IBNEX_SUCCESS;
2107 IBTF_DPRINTF_L4("ibnex", "\tpseudo_create_all_pi rc %x",
2108 rc);
2109 return (rc);
2112 static int
2113 ibnex_pseudo_create_pi_pdip(ibnex_node_data_t *nodep, dev_info_t *hca_dip)
2115 mdi_pathinfo_t *pip;
2116 int rval;
2117 dev_info_t *cdip = NULL;
2118 ibnex_pseudo_node_t *pseudo;
2119 int first_pi = 0;
2121 IBTF_DPRINTF_L4("ibnex", "\tpseudo_create_pi_pdip: %p, %p",
2122 nodep, hca_dip);
2124 pseudo = &nodep->node_data.pseudo_node;
2126 rval = mdi_pi_alloc(hca_dip,
2127 pseudo->pseudo_devi_name, pseudo->pseudo_node_addr,
2128 pseudo->pseudo_node_addr, 0, &pip);
2130 if (rval != MDI_SUCCESS) {
2131 IBTF_DPRINTF_L2("ibnex", "\tpseudo_create_pi_pdip:"
2132 " mdi_pi_alloc failed");
2133 return (IBNEX_FAILURE);
2135 cdip = mdi_pi_get_client(pip);
2137 if (nodep->node_dip == NULL) {
2138 IBTF_DPRINTF_L4("ibnex",
2139 "\tpseudo_create_pi: New dip %p", cdip);
2141 first_pi = 1;
2142 nodep->node_dip = cdip;
2143 ddi_set_parent_data(cdip, nodep);
2146 rval = mdi_pi_online(pip, 0);
2148 if (rval != MDI_SUCCESS) {
2149 IBTF_DPRINTF_L2("ibnex",
2150 "\tpseudo_create_pi: "
2151 "mdi_pi_online: failed for pseudo dip %p,"
2152 " rval %d", cdip, rval);
2153 rval = IBNEX_FAILURE;
2154 if (first_pi == 1) {
2155 ddi_set_parent_data(cdip, NULL);
2156 (void) ibnex_offline_childdip(cdip);
2157 nodep->node_dip = NULL;
2158 } else
2159 (void) mdi_pi_free(pip, 0);
2160 } else
2161 rval = IBNEX_SUCCESS;
2162 return (rval);
2166 * ibnex_ioc_create_pi()
2167 * Create a pathinfo node for the ioc node
2169 static int
2170 ibnex_ioc_create_pi(ibdm_ioc_info_t *ioc_info, ibnex_node_data_t *node_data,
2171 dev_info_t *pdip, int *node_valid)
2173 mdi_pathinfo_t *pip;
2174 int rval = DDI_FAILURE;
2175 dev_info_t *cdip = NULL;
2176 int create_prop = 0;
2177 ibnex_ioc_node_t *ioc = &node_data->node_data.ioc_node;
2179 IBTF_DPRINTF_L4("ibnex",
2180 "\tibnex_ioc_create_pi(%p, %p, %p)", ioc_info, node_data, pdip);
2181 *node_valid = 1;
2184 * For CONFIG_ONE requests through HCA dip, alloc
2185 * for HCA dip driving BUS_CONFIG request.
2187 rval = mdi_pi_alloc(pdip, IBNEX_IOC_CNAME, ioc->ioc_guid_str,
2188 ioc->ioc_phci_guid, 0, &pip);
2189 if (rval != MDI_SUCCESS) {
2190 IBTF_DPRINTF_L2("ibnex",
2191 "\tioc_create_pi: mdi_pi_alloc(%p, %s. %s) failed",
2192 pdip, ioc->ioc_guid_str, ioc->ioc_phci_guid);
2193 return (IBNEX_FAILURE);
2195 cdip = mdi_pi_get_client(pip);
2197 IBTF_DPRINTF_L4("ibnex", "\tioc_create_pi: IOC dip %p",
2198 cdip);
2200 if (node_data->node_dip == NULL) {
2201 node_data->node_dip = cdip;
2202 ddi_set_parent_data(cdip, node_data);
2203 create_prop = 1;
2204 IBTF_DPRINTF_L4("ibnex",
2205 "\tioc_create_pi: creating prop");
2206 if ((rval = ibnex_create_ioc_node_prop(
2207 ioc_info, cdip)) != IBNEX_SUCCESS) {
2208 IBTF_DPRINTF_L4("ibnex",
2209 "\tioc_create_pi: creating prop failed");
2210 ibnex_delete_ioc_node_data(node_data);
2211 *node_valid = 0;
2212 ddi_prop_remove_all(cdip);
2213 ddi_set_parent_data(cdip, NULL);
2215 (void) ibnex_offline_childdip(cdip);
2216 return (IBNEX_FAILURE);
2220 rval = mdi_pi_online(pip, 0);
2222 if (rval != MDI_SUCCESS) {
2223 IBTF_DPRINTF_L2("ibnex", "\tioc_create_pi: "
2224 "mdi_pi_online() failed ioc dip %p, rval %d",
2225 cdip, rval);
2226 rval = IBNEX_FAILURE;
2227 if (create_prop) {
2228 ddi_set_parent_data(cdip, NULL);
2229 ddi_prop_remove_all(cdip);
2230 ibnex_delete_ioc_node_data(node_data);
2231 *node_valid = 0;
2232 (void) ibnex_offline_childdip(cdip);
2233 } else
2234 (void) mdi_pi_free(pip, 0);
2235 } else
2236 rval = IBNEX_SUCCESS;
2238 IBTF_DPRINTF_L4("ibnex", "\tioc_create_pi ret %x", rval);
2239 return (rval);
2244 * ibnex_create_ioc_node_prop()
2245 * Create IOC device node properties
2246 * Returns IBNEX_SUCCESS/IBNEX_FAILURE
2248 static int
2249 ibnex_create_ioc_node_prop(ibdm_ioc_info_t *ioc_info, dev_info_t *cdip)
2251 uint16_t capabilities;
2252 ib_dm_ioc_ctrl_profile_t *ioc_profile = &ioc_info->ioc_profile;
2254 IBTF_DPRINTF_L4("ibnex", "\tcreate_ioc_node_prop");
2256 if (ibnex_create_ioc_compatible_prop(cdip,
2257 ioc_profile) != IBNEX_SUCCESS) {
2258 return (IBNEX_FAILURE);
2260 if ((ioc_info->ioc_iou_dc_valid) &&
2261 (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "iou-diagcode",
2262 ioc_info->ioc_iou_diagcode)) != DDI_PROP_SUCCESS) {
2263 IBTF_DPRINTF_L2("ibnex",
2264 "\tcreate_ioc_node_prop: iou-diagcode create failed");
2265 return (IBNEX_FAILURE);
2267 if ((ioc_info->ioc_diagdeviceid) && (ioc_info->ioc_dc_valid)) {
2268 if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "ioc-diagcode",
2269 ioc_info->ioc_diagcode) != DDI_PROP_SUCCESS) {
2270 IBTF_DPRINTF_L2("ibnex", "\tcreate_ioc_node_prop: "
2271 "ioc-diagcode create failed");
2272 return (IBNEX_FAILURE);
2275 if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "rdma-queue-depth",
2276 ioc_profile->ioc_rdma_read_qdepth) != DDI_PROP_SUCCESS) {
2277 IBTF_DPRINTF_L2("ibnex",
2278 "\tcreate_ioc_node_prop: rdma-queue-depth create failed");
2279 return (IBNEX_FAILURE);
2281 if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "rdma-transfer-size",
2282 ioc_profile->ioc_rdma_xfer_sz) != DDI_PROP_SUCCESS) {
2283 IBTF_DPRINTF_L2("ibnex", "\tcreate_ioc_node_prop: "
2284 "rdma-transfer-size create failed");
2285 return (IBNEX_FAILURE);
2287 if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "send-message-size",
2288 ioc_profile->ioc_send_msg_sz) != DDI_PROP_SUCCESS) {
2289 IBTF_DPRINTF_L2("ibnex",
2290 "\tcreate_ioc_node_prop: send-message-size create failed");
2291 return (IBNEX_FAILURE);
2293 if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "send-queue-depth",
2294 ioc_profile->ioc_send_msg_qdepth) != DDI_PROP_SUCCESS) {
2295 IBTF_DPRINTF_L2("ibnex",
2296 "\tcreate_ioc_node_prop: send-queue-depth create failed");
2297 return (IBNEX_FAILURE);
2300 capabilities = (ioc_profile->ioc_ctrl_opcap_mask << 8);
2301 if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip,
2302 "capabilities", capabilities) != DDI_PROP_SUCCESS) {
2303 IBTF_DPRINTF_L2("ibnex",
2304 "\tcreate_ioc_node_prop: capabilities create failed");
2305 return (IBNEX_FAILURE);
2307 if (ndi_prop_update_string(DDI_DEV_T_NONE, cdip, "id-string",
2308 (char *)ioc_profile->ioc_id_string) != DDI_PROP_SUCCESS) {
2309 IBTF_DPRINTF_L2("ibnex",
2310 "\tcreate_ioc_node_prop: id-string failed");
2311 return (IBNEX_FAILURE);
2315 * Create properties to represent all the service entries supported
2316 * by the IOC. Each service entry consists of 1) Service ID (64 bits)
2317 * and 2) Service name (40 bytes). The service entry table is
2318 * represented by two properties, service-ids and service-names. The
2319 * service-id property is a array of int64's and service names is
2320 * array of strings. The first element in the "service-ids" property
2321 * corresponds to first string in the "service-names" and so on.
2323 if ((ioc_profile->ioc_service_entries != 0) &&
2324 (ibnex_create_ioc_srv_props(cdip, ioc_info) != IBNEX_SUCCESS))
2325 return (IBNEX_FAILURE);
2327 /* Create destination port GID properties */
2328 if (ibnex_create_ioc_portgid_prop(cdip, ioc_info) != IBNEX_SUCCESS)
2329 return (IBNEX_FAILURE);
2331 if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "protocol-version",
2332 ioc_profile->ioc_protocol_ver) != DDI_PROP_SUCCESS) {
2333 IBTF_DPRINTF_L2("ibnex",
2334 "\tcreate_ioc_node_prop: protocol-version create failed");
2335 return (IBNEX_FAILURE);
2337 if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "protocol",
2338 ioc_profile->ioc_protocol) != DDI_PROP_SUCCESS) {
2339 IBTF_DPRINTF_L2("ibnex",
2340 "\tcreate_ioc_node_prop: protocol create failed");
2341 return (IBNEX_FAILURE);
2343 if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "io-subclass",
2344 ioc_profile->ioc_io_subclass) != DDI_PROP_SUCCESS) {
2345 IBTF_DPRINTF_L2("ibnex",
2346 "\tcreate_ioc_node_prop: subclass create failed");
2347 return (IBNEX_FAILURE);
2349 if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "io-class",
2350 ioc_profile->ioc_io_class) != DDI_PROP_SUCCESS) {
2351 IBTF_DPRINTF_L2("ibnex",
2352 "\tcreate_ioc_node_prop: class prop create failed");
2353 return (IBNEX_FAILURE);
2355 if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "subsystem-id",
2356 ioc_profile->ioc_subsys_id) != DDI_PROP_SUCCESS) {
2357 IBTF_DPRINTF_L2("ibnex",
2358 "\tcreate_ioc_node_prop: subsys_id create failed");
2359 return (IBNEX_FAILURE);
2361 if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "subsystem-vendor-id",
2362 ioc_profile->ioc_subsys_vendorid) != DDI_PROP_SUCCESS) {
2363 IBTF_DPRINTF_L2("ibnex",
2364 "\tcreate_ioc_node_prop: subsystem vendor create failed");
2365 return (IBNEX_FAILURE);
2367 if (ndi_prop_update_int64(DDI_DEV_T_NONE, cdip, "ioc-guid",
2368 ioc_profile->ioc_guid) != DDI_PROP_SUCCESS) {
2369 IBTF_DPRINTF_L2("ibnex",
2370 "\tcreate_ioc_node_prop: protocol create failed");
2371 return (IBNEX_FAILURE);
2373 if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "device-version",
2374 ioc_profile->ioc_device_ver) != DDI_PROP_SUCCESS) {
2375 IBTF_DPRINTF_L2("ibnex",
2376 "\tcreate_ioc_node_prop: product-id create failed");
2377 return (IBNEX_FAILURE);
2379 if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "device-id",
2380 ioc_profile->ioc_deviceid) != DDI_PROP_SUCCESS) {
2381 IBTF_DPRINTF_L2("ibnex",
2382 "\tcreate_ioc_node_prop: product-id create failed");
2383 return (IBNEX_FAILURE);
2385 if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "vendor-id",
2386 ioc_profile->ioc_vendorid) != DDI_PROP_SUCCESS) {
2387 IBTF_DPRINTF_L2("ibnex",
2388 "\tcreate_ioc_node_prop: vendor-id create failed");
2389 return (IBNEX_FAILURE);
2391 return (IBNEX_SUCCESS);
2396 * ibnex_create_ioc_portgid_prop()
2397 * Creates "port-entries", "port-list" properties
2398 * Returns IBNEX_SUCCESS/IBNEX_FAILURE
2400 static int
2401 ibnex_create_ioc_portgid_prop(
2402 dev_info_t *cdip, ibdm_ioc_info_t *ioc_info)
2404 uint64_t *port_gids;
2405 int length, ii, jj;
2406 int prop_len;
2407 ibnex_node_data_t *node_data;
2409 IBTF_DPRINTF_L4("ibnex", "\tcreate_ioc_portgid_prop");
2411 node_data = ddi_get_parent_data(cdip);
2412 ASSERT(node_data);
2414 prop_len = (ioc_info->ioc_nportgids != 0) ?
2415 (2 * ioc_info->ioc_nportgids) : 1;
2416 length = sizeof (uint64_t) * prop_len;
2417 port_gids = kmem_zalloc(length, KM_SLEEP);
2419 for (ii = 0, jj = 0; ii < ioc_info->ioc_nportgids; ii++) {
2420 port_gids[jj++] = ioc_info->ioc_gid_list[ii].gid_dgid_hi;
2421 port_gids[jj++] = ioc_info->ioc_gid_list[ii].gid_dgid_lo;
2423 if (ndi_prop_update_int64_array(DDI_DEV_T_NONE, cdip, "port-list",
2424 (int64_t *)port_gids, prop_len) != DDI_PROP_SUCCESS) {
2425 IBTF_DPRINTF_L2("ibnex",
2426 "\tcreate_ioc_portgid_prop: port-list create failed");
2427 kmem_free(port_gids, length);
2428 return (IBNEX_FAILURE);
2430 if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "port-entries",
2431 ioc_info->ioc_nportgids) != DDI_PROP_SUCCESS) {
2432 IBTF_DPRINTF_L2("ibnex",
2433 "\tcreate_ioc_portgid_prop: port-entries create failed");
2434 kmem_free(port_gids, length);
2435 return (IBNEX_FAILURE);
2438 kmem_free(port_gids, length);
2439 return (IBNEX_SUCCESS);
2444 * ibnex_create_ioc_srv_props()
2445 * Creates "service-name" and "service-id" properties
2446 * Returns IBNEX_SUCCESS/IBNEX_FAILURE
2448 static int
2449 ibnex_create_ioc_srv_props(
2450 dev_info_t *cdip, ibdm_ioc_info_t *ioc_info)
2452 int length, ii;
2453 uint64_t *srv_id;
2454 char *temp, *srv_names[IB_DM_MAX_IOCS_IN_IOU];
2455 ib_dm_ioc_ctrl_profile_t *profile = &ioc_info->ioc_profile;
2456 ibdm_srvents_info_t *srvents = ioc_info->ioc_serv;
2458 IBTF_DPRINTF_L4("ibnex", "\tcreate_ioc_srv_props");
2460 length = profile->ioc_service_entries * sizeof (ib_dm_srv_t);
2461 srv_id = kmem_zalloc(length, KM_SLEEP);
2462 temp = (char *)((char *)srv_id + (8 * profile->ioc_service_entries));
2463 for (ii = 0; ii < profile->ioc_service_entries; ii++) {
2464 srv_names[ii] = (char *)temp + (ii * IB_DM_MAX_SVC_NAME_LEN);
2467 for (ii = 0; ii < profile->ioc_service_entries; ii++) {
2468 srv_id[ii] = srvents[ii].se_attr.srv_id;
2469 bcopy(srvents[ii].se_attr.srv_name,
2470 srv_names[ii], (IB_DM_MAX_SVC_NAME_LEN - 1));
2471 IBTF_DPRINTF_L4("ibnex", "\tcreate_ioc_srv_props "
2472 "Service Names : %s", srv_names[ii]);
2473 IBTF_DPRINTF_L4("ibnex", "\tcreate_ioc_srv_props "
2474 "Service ID : %llX", srv_id[ii]);
2477 if (ndi_prop_update_int64_array(DDI_DEV_T_NONE, cdip,
2478 "service-id", (int64_t *)srv_id,
2479 profile->ioc_service_entries) != DDI_PROP_SUCCESS) {
2480 IBTF_DPRINTF_L2("ibnex",
2481 "\tcreate_ioc_srv_props: service-id create failed");
2482 kmem_free(srv_id, length);
2483 return (IBNEX_FAILURE);
2486 if (ndi_prop_update_string_array(DDI_DEV_T_NONE, cdip,
2487 "service-name", (char **)srv_names,
2488 profile->ioc_service_entries) != DDI_PROP_SUCCESS) {
2489 IBTF_DPRINTF_L2("ibnex",
2490 "\tcreate_ioc_srv_props: service-name create failed");
2491 kmem_free(srv_id, length);
2492 return (IBNEX_FAILURE);
2494 kmem_free(srv_id, length);
2495 return (IBNEX_SUCCESS);
2500 * ibnex_create_ioc_compatible_prop()
2501 * Creates "compatible" property values
2502 * Returns IBNEX_SUCCESS/IBNEX_FAILURE
2504 static int
2505 ibnex_create_ioc_compatible_prop(
2506 dev_info_t *cdip, ib_dm_ioc_ctrl_profile_t *ioc_profile)
2508 char *temp;
2509 int rval, ii;
2510 char *compatible[IBNEX_MAX_COMPAT_NAMES];
2513 * Initialize the "compatible" property string as below:
2514 * Compatible Strings :
2515 * 1. ib.V<vid>P<pid>S<subsys vid>s<subsys id>v<ver>
2516 * 2. ib.V<vid>P<pid>S<subsys vid>s<subsys id>
2517 * 3. ib.V<vid>P<pid>v<ver>
2518 * 4. ib.V<vid>P<pid>
2519 * 5. ib.C<Class>c<Subclass>p<protocol>r<protocol ver>
2520 * 6. ib.C<Class>c<Subclass>p<protocol>
2522 * Note:
2523 * All leading zeros must be present
2524 * All numeric values must specified in hex without prefix "0x"
2527 temp = kmem_alloc(IBNEX_MAX_COMPAT_PROP_SZ, KM_SLEEP);
2528 for (ii = 0; ii < IBNEX_MAX_COMPAT_NAMES; ii++)
2529 compatible[ii] = temp + (ii * IBNEX_MAX_COMPAT_LEN);
2531 (void) snprintf(compatible[0], IBNEX_MAX_COMPAT_LEN,
2532 "ib.V%06xP%08xS%06xs%08xv%04x",
2533 ioc_profile->ioc_vendorid, ioc_profile->ioc_deviceid,
2534 ioc_profile->ioc_subsys_vendorid, ioc_profile->ioc_subsys_id,
2535 ioc_profile->ioc_device_ver);
2537 (void) snprintf(compatible[1], IBNEX_MAX_COMPAT_LEN,
2538 "ib.V%06xP%08xS%06xs%08x",
2539 ioc_profile->ioc_vendorid, ioc_profile->ioc_deviceid,
2540 ioc_profile->ioc_subsys_vendorid, ioc_profile->ioc_subsys_id);
2542 (void) snprintf(compatible[2], IBNEX_MAX_COMPAT_LEN,
2543 "ib.V%06xP%08xv%04x",
2544 ioc_profile->ioc_vendorid, ioc_profile->ioc_deviceid,
2545 ioc_profile->ioc_device_ver);
2547 (void) snprintf(compatible[3], IBNEX_MAX_COMPAT_LEN,
2548 "ib.V%06xP%08x",
2549 ioc_profile->ioc_vendorid, ioc_profile->ioc_deviceid);
2551 (void) snprintf(compatible[4], IBNEX_MAX_COMPAT_LEN,
2552 "ib.C%04xc%04xp%04xr%04x",
2553 ioc_profile->ioc_io_class, ioc_profile->ioc_io_subclass,
2554 ioc_profile->ioc_protocol, ioc_profile->ioc_protocol_ver);
2556 (void) snprintf(compatible[5], IBNEX_MAX_COMPAT_LEN,
2557 "ib.C%04xc%04xp%04x",
2558 ioc_profile->ioc_io_class, ioc_profile->ioc_io_subclass,
2559 ioc_profile->ioc_protocol);
2560 for (ii = 0; ii < IBNEX_MAX_COMPAT_NAMES; ii++)
2561 IBTF_DPRINTF_L4("ibnex", "\tcompatible: %s", compatible[ii]);
2563 /* Create the compatible property for child cdip */
2564 rval = ndi_prop_update_string_array(DDI_DEV_T_NONE, cdip,
2565 "compatible", (char **)compatible, IBNEX_MAX_COMPAT_NAMES);
2567 if (rval != DDI_PROP_SUCCESS) {
2568 IBTF_DPRINTF_L2("ibnex", "\tcompatible prop_create failed");
2569 kmem_free(temp, IBNEX_MAX_COMPAT_PROP_SZ);
2570 return (IBNEX_FAILURE);
2573 kmem_free(temp, IBNEX_MAX_COMPAT_PROP_SZ);
2574 return (IBNEX_SUCCESS);
2578 static void
2579 ibnex_ioc_node_cleanup()
2581 ibnex_node_data_t *node, *delete;
2583 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
2584 for (node = ibnex.ibnex_ioc_node_head; node; ) {
2585 delete = node;
2586 node = node->node_next;
2587 mutex_exit(&ibnex.ibnex_mutex);
2588 ibnex_delete_ioc_node_data(delete);
2589 mutex_enter(&ibnex.ibnex_mutex);
2594 * ibnex_delete_ioc_node_data()
2595 * Delete IOC node from the list
2597 static void
2598 ibnex_delete_ioc_node_data(ibnex_node_data_t *node)
2600 IBTF_DPRINTF_L4("ibnex", "\tdelete_ioc_node_data:");
2602 mutex_enter(&ibnex.ibnex_mutex);
2603 if ((node->node_next == NULL) && (node->node_prev == NULL)) {
2604 ASSERT(ibnex.ibnex_ioc_node_head == node);
2605 ibnex.ibnex_ioc_node_head = NULL;
2606 } else if (node->node_next == NULL)
2607 node->node_prev->node_next = NULL;
2608 else if (node->node_prev == NULL) {
2609 node->node_next->node_prev = NULL;
2610 ibnex.ibnex_ioc_node_head = node->node_next;
2611 } else {
2612 node->node_prev->node_next = node->node_next;
2613 node->node_next->node_prev = node->node_prev;
2615 IBTF_DPRINTF_L4("ibnex", "\tdelete_ioc_node_data: head %p",
2616 ibnex.ibnex_ioc_node_head);
2617 mutex_exit(&ibnex.ibnex_mutex);
2618 kmem_free(node, sizeof (ibnex_node_data_t));
2623 * ibnex_dm_callback()
2625 * This routine is registered with the IBDM during IB nexus attach. It
2626 * is called by the IBDM module when it discovers
2627 * New HCA port
2628 * HCA port removal
2629 * New HCA added
2630 * HCA removed
2632 void
2633 ibnex_dm_callback(void *arg, ibdm_events_t flag)
2635 char hca_guid[IBNEX_HCAGUID_STRSZ];
2636 ibdm_ioc_info_t *ioc_list, *ioc;
2637 ibnex_node_data_t *node_data;
2638 dev_info_t *phci;
2639 ib_guid_t *guid;
2641 IBTF_DPRINTF_L4("ibnex", "\tdm_callback: attr %p event %x", arg, flag);
2643 switch (flag) {
2644 case IBDM_EVENT_HCA_ADDED:
2645 (void) snprintf(hca_guid, IBNEX_HCAGUID_STRSZ, "%llX",
2646 (*(longlong_t *)arg));
2647 /* Create a devctl minor node for the HCA's port */
2648 if (ddi_create_minor_node(ibnex.ibnex_dip, hca_guid, S_IFCHR,
2649 ddi_get_instance(ibnex.ibnex_dip),
2650 DDI_NT_IB_ATTACHMENT_POINT, 0) != DDI_SUCCESS) {
2651 IBTF_DPRINTF_L4("ibnex", "\tdm_callback: failed to "
2652 "create minor node for port w/ guid %s", hca_guid);
2655 guid = kmem_alloc(sizeof (ib_guid_t), KM_SLEEP);
2656 *guid = *(ib_guid_t *)arg;
2657 if (ddi_taskq_dispatch(ibnex.ibnex_taskq_id,
2658 ibnex_handle_hca_attach, guid, DDI_NOSLEEP)
2659 != DDI_SUCCESS) {
2660 kmem_free(guid, sizeof (ib_guid_t));
2661 IBTF_DPRINTF_L4("ibnex", "\tdm_callback: failed to "
2662 "dispatch HCA add event for guid %s", hca_guid);
2665 break;
2667 case IBDM_EVENT_HCA_REMOVED:
2668 (void) snprintf(hca_guid, IBNEX_HCAGUID_STRSZ, "%llX",
2669 (*(longlong_t *)arg));
2670 ddi_remove_minor_node(ibnex.ibnex_dip, hca_guid);
2671 break;
2673 case IBDM_EVENT_IOC_PROP_UPDATE:
2674 ioc = ioc_list = (ibdm_ioc_info_t *)arg;
2675 if (ioc_list == NULL)
2676 break;
2678 mutex_enter(&ibnex.ibnex_mutex);
2679 while (ioc_list) {
2680 if ((node_data = ibnex_is_node_data_present(
2681 IBNEX_IOC_NODE, ioc_list, 0, 0)) != NULL &&
2682 node_data->node_dip != NULL) {
2683 ibnex_update_prop(node_data, ioc_list);
2685 ioc_list = ioc_list->ioc_next;
2687 mutex_exit(&ibnex.ibnex_mutex);
2688 ibdm_ibnex_free_ioc_list(ioc);
2689 break;
2691 case IBDM_EVENT_PORT_UP:
2692 case IBDM_EVENT_PORT_PKEY_CHANGE:
2693 phci = ibtl_ibnex_hcaguid2dip(*(longlong_t *)arg);
2694 (void) devfs_clean(phci, NULL, 0);
2695 break;
2696 default:
2697 break;
2704 * ibnex_get_node_and_dip_from_guid()
2706 * Searches the linked list of the port nodes and returns the dip for
2707 * the of the Port / Node guid requested.
2708 * Returns NULL if not found
2711 ibnex_get_node_and_dip_from_guid(ib_guid_t guid, int index, ib_pkey_t pkey,
2712 ibnex_node_data_t **nodep, dev_info_t **dip)
2714 int node_index;
2715 ib_guid_t node_guid;
2716 ib_pkey_t node_pkey;
2717 ibnex_node_data_t *node_data;
2719 IBTF_DPRINTF_L4("ibnex",
2720 "\tget_node_and_dip_from_guid: guid = %llX", guid);
2722 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
2723 /* Search for a matching entry in internal lists */
2724 node_data = ibnex.ibnex_port_node_head;
2725 while (node_data) {
2726 node_guid = node_data->node_data.port_node.port_guid;
2727 node_index = node_data->node_data.port_node.port_commsvc_idx;
2728 node_pkey = node_data->node_data.port_node.port_pkey;
2729 if ((node_guid == guid) && (index == node_index) &&
2730 (node_pkey == pkey)) {
2731 break;
2733 node_data = node_data->node_next;
2736 /* matching found with a valid dip */
2737 if (node_data && node_data->node_dip) {
2738 *nodep = node_data;
2739 *dip = node_data->node_dip;
2740 return (IBNEX_SUCCESS);
2741 } else if (node_data && !node_data->node_dip) { /* dip is invalid */
2742 *nodep = node_data;
2743 *dip = NULL;
2744 return (IBNEX_SUCCESS);
2747 /* no match found */
2748 *nodep = NULL;
2749 *dip = NULL;
2750 return (IBNEX_FAILURE);
2754 * ibnex_get_dip_from_guid()
2756 * Searches the linked list of the port nodes and returns the dip for
2757 * the of the Port / Node guid requested.
2758 * Returns NULL if not found
2761 ibnex_get_dip_from_guid(ib_guid_t guid, int index, ib_pkey_t pkey,
2762 dev_info_t **dip)
2764 int node_index;
2765 ib_guid_t node_guid;
2766 ib_pkey_t node_pkey;
2767 ibnex_node_data_t *node_data;
2769 IBTF_DPRINTF_L4("ibnex",
2770 "\tget_dip_from_guid: guid = %llX", guid);
2772 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
2773 /* Search for a matching entry in internal lists */
2774 node_data = ibnex.ibnex_port_node_head;
2775 while (node_data) {
2776 node_guid = node_data->node_data.port_node.port_guid;
2777 node_index = node_data->node_data.port_node.port_commsvc_idx;
2778 node_pkey = node_data->node_data.port_node.port_pkey;
2779 if ((node_guid == guid) && (index == node_index) &&
2780 (node_pkey == pkey)) {
2781 break;
2783 node_data = node_data->node_next;
2786 /* matching found with a valid dip */
2787 if (node_data && node_data->node_dip) {
2788 *dip = node_data->node_dip;
2789 return (IBNEX_SUCCESS);
2790 } else if (node_data && !node_data->node_dip) { /* dip is invalid */
2791 *dip = NULL;
2792 return (IBNEX_SUCCESS);
2795 /* no match found */
2796 *dip = NULL;
2797 return (IBNEX_FAILURE);
2802 * ibnex_comm_svc_init()
2803 * Read the property and cache the values in the global
2804 * structure.
2805 * Check for max allowed length (4 bytes) of service name
2806 * (each element of the property)
2807 * Returns IBNEX_SUCCESS/IBNEX_FAILURE
2809 static ibnex_rval_t
2810 ibnex_comm_svc_init(char *property, ibnex_node_type_t type)
2812 int i, len, count;
2813 int ncomm_svcs;
2814 char **comm_svcp;
2815 char **servicep = NULL;
2816 uint_t nservices = 0;
2817 int *valid = NULL;
2819 IBTF_DPRINTF_L4("ibnex", "\tcomm_svc_init : %s property, type = %x",
2820 property, type);
2822 /* lookup the string array property */
2823 if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, ibnex.ibnex_dip,
2824 DDI_PROP_DONTPASS, property, &servicep, &nservices) !=
2825 DDI_PROP_SUCCESS) {
2826 IBTF_DPRINTF_L2("ibnex", "\t%s property undefined", property);
2827 return (IBNEX_SUCCESS);
2830 if (nservices)
2831 valid = kmem_zalloc(nservices * sizeof (int), KM_SLEEP);
2834 /* first read the file to get a count of valid service entries */
2835 for (ncomm_svcs = 0, count = 0; count < nservices; count++) {
2836 int j;
2838 len = strlen(servicep[count]);
2840 * ib.conf has NULL strings for port-svc-list &
2841 * hca-svc-list, by default. Do not have L2 message
2842 * for these.
2844 if (len == 1 || len > 4) {
2845 IBTF_DPRINTF_L2("ibnex", "\tcomm_svc_init : "
2846 "Service name %s for property %s invalid : "
2847 "length %d", servicep[count], property, len);
2848 continue;
2849 } else if (len == 0) {
2850 continue;
2852 if (ibnex_unique_svcname(servicep[count]) != IBNEX_SUCCESS) {
2853 IBTF_DPRINTF_L2("ibnex", "\tcomm_svc_init : "
2854 "Service name %s invalid : Not unique",
2855 servicep[count]);
2856 continue;
2860 * ibnex_unique_svcname checks for uniqueness in service names
2861 * communication services fully initialized. Check uniqueness
2862 * in service names currently initialized.
2864 for (j = 0; j < count; j++)
2865 if (valid[j] && strncmp(servicep[count],
2866 servicep[j], 4) == 0) {
2867 IBTF_DPRINTF_L2("ibnex", "\tcomm_svc_init : "
2868 "Service name %s invalid : Not unique",
2869 servicep[count]);
2870 continue;
2873 valid[count] = 1;
2874 ncomm_svcs++;
2877 /* if no valid entries found, bailout */
2878 if (nservices == 0 || ncomm_svcs == 0) {
2879 IBTF_DPRINTF_L4("ibnex", "\tNo %s entries found", property);
2880 ddi_prop_free(servicep); /* free the property */
2881 if (valid)
2882 kmem_free(valid, nservices * sizeof (int));
2883 return (IBNEX_SUCCESS);
2886 comm_svcp = kmem_zalloc((ncomm_svcs * sizeof (char *)), KM_SLEEP);
2887 if (type == IBNEX_PORT_COMMSVC_NODE) {
2888 ibnex.ibnex_comm_svc_names = comm_svcp;
2889 ibnex.ibnex_num_comm_svcs = ncomm_svcs;
2890 } else if (type == IBNEX_VPPA_COMMSVC_NODE) {
2891 ibnex.ibnex_vppa_comm_svc_names = comm_svcp;
2892 ibnex.ibnex_nvppa_comm_svcs = ncomm_svcs;
2893 } else if (type == IBNEX_HCASVC_COMMSVC_NODE) {
2894 ibnex.ibnex_hcasvc_comm_svc_names = comm_svcp;
2895 ibnex.ibnex_nhcasvc_comm_svcs = ncomm_svcs;
2898 /* copy the services into an array of strings */
2899 for (i = 0, count = 0; count < nservices; count++) {
2900 if (valid[count] == 0) /* Skip invalid ones */
2901 continue;
2902 comm_svcp[i] = kmem_alloc(len + 1, KM_SLEEP);
2903 (void) strcpy(comm_svcp[i], servicep[count]);
2904 IBTF_DPRINTF_L4("ibnex",
2905 "\t\tService [%d]: %s", i, comm_svcp[i]);
2906 ++i;
2908 ddi_prop_free(servicep);
2909 kmem_free(valid, nservices * sizeof (int));
2910 return (IBNEX_SUCCESS);
2915 * ibnex_comm_svc_fini()
2916 * Deallocate all the memory allocated for the communication
2917 * service arrays.
2919 static void
2920 ibnex_comm_svc_fini()
2922 int index;
2924 for (index = 0; index < ibnex.ibnex_num_comm_svcs; index++) {
2925 kmem_free(ibnex.ibnex_comm_svc_names[index],
2926 (strlen(ibnex.ibnex_comm_svc_names[index]) + 1));
2928 if (ibnex.ibnex_comm_svc_names) {
2929 kmem_free(ibnex.ibnex_comm_svc_names,
2930 ibnex.ibnex_num_comm_svcs * sizeof (char *));
2932 for (index = 0; index < ibnex.ibnex_nvppa_comm_svcs; index++) {
2933 kmem_free(ibnex.ibnex_vppa_comm_svc_names[index],
2934 strlen(ibnex.ibnex_vppa_comm_svc_names[index]) +1);
2936 if (ibnex.ibnex_vppa_comm_svc_names) {
2937 kmem_free(ibnex.ibnex_vppa_comm_svc_names,
2938 ibnex.ibnex_nvppa_comm_svcs * sizeof (char *));
2940 for (index = 0; index < ibnex.ibnex_nhcasvc_comm_svcs; index++) {
2941 kmem_free(ibnex.ibnex_hcasvc_comm_svc_names[index],
2942 strlen(ibnex.ibnex_hcasvc_comm_svc_names[index]) +1);
2944 if (ibnex.ibnex_hcasvc_comm_svc_names) {
2945 kmem_free(ibnex.ibnex_hcasvc_comm_svc_names,
2946 ibnex.ibnex_nhcasvc_comm_svcs * sizeof (char *));
2948 ibnex.ibnex_comm_svc_names = NULL;
2949 ibnex.ibnex_num_comm_svcs = 0;
2950 ibnex.ibnex_vppa_comm_svc_names = NULL;
2951 ibnex.ibnex_nvppa_comm_svcs = 0;
2952 ibnex.ibnex_hcasvc_comm_svc_names = NULL;
2953 ibnex.ibnex_nhcasvc_comm_svcs = 0;
2958 * ibnex_commsvc_initnode()
2959 * This routine is specific to port/VPPA node creation
2960 * Creates a device node for the comm service specified by commsvc_index
2961 * Creates all the device node properties
2962 * Allocates and initializes the node specific data
2963 * Binds the device driver of the device node
2964 * Returns "dev_info_t" of the child node or NULL in case of failure
2965 * Sets IBNEX_SUCCESS/IBNEX_FAILURE/IBNEX_BUSY in "rval" to reflect
2966 * if the operation was successful, failed or was not performed.
2968 dev_info_t *
2969 ibnex_commsvc_initnode(dev_info_t *parent, ibdm_port_attr_t *port_attr,
2970 int index, int node_type, ib_pkey_t pkey, int *rval, int flag)
2972 int ret;
2973 char *svcname;
2974 dev_info_t *cdip;
2975 ibnex_node_data_t *node_data;
2976 ibnex_port_node_t *port_node;
2977 char devname[MAXNAMELEN];
2978 int cdip_allocated = 0;
2980 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
2982 *rval = IBNEX_SUCCESS;
2985 * prevent any races
2986 * we have seen this node_data and it has been initialized
2987 * Note that node_dip is already NULL if unconfigure is in
2988 * progress.
2990 node_data = ibnex_is_node_data_present(node_type, (void *)port_attr,
2991 index, pkey);
2994 * If this node has been explicity unconfigured by cfgadm, then it can
2995 * be configured back again only by cfgadm configure.
2997 if (node_data && (node_data->node_ap_state ==
2998 IBNEX_NODE_AP_UNCONFIGURED)) {
2999 *rval = IBNEX_FAILURE;
3000 return (NULL);
3003 if (node_data && node_data->node_dip) {
3005 * Return NULL if another configure
3006 * operation is in progress
3008 if (node_data->node_state == IBNEX_CFGADM_CONFIGURING) {
3009 *rval = IBNEX_BUSY;
3010 return (NULL);
3011 } else {
3012 return (node_data->node_dip);
3014 } else if (node_data == NULL) {
3015 /* allocate a new ibnex_node_data_t */
3016 node_data = ibnex_init_child_nodedata(node_type, port_attr,
3017 index, pkey);
3018 node_data->node_data.port_node.port_pdip = parent;
3022 * Return NULL if another unconfigure operation is in progress
3024 if (node_data->node_state == IBNEX_CFGADM_UNCONFIGURING) {
3025 *rval = IBNEX_BUSY;
3026 return (NULL);
3029 ASSERT(node_data->node_state != IBNEX_CFGADM_CONFIGURED);
3030 node_data->node_state = IBNEX_CFGADM_CONFIGURING;
3032 switch (node_type) {
3033 case IBNEX_VPPA_COMMSVC_NODE :
3034 svcname = ibnex.ibnex_vppa_comm_svc_names[index];
3035 port_node = &node_data->node_data.port_node;
3036 (void) snprintf(devname, MAXNAMELEN, "%s@%x,%x,%s",
3037 IBNEX_IBPORT_CNAME, port_node->port_num,
3038 port_node->port_pkey, svcname);
3039 break;
3040 case IBNEX_HCASVC_COMMSVC_NODE :
3041 svcname = ibnex.ibnex_hcasvc_comm_svc_names[index];
3042 port_node = &node_data->node_data.port_node;
3043 (void) snprintf(devname, MAXNAMELEN, "%s@%x,0,%s",
3044 IBNEX_IBPORT_CNAME, port_node->port_num, svcname);
3045 break;
3046 case IBNEX_PORT_COMMSVC_NODE :
3047 svcname = ibnex.ibnex_comm_svc_names[index];
3048 port_node = &node_data->node_data.port_node;
3049 (void) snprintf(devname, MAXNAMELEN, "%s@%x,0,%s",
3050 IBNEX_IBPORT_CNAME, port_node->port_num, svcname);
3051 break;
3052 default :
3053 IBTF_DPRINTF_L2("ibnex", "\tcommsvc_initnode:"
3054 "\tInvalid Node type");
3055 *rval = IBNEX_FAILURE;
3056 ibnex_delete_port_node_data(node_data);
3057 return (NULL);
3060 if ((cdip = ndi_devi_findchild(parent, devname)) != NULL) {
3061 if (i_ddi_devi_attached(cdip)) {
3062 node_data->node_dip = cdip;
3063 node_data->node_data.port_node.port_pdip = parent;
3064 node_data->node_state = IBNEX_CFGADM_CONFIGURED;
3065 ddi_set_parent_data(cdip, node_data);
3066 IBTF_DPRINTF_L4("ibnex", "\tcommsvc_initnode: found "
3067 "attached cdip 0x%p for devname %s", cdip, devname);
3068 return (cdip);
3070 } else {
3071 ndi_devi_alloc_sleep(parent,
3072 IBNEX_IBPORT_CNAME, (pnode_t)DEVI_SID_NODEID, &cdip);
3073 cdip_allocated = 1;
3076 node_data->node_dip = cdip;
3077 ddi_set_parent_data(cdip, node_data);
3078 mutex_exit(&ibnex.ibnex_mutex);
3081 if (ibnex_create_port_node_prop(port_attr, cdip, svcname, pkey) ==
3082 IBNEX_SUCCESS) {
3083 if (flag == IBNEX_DEVFS_ENUMERATE)
3084 ret = ndi_devi_bind_driver(cdip, 0);
3085 else
3086 ret = ndi_devi_online(cdip, 0);
3087 if (ret == NDI_SUCCESS) {
3088 mutex_enter(&ibnex.ibnex_mutex);
3089 node_data->node_state = IBNEX_CFGADM_CONFIGURED;
3090 node_data->node_data.port_node.port_pdip = parent;
3091 return (cdip);
3093 IBTF_DPRINTF_L4("ibnex", "\tcommsvc_initnode: BIND/ONLINE "
3094 "of cdip 0x%p for devname %s and flag %d failed", cdip,
3095 devname, flag);
3098 *rval = IBNEX_FAILURE;
3099 node_data->node_dip = NULL;
3100 ddi_set_parent_data(cdip, NULL);
3101 if (cdip_allocated)
3102 (void) ndi_devi_free(cdip);
3103 mutex_enter(&ibnex.ibnex_mutex);
3104 IBTF_DPRINTF_L4("ibnex", "\tcommsvc_initnode: failure exit");
3105 return (NULL);
3110 * ibnex_create_port_node_prop()
3111 * Returns IBNEX_SUCCESS/IBNEX_FAILURE
3113 static int
3114 ibnex_create_port_node_prop(ibdm_port_attr_t *port_attr,
3115 dev_info_t *child_dip, char *srvname, ib_pkey_t pkey)
3117 if (ibnex_create_port_compatible_prop(child_dip,
3118 srvname, port_attr) != DDI_PROP_SUCCESS) {
3119 IBTF_DPRINTF_L2("ibnex",
3120 "\tcreate_port_node_prop: compatible update failed");
3121 return (IBNEX_FAILURE);
3123 if ((pkey != 0) && (ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
3124 "port-pkey", pkey) != DDI_PROP_SUCCESS)) {
3125 IBTF_DPRINTF_L2("ibnex",
3126 "\tcreate_port_node_prop: port-num update failed");
3127 return (IBNEX_FAILURE);
3131 * For HCA_SVC device nodes, port_num will be 0.
3132 * Do not create the "port-number" & "port-guid" properties.
3134 if (port_attr->pa_port_num != 0) {
3135 if (ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
3136 "port-number", port_attr->pa_port_num) !=
3137 DDI_PROP_SUCCESS) {
3138 IBTF_DPRINTF_L2("ibnex",
3139 "\tcreate_port_node_prop: port-num update failed");
3140 return (IBNEX_FAILURE);
3142 if (ndi_prop_update_int64(DDI_DEV_T_NONE, child_dip,
3143 "port-guid", port_attr->pa_port_guid) !=
3144 DDI_PROP_SUCCESS) {
3145 IBTF_DPRINTF_L2("ibnex",
3146 "\tcreate_port_node_prop: port-guid update failed");
3147 return (IBNEX_FAILURE);
3149 } else {
3150 ibdm_hca_list_t *hca_list;
3153 * HCA_SVC nodes require "num-ports" & "port-guids"
3154 * properties.
3156 * To create the num-ports & port-guids attribute :
3157 * 1. Get HCA list (ibdm_ibnex_get_hca_info_by_guid)
3158 * 2. Form the array of port GUIDs.
3160 if ((hca_list = ibdm_ibnex_get_hca_info_by_guid(
3161 port_attr->pa_hca_guid)) == NULL) {
3162 IBTF_DPRINTF_L2("ibnex",
3163 "\tcreate_port_node_prop: hca_info_by_guid failed");
3164 return (IBNEX_FAILURE);
3167 if (hca_list->hl_nports != 0) {
3168 ib_guid_t *port_guids;
3169 uint8_t portnum;
3171 ASSERT(hca_list->hl_port_attr != NULL);
3173 port_guids = kmem_zalloc(
3174 hca_list->hl_nports * sizeof (ib_guid_t),
3175 KM_SLEEP);
3177 for (portnum = 0; portnum < hca_list->hl_nports;
3178 portnum++) {
3179 port_guids[portnum] = (hca_list->
3180 hl_port_attr[portnum]).pa_port_guid;
3183 if (ndi_prop_update_int64_array(DDI_DEV_T_NONE,
3184 child_dip, "port-guids", (int64_t *)port_guids,
3185 hca_list->hl_nports) != DDI_PROP_SUCCESS) {
3186 IBTF_DPRINTF_L2("ibnex",
3187 "\tcreate_port_node_prop: port-guids "
3188 "create failed");
3189 kmem_free(port_guids, hca_list->hl_nports *
3190 sizeof (ib_guid_t));
3191 ibdm_ibnex_free_hca_list(hca_list);
3192 return (IBNEX_FAILURE);
3194 kmem_free(port_guids, hca_list->hl_nports *
3195 sizeof (ib_guid_t));
3198 if (ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
3199 "num-ports", hca_list->hl_nports) != DDI_PROP_SUCCESS) {
3200 IBTF_DPRINTF_L2("ibnex",
3201 "\tcreate_port_node_prop: num-ports update failed");
3202 ibdm_ibnex_free_hca_list(hca_list);
3203 return (IBNEX_FAILURE);
3205 ibdm_ibnex_free_hca_list(hca_list);
3208 if (ndi_prop_update_int64(DDI_DEV_T_NONE, child_dip,
3209 "hca-guid", port_attr->pa_hca_guid) != DDI_PROP_SUCCESS) {
3210 IBTF_DPRINTF_L2("ibnex",
3211 "\tcreate_port_node_prop: hca-guid update failed");
3212 return (IBNEX_FAILURE);
3214 if (ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
3215 "product-id", port_attr->pa_productid) != DDI_PROP_SUCCESS) {
3216 IBTF_DPRINTF_L2("ibnex",
3217 "\tcreate_port_node_prop: product-id update failed");
3218 return (IBNEX_FAILURE);
3220 if (ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
3221 "vendor-id", port_attr->pa_vendorid) != DDI_PROP_SUCCESS) {
3222 IBTF_DPRINTF_L2("ibnex",
3223 "\tcreate_port_node_prop: vendor-id update failed");
3224 return (IBNEX_FAILURE);
3226 if (ndi_prop_update_int(DDI_DEV_T_NONE, child_dip, "device-version",
3227 port_attr->pa_dev_version) != DDI_PROP_SUCCESS) {
3228 IBTF_DPRINTF_L2("ibnex",
3229 "\tcreate_port_node_prop: device-version update failed");
3230 return (IBNEX_FAILURE);
3232 return (IBNEX_SUCCESS);
3237 * ibnex_str2int()
3238 * Utility function that converts a string of length "len" to
3239 * integer.
3240 * Returns IBNEX_SUCCESS/IBNEX_FAILURE
3243 ibnex_str2int(char *c, int len, int *ret)
3245 int intval = 0, ii;
3247 IBTF_DPRINTF_L4("ibnex", "\tstr2int: Int string %s..", c);
3248 *ret = IBNEX_SUCCESS;
3249 for (ii = 0; ii < len; ii ++) {
3250 if ((c[ii] >= '0') && (c[ii] <= '9'))
3251 intval = intval * 10 +c[ii] - '0';
3252 else {
3253 IBTF_DPRINTF_L2("ibnex",
3254 "\tstr2int: Invalid integer string %s..", c);
3255 *ret = IBNEX_FAILURE;
3256 break;
3260 return (intval);
3265 * ibnex_str2hex()
3266 * Utility functions that converts a string of length "len" to
3267 * hex value. Note. This function does not handle strings which
3268 * string length more than 8 bytes.
3271 uint64_t
3272 ibnex_str2hex(char *c, int len, int *ret)
3274 uint64_t hex = 0, ii;
3276 *ret = IBNEX_SUCCESS;
3277 for (ii = 0; ii < len; ii ++) {
3278 hex = (ii == 0) ? hex : (hex << 4);
3279 if ((c[ii] >= '0') && (c[ii] <= '9'))
3280 hex |= c[ii] - '0';
3281 else if ((c[ii] >= 'a') && (c[ii] <= 'f'))
3282 hex |= c[ii] - 'a' + 10;
3283 else if ((c[ii] >= 'A') && (c[ii] <= 'F'))
3284 hex |= c[ii] - 'A' + 10;
3285 else {
3286 IBTF_DPRINTF_L2("ibnex",
3287 "\tstr2hex: Invalid integer string");
3288 *ret = IBNEX_FAILURE;
3289 break;
3293 return (hex);
3298 * ibnex_create_port_compatible_prop()
3299 * Creates 'Compatibility' property for port / HCA_SVC device nodes
3300 * Returns IBNEX_SUCCESS/IBNEX_FAILURE
3302 static int
3303 ibnex_create_port_compatible_prop(dev_info_t *child_dip,
3304 char *comm_svcp, ibdm_port_attr_t *port_attr)
3306 int rval, i;
3307 char *temp;
3308 char *compatible[IBNEX_MAX_IBPORT_COMPAT_NAMES];
3310 IBTF_DPRINTF_L4("ibnex", "\tcreate_port_compatible_prop: Begin");
3312 * Initialize the "compatible" property string as below:
3313 * Compatible Strings :
3314 * 1. ib.V<vid>P<pid>v<revision>.<service name>.
3315 * 2. ib.V<vid>P<pid>.<service name>.
3316 * 3. ib.<service name>
3317 * Leading zeros must be present
3319 temp = kmem_alloc(IBNEX_MAX_IBPORT_COMPAT_PROP_SZ, KM_SLEEP);
3320 for (i = 0; i < IBNEX_MAX_IBPORT_COMPAT_NAMES; i++) {
3321 compatible[i] = temp + (i * IBNEX_MAX_COMPAT_LEN);
3324 (void) snprintf(compatible[0], IBNEX_MAX_COMPAT_LEN,
3325 "ib.V%06xP%08xv%04x.%s",
3326 port_attr->pa_vendorid, port_attr->pa_productid,
3327 port_attr->pa_dev_version, comm_svcp);
3328 (void) snprintf(compatible[1], IBNEX_MAX_COMPAT_LEN,
3329 "ib.V%06xP%08x.%s",
3330 port_attr->pa_vendorid, port_attr->pa_productid,
3331 comm_svcp);
3332 (void) snprintf(compatible[2], IBNEX_MAX_COMPAT_LEN,
3333 "ib.%s", comm_svcp);
3335 for (i = 0; i < IBNEX_MAX_IBPORT_COMPAT_NAMES; i++)
3336 IBTF_DPRINTF_L4("ibnex", "\tcompatible: %s", compatible[i]);
3338 rval = ndi_prop_update_string_array(DDI_DEV_T_NONE, child_dip,
3339 "compatible", (char **)compatible, IBNEX_MAX_IBPORT_COMPAT_NAMES);
3341 if (rval != DDI_PROP_SUCCESS) {
3342 kmem_free(temp, IBNEX_MAX_IBPORT_COMPAT_PROP_SZ);
3343 return (IBNEX_FAILURE);
3345 kmem_free(temp, IBNEX_MAX_IBPORT_COMPAT_PROP_SZ);
3346 return (IBNEX_SUCCESS);
3351 * ibnex_delete_port_node_data()
3352 * Delete the parent private node data from the linked list
3353 * Deallocate the memory of the port/ioc attributes
3354 * Deallocate the memory of the node data
3356 static void
3357 ibnex_delete_port_node_data(ibnex_node_data_t *node)
3359 if ((node->node_next == NULL) && (node->node_prev == NULL))
3360 ibnex.ibnex_port_node_head = NULL;
3361 else if (node->node_next == NULL)
3362 node->node_prev->node_next = NULL;
3363 else if (node->node_prev == NULL) {
3364 node->node_next->node_prev = NULL;
3365 ibnex.ibnex_port_node_head = node->node_next;
3366 } else {
3367 node->node_prev->node_next = node->node_next;
3368 node->node_next->node_prev = node->node_prev;
3370 kmem_free(node, sizeof (ibnex_node_data_t));
3375 * ibnex_is_node_data_present()
3376 * Checks whether ibnex_node_t is created already
3377 * Returns ibnex_node_data_t if found, otherwise NULL
3379 static ibnex_node_data_t *
3380 ibnex_is_node_data_present(ibnex_node_type_t node_type, void *attr,
3381 int index, ib_pkey_t pkey)
3383 ibnex_node_data_t *nodep;
3384 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
3385 if (node_type == IBNEX_IOC_NODE) {
3386 ibdm_ioc_info_t *ioc_infop = (ibdm_ioc_info_t *)attr;
3388 for (nodep = ibnex.ibnex_ioc_node_head; nodep != NULL;
3389 nodep = nodep->node_next) {
3390 if (nodep->node_data.ioc_node.ioc_guid ==
3391 ioc_infop->ioc_profile.ioc_guid) {
3392 return (nodep);
3396 } else if (node_type == IBNEX_PSEUDO_NODE) {
3397 for (nodep = ibnex.ibnex_pseudo_node_head; nodep;
3398 nodep = nodep->node_next)
3399 if (strcmp(nodep->node_data.pseudo_node.
3400 pseudo_node_addr, (char *)attr) == 0)
3401 return (nodep);
3403 } else {
3404 ibdm_port_attr_t *pattrp = (ibdm_port_attr_t *)attr;
3406 for (nodep = ibnex.ibnex_port_node_head; nodep != NULL;
3407 nodep = nodep->node_next) {
3408 if ((nodep->node_data.port_node.port_guid ==
3409 pattrp->pa_port_guid) &&
3410 (nodep->node_data.port_node.port_commsvc_idx ==
3411 index) &&
3412 (nodep->node_data.port_node.port_pkey == pkey)) {
3413 return (nodep);
3417 return (NULL);
3421 * ibnex_lookup_unit_address_prop:
3423 * If property with name is found, return its value
3424 * otherwise return NULL.
3426 static char *
3427 ibnex_lookup_named_prop(ddi_prop_t *head, char *name)
3429 ddi_prop_t *propp;
3431 /* Search the list of properties for name */
3432 for (propp = head; propp != NULL; propp = propp->prop_next) {
3433 if (strcmp(propp->prop_name, name) != 0)
3434 continue;
3435 /* named property should be valid and have a value */
3436 if (propp->prop_len <= 1)
3437 break;
3438 return ((char *)propp->prop_val);
3441 return (NULL);
3446 * ibnex_pseudo_initnodes()
3447 * This routine is specific to pseudo node information handling
3448 * Creates a ibnex_node_data_t all pseudo nodes children of ibnex
3450 void
3451 ibnex_pseudo_initnodes()
3453 int pnam_len, len;
3454 ibnex_node_data_t *nodep;
3455 struct hwc_spec *list, *spec;
3456 char *node_addr, *temp, *unit_addr;
3457 char *node_type;
3459 IBTF_DPRINTF_L4("ibnex", "\tpseudo_initnodes");
3461 mutex_enter(&ibnex.ibnex_mutex);
3463 * get a list of all "pseudo" children of "ib".
3464 * for these children initialize/allocate an internal
3465 * ibnex_node_data_t.
3467 list = hwc_get_child_spec(ibnex.ibnex_dip, (major_t)-1);
3468 for (spec = list; spec != NULL; spec = spec->hwc_next) {
3469 if (spec->hwc_devi_sys_prop_ptr == NULL)
3470 continue;
3472 /* Check "ib-node-type" property for IOC .conf */
3473 node_type = ibnex_lookup_named_prop(
3474 spec->hwc_devi_sys_prop_ptr, "ib-node-type");
3476 /* "unit-address" property should be present */
3477 temp = ibnex_lookup_named_prop(
3478 spec->hwc_devi_sys_prop_ptr, "unit-address");
3479 if (temp == NULL)
3480 continue;
3482 pnam_len = strlen(spec->hwc_devi_name) + strlen(temp) + 2;
3484 node_addr = kmem_zalloc(pnam_len, KM_SLEEP);
3486 (void) snprintf(node_addr,
3487 pnam_len, "%s,%s", spec->hwc_devi_name, temp);
3489 nodep = ibnex_is_node_data_present(
3490 IBNEX_PSEUDO_NODE, (void *)node_addr, 0, 0);
3492 if (nodep) {
3493 kmem_free(node_addr, pnam_len);
3494 continue;
3497 nodep = ibnex_init_child_nodedata(IBNEX_PSEUDO_NODE,
3498 (void *)spec->hwc_devi_name, 0, 0);
3500 nodep->node_data.pseudo_node.pseudo_node_addr = node_addr;
3501 (void) snprintf(nodep->node_data.
3502 pseudo_node.pseudo_node_addr, pnam_len, "%s", node_addr);
3504 len = strlen(temp) + 1;
3505 unit_addr = kmem_alloc(len, KM_SLEEP);
3506 nodep->node_data.pseudo_node.pseudo_unit_addr = unit_addr;
3507 (void) snprintf(unit_addr, len, "%s", temp);
3508 nodep->node_data.pseudo_node.pseudo_unit_addr_len = len;
3510 if (node_type && strcmp(node_type, "merge") == 0)
3511 nodep->node_data.pseudo_node.pseudo_merge_node = 1;
3513 IBTF_DPRINTF_L3("ibnex", "\tpseudo_initnodes: unit addr = %s"
3514 " : drv name = %s", unit_addr, spec->hwc_devi_name);
3516 hwc_free_spec_list(list);
3517 mutex_exit(&ibnex.ibnex_mutex);
3522 * ibnex_init_child_nodedata()
3524 * Allocate memory for the parent private data for device node
3525 * Initializes the parent private child device node data.
3526 * Returns pointer to the parent private data
3528 static ibnex_node_data_t *
3529 ibnex_init_child_nodedata(ibnex_node_type_t node_type, void *attr, int index,
3530 ib_pkey_t pkey)
3532 char *devi_name;
3533 ibdm_ioc_info_t *ioc_info;
3534 ibnex_ioc_node_t *ioc_node;
3535 ibnex_node_data_t *node_data;
3536 ib_dm_ioc_ctrl_profile_t *ioc_profile;
3538 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
3540 node_data = kmem_zalloc(sizeof (ibnex_node_data_t), KM_SLEEP);
3541 node_data->node_ap_state = IBNEX_NODE_AP_CONFIGURED;
3542 node_data->node_state = IBNEX_CFGADM_CONFIGURING;
3543 node_data->node_type = node_type;
3545 if (node_type == IBNEX_IOC_NODE) {
3546 ioc_info = (ibdm_ioc_info_t *)attr;
3547 ioc_profile = &ioc_info->ioc_profile;
3548 ioc_node = &node_data->node_data.ioc_node;
3550 ioc_node->iou_guid = ioc_info->ioc_iou_guid;
3551 ioc_node->ioc_guid = ioc_profile->ioc_guid;
3552 (void) strncpy(ioc_node->ioc_id_string,
3553 (char *)ioc_profile->ioc_id_string,
3554 IB_DM_IOC_ID_STRING_LEN);
3555 ioc_node->ioc_ngids = ioc_info->ioc_nportgids;
3557 node_data->node_next = ibnex.ibnex_ioc_node_head;
3558 node_data->node_prev = NULL;
3559 if (ibnex.ibnex_ioc_node_head)
3560 ibnex.ibnex_ioc_node_head->node_prev = node_data;
3561 ibnex.ibnex_ioc_node_head = node_data;
3562 } else if (node_type == IBNEX_PSEUDO_NODE) {
3563 devi_name = (char *)attr;
3564 node_data->node_data.pseudo_node.pseudo_devi_name =
3565 kmem_zalloc(strlen(devi_name) + 1, KM_SLEEP);
3566 (void) strncpy(node_data->node_data.pseudo_node.
3567 pseudo_devi_name, devi_name, strlen(devi_name));
3568 node_data->node_next = ibnex.ibnex_pseudo_node_head;
3569 node_data->node_prev = NULL;
3570 if (ibnex.ibnex_pseudo_node_head)
3571 ibnex.ibnex_pseudo_node_head->node_prev = node_data;
3572 ibnex.ibnex_pseudo_node_head = node_data;
3573 } else {
3574 node_data->node_data.port_node.port_hcaguid =
3575 ((ibdm_port_attr_t *)attr)->pa_hca_guid;
3576 node_data->node_data.port_node.port_guid =
3577 ((ibdm_port_attr_t *)attr)->pa_port_guid;
3578 node_data->node_data.port_node.port_num =
3579 ((ibdm_port_attr_t *)attr)->pa_port_num;
3580 node_data->node_data.port_node.port_commsvc_idx = index;
3581 node_data->node_data.port_node.port_pkey = pkey;
3583 node_data->node_next = ibnex.ibnex_port_node_head;
3584 node_data->node_prev = NULL;
3585 if (ibnex.ibnex_port_node_head)
3586 ibnex.ibnex_port_node_head->node_prev = node_data;
3587 ibnex.ibnex_port_node_head = node_data;
3589 return (node_data);
3592 static int
3593 ibnex_get_eventcookie(dev_info_t *dip, dev_info_t *rdip,
3594 char *eventname, ddi_eventcookie_t *cookie)
3596 int rc;
3599 IBTF_DPRINTF_L4("ibnex", "ibnex_get_eventcookie(%p, %p, %s, 0x%X)",
3600 dip, rdip, eventname, cookie);
3602 rc = ndi_event_retrieve_cookie(ibnex.ibnex_ndi_event_hdl,
3603 rdip, eventname, cookie, NDI_EVENT_NOPASS);
3604 if (rc == NDI_SUCCESS) {
3605 mutex_enter(&ibnex.ibnex_mutex);
3606 ibnex.ibnex_prop_update_evt_cookie = *cookie;
3607 mutex_exit(&ibnex.ibnex_mutex);
3610 return (rc);
3613 static int
3614 ibnex_add_eventcall(dev_info_t *dip, dev_info_t *rdip,
3615 ddi_eventcookie_t cookie, void (*callback)(dev_info_t *dip,
3616 ddi_eventcookie_t cookie, void *arg, void *bus_impldata),
3617 void *arg, ddi_callback_id_t *cb_id)
3619 IBTF_DPRINTF_L4("ibnex",
3620 "ibnex_add_eventcall(%p, %p, 0x%X, %p, %p, %p)",
3621 dip, rdip, cookie, callback, arg, cb_id);
3623 return (ndi_event_add_callback(ibnex.ibnex_ndi_event_hdl,
3624 rdip, cookie, callback, arg, NDI_SLEEP, cb_id));
3627 static int
3628 ibnex_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id)
3630 IBTF_DPRINTF_L4("ibnex", "ibnex_remove_eventcall(%p, 0x%X)",
3631 dip, cb_id);
3633 return (ndi_event_remove_callback(ibnex.ibnex_ndi_event_hdl,
3634 cb_id));
3637 static int
3638 ibnex_post_event(dev_info_t *dip, dev_info_t *rdip,
3639 ddi_eventcookie_t cookie, void *bus_impldata)
3641 IBTF_DPRINTF_L4("ibnex", "ibnex_post_event(%p, %p, 0x%X, %p)",
3642 dip, rdip, cookie, bus_impldata);
3644 return (ndi_event_run_callbacks(ibnex.ibnex_ndi_event_hdl, rdip,
3645 cookie, bus_impldata));
3649 * ibnex_reprobe_ioc_dev()
3651 * This could be called as a result of ibt_reprobe_dev request or
3652 * cfgadm command. The function is called from a taskq in case of
3653 * ibt_reprobe_dev and from user context for cfgadm command.
3655 * This function reprobes the properties for one IOC dip.
3657 * node_reprobe_state should be set before calling this function.
3659 void
3660 ibnex_reprobe_ioc_dev(void *arg)
3662 dev_info_t *dip = (dev_info_t *)arg;
3663 ibnex_node_data_t *node_data;
3664 ibnex_ioc_node_t *ioc_data;
3665 ibdm_ioc_info_t *ioc_info;
3667 /* ASSERT(NO_LOCKS_HELD); */
3668 ASSERT(dip != NULL);
3670 node_data = ddi_get_parent_data(dip);
3671 ASSERT(node_data);
3673 if (node_data->node_dip == NULL) {
3674 IBTF_DPRINTF_L4("ibnex", "reprobe for unconfigured dip");
3675 mutex_enter(&ibnex.ibnex_mutex);
3676 ibnex_wakeup_reprobe_ioc(node_data, 0);
3677 mutex_exit(&ibnex.ibnex_mutex);
3678 return;
3680 ioc_data = &(node_data->node_data.ioc_node);
3682 /* Reprobe the IOC */
3683 ioc_info = ibdm_ibnex_probe_ioc(ioc_data->iou_guid, ioc_data->ioc_guid,
3685 if (ioc_info == NULL) {
3686 IBTF_DPRINTF_L2("ibnex", "Null ioc_info from reprobe");
3687 mutex_enter(&ibnex.ibnex_mutex);
3688 ibnex_wakeup_reprobe_ioc(node_data, 1);
3689 mutex_exit(&ibnex.ibnex_mutex);
3690 return;
3693 mutex_enter(&ibnex.ibnex_mutex);
3694 if (node_data->node_dip)
3695 ibnex_update_prop(node_data, ioc_info);
3696 ibnex_wakeup_reprobe_ioc(node_data, 0);
3697 mutex_exit(&ibnex.ibnex_mutex);
3699 ibdm_ibnex_free_ioc_list(ioc_info);
3703 * ibnex_reprobe_all()
3705 * This could be called as a result of cfgadm command. The function
3706 * is called from user context.
3708 * This function reprobes the properties for all IOC dips.
3710 * ibnex_reprobe_state should be set before calling this function.
3712 void
3713 ibnex_reprobe_ioc_all()
3715 ibnex_node_data_t *node_data;
3716 ibdm_ioc_info_t *ioc_info_list, *ioc;
3718 /* ASSERT(NO_LOCKS_HELD); */
3720 /* Sweep the fabric */
3721 ioc = ioc_info_list = ibdm_ibnex_get_ioc_list(
3722 IBDM_IBNEX_REPROBE_ALL);
3723 if (ioc_info_list == NULL) {
3724 mutex_enter(&ibnex.ibnex_mutex);
3725 ibnex_wakeup_reprobe_all();
3726 mutex_exit(&ibnex.ibnex_mutex);
3727 return;
3730 mutex_enter(&ibnex.ibnex_mutex);
3731 while (ioc_info_list) {
3732 if ((node_data = ibnex_is_node_data_present(IBNEX_IOC_NODE,
3733 ioc_info_list, 0, 0)) != NULL &&
3734 node_data->node_dip != NULL) {
3735 ibnex_update_prop(node_data, ioc_info_list);
3737 ioc_info_list = ioc_info_list->ioc_next;
3739 ibnex_wakeup_reprobe_all();
3740 mutex_exit(&ibnex.ibnex_mutex);
3742 ibdm_ibnex_free_ioc_list(ioc);
3746 * Update the properties, if it has modified and notify IBTF client.
3748 static void
3749 ibnex_update_prop(ibnex_node_data_t *node_data, ibdm_ioc_info_t *ioc_info)
3751 ibt_prop_update_payload_t evt_data;
3752 dev_info_t *dip = node_data->node_dip;
3753 ddi_eventcookie_t evt_cookie;
3754 ibnex_ioc_node_t *ioc;
3756 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
3758 ASSERT(dip != NULL);
3760 ioc = &node_data->node_data.ioc_node;
3762 evt_data = ioc_info->ioc_info_updated;
3763 evt_cookie = ibnex.ibnex_prop_update_evt_cookie;
3766 * For a disconnected IOC :
3767 * Store the ioc_profile for supplying cfgadm info
3768 * ibdm maintains no info of disconnected IOC
3770 * For reconnected IOC :
3771 * ibdm has info of previous service entries
3772 * ioc_profile maintained by ibnexus is used to
3773 * update ib_srv_prop_updated.
3774 * Free the ibnex maintained ioc_profile
3776 if (ioc_info->ioc_nportgids == 0) {
3777 IBTF_DPRINTF_L4("ibnex",
3778 "\tupdate_prop: IOC disconnected");
3779 ioc->ioc_profile = (ib_dm_ioc_ctrl_profile_t *)kmem_zalloc(
3780 sizeof (ib_dm_ioc_ctrl_profile_t), KM_SLEEP);
3781 bcopy(&ioc_info->ioc_profile, ioc->ioc_profile,
3782 sizeof (ib_dm_ioc_ctrl_profile_t));
3784 ibnex.ibnex_num_disconnect_iocs++;
3785 } else if (ioc_info->ioc_nportgids != 0 && ioc->ioc_ngids == 0 &&
3786 ioc->ioc_profile != NULL) {
3787 IBTF_DPRINTF_L4("ibnex",
3788 "\tupdate_prop: IOC reconnected");
3789 if (ioc->ioc_profile->ioc_service_entries !=
3790 ioc_info->ioc_profile.ioc_service_entries)
3791 evt_data.ib_srv_prop_updated = 1;
3793 ibnex.ibnex_num_disconnect_iocs--;
3794 kmem_free(ioc->ioc_profile, sizeof (ib_dm_ioc_ctrl_profile_t));
3795 ioc->ioc_profile = NULL;
3798 /* Update the properties that have changed */
3799 mutex_exit(&ibnex.ibnex_mutex);
3800 if (evt_data.ib_gid_prop_updated) {
3801 if (ibnex_create_ioc_portgid_prop(dip, ioc_info) !=
3802 IBNEX_SUCCESS) {
3803 mutex_enter(&ibnex.ibnex_mutex);
3804 return;
3807 if (evt_data.ib_srv_prop_updated) {
3808 if (ioc_info->ioc_profile.ioc_service_entries != 0 &&
3809 (ibnex_create_ioc_srv_props(dip, ioc_info) !=
3810 IBNEX_SUCCESS)) {
3811 mutex_enter(&ibnex.ibnex_mutex);
3812 return;
3813 } else if (ioc_info->ioc_profile.ioc_service_entries == 0) {
3814 (void) ndi_prop_remove(DDI_DEV_T_NONE, dip,
3815 "service-id");
3816 (void) ndi_prop_remove(DDI_DEV_T_NONE, dip,
3817 "service-name");
3820 mutex_enter(&ibnex.ibnex_mutex);
3821 ioc->ioc_ngids = ioc_info->ioc_nportgids;
3824 * Post an event if :
3825 * 1. Properites have changed or NOTIFY_ALWAYS is set.
3826 * 2. child dip is configured and a valid cookie for
3827 * IB_PROP_UPDATE_EVENT.
3829 if ((evt_data.ib_prop_updated != 0 ||
3830 (node_data->node_reprobe_state &
3831 IBNEX_NODE_REPROBE_NOTIFY_ALWAYS)) &&
3832 ((node_data->node_state == IBNEX_CFGADM_CONFIGURED) &&
3833 (evt_cookie != NULL))) {
3834 mutex_exit(&ibnex.ibnex_mutex);
3836 if (ndi_post_event(ibnex.ibnex_dip, dip,
3837 evt_cookie, &evt_data) != NDI_SUCCESS)
3838 IBTF_DPRINTF_L2("ibnex",
3839 "\tndi_post_event failed\n");
3841 mutex_enter(&ibnex.ibnex_mutex);
3845 * Cleanup node_reprobe_state, for ibt_reprobe_dev
3846 * requests, when reprobe all / node reprobe is in
3847 * progress. ibnex_reprobe_ioc_dev is not called
3848 * in this case.
3850 if (node_data->node_reprobe_state ==
3851 IBNEX_NODE_REPROBE_NOTIFY_ALWAYS)
3852 ibnex_wakeup_reprobe_ioc(node_data, 0);
3855 static ibnex_rval_t
3856 ibnex_unique_svcname(char *svcname)
3858 int i;
3860 /* Check Port Services */
3861 for (i = 0; i < ibnex.ibnex_num_comm_svcs; i++)
3862 if (ibnex.ibnex_comm_svc_names[i] && strncmp(svcname,
3863 ibnex.ibnex_comm_svc_names[i], 4) == 0)
3864 return (IBNEX_FAILURE);
3866 /* Check VPPA Services */
3867 for (i = 0; i < ibnex.ibnex_nvppa_comm_svcs; i++)
3868 if (ibnex.ibnex_vppa_comm_svc_names[i] && strncmp(svcname,
3869 ibnex.ibnex_vppa_comm_svc_names[i], 4) == 0)
3870 return (IBNEX_FAILURE);
3872 /* Check HCA_SVC Services */
3873 for (i = 0; i < ibnex.ibnex_nhcasvc_comm_svcs; i++)
3874 if (ibnex.ibnex_hcasvc_comm_svc_names[i] && strncmp(svcname,
3875 ibnex.ibnex_hcasvc_comm_svc_names[i], 4) == 0)
3876 return (IBNEX_FAILURE);
3878 return (IBNEX_SUCCESS);
3881 static void
3882 ibnex_handle_reprobe_dev(void *arg)
3884 dev_info_t *dip = (dev_info_t *)arg;
3885 ibnex_node_data_t *node_data;
3887 ASSERT(dip != NULL);
3888 node_data = ddi_get_parent_data(dip);
3889 ASSERT(node_data);
3892 * Return success if:
3893 * 1. Reprobe for all nodes are in progress
3894 * 2. Reprobe for this node is in progress.
3895 * The reprobe in progress will complete eventually and
3896 * update the properties, if required.
3898 mutex_enter(&ibnex.ibnex_mutex);
3899 if (ibnex.ibnex_reprobe_state != 0 ||
3900 node_data->node_reprobe_state != 0) {
3902 * Setting NOTIFY_ALWAYS to ensure that
3903 * DDI event is delivered always for
3904 * ibt_reprobe_dev
3906 node_data->node_reprobe_state |=
3907 IBNEX_NODE_REPROBE_NOTIFY_ALWAYS;
3908 mutex_exit(&ibnex.ibnex_mutex);
3909 return;
3911 node_data->node_reprobe_state =
3912 IBNEX_NODE_REPROBE_NOTIFY_ALWAYS;
3913 mutex_exit(&ibnex.ibnex_mutex);
3914 ibnex_reprobe_ioc_dev(arg);
3919 * MPxIO pathmangement routines. Currently IB nexus does not support
3920 * any kind of pathmangement. So, just return success to make MPxIO
3921 * framework happy.
3923 /*ARGSUSED*/
3924 static int
3925 ib_vhci_pi_init(dev_info_t *vdip, mdi_pathinfo_t *pip, int flag)
3927 IBTF_DPRINTF_L4("ibnex", "\tpi_init: dip %p pip %p", vdip, pip);
3928 return (MDI_SUCCESS);
3932 /*ARGSUSED*/
3933 static int
3934 ib_vhci_pi_uninit(dev_info_t *vdip, mdi_pathinfo_t *pip, int flag)
3936 dev_info_t *cdip;
3937 ibnex_node_data_t *node_data;
3938 int clnt_num_pi;
3939 IBTF_DPRINTF_L4("ibnex", "\tpi_uninit: dip %p pip %p", vdip, pip);
3941 if (pip == NULL)
3942 return (MDI_FAILURE);
3944 * Get the Client dev_info from the pathinfo.
3946 cdip = mdi_pi_get_client(pip);
3947 if (cdip == NULL)
3948 return (MDI_FAILURE);
3951 * How many PIs do we have from this cdip ?
3953 clnt_num_pi = mdi_client_get_path_count(cdip);
3956 * If this is the last PI that is being free'd ( called from
3957 * mdi_pi_free) we have to clean up the node data for the cdip since
3958 * the client would have been detached by mdi_devi_offline.
3960 if (clnt_num_pi == 1) {
3961 node_data = ddi_get_parent_data(cdip);
3962 if (node_data == NULL)
3963 return (MDI_SUCCESS);
3964 if (node_data->node_dip == cdip) {
3965 node_data->node_dip = NULL;
3966 node_data->node_state = IBNEX_CFGADM_UNCONFIGURED;
3967 return (MDI_SUCCESS);
3970 return (MDI_SUCCESS);
3974 /*ARGSUSED*/
3975 static int
3976 ib_vhci_pi_state_change(dev_info_t *vdip, mdi_pathinfo_t *pip,
3977 mdi_pathinfo_state_t state, uint32_t arg1, int arg2)
3979 IBTF_DPRINTF_L4("ibnex",
3980 "\tpi_state_change: dip %p pip %p state %x", vdip, pip, state);
3981 return (MDI_SUCCESS);
3985 /*ARGSUSED*/
3986 static int
3987 ib_vhci_failover(dev_info_t *dip1, dev_info_t *dip2, int arg)
3989 return (MDI_SUCCESS);
3993 static int
3994 ibnex_bus_power(dev_info_t *parent, void *impl_arg,
3995 pm_bus_power_op_t op, void *arg, void *result)
3998 int ret = DDI_SUCCESS;
4000 IBTF_DPRINTF_L4("ibnex", "\tbus_power: begin: op = %d", op);
4003 * Generic processing in MPxIO framework
4005 ret = mdi_bus_power(parent, impl_arg, op, arg, result);
4007 switch (ret) {
4008 case MDI_SUCCESS:
4009 ret = DDI_SUCCESS;
4010 break;
4011 case MDI_FAILURE:
4012 ret = DDI_FAILURE;
4013 break;
4014 default:
4015 break;
4018 return (ret);
4023 * If enumerated as a child of IB Nexus / VHCI, call mdi_vhci_bus_config.
4024 * ndi_devi_enter is not held during this call. mdi_vhci_bus_config()
4025 * will have called ndi_busop_bus_config(), no need for the caller to call
4026 * ndi_busop_bus_config() again.
4028 * If enumerated as a child of HCA device, this could be a case for
4029 * Sparc boot or device enumeration from PHCI, driven by MDI.
4030 * Hold parent lock (ndi_devi_enter). The caller will have to call
4031 * ndi_busop_bus_config() if this function returns SUCCESS.
4033 * if the device name contains ":port", then it is the Sparc boot case.
4034 * Handle this as before.
4036 * If the device name does *not* contain the ":port", then :
4037 * 1. ibdm to probe IOC
4038 * 2. Create a pathinfo only if the IOC is reachable from the parent dip.
4041 ibnex_ioc_bus_config_one(dev_info_t **pdipp, uint_t flag,
4042 ddi_bus_config_op_t op, void *devname, dev_info_t **child,
4043 int *need_bus_config)
4045 int ret = DDI_FAILURE, circ;
4046 dev_info_t *pdip = *pdipp;
4047 ib_guid_t iou_guid, ioc_guid;
4048 char *ioc_guid_str;
4051 *need_bus_config = 1;
4053 if (pdip == ibnex.ibnex_dip) {
4054 if (ibnex_devname_to_node_n_ioc_guids(
4055 (char *)devname, &iou_guid, &ioc_guid,
4056 &ioc_guid_str) != IBNEX_SUCCESS) {
4057 return (ret);
4059 ret = mdi_vhci_bus_config(pdip, flag, op, devname, child,
4060 ioc_guid_str);
4061 kmem_free(ioc_guid_str, strlen(ioc_guid_str) + 1);
4062 if (ret == MDI_SUCCESS)
4063 *need_bus_config = 0;
4064 } else {
4065 mdi_devi_enter(pdip, &circ);
4066 if (strstr((char *)devname, ":port=") != NULL) {
4067 ret = ibnex_config_root_iocnode(pdip, devname);
4068 ASSERT(ibnex.ibnex_dip == NULL);
4069 *pdipp = ibnex.ibnex_dip;
4070 } else {
4071 ret = ibnex_config_ioc_node(devname, pdip);
4073 mdi_devi_exit(pdip, circ);
4075 return (ret);
4078 static int
4079 ibnex_is_merge_node(dev_info_t *child)
4081 char *node;
4082 int ret = IBNEX_INVALID_NODE;
4084 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, child,
4085 DDI_PROP_DONTPASS, "ib-node-type", &node) !=
4086 DDI_PROP_SUCCESS) {
4087 return (IBNEX_FAILURE);
4090 if (node != NULL && *node != 0) {
4091 if (strcmp(node, "merge") == 0)
4092 ret = IBNEX_SUCCESS;
4093 else {
4094 IBTF_DPRINTF_L4("ibnex",
4095 "\tis_merge_node: ib-node-type = %s", node);
4099 ddi_prop_free(node);
4100 return (ret);
4104 * Checks if the dn_head for the driver has already
4105 * initialized by the prom tree.
4107 void
4108 ibnex_hw_in_dev_tree(char *driver_name)
4110 major_t major;
4112 IBTF_DPRINTF_L4("ibnex", "\thw_in_dev_tree(%s)", driver_name);
4114 if (devnamesp == NULL)
4115 return;
4117 major = ddi_name_to_major(driver_name);
4118 if (major == -1)
4119 return;
4121 if (devnamesp[major].dn_head != (dev_info_t *)NULL)
4122 ibnex_hw_status = IBNEX_HW_IN_DEVTREE;
4126 ibnex_ioc_initnode_all_pi(ibdm_ioc_info_t *ioc_info)
4128 ibdm_hca_list_t *hca_list;
4129 dev_info_t *hca_dip;
4130 int rc = IBNEX_FAILURE;
4132 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
4134 * We return failure even if we fail for all HCAs
4136 for (hca_list = ioc_info->ioc_hca_list; hca_list;
4137 hca_list = hca_list->hl_next) {
4138 hca_dip = ibtl_ibnex_hcaguid2dip(hca_list->hl_hca_guid);
4139 if (ibnex_ioc_config_from_pdip(ioc_info, hca_dip, 1) ==
4140 IBNEX_SUCCESS)
4141 rc = IBNEX_SUCCESS;
4143 return (rc);
4146 static int
4147 ibnex_ioc_config_from_pdip(ibdm_ioc_info_t *ioc_info, dev_info_t *pdip,
4148 int pdip_reachable_checked)
4150 ibnex_node_data_t *node_data;
4151 int create_pdip = 0;
4152 int rc = IBNEX_SUCCESS;
4155 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
4156 IBTF_DPRINTF_L4("ibnex",
4157 "/tioc_config_from_pdip(%p, %p, %d)", ioc_info, pdip,
4158 pdip_reachable_checked);
4160 if (pdip_reachable_checked == 0) {
4161 if (ibnex_ioc_pi_reachable(ioc_info, pdip) == IBNEX_FAILURE) {
4162 IBTF_DPRINTF_L4("ibnex",
4163 "/tioc_config_from_pdip: ioc %p not reachable"
4164 "from %p", ioc_info, pdip);
4165 return (IBNEX_FAILURE);
4169 node_data = ibnex_is_node_data_present(IBNEX_IOC_NODE,
4170 (void *)ioc_info, 0, 0);
4172 if (node_data && node_data->node_ap_state ==
4173 IBNEX_NODE_AP_UNCONFIGURED) {
4174 IBTF_DPRINTF_L4("ibnex",
4175 "\tioc_config_from_pdip: Unconfigured node");
4176 return (IBNEX_FAILURE);
4180 if (node_data == NULL) {
4181 ibnex_ioc_node_t *ioc;
4183 create_pdip = 1;
4185 node_data = ibnex_init_child_nodedata(IBNEX_IOC_NODE,
4186 ioc_info, 0, 0);
4187 ASSERT(node_data);
4188 ioc = &node_data->node_data.ioc_node;
4189 (void) snprintf(ioc->ioc_guid_str, IBNEX_IOC_GUID_LEN,
4190 "%llX",
4191 (longlong_t)ioc_info->ioc_profile.ioc_guid);
4192 (void) snprintf(ioc->ioc_phci_guid, IBNEX_PHCI_GUID_LEN,
4193 "%llX,%llX",
4194 (longlong_t)ioc_info->ioc_profile.ioc_guid,
4195 (longlong_t)ioc_info->ioc_iou_guid);
4196 } else if (ibnex_ioc_pi_exists(node_data, pdip) == IBNEX_FAILURE) {
4197 create_pdip = 1;
4200 if (create_pdip) {
4201 rc = ibnex_ioc_initnode_pdip(node_data, ioc_info, pdip);
4204 IBTF_DPRINTF_L4("ibnex", "\tioc_config_from_pdip ret %x",
4205 rc);
4206 return (rc);
4210 * This function checks if a pathinfo has already been created
4211 * for the HCA parent. The function returns SUCCESS if a pathinfo
4212 * has already been created, FAILURE if not.
4214 static int
4215 ibnex_ioc_pi_exists(ibnex_node_data_t *node_data, dev_info_t *parent)
4217 int rc;
4218 ibnex_ioc_node_t *ioc;
4220 ioc = &node_data->node_data.ioc_node;
4221 if (mdi_pi_find(parent, (char *)ioc->ioc_guid_str,
4222 (char *)ioc->ioc_phci_guid) != NULL)
4223 rc = IBNEX_SUCCESS;
4224 else
4225 rc = IBNEX_FAILURE;
4227 IBTF_DPRINTF_L4("ibnex", "\tioc_pi_created- client_guid %s, "
4228 "phci_guid %s, parent %p, rc %x",
4229 ioc->ioc_guid_str, ioc->ioc_phci_guid, parent, rc);
4230 return (rc);
4233 static int
4234 ibnex_ioc_pi_reachable(ibdm_ioc_info_t *ioc_info, dev_info_t *pdip)
4236 ibdm_hca_list_t *hca_list;
4237 dev_info_t *hca_dip;
4239 IBTF_DPRINTF_L4("ibnex", "\tioc_pi_reachable(%p, %p)",
4240 ioc_info, pdip);
4241 for (hca_list = ioc_info->ioc_hca_list; hca_list;
4242 hca_list = hca_list->hl_next) {
4243 hca_dip = ibtl_ibnex_hcaguid2dip(hca_list->hl_hca_guid);
4244 if (hca_dip == pdip) {
4245 IBTF_DPRINTF_L4("ibnex",
4246 "\tioc_pi_reachable FAILURE");
4247 return (IBNEX_SUCCESS);
4251 IBTF_DPRINTF_L4("ibnex", "\tioc_pi_reachable FAILURE");
4252 return (IBNEX_FAILURE);