1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25 /*
26 * The InfiniBand Nexus driver (IB nexus) is a bus nexus driver for IB bus.
27 * It supports Port nodes, Virtual Physical Point of Attachment nodes (VPPA)
28 * for HCAs registered with IBTL and IOC nodes for all the IOCs present in
29 * the IB fabric (that are accessible to the host). It also supports Pseudo
30 * device children to be enumerated using their .conf file(s). All Port nodes
31 * and VPPA nodes are children of HCA drivers. All the IOC nodes and the Pseudo
32 * device nodes are children of the IB nexus driver.
33 *
34 * IB nexus driver provides bus nexus entry points to all the HCA drivers.
35 *
36 * IB nexus driver registers with InfiniBand Device Manager (IBDM) to get
37 * information about all the HCA ports and I/O Controllers (IOCs) connected
38 * to the IB fabric. Based on that information, IB nexus will create all the
39 * device tree nodes.
40 */
41
42 #include <sys/conf.h>
43 #include <sys/stat.h>
44 #include <sys/modctl.h>
45 #include <sys/taskq.h>
46 #include <sys/mdi_impldefs.h>
47 #include <sys/sunmdi.h>
48 #include <sys/sunpm.h>
49 #include <sys/ib/mgt/ibdm/ibdm_impl.h>
50 #include <sys/ib/ibnex/ibnex.h>
51 #include <sys/ib/ibnex/ibnex_devctl.h>
52 #include <sys/ib/ibtl/ibti.h>
53 #include <sys/ib/ibtl/impl/ibtl_ibnex.h>
54 #include <sys/file.h>
55 #include <sys/hwconf.h>
56 #include <sys/fs/dv_node.h>
57
58 /* Function prototypes */
59 static int ibnex_attach(dev_info_t *, ddi_attach_cmd_t);
60 static int ibnex_getinfo(dev_info_t *, ddi_info_cmd_t,
61 void *, void **);
62 static int ibnex_detach(dev_info_t *, ddi_detach_cmd_t);
63 int ibnex_busctl(dev_info_t *,
64 dev_info_t *, ddi_ctl_enum_t, void *, void *);
65 int ibnex_map_fault(dev_info_t *,
66 dev_info_t *, struct hat *, struct seg *,
67 caddr_t, struct devpage *, pfn_t, uint_t, uint_t);
68 static int ibnex_init_child(dev_info_t *);
69 static ibnex_rval_t ibnex_comm_svc_init(char *, ibnex_node_type_t);
70 static void ibnex_comm_svc_fini();
71 dev_info_t *ibnex_commsvc_initnode(dev_info_t *,
72 ibdm_port_attr_t *, int, int, ib_pkey_t, int *,
73 int);
74 static void ibnex_delete_port_node_data(ibnex_node_data_t *);
75 int ibnex_get_dip_from_guid(ib_guid_t, int,
76 ib_pkey_t, dev_info_t **);
77 int ibnex_get_node_and_dip_from_guid(ib_guid_t, int,
78 ib_pkey_t, ibnex_node_data_t **, dev_info_t **);
79 static ibnex_node_data_t *ibnex_is_node_data_present(ibnex_node_type_t,
80 void *, int, ib_pkey_t);
81 static ibnex_node_data_t *ibnex_init_child_nodedata(ibnex_node_type_t, void *,
82 int, ib_pkey_t);
83 static int ibnex_create_port_node_prop(ibdm_port_attr_t *,
84 dev_info_t *, char *, ib_pkey_t);
85 void ibnex_dm_callback(void *, ibdm_events_t);
86 static int ibnex_create_port_compatible_prop(dev_info_t *,
87 char *, ibdm_port_attr_t *);
88 static int ibnex_create_ioc_srv_props(
89 dev_info_t *, ibdm_ioc_info_t *);
90 static int ibnex_get_eventcookie(dev_info_t *,
91 dev_info_t *, char *, ddi_eventcookie_t *);
92 static int ibnex_add_eventcall(dev_info_t *, dev_info_t *,
93 ddi_eventcookie_t, void (*)(dev_info_t *,
94 ddi_eventcookie_t, void *, void *),
95 void *arg, ddi_callback_id_t *cb_id);
96 static int ibnex_remove_eventcall(dev_info_t *,
97 ddi_callback_id_t);
98 static int ibnex_post_event(dev_info_t *, dev_info_t *,
99 ddi_eventcookie_t, void *);
100 static int ibnex_bus_config(dev_info_t *, uint_t,
101 ddi_bus_config_op_t, void *, dev_info_t **);
102 static int ibnex_bus_unconfig(dev_info_t *,
103 uint_t, ddi_bus_config_op_t, void *);
104 dev_info_t *ibnex_config_port_node(dev_info_t *, char *);
105 int ibnex_get_pkey_commsvc_index_portnum(
106 char *, int *, ib_pkey_t *, uint8_t *);
107 void ibnex_config_all_children(dev_info_t *);
108 static int ibnex_devname_to_portnum(char *, uint8_t *);
109 void ibnex_create_vppa_nodes(dev_info_t *, ibdm_port_attr_t *);
110 void ibnex_create_port_nodes(
111 dev_info_t *, ibdm_port_attr_t *);
112 void ibnex_create_hcasvc_nodes(
113 dev_info_t *, ibdm_port_attr_t *);
114 static int ibnex_config_root_iocnode(dev_info_t *, char *);
115 static int ibnex_devname2port(char *, int *);
116 static int ibnex_config_ioc_node(char *, dev_info_t *);
117 static int ibnex_devname_to_node_n_ioc_guids(
118 char *, ib_guid_t *, ib_guid_t *, char **);
119 static void ibnex_ioc_node_cleanup();
120 static void ibnex_delete_ioc_node_data(ibnex_node_data_t *);
121 int ibnex_ioc_initnode_all_pi(ibdm_ioc_info_t *);
122 static int ibnex_ioc_initnode_pdip(ibnex_node_data_t *,
123 ibdm_ioc_info_t *, dev_info_t *);
124 static int ibnex_create_ioc_node_prop(
125 ibdm_ioc_info_t *, dev_info_t *);
126 static int ibnex_create_ioc_compatible_prop(
127 dev_info_t *, ib_dm_ioc_ctrl_profile_t *);
128 uint64_t ibnex_str2hex(char *, int, int *);
129 int ibnex_str2int(char *, int, int *);
130 static int ibnex_create_ioc_portgid_prop(
131 dev_info_t *, ibdm_ioc_info_t *);
132 static void ibnex_wakeup_reprobe_ioc(ibnex_node_data_t *, int);
133 static void ibnex_wakeup_reprobe_all();
134 ibt_status_t ibnex_ibtl_callback(ibtl_ibnex_cb_args_t *);
135 void ibnex_pseudo_initnodes(void);
136 static char *ibnex_lookup_named_prop(ddi_prop_t *, char *);
137 static void ibnex_pseudo_node_cleanup(void);
138 static int ibnex_name_child(dev_info_t *, char *, int);
139 static int ibnex_name_pseudo_child(dev_info_t *, char *);
140
141 void ibnex_reprobe_ioc_dev(void *);
142 void ibnex_reprobe_ioc_all();
143 static void ibnex_update_prop(ibnex_node_data_t *,
144 ibdm_ioc_info_t *);
145 static ibnex_rval_t ibnex_unique_svcname(char *);
146 static void ibnex_handle_reprobe_dev(void *arg);
147
148 extern int ibnex_open(dev_t *, int, int, cred_t *);
149 extern int ibnex_close(dev_t, int, int, cred_t *);
150 extern int ibnex_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
151 extern int ibnex_offline_childdip(dev_info_t *);
152
153 static int ibnex_ioc_create_pi(
154 ibdm_ioc_info_t *, ibnex_node_data_t *,
155 dev_info_t *, int *);
156 static int ibnex_bus_power(dev_info_t *, void *,
157 pm_bus_power_op_t, void *, void *);
158 int ibnex_pseudo_create_all_pi(ibnex_node_data_t *);
159 static int ibnex_pseudo_create_pi_pdip(ibnex_node_data_t *,
160 dev_info_t *);
161 int ibnex_pseudo_config_one(
162 ibnex_node_data_t *, char *, dev_info_t *);
163 int ibnex_pseudo_mdi_config_one(int, void *, dev_info_t **,
164 char *, char *);
165 static void ibnex_config_pseudo_all(dev_info_t *);
166 int ibnex_ioc_bus_config_one(dev_info_t **, uint_t,
167 ddi_bus_config_op_t, void *, dev_info_t **, int *);
168 static int ibnex_is_merge_node(dev_info_t *);
169 static void ibnex_hw_in_dev_tree(char *);
170 static int ibnex_ioc_config_from_pdip(ibdm_ioc_info_t *,
171 dev_info_t *, int);
172 static int ibnex_ioc_pi_exists(ibnex_node_data_t *, dev_info_t *);
173 static int ibnex_ioc_pi_reachable(ibdm_ioc_info_t *,
174 dev_info_t *);
175
176 extern void ibnex_handle_hca_attach(void *);
177
178 extern struct bus_ops ibnex_ci_busops;
179 /*
180 * Prototype declarations for the VHCI options
181 */
182 /*
183 * Functions registered with the mpxio framework
184 */
185 static int ib_vhci_pi_init(dev_info_t *, mdi_pathinfo_t *, int);
186 static int ib_vhci_pi_uninit(dev_info_t *, mdi_pathinfo_t *, int);
187 static int ib_vhci_pi_state_change(dev_info_t *, mdi_pathinfo_t *,
188 mdi_pathinfo_state_t, uint32_t, int);
189 static int ib_vhci_failover(dev_info_t *, dev_info_t *, int);
190
191
192 static mdi_vhci_ops_t ibnex_vhci_ops = {
193 MDI_VHCI_OPS_REV,
194 ib_vhci_pi_init,
195 ib_vhci_pi_uninit,
196 ib_vhci_pi_state_change,
197 ib_vhci_failover
198 };
199
200
201 /*
202 * The bus_ops structure defines the capabilities of IB nexus driver.
203 * IB nexus drivers does not support any DMA operations for its children
204 * as there is no such concept in Infiniband. All the memory operations
205 * and DMA operations required by the child drivers can be performed using
206 * the IBTF API.
207 */
208 struct bus_ops ibnex_bus_ops = {
209 BUSO_REV,
210 nullbusmap, /* bus_map */
211 NULL, /* bus_get_intrspec */
212 NULL, /* bus_add_intrspec */
213 NULL, /* bus_remove_intrspec */
214 ibnex_map_fault, /* Map Fault */
215 ddi_no_dma_map, /* DMA related entry points */
216 ddi_no_dma_allochdl,
217 NULL,
218 NULL,
219 NULL,
220 NULL,
221 NULL,
222 NULL,
223 ibnex_busctl, /* bus_ctl */
224 ddi_bus_prop_op, /* bus_prop_op */
225 ibnex_get_eventcookie, /* bus_get_eventcookie */
226 ibnex_add_eventcall, /* bus_add_eventcall */
227 ibnex_remove_eventcall, /* bus_remove_eventcall */
228 ibnex_post_event, /* bus_post_event */
229 NULL,
230 ibnex_bus_config, /* bus config */
231 ibnex_bus_unconfig, /* bus unconfig */
232 NULL, /* bus fm init */
233 NULL, /* bus fm fini */
234 NULL, /* bus fm access enter */
235 NULL, /* bus fm access exit */
236 ibnex_bus_power /* bus power */
237 };
238
239 /* ibnex cb_ops */
240 static struct cb_ops ibnex_cbops = {
241 ibnex_open, /* open */
242 ibnex_close, /* close */
243 nodev, /* strategy */
244 nodev, /* print */
245 nodev, /* dump */
246 nodev, /* read */
247 nodev, /* write */
248 ibnex_ioctl, /* ioctl */
249 nodev, /* devmap */
250 nodev, /* mmap */
251 nodev, /* segmap */
252 nochpoll, /* poll */
253 ddi_prop_op, /* prop_op */
254 NULL, /* stream */
255 D_MP, /* cb_flag */
256 CB_REV, /* rev */
257 nodev, /* int (*cb_aread)() */
258 nodev /* int (*cb_awrite)() */
259 };
260
261 /*
262 * Device options
263 * Note: ddi_no_info needs to change during devfs time frame. The drivers
264 * with 1 to 1 mapping between minor node and instance should use
265 * ddi_1to1_info. (See bug id 4424752)
266 */
267 static struct dev_ops ibnex_ops = {
268 DEVO_REV, /* devo_rev, */
269 0, /* refcnt */
270 ibnex_getinfo, /* info */
271 nulldev, /* identify */
272 nulldev, /* probe */
273 ibnex_attach, /* attach */
274 ibnex_detach, /* detach */
275 nodev, /* reset */
276 &ibnex_cbops, /* driver ops - devctl interfaces */
277 &ibnex_bus_ops, /* bus operations */
278 nulldev, /* power */
279 ddi_quiesce_not_needed, /* quiesce */
280 };
281
282 /* Module linkage information for the kernel. */
283 static struct modldrv modldrv = {
284 &mod_driverops, /* Driver module */
285 "IB nexus", /* Driver name and version */
286 &ibnex_ops, /* driver ops */
287 };
288
289 static struct modlinkage modlinkage = {
290 MODREV_1, (void *)&modldrv, NULL
291 };
292
293 /*
294 * Global per-instance IB Nexus data.
295 * There is only one instance of IB Nexus supported.
296 */
297 ibnex_t ibnex;
298
299 /* The port settling time in seconds */
300 int ibnex_port_settling_time = 8;
301
302 /* create an array of properties supported, easier to add new ones here */
303 static struct ibnex_property {
304 char *name;
305 ibnex_node_type_t type;
306 } ibnex_properties[] = {
307 { "port-svc-list", IBNEX_PORT_COMMSVC_NODE},
308 { "vppa-svc-list", IBNEX_VPPA_COMMSVC_NODE},
309 { "hca-svc-list", IBNEX_HCASVC_COMMSVC_NODE}
310 };
311
312 #define N_IBNEX_PROPS (sizeof (ibnex_properties))/ \
313 (sizeof (struct ibnex_property))
314
315 /*
316 * Event Definition
317 * Single event, event name defined in ibti_common.h.
318 * Event posted to specific child handler. Event posted
319 * at kernel priority.
320 */
321 static ndi_event_definition_t ibnex_ndi_event_defs[] = {
322 {IB_EVENT_TAG_PROP_UPDATE, IB_PROP_UPDATE_EVENT, EPL_KERNEL,
323 NDI_EVENT_POST_TO_TGT}
324 };
325
326 #define IB_N_NDI_EVENTS \
327 (sizeof (ibnex_ndi_event_defs) / sizeof (ndi_event_definition_t))
328
329 static ndi_event_set_t ib_ndi_events = {
330 NDI_EVENTS_REV1, IB_N_NDI_EVENTS, ibnex_ndi_event_defs};
331 static int ibnex_hw_status = IBNEX_DEVTREE_NOT_CHECKED;
332
333
334 /*
335 * _init
336 * Loadable module init, called before any other module.
337 */
338 int
339 _init(void)
340 {
341 int error;
342 char **hca_driver_list;
343 int i, ndrivers;
344
345 if (ibnex_hw_status == IBNEX_DEVTREE_NOT_CHECKED) {
346 ibnex_hw_status = IBNEX_HW_NOT_IN_DEVTREE;
347 hca_driver_list = mdi_get_phci_driver_list("ib", &ndrivers);
348 for (i = 0; i < ndrivers; i++) {
349 ibnex_hw_in_dev_tree(hca_driver_list[i]);
350 if (ibnex_hw_status == IBNEX_HW_IN_DEVTREE)
351 break;
352 }
353 mdi_free_phci_driver_list(hca_driver_list, ndrivers);
354 }
355
356 /*
357 * IB Nexus _init can be called while force attaching
358 * IB Nexus driver or when a HCA is hotplugged.
359 *
360 * If IB HW is not in device tree or if no HCA driver
361 * has been attached, fail IB Nexus _init().
362 */
363 if (ibnex_hw_status == IBNEX_HW_NOT_IN_DEVTREE &&
364 ibt_hw_is_present() == 0) {
365 IBTF_DPRINTF_L4("ibnex", "\t_init: NO IB HW");
366 return (DDI_FAILURE);
367 }
368
369 IBTF_DPRINTF_L4("ibnex", "\t_init");
370 mutex_init(&ibnex.ibnex_mutex, NULL, MUTEX_DRIVER, NULL);
371 cv_init(&ibnex.ibnex_reprobe_cv, NULL, CV_DRIVER, NULL);
372 cv_init(&ibnex.ibnex_ioc_list_cv, NULL, CV_DRIVER, NULL);
373 if ((error = mod_install(&modlinkage)) != 0) {
374 IBTF_DPRINTF_L2("ibnex", "\t_init: mod_install failed");
375 mutex_destroy(&ibnex.ibnex_mutex);
376 cv_destroy(&ibnex.ibnex_reprobe_cv);
377 cv_destroy(&ibnex.ibnex_ioc_list_cv);
378 } else {
379 ibdm_ibnex_register_callback(ibnex_dm_callback);
380 ibtl_ibnex_register_callback(ibnex_ibtl_callback);
381 }
382 return (error);
383 }
384
385
386 /*
387 * _fini
388 * Prepares a module for unloading.
389 */
390 int
391 _fini(void)
392 {
393 int error;
394
395 IBTF_DPRINTF_L4("ibnex", "\t_fini");
396 if ((error = mod_remove(&modlinkage)) != 0) {
397 return (error);
398 }
399 ibdm_ibnex_unregister_callback();
400 ibtl_ibnex_unregister_callback();
401 mutex_destroy(&ibnex.ibnex_mutex);
402 cv_destroy(&ibnex.ibnex_reprobe_cv);
403 cv_destroy(&ibnex.ibnex_ioc_list_cv);
404 return (0);
405 }
406
407
408 /*
409 * _info
410 * Returns information about loadable module.
411 */
412 int
413 _info(struct modinfo *modinfop)
414 {
415 IBTF_DPRINTF_L4("ibnex", "\t_info");
416 return (mod_info(&modlinkage, modinfop));
417 }
418
419
420 /*
421 * ibnex_attach
422 * Configure and attach an instance of the IB Nexus driver
423 * Only one instance of IB Nexus is supported
424 * Create a minor node for cfgadm purpose
425 * Initialize communication services
426 * Register callback with IBDM
427 * Register callback with IBTL
428 */
429 static int
430 ibnex_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
431 {
432 int i;
433 int instance = ddi_get_instance(dip);
434
435 IBTF_DPRINTF_L4("ibnex", "\tattach: device = %p cmd = %x)", dip, cmd);
436
437 switch (cmd) {
438 case DDI_ATTACH:
439 break;
440 case DDI_RESUME:
441 IBTF_DPRINTF_L4("ibnex", "\tattach: RESUME");
442 return (DDI_SUCCESS);
443 default:
444 return (DDI_FAILURE);
445 }
446
447 /* Fail attach for more than one instance */
448 mutex_enter(&ibnex.ibnex_mutex);
449 if (ibnex.ibnex_dip != NULL) {
450 mutex_exit(&ibnex.ibnex_mutex);
451 return (DDI_FAILURE);
452 }
453 mutex_exit(&ibnex.ibnex_mutex);
454
455 /*
456 * Create a IB nexus taskq
457 */
458
459 ibnex.ibnex_taskq_id = ddi_taskq_create(dip,
460 "ibnex-enum-taskq", 1, TASKQ_DEFAULTPRI, 0);
461 if (ibnex.ibnex_taskq_id == NULL) {
462 IBTF_DPRINTF_L2("ibnex",
463 "\tattach: ddi_taskq_create() failed");
464 return (DDI_FAILURE);
465
466 }
467
468 /* Register with MPxIO framework */
469
470 if (mdi_vhci_register(MDI_HCI_CLASS_IB, dip, &ibnex_vhci_ops, 0)
471 != MDI_SUCCESS) {
472 IBTF_DPRINTF_L2("ibnex",
473 "\tattach: mdi_vhci_register() failed");
474 (void) ddi_taskq_destroy(ibnex.ibnex_taskq_id);
475 ibnex.ibnex_taskq_id = NULL;
476 return (DDI_FAILURE);
477 }
478
479
480 /*
481 * Create the "fabric" devctl minor-node for IB DR support.
482 * The minor number for the "devctl" node is in the same format
483 * as the AP minor nodes.
484 */
485 if (ddi_create_minor_node(dip, IBNEX_FABRIC, S_IFCHR, instance,
486 DDI_NT_IB_ATTACHMENT_POINT, 0) != DDI_SUCCESS) {
487 IBTF_DPRINTF_L2("ibnex",
488 "\tattach: failed to create fabric minornode");
489 (void) ddi_taskq_destroy(ibnex.ibnex_taskq_id);
490 ibnex.ibnex_taskq_id = NULL;
491 (void) mdi_vhci_unregister(dip, 0);
492 return (DDI_FAILURE);
493 }
494
495 /*
496 * Create "devctl" minor node for general ioctl interface to the
497 * ib nexus.
498 */
499 if (ddi_create_minor_node(dip, "devctl", S_IFCHR, instance,
500 DDI_NT_IB_NEXUS, 0) != DDI_SUCCESS) {
501 IBTF_DPRINTF_L2("ibnex",
502 "\tattach: failed to create devctl minornode");
503 (void) ddi_remove_minor_node(dip, NULL);
504 (void) ddi_taskq_destroy(ibnex.ibnex_taskq_id);
505 ibnex.ibnex_taskq_id = NULL;
506 (void) mdi_vhci_unregister(dip, 0);
507 return (DDI_FAILURE);
508 }
509
510 /*
511 * Set pm-want-child-notification property for
512 * power management of the phci and client
513 */
514 if (ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
515 "pm-want-child-notification?", NULL, NULL) != DDI_PROP_SUCCESS) {
516 IBTF_DPRINTF_L2("ibnex",
517 "_attach: create pm-want-child-notification failed");
518 (void) ddi_remove_minor_node(dip, NULL);
519 (void) ddi_taskq_destroy(ibnex.ibnex_taskq_id);
520 ibnex.ibnex_taskq_id = NULL;
521 (void) mdi_vhci_unregister(dip, 0);
522 return (DDI_FAILURE);
523 }
524
525 mutex_enter(&ibnex.ibnex_mutex);
526 ibnex.ibnex_dip = dip;
527 mutex_exit(&ibnex.ibnex_mutex);
528
529 /*
530 * Event Handling: Definition and Binding.
531 */
532 if (ndi_event_alloc_hdl(dip, 0, &ibnex.ibnex_ndi_event_hdl,
533 NDI_SLEEP) != NDI_SUCCESS) {
534 IBTF_DPRINTF_L2("ibnex",
535 "_attach: ndi_event_alloc_hdl failed");
536 (void) ddi_remove_minor_node(dip, NULL);
537 (void) ddi_taskq_destroy(ibnex.ibnex_taskq_id);
538 ibnex.ibnex_taskq_id = NULL;
539 (void) mdi_vhci_unregister(dip, 0);
540 return (DDI_FAILURE);
541 }
542 if (ndi_event_bind_set(ibnex.ibnex_ndi_event_hdl, &ib_ndi_events,
543 NDI_SLEEP) != NDI_SUCCESS) {
544 (void) ddi_remove_minor_node(dip, NULL);
545 (void) ndi_event_free_hdl(ibnex.ibnex_ndi_event_hdl);
546 IBTF_DPRINTF_L2("ibnex",
547 "_attach: ndi_event_bind_set failed");
548 (void) ddi_taskq_destroy(ibnex.ibnex_taskq_id);
549 ibnex.ibnex_taskq_id = NULL;
550 (void) mdi_vhci_unregister(dip, 0);
551 return (DDI_FAILURE);
552 }
553
554 for (i = 0; i < N_IBNEX_PROPS; i++) {
555 if (ibnex_comm_svc_init(ibnex_properties[i].name,
556 ibnex_properties[i].type) != IBNEX_SUCCESS) {
557 ibnex_comm_svc_fini();
558 (void) ndi_event_unbind_set(ibnex.ibnex_ndi_event_hdl,
559 &ib_ndi_events, NDI_SLEEP);
560 (void) ddi_remove_minor_node(dip, NULL);
561 (void) ndi_event_free_hdl(
562 ibnex.ibnex_ndi_event_hdl);
563 ibnex.ibnex_ndi_event_hdl = NULL;
564 IBTF_DPRINTF_L2("ibnex", "_attach: ibnex_comm_svc_init"
565 " failed %s", ibnex_properties[i].name);
566 (void) ddi_taskq_destroy(ibnex.ibnex_taskq_id);
567 ibnex.ibnex_taskq_id = NULL;
568 (void) mdi_vhci_unregister(dip, 0);
569 return (DDI_FAILURE);
570 }
571 }
572
573 /*
574 * before anything else comes up:
575 * Initialize the internal list of pseudo device nodes by
576 * getting all pseudo children of "ib" and processing them.
577 */
578 ibnex_pseudo_initnodes();
579
580 return (DDI_SUCCESS);
581 }
582
583
584 /*
585 * ibnex_getinfo()
586 * Given the device number, return the devinfo pointer or the
587 * instance number.
588 * Note: always succeed DDI_INFO_DEVT2INSTANCE, even before attach.
589 */
590
591 /*ARGSUSED*/
592 static int
593 ibnex_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
594 {
595 int ret = DDI_SUCCESS;
596
597 IBTF_DPRINTF_L4("ibnex", "\tgetinfo: Begin");
598 switch (cmd) {
599 case DDI_INFO_DEVT2DEVINFO:
600 if (ibnex.ibnex_dip != NULL)
601 *result = ibnex.ibnex_dip;
602 else {
603 *result = NULL;
604 ret = DDI_FAILURE;
605 }
606 break;
607
608 case DDI_INFO_DEVT2INSTANCE:
609 *result = 0;
610 break;
611
612 default:
613 ret = DDI_FAILURE;
614 }
615 return (ret);
616 }
617
618
619 /*
620 * ibnex_detach
621 * Unregister callback with the IBDM
622 * Unregister callback with the IBTL
623 * Uninitialize the communication entries
624 * Remove all the minor nodes created by this instance
625 */
626 static int
627 ibnex_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
628 {
629
630 IBTF_DPRINTF_L4("ibnex", "\tdetach: dip = %p cmd = %x)", dip, cmd);
631
632 switch (cmd) {
633
634 case DDI_DETACH:
635 break;
636 case DDI_SUSPEND:
637 IBTF_DPRINTF_L4("ibnex", "\t_detach: Suspend");
638 return (DDI_SUCCESS);
639 default:
640 return (DDI_FAILURE);
641 }
642
643 mutex_enter(&ibnex.ibnex_mutex);
644 if (ibt_hw_is_present()) {
645 IBTF_DPRINTF_L2("ibnex",
646 "\tdetach: IB HW is present ");
647 mutex_exit(&ibnex.ibnex_mutex);
648 return (DDI_FAILURE);
649 }
650 if (ndi_event_free_hdl(ibnex.ibnex_ndi_event_hdl)) {
651 IBTF_DPRINTF_L2("ibnex",
652 "\tdetach: ndi_event_free_hdl() failed");
653 mutex_exit(&ibnex.ibnex_mutex);
654 return (DDI_FAILURE);
655 }
656 ibnex.ibnex_ndi_event_hdl = NULL;
657 ibnex.ibnex_prop_update_evt_cookie = NULL;
658
659 ibnex_pseudo_node_cleanup();
660 ibnex_comm_svc_fini();
661 ibnex_ioc_node_cleanup();
662
663 (void) ddi_remove_minor_node(dip, NULL);
664 ibnex.ibnex_dip = NULL;
665 mutex_exit(&ibnex.ibnex_mutex);
666 (void) mdi_vhci_unregister(dip, 0);
667
668 if (ibnex.ibnex_taskq_id != NULL) {
669 ddi_taskq_destroy(ibnex.ibnex_taskq_id);
670 ibnex.ibnex_taskq_id = NULL;
671 }
672
673 return (DDI_SUCCESS);
674 }
675
676
677 /*
678 * ibnex_pseudo_node_cleanup()
679 * This checks if all the "dips" have been deallocated (implying
680 * that all the children have been unconfigured) first.
681 * If not, it just returns.
682 * If yes, then it frees up memory allocated for devi_name,
683 * node_addr, and property list.
684 */
685 static void
686 ibnex_pseudo_node_cleanup(void)
687 {
688 ibnex_node_data_t *nodep = ibnex.ibnex_pseudo_node_head;
689 ibnex_pseudo_node_t *pseudo;
690
691 IBTF_DPRINTF_L4("ibnex", "\tpseudo_node_cleanup:");
692 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
693
694 for (; nodep; nodep = nodep->node_next)
695 if (nodep->node_dip)
696 return;
697
698 IBTF_DPRINTF_L4("ibnex", "\tpseudo_node_cleanup: freeing up memory");
699 for (nodep = ibnex.ibnex_pseudo_node_head; nodep;
700 nodep = nodep->node_next) {
701
702 pseudo = &nodep->node_data.pseudo_node;
703 if (pseudo->pseudo_node_addr) {
704 kmem_free(pseudo->pseudo_node_addr,
705 strlen(pseudo-> pseudo_node_addr) + 1);
706 pseudo->pseudo_node_addr = NULL;
707 }
708
709 if (pseudo->pseudo_devi_name) {
710 kmem_free(pseudo->pseudo_devi_name,
711 strlen(pseudo-> pseudo_devi_name) + 1);
712 pseudo->pseudo_devi_name = NULL;
713 }
714
715 if (pseudo->pseudo_unit_addr) {
716 kmem_free(pseudo->pseudo_unit_addr,
717 pseudo->pseudo_unit_addr_len);
718 }
719 }
720 }
721
722
723 /*
724 * This functions wakes up any reprobe requests waiting for completion
725 * of reprobe of this IOC. It also send an NDI event, if :
726 *
727 * notify_flag is set. This is set if :
728 * ibt_reprobe_ioc has returned with SUCCESS
729 * IBTF client has not been notified for this node.
730 * node_data->node_dip != NULL
731 * node_state has IBNEX_NODE_REPROBE_NOTIFY_ALWAYS set
732 * An NDI event cookie has been registered.
733 */
734 static void
735 ibnex_wakeup_reprobe_ioc(ibnex_node_data_t *node_data, int notify_flag)
736 {
737 ddi_eventcookie_t evt_cookie;
738
739 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
740 evt_cookie = ibnex.ibnex_prop_update_evt_cookie;
741
742 if ((ibnex.ibnex_reprobe_state == IBNEX_REPROBE_IOC_WAIT) ||
743 (node_data->node_reprobe_state != 0)) {
744 if (notify_flag && (node_data->node_dip != NULL) &&
745 (node_data->node_state &
746 IBNEX_NODE_REPROBE_NOTIFY_ALWAYS) &&
747 (evt_cookie != NULL)) {
748 ibt_prop_update_payload_t evt_data;
749
750 mutex_exit(&ibnex.ibnex_mutex);
751
752 bzero(&evt_data, sizeof (evt_data));
753 if (ndi_post_event(ibnex.ibnex_dip,
754 node_data->node_dip,
755 evt_cookie, &evt_data) != NDI_SUCCESS)
756 IBTF_DPRINTF_L2("ibnex",
757 "\tndi_post_event failed\n");
758
759 mutex_enter(&ibnex.ibnex_mutex);
760 }
761
762 node_data->node_reprobe_state = 0;
763 cv_broadcast(&ibnex.ibnex_reprobe_cv);
764 }
765 node_data->node_reprobe_state = 0;
766 }
767
768 /*
769 * This function wakes up any reprobe request waiting for completion
770 * of reprobe of all IOCs.
771 */
772 static void
773 ibnex_wakeup_reprobe_all()
774 {
775 ibnex_node_data_t *ioc_node;
776
777 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
778
779 /* Notify if another reprobe_all is pending */
780 if (ibnex.ibnex_reprobe_state == IBNEX_REPROBE_ALL_WAIT) {
781 ibnex.ibnex_reprobe_state = 0;
782 cv_broadcast(&ibnex.ibnex_reprobe_cv);
783 }
784 ibnex.ibnex_reprobe_state = 0;
785
786 /*
787 * The IOC may be hot-removed after the reprobe request.
788 * Reset the reprobe states for such IOCs.
789 */
790 for (ioc_node = ibnex.ibnex_ioc_node_head; ioc_node;
791 ioc_node = ioc_node->node_next) {
792 if (ioc_node->node_reprobe_state != 0) {
793 ibnex_wakeup_reprobe_ioc(ioc_node, 1);
794 }
795 }
796 }
797
798 /*
799 * ibnex_ibnex_callback:
800 * IBTL_IBNEX_IBC_INIT:
801 * Called from ibc_init() which is called from
802 * HCA driver _init entry point
803 * Initializes the HCA dev_ops structure with default
804 * IB nexus structure.
805 * IBTL_IBNEX_IBC_FINI:
806 * Called from ibc_fini() which is called from
807 * HCA driver _fini entry point
808 * Un-Initializes the HCA dev_ops structure with default
809 * IB nexus strucuture.
810 * Returns IBT_SUCCESS
811 */
812 ibt_status_t
813 ibnex_ibtl_callback(ibtl_ibnex_cb_args_t *cb_args)
814 {
815 int retval = IBT_SUCCESS;
816 struct dev_ops *hca_dev_ops;
817 dev_info_t *clnt_dip;
818 ibnex_node_data_t *node_data;
819
820 IBTF_DPRINTF_L5("ibnex", "\tibtl_callback");
821
822 switch (cb_args->cb_flag) {
823 case IBTL_IBNEX_IBC_INIT:
824 /*
825 * Get the devops structure of the HCA,
826 * and put IB nexus default busops vector in its place.
827 */
828 hca_dev_ops = ((struct modldrv *)
829 (cb_args->cb_modlp->ml_linkage[0]))->drv_dev_ops;
830 ASSERT((hca_dev_ops) && (hca_dev_ops->devo_bus_ops == NULL));
831 hca_dev_ops->devo_bus_ops = &ibnex_ci_busops;
832 break;
833
834 case IBTL_IBNEX_IBC_FINI:
835 hca_dev_ops = ((struct modldrv *)
836 (cb_args->cb_modlp->ml_linkage[0]))->drv_dev_ops;
837 hca_dev_ops->devo_bus_ops = NULL;
838 break;
839
840 case IBTL_IBNEX_REPROBE_DEV_REQ:
841 /* IBTL pass down request for ibt_reprobe_dev */
842 clnt_dip = cb_args->cb_dip;
843 ASSERT(clnt_dip);
844
845 node_data = ddi_get_parent_data(clnt_dip);
846 ASSERT(node_data);
847
848 /* Reprobe for IOC nodes only */
849 ASSERT(node_data->node_type == IBNEX_IOC_NODE);
850
851 /*
852 * Start the reprobe. This could sleep as it is not
853 * from interrupt context.
854 */
855 if (taskq_dispatch(system_taskq, ibnex_handle_reprobe_dev,
856 clnt_dip, TQ_SLEEP) == 0) {
857 IBTF_DPRINTF_L2("ibnex",
858 "ibnex_ibtl_callback: taskq_dispatch failed");
859 mutex_enter(&ibnex.ibnex_mutex);
860 ibnex_wakeup_reprobe_ioc(node_data, 0);
861 mutex_exit(&ibnex.ibnex_mutex);
862 return (IBT_INSUFF_KERNEL_RESOURCE);
863 }
864 return (IBT_SUCCESS);
865 }
866
867 return (retval);
868 }
869
870
871 /*
872 * Bus-ops entry points
873 */
874
875 /*
876 * ibnex_map_fault
877 * IOC drivers need not map memory. Return failure to fail any
878 * such calls.
879 */
880 /*ARGSUSED*/
881 int
882 ibnex_map_fault(dev_info_t *dip, dev_info_t *rdip, struct hat *hat,
883 struct seg *seg, caddr_t addr, struct devpage *dp, pfn_t pfn,
884 uint_t prot, uint_t lock)
885 {
886 return (DDI_FAILURE);
887 }
888
889
890 /*
891 * ibnex_busctl
892 * bus_ctl bus_ops entry point
893 */
894 /*ARGSUSED*/
895 int
896 ibnex_busctl(dev_info_t *dip, dev_info_t *rdip,
897 ddi_ctl_enum_t ctlop, void *arg, void *result)
898 {
899 dev_info_t *child_dip;
900
901 IBTF_DPRINTF_L4("ibnex",
902 "\tbusctl: dip = %p, rdip = %p, ctlop = %x,", dip, rdip, ctlop);
903 IBTF_DPRINTF_L4("ibnex", "\tbusctl: targ = %p, result %p", arg, result);
904
905 switch (ctlop) {
906 case DDI_CTLOPS_REPORTDEV:
907 if (rdip == NULL) {
908 return (DDI_FAILURE);
909 }
910
911 /* Log the relevant details of dip to sysbuf */
912 cmn_err(CE_CONT, "?IB device: %s@%s, %s%d\n",
913 ddi_node_name(rdip), ddi_get_name_addr(rdip),
914 ddi_driver_name(rdip), ddi_get_instance(rdip));
915
916 return (DDI_SUCCESS);
917
918 case DDI_CTLOPS_INITCHILD:
919 child_dip = (dev_info_t *)arg;
920 return (ibnex_init_child(child_dip));
921
922 case DDI_CTLOPS_UNINITCHILD:
923 child_dip = (dev_info_t *)arg;
924 ddi_set_name_addr(child_dip, NULL);
925 return (DDI_SUCCESS);
926
927 case DDI_CTLOPS_ATTACH:
928 case DDI_CTLOPS_DETACH:
929 case DDI_CTLOPS_POWER :
930 return (DDI_SUCCESS);
931
932 case DDI_CTLOPS_SIDDEV:
933 /*
934 * Return DDI_SUCCESS for IOC/PORT/VPPA nodes and
935 * DDI_FAILURE for the nodes enumerated by a Pseudo file.
936 */
937 return (ndi_dev_is_persistent_node(rdip) ?
938 DDI_SUCCESS : DDI_FAILURE);
939
940
941 case DDI_CTLOPS_IOMIN:
942 /*
943 * Return DDI_SUCCESS, so that consistent buf alloc
944 * gets the default DMA IO minimum for the platform
945 */
946 return (DDI_SUCCESS);
947
948 /*
949 * These ops correspond to functions that "shouldn't" be
950 * called by IB Nexus driver.
951 */
952 case DDI_CTLOPS_DMAPMAPC:
953 case DDI_CTLOPS_REPORTINT:
954 case DDI_CTLOPS_REGSIZE:
955 case DDI_CTLOPS_NREGS:
956 case DDI_CTLOPS_SLAVEONLY:
957 case DDI_CTLOPS_AFFINITY:
958 case DDI_CTLOPS_POKE:
959 case DDI_CTLOPS_PEEK:
960 IBTF_DPRINTF_L2("ibnex",
961 "%s%d: invalid op (%d) from %s inst%d",
962 ddi_get_name(dip), ddi_get_instance(dip),
963 ctlop, ddi_get_name(rdip), ddi_get_instance(rdip));
964 return (DDI_FAILURE);
965
966 /*
967 * Everything else (PTOB/BTOP/BTOPR/DVMAPAGESIZE requests) we
968 * pass up
969 */
970 default:
971 return (ddi_ctlops(dip, rdip, ctlop, arg, result));
972 }
973 }
974
975
976 /*
977 * ibnex_init_child()
978 *
979 * Initialize a child device node. This is called for the DDI_CTLOPS_INITCHILD
980 * entry. Function returns DDI_SUCCESS, DDI_FAILURE or DDI_NOT_WELL_FORMED.
981 */
982 static int
983 ibnex_init_child(dev_info_t *child)
984 {
985 int ret;
986 char name[MAXNAMELEN];
987
988 IBTF_DPRINTF_L4("ibnex", "\tinit_child: child = %p", child);
989
990 /* Handle Pseudo nodes of client children */
991 if (ndi_dev_is_persistent_node(child) == 0) {
992 /* Skip nodes without ib-node-type="merge" */
993 if (ibnex_is_merge_node(child) != IBNEX_SUCCESS)
994 return (DDI_FAILURE);
995
996 if (ibnex_name_pseudo_child(child, name) != DDI_SUCCESS)
997 return (DDI_FAILURE);
998
999 ddi_set_name_addr(child, name);
1000 /*
1001 * Merge the .conf node
1002 */
1003 if (ndi_merge_node(child,
1004 ibnex_name_child) == DDI_SUCCESS) {
1005 ddi_set_name_addr(child, NULL);
1006 return (DDI_FAILURE);
1007 }
1008 return (DDI_NOT_WELL_FORMED);
1009
1010 }
1011
1012 if ((ret = ibnex_name_child(child, name, 0)) != DDI_SUCCESS)
1013 return (ret);
1014
1015 ddi_set_name_addr(child, name);
1016
1017 return (DDI_SUCCESS);
1018 }
1019
1020
1021 int
1022 ibnex_name_pseudo_child(dev_info_t *child, char *name)
1023 {
1024 char **unit_addr;
1025 uint_t n;
1026 if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child,
1027 DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) !=
1028 DDI_PROP_SUCCESS) {
1029 IBTF_DPRINTF_L4("ibnex",
1030 "\tname_pseudo_child: cannot find unit-address in %s.conf",
1031 ddi_get_name(child));
1032 return (DDI_FAILURE);
1033 }
1034 if (n != 1 || *unit_addr == NULL || **unit_addr == 0) {
1035 cmn_err(CE_WARN, "unit-address property in %s.conf"
1036 " not well-formed", ddi_get_name(child));
1037 ddi_prop_free(unit_addr);
1038 return (DDI_FAILURE);
1039 }
1040 (void) snprintf(name, MAXNAMELEN, "%s", *unit_addr);
1041 ddi_prop_free(unit_addr);
1042 return (DDI_SUCCESS);
1043 }
1044
1045
1046 /*ARGSUSED*/
1047 int
1048 ibnex_name_child(dev_info_t *child, char *name, int flag)
1049 {
1050 ibnex_pseudo_node_t *pseudo;
1051 ibnex_node_data_t *node_datap;
1052 ibnex_port_node_t *port_node;
1053 ibnex_ioc_node_t *ioc;
1054
1055 node_datap = ddi_get_parent_data(child);
1056 if (node_datap == NULL) {
1057 IBTF_DPRINTF_L2("ibnex", "\tname_child: Node data is NULL");
1058 return (DDI_NOT_WELL_FORMED);
1059 }
1060 IBTF_DPRINTF_L4("ibnex", "\tname_sid_child: Node data %p"
1061 "Node type %x", node_datap, node_datap->node_type);
1062 switch (node_datap->node_type) {
1063 case IBNEX_PORT_COMMSVC_NODE:
1064 port_node = &node_datap->node_data.port_node;
1065 (void) snprintf(name, IBNEX_MAX_NODEADDR_SZ, "%x,0,%s",
1066 port_node->port_num,
1067 ibnex.ibnex_comm_svc_names[port_node->port_commsvc_idx]);
1068 break;
1069 case IBNEX_VPPA_COMMSVC_NODE:
1070 port_node = &node_datap->node_data.port_node;
1071 (void) snprintf(name, IBNEX_MAX_NODEADDR_SZ, "%x,%x,%s",
1072 port_node->port_num, port_node->port_pkey, ibnex.
1073 ibnex_vppa_comm_svc_names[port_node->port_commsvc_idx]);
1074 break;
1075 case IBNEX_HCASVC_COMMSVC_NODE:
1076 port_node = &node_datap->node_data.port_node;
1077 (void) snprintf(name, IBNEX_MAX_NODEADDR_SZ, "%x,0,%s",
1078 port_node->port_num,
1079 ibnex.ibnex_hcasvc_comm_svc_names[port_node->
1080 port_commsvc_idx]);
1081 break;
1082 case IBNEX_IOC_NODE:
1083 ioc = &node_datap->node_data.ioc_node;
1084 (void) snprintf(name, IBNEX_MAX_NODEADDR_SZ, "%llX,%llX",
1085 (longlong_t)ioc->ioc_guid, (longlong_t)ioc->iou_guid);
1086 break;
1087 case IBNEX_PSEUDO_NODE:
1088 pseudo = &node_datap->node_data.pseudo_node;
1089 (void) snprintf(name,
1090 IBNEX_MAX_NODEADDR_SZ, pseudo->pseudo_unit_addr);
1091 break;
1092 default:
1093 IBTF_DPRINTF_L2("ibnex", "\name_child: Not well formed");
1094 return (DDI_NOT_WELL_FORMED);
1095 }
1096
1097 return (DDI_SUCCESS);
1098 }
1099
1100
1101 /*
1102 * ibnex_bus_config()
1103 *
1104 * BUS_CONFIG_ONE:
1105 * Enumerate the exact instance of the driver. Use the device node name
1106 * to locate the exact instance.
1107 * Query IBDM to find whether the hardware exits for the instance of the
1108 * driver. If exists, create a device node and return NDI_SUCCESS.
1109 *
1110 * BUS_CONFIG_ALL:
1111 * Enumerate all the instances of all the possible children (seen before
1112 * and never seen before).
1113 *
1114 * BUS_CONFIG_DRIVER:
1115 * Enumerate all the instances of a particular driver.
1116 */
1117
1118 static int
1119 ibnex_bus_config(dev_info_t *parent, uint_t flag,
1120 ddi_bus_config_op_t op, void *devname, dev_info_t **child)
1121 {
1122 int ret = IBNEX_SUCCESS, len, circ, need_bus_config;
1123 char *device_name, *cname = NULL, *caddr = NULL;
1124 dev_info_t *cdip;
1125 ibnex_node_data_t *node_data;
1126
1127 switch (op) {
1128 case BUS_CONFIG_ONE:
1129 IBTF_DPRINTF_L4("ibnex", "\tbus_config: CONFIG_ONE, "
1130 "parent %p", parent);
1131
1132 ndi_devi_enter(parent, &circ);
1133
1134 len = strlen((char *)devname) + 1;
1135 device_name = i_ddi_strdup(devname, KM_SLEEP);
1136 i_ddi_parse_name(device_name, &cname, &caddr, NULL);
1137
1138 if (caddr == NULL || (strlen(caddr) == 0)) {
1139 kmem_free(device_name, len);
1140 ndi_devi_exit(parent, circ);
1141 return (NDI_FAILURE);
1142 }
1143
1144 cdip = ndi_devi_findchild(parent, devname);
1145 if (cdip)
1146 node_data = ddi_get_parent_data(cdip);
1147
1148 ndi_devi_exit(parent, circ);
1149
1150 if (cdip == NULL || (node_data != NULL &&
1151 node_data->node_dip == NULL)) {
1152 /* Node is not present */
1153 if (strncmp(cname, IBNEX_IOC_CNAME, 3) == 0) {
1154 ret = ibnex_ioc_bus_config_one(&parent, flag,
1155 op, devname, child, &need_bus_config);
1156 if (!need_bus_config) {
1157 kmem_free(device_name, len);
1158 return (ret);
1159 }
1160 } else {
1161 /*
1162 * if IB Nexus is the parent, call MDI. Bus
1163 * config with HCA as the parent would have
1164 * enumerated the Pseudo node.
1165 */
1166 ret = IBNEX_SUCCESS;
1167 ibnex_pseudo_initnodes();
1168 mutex_enter(&ibnex.ibnex_mutex);
1169 ret = ibnex_pseudo_mdi_config_one(flag, devname,
1170 child, cname, caddr);
1171 mutex_exit(&ibnex.ibnex_mutex);
1172 kmem_free(device_name, len);
1173 return (ret);
1174 }
1175 }
1176 kmem_free(device_name, len);
1177 break;
1178
1179 case BUS_CONFIG_ALL:
1180 /*FALLTHRU*/
1181 case BUS_CONFIG_DRIVER:
1182 if (op == BUS_CONFIG_ALL)
1183 IBTF_DPRINTF_L4("ibnex", "\tbus_config: CONFIG_ALL, "
1184 "parent %p", parent);
1185 else
1186 IBTF_DPRINTF_L4("ibnex", "\tbus_config: CONFIG_DRIVER"
1187 ", parent %p", parent);
1188
1189 /*
1190 * Drive CONFIG requests for IB Nexus parent through
1191 * MDI. This is needed to load the HCA drivers in x86 SRP
1192 * boot case.
1193 *
1194 * CONFIG Requests with HCA parent will probe devices using
1195 * ibdm and configure all children.
1196 */
1197 ibdm_ioc_info_t *ioc_list, *new_ioc_list;
1198
1199 mutex_enter(&ibnex.ibnex_mutex);
1200 while (ibnex.ibnex_ioc_list_state !=
1201 IBNEX_IOC_LIST_READY) {
1202 cv_wait(&ibnex.ibnex_ioc_list_cv,
1203 &ibnex.ibnex_mutex);
1204 }
1205 ibnex.ibnex_ioc_list_state = IBNEX_IOC_LIST_RENEW;
1206 mutex_exit(&ibnex.ibnex_mutex);
1207 /* Enumerate all the IOC's */
1208 ibdm_ibnex_port_settle_wait(0, ibnex_port_settling_time);
1209
1210 new_ioc_list = ibdm_ibnex_get_ioc_list(
1211 IBDM_IBNEX_NORMAL_PROBE);
1212 IBTF_DPRINTF_L4("ibnex",
1213 "\tbus_config: alloc ioc_list %p", new_ioc_list);
1214 /*
1215 * Optimize the calls for each BUS_CONFIG_ALL request
1216 * to the IB Nexus dip. This is currently done for
1217 * each PDIP.
1218 */
1219 mutex_enter(&ibnex.ibnex_mutex);
1220 ioc_list = ibnex.ibnex_ioc_list;
1221 ibnex.ibnex_ioc_list = new_ioc_list;
1222 ibnex.ibnex_ioc_list_state = IBNEX_IOC_LIST_READY;
1223 cv_broadcast(&ibnex.ibnex_ioc_list_cv);
1224 mutex_exit(&ibnex.ibnex_mutex);
1225
1226 if (ioc_list) {
1227 IBTF_DPRINTF_L4("ibnex",
1228 "\tbus_config: freeing ioc_list %p",
1229 ioc_list);
1230 ibdm_ibnex_free_ioc_list(ioc_list);
1231 }
1232
1233
1234 ret = mdi_vhci_bus_config(parent,
1235 flag, op, devname, child, NULL);
1236 return (ret);
1237 default:
1238 IBTF_DPRINTF_L4("ibnex", "\tbus_config: error");
1239 ret = IBNEX_FAILURE;
1240 break;
1241 }
1242
1243 if (ret == IBNEX_SUCCESS) {
1244 ret = ndi_busop_bus_config(
1245 parent, flag, op, devname, child, 0);
1246 IBTF_DPRINTF_L4("ibnex", "\tbus_config:"
1247 "ndi_busop_bus_config : retval %d", ret);
1248 return (ret);
1249 }
1250
1251 return (NDI_FAILURE);
1252 }
1253
1254
1255 /*
1256 * ibnex_config_root_iocnode()
1257 * Configures one particular instance of the IOC driver.
1258 * Returns IBNEX_SUCCESS/IBNEX_FAILURE
1259 */
1260 static int
1261 ibnex_config_root_iocnode(dev_info_t *parent, char *device_name)
1262 {
1263 int ret, port = 0, iter = 0;
1264 boolean_t displayed = B_FALSE;
1265 char *portstr;
1266 ib_guid_t hca_guid, iou_guid, ioc_guid;
1267 ibdm_ioc_info_t *ioc_info;
1268 ibdm_port_attr_t *port_attr;
1269
1270 IBTF_DPRINTF_L4("ibnex",
1271 "\tconfig_root_iocnode: name %s", device_name);
1272
1273 portstr = strstr(device_name, ":port=");
1274 if (portstr == NULL) {
1275 return (IBNEX_FAILURE);
1276 }
1277
1278 portstr[0] = 0; portstr++;
1279 if (ibnex_devname2port(portstr, &port)) {
1280 IBTF_DPRINTF_L4("ibnex", "\tconfig_root_iocnode: invalid port");
1281 return (IBNEX_FAILURE);
1282 }
1283
1284 if (ibnex_devname_to_node_n_ioc_guids(
1285 device_name, &iou_guid, &ioc_guid, NULL) != IBNEX_SUCCESS) {
1286 return (IBNEX_FAILURE);
1287 }
1288
1289 (void) snprintf(device_name, (IBNEX_MAX_NODEADDR_SZ + 4),
1290 "ioc@%llX,%llX", (longlong_t)ioc_guid, (longlong_t)iou_guid);
1291
1292 hca_guid = ibtl_ibnex_hcadip2guid(parent);
1293 if ((port_attr = ibdm_ibnex_probe_hcaport(hca_guid, port)) == NULL) {
1294 IBTF_DPRINTF_L2("ibnex",
1295 "\tconfig_root_iocnode: Port does not exist");
1296 return (IBNEX_FAILURE);
1297 }
1298
1299 /* Wait until "port is up" */
1300 while (port_attr->pa_state != IBT_PORT_ACTIVE) {
1301 ibdm_ibnex_free_port_attr(port_attr);
1302 delay(drv_usectohz(10000));
1303 if ((port_attr = ibdm_ibnex_probe_hcaport(
1304 hca_guid, port)) == NULL) {
1305 return (IBNEX_FAILURE);
1306 }
1307
1308 if (iter++ == 400) {
1309 if (displayed == B_FALSE) {
1310 cmn_err(CE_NOTE, "\tWaiting for Port %d "
1311 "initialization", port_attr->pa_port_num);
1312 displayed = B_TRUE;
1313 }
1314 }
1315 }
1316 ibdm_ibnex_free_port_attr(port_attr);
1317 IBTF_DPRINTF_L4("ibnex", "\tconfig_rootioc_node:"
1318 "Port is initialized");
1319
1320 if ((ioc_info = ibdm_ibnex_probe_ioc(iou_guid, ioc_guid, 0)) == NULL) {
1321 ibdm_ibnex_free_ioc_list(ioc_info);
1322 return (IBNEX_FAILURE);
1323 }
1324 mutex_enter(&ibnex.ibnex_mutex);
1325 if ((ret = ibnex_ioc_config_from_pdip(ioc_info, parent, 0)) !=
1326 IBNEX_SUCCESS) {
1327 IBTF_DPRINTF_L2("ibnex",
1328 "\tconfig_root_ioc_node failed for pdip %p", parent);
1329 }
1330 mutex_exit(&ibnex.ibnex_mutex);
1331 ibdm_ibnex_free_ioc_list(ioc_info);
1332 return (ret);
1333 }
1334
1335
1336 static int
1337 ibnex_devname2port(char *portstr, int *port)
1338 {
1339 char *temp;
1340 int ret = IBNEX_FAILURE;
1341
1342 IBTF_DPRINTF_L4("ibnex", "\tdevname2port: Begin");
1343
1344 temp = strchr(portstr, '=');
1345 if (temp != NULL) {
1346 temp++;
1347 *port = ibnex_str2int(temp, strlen(temp), &ret);
1348 }
1349 return (ret);
1350 }
1351
1352
1353 /*
1354 * ibnex_config_all_children()
1355 * Wait for lata SM initialization case before enumerating the nodes
1356 * Get list of HCA's and HCA port information
1357 * Create device device nodes and its node properties
1358 * for port nodes and VPPA nodes
1359 * Get list of all the IOC node information
1360 * Create device nodes and its properties for all the IOCs
1361 * if not created already
1362 * Bind drivers for all the newly created device nodes
1363 * Support Pseudo nodes enumerated using their .conf file
1364 */
1365 void
1366 ibnex_config_all_children(dev_info_t *parent)
1367 {
1368 int ii;
1369 ibdm_ioc_info_t *ioc_list;
1370 ibdm_hca_list_t *hca_list;
1371 ib_guid_t hca_guid;
1372 int circ;
1373
1374 IBTF_DPRINTF_L4("ibnex", "\tconfig_all_children: Begin");
1375
1376
1377 /*
1378 * Enumerate children of this HCA, port nodes,
1379 * VPPA & HCA_SVC nodes. Use ndi_devi_enter() for
1380 * locking. IB Nexus is enumerating the children
1381 * of HCA, not MPXIO clients.
1382 */
1383 ndi_devi_enter(parent, &circ);
1384 hca_guid = ibtl_ibnex_hcadip2guid(parent);
1385 ibdm_ibnex_port_settle_wait(hca_guid, ibnex_port_settling_time);
1386 hca_list = ibdm_ibnex_get_hca_info_by_guid(hca_guid);
1387 if (hca_list == NULL) {
1388 ndi_devi_exit(parent, circ);
1389 return;
1390 }
1391 ibnex_create_hcasvc_nodes(parent, hca_list->hl_hca_port_attr);
1392 for (ii = 0; ii < hca_list->hl_nports; ii++) {
1393 ibnex_create_port_nodes(
1394 parent, &hca_list->hl_port_attr[ii]);
1395 ibnex_create_vppa_nodes(parent, &hca_list->hl_port_attr[ii]);
1396 }
1397 ibdm_ibnex_free_hca_list(hca_list);
1398 ndi_devi_exit(parent, circ);
1399
1400 /*
1401 * Use mdi_devi_enter() for locking. IB Nexus is
1402 * enumerating MPxIO clients.
1403 */
1404 mdi_devi_enter(parent, &circ);
1405
1406 ibnex_pseudo_initnodes();
1407
1408 mutex_enter(&ibnex.ibnex_mutex);
1409 while (ibnex.ibnex_ioc_list_state != IBNEX_IOC_LIST_READY) {
1410 cv_wait(&ibnex.ibnex_ioc_list_cv, &ibnex.ibnex_mutex);
1411 }
1412 ibnex.ibnex_ioc_list_state = IBNEX_IOC_LIST_ACCESS;
1413 ioc_list = ibnex.ibnex_ioc_list;
1414 while (ioc_list) {
1415 (void) ibnex_ioc_config_from_pdip(ioc_list, parent, 0);
1416 ioc_list = ioc_list->ioc_next;
1417 }
1418 ibnex.ibnex_ioc_list_state = IBNEX_IOC_LIST_READY;
1419 cv_broadcast(&ibnex.ibnex_ioc_list_cv);
1420
1421 /* Config IBTF Pseudo clients */
1422 ibnex_config_pseudo_all(parent);
1423
1424 mutex_exit(&ibnex.ibnex_mutex);
1425 mdi_devi_exit(parent, circ);
1426
1427 IBTF_DPRINTF_L4("ibnex", "\tconfig_all_children: End");
1428 }
1429
1430
1431 /*
1432 * ibnex_create_port_nodes:
1433 * Creates a device node per each communication service defined
1434 * in the "port-commsvc-list" property per HCA port
1435 */
1436 void
1437 ibnex_create_port_nodes(dev_info_t *parent, ibdm_port_attr_t *port_attr)
1438 {
1439 int idx;
1440 dev_info_t *dip;
1441 int rval;
1442
1443 mutex_enter(&ibnex.ibnex_mutex);
1444 for (idx = 0; idx < ibnex.ibnex_num_comm_svcs; idx++) {
1445 rval = ibnex_get_dip_from_guid(port_attr->pa_port_guid,
1446 idx, 0, &dip);
1447 if (rval != IBNEX_SUCCESS || dip == NULL) {
1448 (void) ibnex_commsvc_initnode(parent, port_attr, idx,
1449 IBNEX_PORT_COMMSVC_NODE, 0, &rval,
1450 IBNEX_DEVFS_ENUMERATE);
1451 }
1452 }
1453 mutex_exit(&ibnex.ibnex_mutex);
1454 }
1455
1456
1457 /*
1458 * ibnex_create_vppa_nodes:
1459 * Creates a device node per each communication service defined
1460 * in the "vppa-commsvc-list" property and per each PKEY that
1461 * this particular port supports and per HCA port
1462 */
1463 void
1464 ibnex_create_vppa_nodes(
1465 dev_info_t *parent, ibdm_port_attr_t *port_attr)
1466 {
1467 int idx, ii;
1468 int rval;
1469 ib_pkey_t pkey;
1470 dev_info_t *dip;
1471
1472 IBTF_DPRINTF_L4("ibnex", "\tcreate_vppa_nodes: Begin");
1473
1474 mutex_enter(&ibnex.ibnex_mutex);
1475 if (port_attr->pa_state != IBT_PORT_ACTIVE) {
1476 IBTF_DPRINTF_L4("ibnex", "\tcreate_vppa_nodes: "
1477 "Port %d is down", port_attr->pa_port_num);
1478 mutex_exit(&ibnex.ibnex_mutex);
1479 return;
1480 }
1481 for (idx = 0; idx < ibnex.ibnex_nvppa_comm_svcs; idx++) {
1482 if (strcmp("ipib", ibnex.ibnex_vppa_comm_svc_names[idx]) == 0) {
1483 IBTF_DPRINTF_L2("ibnex", "Skipping IBD devices...");
1484 continue;
1485 }
1486 for (ii = 0; ii < port_attr->pa_npkeys; ii++) {
1487 pkey = port_attr->pa_pkey_tbl[ii].pt_pkey;
1488
1489 if (IBNEX_INVALID_PKEY(pkey)) {
1490 continue;
1491 }
1492 rval = ibnex_get_dip_from_guid(
1493 port_attr->pa_port_guid, idx, pkey, &dip);
1494 if ((rval != IBNEX_SUCCESS) || (dip == NULL)) {
1495 (void) ibnex_commsvc_initnode(parent, port_attr,
1496 idx, IBNEX_VPPA_COMMSVC_NODE,
1497 pkey, &rval, IBNEX_CFGADM_ENUMERATE);
1498 }
1499 }
1500 }
1501 mutex_exit(&ibnex.ibnex_mutex);
1502 }
1503
1504
1505 /*
1506 * ibnex_create_hcasvc_nodes:
1507 * Creates a device node per each communication service defined
1508 * in the "port-commsvc-list" property per HCA port
1509 */
1510 void
1511 ibnex_create_hcasvc_nodes(dev_info_t *parent, ibdm_port_attr_t *port_attr)
1512 {
1513 int idx;
1514 dev_info_t *dip;
1515 int rval;
1516
1517 mutex_enter(&ibnex.ibnex_mutex);
1518 for (idx = 0; idx < ibnex.ibnex_nhcasvc_comm_svcs; idx++) {
1519 rval = ibnex_get_dip_from_guid(port_attr->pa_port_guid,
1520 idx, 0, &dip);
1521 if (rval != IBNEX_SUCCESS || dip == NULL) {
1522 (void) ibnex_commsvc_initnode(parent, port_attr, idx,
1523 IBNEX_HCASVC_COMMSVC_NODE, 0, &rval,
1524 IBNEX_DEVFS_ENUMERATE);
1525 IBTF_DPRINTF_L5("ibnex", "create_hcasvc_nodes: "
1526 "commsvc_initnode failed, rval %x", rval);
1527 }
1528 }
1529 mutex_exit(&ibnex.ibnex_mutex);
1530 }
1531
1532
1533 /*
1534 * ibnex_bus_unconfig()
1535 *
1536 * Unconfigure a particular device node or all instance of a device
1537 * driver device or all children of IBnex
1538 */
1539 static int
1540 ibnex_bus_unconfig(dev_info_t *parent,
1541 uint_t flag, ddi_bus_config_op_t op, void *device_name)
1542 {
1543 ibnex_node_data_t *ndp;
1544 major_t major = (major_t)(uintptr_t)device_name;
1545 dev_info_t *dip = NULL;
1546
1547 if (ndi_busop_bus_unconfig(parent, flag, op, device_name) !=
1548 DDI_SUCCESS)
1549 return (DDI_FAILURE);
1550
1551 if ((op == BUS_UNCONFIG_ALL || op == BUS_UNCONFIG_DRIVER) &&
1552 (flag & (NDI_UNCONFIG | NDI_DETACH_DRIVER))) {
1553 mutex_enter(&ibnex.ibnex_mutex);
1554 /*
1555 * IB dip. here we handle IOC and pseudo nodes which
1556 * are the children of IB nexus. Cleanup only the nodes
1557 * with matching major number. We also need to cleanup
1558 * the PathInfo links to the PHCI here.
1559 */
1560 for (ndp = ibnex.ibnex_ioc_node_head;
1561 ndp; ndp = ndp->node_next) {
1562 dip = ndp->node_dip;
1563 if (dip && (ddi_driver_major(dip) == major)) {
1564 (void) ibnex_offline_childdip(dip);
1565 }
1566 }
1567 for (ndp = ibnex.ibnex_pseudo_node_head;
1568 ndp; ndp = ndp->node_next) {
1569 dip = ndp->node_dip;
1570 if (dip && (ddi_driver_major(dip) == major)) {
1571 (void) ibnex_offline_childdip(dip);
1572 }
1573 }
1574 mutex_exit(&ibnex.ibnex_mutex);
1575 }
1576 return (DDI_SUCCESS);
1577 }
1578
1579
1580 /*
1581 * ibnex_config_port_node()
1582 *
1583 * Configures a particular port / HCA node for a particular
1584 * communication service.
1585 * The format of the device_name is
1586 * ibport@<Port#>,<pkey>,<service name>
1587 * where pkey = 0 for port communication service nodes
1588 * Port# = 0 for HCA_SVC communication service nodes
1589 * Returns "dev_info_t" of the "child" node just created
1590 * NULL when failed to enumerate the child node
1591 */
1592 dev_info_t *
1593 ibnex_config_port_node(dev_info_t *parent, char *devname)
1594 {
1595 int ii, index;
1596 int rval;
1597 uint8_t port_num;
1598 ib_guid_t hca_guid, port_guid;
1599 ib_pkey_t pkey;
1600 dev_info_t *cdip;
1601 ibdm_port_attr_t *port_attr;
1602 ibdm_hca_list_t *hca_list;
1603
1604 IBTF_DPRINTF_L4("ibnex", "\tconfig_port_node: %s", devname);
1605
1606 if (ibnex_get_pkey_commsvc_index_portnum(devname,
1607 &index, &pkey, &port_num) != IBNEX_SUCCESS) {
1608 IBTF_DPRINTF_L2("ibnex",
1609 "\tconfig_port_node: Invalid Service Name");
1610 return (NULL);
1611 }
1612
1613 hca_guid = ibtl_ibnex_hcadip2guid(parent);
1614 if (port_num == 0) {
1615 /*
1616 * Use the dummy port attribute for HCA node in hca_list
1617 * Note : pa_state is always IBT_PORT_ACTIVE.
1618 */
1619 hca_list = ibdm_ibnex_get_hca_info_by_guid(hca_guid);
1620 ASSERT(hca_list != NULL);
1621 port_attr = hca_list->hl_hca_port_attr;
1622 } else {
1623 if ((port_attr = ibdm_ibnex_probe_hcaport(
1624 hca_guid, port_num)) == NULL) {
1625 IBTF_DPRINTF_L2("ibnex",
1626 "\tconfig_port_node: Port does not exist");
1627 return (NULL);
1628 }
1629
1630 if (port_attr->pa_state != IBT_PORT_ACTIVE) {
1631 ibdm_ibnex_port_settle_wait(
1632 hca_guid, ibnex_port_settling_time);
1633 ibdm_ibnex_free_port_attr(port_attr);
1634 if ((port_attr = ibdm_ibnex_probe_hcaport(
1635 hca_guid, port_num)) == NULL) {
1636 return (NULL);
1637 }
1638 }
1639 }
1640
1641 port_guid = port_attr->pa_port_guid;
1642 mutex_enter(&ibnex.ibnex_mutex);
1643 rval = ibnex_get_dip_from_guid(port_guid, index, pkey, &cdip);
1644 if ((rval == IBNEX_SUCCESS) && cdip != NULL) {
1645 IBTF_DPRINTF_L4("ibnex", "\tconfig_port_node: Node exists");
1646 mutex_exit(&ibnex.ibnex_mutex);
1647 if (port_num != 0)
1648 ibdm_ibnex_free_port_attr(port_attr);
1649 else
1650 ibdm_ibnex_free_hca_list(hca_list);
1651 return (cdip);
1652 }
1653
1654 if (pkey == 0 && port_num != 0) {
1655 cdip = ibnex_commsvc_initnode(parent,
1656 port_attr, index, IBNEX_PORT_COMMSVC_NODE, pkey, &rval,
1657 IBNEX_DEVFS_ENUMERATE);
1658 IBTF_DPRINTF_L5("ibnex",
1659 "\t ibnex_commsvc_initnode rval %x", rval);
1660 } else if (pkey == 0 && port_num == 0) {
1661 cdip = ibnex_commsvc_initnode(parent,
1662 port_attr, index, IBNEX_HCASVC_COMMSVC_NODE, pkey, &rval,
1663 IBNEX_DEVFS_ENUMERATE);
1664 IBTF_DPRINTF_L5("ibnex",
1665 "\t ibnex_commsvc_initnode rval %x", rval);
1666 } else {
1667 if (port_attr->pa_state != IBT_PORT_ACTIVE) {
1668 IBTF_DPRINTF_L4("ibnex", "\tconfig_port_nodes: "
1669 "Port %d is down", port_attr->pa_port_num);
1670 ibdm_ibnex_free_port_attr(port_attr);
1671 mutex_exit(&ibnex.ibnex_mutex);
1672 return (NULL);
1673 }
1674 for (ii = 0; ii < port_attr->pa_npkeys; ii++) {
1675 if (pkey == port_attr->pa_pkey_tbl[ii].pt_pkey) {
1676 cdip = ibnex_commsvc_initnode(parent, port_attr,
1677 index, IBNEX_VPPA_COMMSVC_NODE,
1678 pkey, &rval, IBNEX_CFGADM_ENUMERATE);
1679 IBTF_DPRINTF_L5("ibnex",
1680 "\t ibnex_commsvc_initnode rval %x", rval);
1681 break;
1682 }
1683 }
1684 }
1685 mutex_exit(&ibnex.ibnex_mutex);
1686 if (port_num != 0)
1687 ibdm_ibnex_free_port_attr(port_attr);
1688 else
1689 ibdm_ibnex_free_hca_list(hca_list);
1690 return (cdip);
1691 }
1692
1693
1694 /*
1695 * ibnex_get_pkey_commsvc_index_portnum()
1696 * Parses the device node name and extracts PKEY, communication
1697 * service index & Port #.
1698 * Returns IBNEX_SUCCESS/IBNEX_FAILURE
1699 */
1700 int
1701 ibnex_get_pkey_commsvc_index_portnum(char *device_name, int *index,
1702 ib_pkey_t *pkey, uint8_t *port_num)
1703 {
1704 char *srv, **service_name, *temp;
1705 int ii, ncommsvcs, ret;
1706
1707 if (ibnex_devname_to_portnum(device_name, port_num) !=
1708 IBNEX_SUCCESS) {
1709 IBTF_DPRINTF_L2("ibnex",
1710 "\tget_pkey_commsvc_index_portnum: Invalid Service Name");
1711 return (IBNEX_FAILURE);
1712 }
1713 srv = strchr(device_name, ',');
1714 if (srv == 0)
1715 return (IBNEX_FAILURE);
1716
1717 srv++;
1718 temp = strchr(srv, ',');
1719 if (temp == 0)
1720 return (IBNEX_FAILURE);
1721 temp++;
1722 *pkey = ibnex_str2hex(srv, (temp - srv - 1), &ret);
1723 if (ret != IBNEX_SUCCESS)
1724 return (ret);
1725
1726 if (*pkey == 0 && *port_num != 0) {
1727 service_name = ibnex.ibnex_comm_svc_names;
1728 ncommsvcs = ibnex.ibnex_num_comm_svcs;
1729 } else if (*pkey == 0 && *port_num == 0) {
1730 service_name = ibnex.ibnex_hcasvc_comm_svc_names;
1731 ncommsvcs = ibnex.ibnex_nhcasvc_comm_svcs;
1732 } else {
1733 service_name = ibnex.ibnex_vppa_comm_svc_names;
1734 ncommsvcs = ibnex.ibnex_nvppa_comm_svcs;
1735 }
1736
1737 for (ii = 0; ii < ncommsvcs; ii++) {
1738 if (strcmp(service_name[ii], temp) == 0) {
1739 break;
1740 }
1741 }
1742 if (ii == ncommsvcs)
1743 return (IBNEX_FAILURE);
1744
1745 *index = ii;
1746 return (IBNEX_SUCCESS);
1747 }
1748
1749
1750 /*
1751 * ibnex_devname_to_portnum()
1752 * Get portguid from device name
1753 * Returns IBNEX_SUCCESS/IBNEX_FAILURE
1754 */
1755 static int
1756 ibnex_devname_to_portnum(char *device_name, uint8_t *portnum)
1757 {
1758 int ret;
1759 char *temp1, *temp2;
1760
1761 temp1 = strchr(device_name, '@');
1762 if (temp1 == NULL) {
1763 return (IBNEX_FAILURE);
1764 }
1765 temp2 = strchr(temp1, ',');
1766 if (temp2 == NULL)
1767 return (IBNEX_FAILURE);
1768 temp1++;
1769 *portnum = ibnex_str2hex(temp1, (temp2 - temp1), &ret);
1770 return (ret);
1771 }
1772
1773
1774 /*
1775 * ibnex_config_ioc_node()
1776 * Configures one particular instance of the IOC driver.
1777 * Returns IBNEX_SUCCESS/IBNEX_FAILURE
1778 */
1779 static int
1780 ibnex_config_ioc_node(char *device_name, dev_info_t *pdip)
1781 {
1782 int ret;
1783 ib_guid_t iou_guid, ioc_guid;
1784 ibdm_ioc_info_t *ioc_info;
1785
1786 IBTF_DPRINTF_L4("ibnex", "\tconfig_ioc_node: Begin");
1787
1788 if (ibnex_devname_to_node_n_ioc_guids(
1789 device_name, &iou_guid, &ioc_guid, NULL) != IBNEX_SUCCESS) {
1790 return (IBNEX_FAILURE);
1791 }
1792
1793 ibdm_ibnex_port_settle_wait(0, ibnex_port_settling_time);
1794
1795 if ((ioc_info = ibdm_ibnex_probe_ioc(iou_guid, ioc_guid, 0)) ==
1796 NULL) {
1797 ibdm_ibnex_free_ioc_list(ioc_info);
1798 return (IBNEX_FAILURE);
1799 }
1800 mutex_enter(&ibnex.ibnex_mutex);
1801 ret = ibnex_ioc_config_from_pdip(ioc_info, pdip, 0);
1802 mutex_exit(&ibnex.ibnex_mutex);
1803 ibdm_ibnex_free_ioc_list(ioc_info);
1804 IBTF_DPRINTF_L4("ibnex", "\tconfig_ioc_node: ret %x",
1805 ret);
1806 return (ret);
1807 }
1808
1809
1810 /*
1811 * ibnex_devname_to_node_n_ioc_guids()
1812 * Get node guid and ioc guid from the device name
1813 * Format of the device node name is:
1814 * ioc@<IOC GUID>,<IOU GUID>
1815 * Returns IBNEX_SUCCESS/IBNEX_FAILURE
1816 */
1817 static int
1818 ibnex_devname_to_node_n_ioc_guids(
1819 char *device_name, ib_guid_t *iou_guid, ib_guid_t *ioc_guid,
1820 char **ioc_guid_strp)
1821 {
1822 char *temp1, *temp;
1823 int len, ret;
1824 char *ioc_guid_str;
1825
1826 IBTF_DPRINTF_L4("ibnex", "\tdevname_to_node_n_ioc_guids:"
1827 "Device Name %s", device_name);
1828
1829 if ((temp = strchr(device_name, '@')) == NULL) {
1830 return (IBNEX_FAILURE);
1831 }
1832 if ((temp1 = strchr(++temp, ',')) == NULL) {
1833 return (IBNEX_FAILURE);
1834 }
1835 *ioc_guid = ibnex_str2hex(temp, (temp1 - temp), &ret);
1836 if (ret == IBNEX_SUCCESS) {
1837 if (ioc_guid_strp) {
1838 ioc_guid_str = *ioc_guid_strp = kmem_zalloc((temp1
1839 - temp) + 1, KM_SLEEP);
1840 (void) strncpy(ioc_guid_str, temp, temp1 - temp + 1);
1841 ioc_guid_str[temp1 - temp] = '\0';
1842 }
1843 len = device_name + strlen(device_name) - ++temp1;
1844 *iou_guid = ibnex_str2hex(temp1, len, &ret);
1845 }
1846 return (ret);
1847 }
1848
1849
1850 /*
1851 * ibnex_ioc_initnode()
1852 * Allocate a pathinfo node for the IOC
1853 * Initialize the device node
1854 * Bind driver to the node
1855 * Update IBnex global data
1856 * Returns IBNEX_SUCCESS/IBNEX_FAILURE/IBNEX_BUSY
1857 */
1858 static int
1859 ibnex_ioc_initnode_pdip(ibnex_node_data_t *node_data,
1860 ibdm_ioc_info_t *ioc_info, dev_info_t *pdip)
1861 {
1862 int rval, node_valid;
1863 ibnex_node_state_t prev_state;
1864
1865 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
1866 ASSERT(node_data);
1867
1868
1869 /*
1870 * Return EBUSY if another configure/unconfigure
1871 * operation is in progress
1872 */
1873 if (node_data->node_state == IBNEX_CFGADM_UNCONFIGURING) {
1874 IBTF_DPRINTF_L4("ibnex",
1875 "\tioc_initnode_pdip : BUSY");
1876 return (IBNEX_BUSY);
1877 }
1878
1879 prev_state = node_data->node_state;
1880 node_data->node_state = IBNEX_CFGADM_CONFIGURING;
1881 mutex_exit(&ibnex.ibnex_mutex);
1882
1883 rval = ibnex_ioc_create_pi(ioc_info, node_data, pdip, &node_valid);
1884
1885 mutex_enter(&ibnex.ibnex_mutex);
1886 if (rval == IBNEX_SUCCESS)
1887 node_data->node_state = IBNEX_CFGADM_CONFIGURED;
1888 else if (node_valid)
1889 node_data->node_state = prev_state;
1890
1891 return (rval);
1892 }
1893
1894 /*
1895 * ibnex_config_pseudo_all()
1896 * Configure all the pseudo nodes
1897 */
1898 static void
1899 ibnex_config_pseudo_all(dev_info_t *pdip)
1900 {
1901 ibnex_node_data_t *nodep;
1902
1903 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
1904
1905 for (nodep = ibnex.ibnex_pseudo_node_head;
1906 nodep; nodep = nodep->node_next) {
1907 (void) ibnex_pseudo_config_one(nodep, NULL, pdip);
1908 }
1909 }
1910
1911
1912 /*
1913 * ibnex_pseudo_config_one()
1914 */
1915 int
1916 ibnex_pseudo_config_one(ibnex_node_data_t *node_data, char *caddr,
1917 dev_info_t *pdip)
1918 {
1919 int rval;
1920 ibnex_pseudo_node_t *pseudo;
1921 ibnex_node_state_t prev_state;
1922
1923 IBTF_DPRINTF_L4("ibnex", "\tpseudo_config_one(%p, %p, %p)",
1924 node_data, caddr, pdip);
1925
1926 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
1927
1928 if (node_data == NULL) {
1929 IBTF_DPRINTF_L4("ibnex",
1930 "\tpseudo_config_one: caddr = %s", caddr);
1931
1932 /*
1933 * This function is now called with PHCI / HCA driver
1934 * as parent. The format of devicename is :
1935 * <driver_name>@<driver_name>,<unit_address>
1936 * The "caddr" part of the devicename matches the
1937 * format of pseudo_node_addr.
1938 *
1939 * Use "caddr" to find a matching Pseudo node entry.
1940 */
1941 node_data = ibnex_is_node_data_present(IBNEX_PSEUDO_NODE,
1942 (void *)caddr, 0, 0);
1943 }
1944
1945 if (node_data == NULL) {
1946 IBTF_DPRINTF_L2("ibnex",
1947 "\tpseudo_config_one: Invalid node");
1948 return (IBNEX_FAILURE);
1949 }
1950
1951 if (node_data->node_ap_state == IBNEX_NODE_AP_UNCONFIGURED) {
1952 IBTF_DPRINTF_L4("ibnex",
1953 "\tpseudo_config_one: Unconfigured node");
1954 return (IBNEX_FAILURE);
1955 }
1956
1957 pseudo = &node_data->node_data.pseudo_node;
1958
1959 /*
1960 * Do not enumerate nodes with ib-node-type set as "merge"
1961 */
1962 if (pseudo->pseudo_merge_node == 1) {
1963 IBTF_DPRINTF_L4("ibnex",
1964 "\tpseudo_config_one: merge_node");
1965 return (IBNEX_FAILURE);
1966 }
1967
1968 /*
1969 * Check if a PI has already been created for the PDIP.
1970 * If so, return SUCCESS.
1971 */
1972 if (node_data->node_dip != NULL && mdi_pi_find(pdip,
1973 pseudo->pseudo_node_addr, pseudo->pseudo_node_addr) != NULL) {
1974 IBTF_DPRINTF_L4("ibnex",
1975 "\tpseudo_config_one: PI created,"
1976 " pdip %p, addr %s", pdip, pseudo->pseudo_node_addr);
1977 return (IBNEX_SUCCESS);
1978 }
1979
1980 /*
1981 * Return EBUSY if another unconfigure
1982 * operation is in progress
1983 */
1984 if (node_data->node_state == IBNEX_CFGADM_UNCONFIGURING) {
1985 IBTF_DPRINTF_L4("ibnex",
1986 "\tpseudo_config_one: BUSY");
1987 return (IBNEX_BUSY);
1988 }
1989
1990
1991 prev_state = node_data->node_state;
1992 node_data->node_state = IBNEX_CFGADM_CONFIGURING;
1993
1994 mutex_exit(&ibnex.ibnex_mutex);
1995 rval = ibnex_pseudo_create_pi_pdip(node_data, pdip);
1996 mutex_enter(&ibnex.ibnex_mutex);
1997
1998 if (rval == IBNEX_SUCCESS) {
1999 node_data->node_state = IBNEX_CFGADM_CONFIGURED;
2000 } else {
2001 node_data->node_state = prev_state;
2002 }
2003
2004 IBTF_DPRINTF_L4("ibnex", "\tpseudo_config_one: ret %x",
2005 rval);
2006 return (rval);
2007 }
2008
2009
2010 /*
2011 * ibnex_pseudo_mdi_config_one()
2012 * This is similar to ibnex_pseudo_config_one. Few
2013 * differences :
2014 * 1. parent device lock not held(no ndi_devi_enter)
2015 * 2. Called for IB Nexus as parent, not IB HCA as
2016 * parent.
2017 * 3. Calls mdi_vhci_bus_config()
2018 * This function skips checks for node_state, initializing
2019 * node_state, node_dip, etc. These checks and initializations
2020 * are done when BUS_CONFIG is called with PHCI as the parent.
2021 */
2022 int
2023 ibnex_pseudo_mdi_config_one(int flag, void *devname, dev_info_t **child,
2024 char *cname, char *caddr)
2025 {
2026 int rval, len;
2027 char *node_addr;
2028 ibnex_node_data_t *node_data;
2029
2030 IBTF_DPRINTF_L4("ibnex", "\tpseudo_mdi_config_one:"
2031 "cname = %s caddr = %s", cname, caddr);
2032
2033 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
2034
2035 len = strlen(cname) + strlen(caddr) + 2;
2036 node_addr = (char *)kmem_alloc(len, KM_SLEEP);
2037
2038 (void) snprintf(node_addr, len, "%s,%s", cname, caddr);
2039 node_data = ibnex_is_node_data_present(IBNEX_PSEUDO_NODE,
2040 (void *)node_addr, 0, 0);
2041 kmem_free(node_addr, len);
2042
2043 if (node_data == NULL) {
2044 IBTF_DPRINTF_L2("ibnex",
2045 "\tpseudo_mdi_config_one: Invalid node");
2046 return (IBNEX_FAILURE);
2047 }
2048
2049 mutex_exit(&ibnex.ibnex_mutex);
2050 rval = mdi_vhci_bus_config(ibnex.ibnex_dip, flag, BUS_CONFIG_ONE,
2051 devname, child, node_data->node_data.pseudo_node.pseudo_node_addr);
2052 mutex_enter(&ibnex.ibnex_mutex);
2053
2054 return (rval);
2055 }
2056
2057
2058 /*
2059 * ibnex_pseudo_create_all_pi()
2060 * Create all path infos node for a pseudo entry
2061 */
2062 int
2063 ibnex_pseudo_create_all_pi(ibnex_node_data_t *nodep)
2064 {
2065 int hcacnt, rc;
2066 int hcafailcnt = 0;
2067 dev_info_t *hca_dip;
2068 ibdm_hca_list_t *hca_list, *head;
2069
2070 IBTF_DPRINTF_L4("ibnex", "\tpseudo_create_all_pi(%p)",
2071 nodep);
2072 ibdm_ibnex_get_hca_list(&hca_list, &hcacnt);
2073
2074 head = hca_list;
2075
2076 /*
2077 * We return failure even if we fail for all HCAs.
2078 */
2079 for (; hca_list != NULL; hca_list = hca_list->hl_next) {
2080 hca_dip = ibtl_ibnex_hcaguid2dip(hca_list->hl_hca_guid);
2081 rc = ibnex_pseudo_create_pi_pdip(nodep, hca_dip);
2082 if (rc != IBNEX_SUCCESS)
2083 hcafailcnt++;
2084 }
2085 if (head)
2086 ibdm_ibnex_free_hca_list(head);
2087
2088 if (hcafailcnt == hcacnt)
2089 rc = IBNEX_FAILURE;
2090 else
2091 rc = IBNEX_SUCCESS;
2092
2093 IBTF_DPRINTF_L4("ibnex", "\tpseudo_create_all_pi rc %x",
2094 rc);
2095 return (rc);
2096 }
2097
2098 static int
2099 ibnex_pseudo_create_pi_pdip(ibnex_node_data_t *nodep, dev_info_t *hca_dip)
2100 {
2101 mdi_pathinfo_t *pip;
2102 int rval;
2103 dev_info_t *cdip = NULL;
2104 ibnex_pseudo_node_t *pseudo;
2105 int first_pi = 0;
2106
2107 IBTF_DPRINTF_L4("ibnex", "\tpseudo_create_pi_pdip: %p, %p",
2108 nodep, hca_dip);
2109
2110 pseudo = &nodep->node_data.pseudo_node;
2111
2112 rval = mdi_pi_alloc(hca_dip,
2113 pseudo->pseudo_devi_name, pseudo->pseudo_node_addr,
2114 pseudo->pseudo_node_addr, 0, &pip);
2115
2116 if (rval != MDI_SUCCESS) {
2117 IBTF_DPRINTF_L2("ibnex", "\tpseudo_create_pi_pdip:"
2118 " mdi_pi_alloc failed");
2119 return (IBNEX_FAILURE);
2120 }
2121 cdip = mdi_pi_get_client(pip);
2122
2123 if (nodep->node_dip == NULL) {
2124 IBTF_DPRINTF_L4("ibnex",
2125 "\tpseudo_create_pi: New dip %p", cdip);
2126
2127 first_pi = 1;
2128 nodep->node_dip = cdip;
2129 ddi_set_parent_data(cdip, nodep);
2130 }
2131
2132 rval = mdi_pi_online(pip, 0);
2133
2134 if (rval != MDI_SUCCESS) {
2135 IBTF_DPRINTF_L2("ibnex",
2136 "\tpseudo_create_pi: "
2137 "mdi_pi_online: failed for pseudo dip %p,"
2138 " rval %d", cdip, rval);
2139 rval = IBNEX_FAILURE;
2140 if (first_pi == 1) {
2141 ddi_set_parent_data(cdip, NULL);
2142 (void) ibnex_offline_childdip(cdip);
2143 nodep->node_dip = NULL;
2144 } else
2145 (void) mdi_pi_free(pip, 0);
2146 } else
2147 rval = IBNEX_SUCCESS;
2148 return (rval);
2149 }
2150
2151 /*
2152 * ibnex_ioc_create_pi()
2153 * Create a pathinfo node for the ioc node
2154 */
2155 static int
2156 ibnex_ioc_create_pi(ibdm_ioc_info_t *ioc_info, ibnex_node_data_t *node_data,
2157 dev_info_t *pdip, int *node_valid)
2158 {
2159 mdi_pathinfo_t *pip;
2160 int rval = DDI_FAILURE;
2161 dev_info_t *cdip = NULL;
2162 int create_prop = 0;
2163 ibnex_ioc_node_t *ioc = &node_data->node_data.ioc_node;
2164
2165 IBTF_DPRINTF_L4("ibnex",
2166 "\tibnex_ioc_create_pi(%p, %p, %p)", ioc_info, node_data, pdip);
2167 *node_valid = 1;
2168
2169 /*
2170 * For CONFIG_ONE requests through HCA dip, alloc
2171 * for HCA dip driving BUS_CONFIG request.
2172 */
2173 rval = mdi_pi_alloc(pdip, IBNEX_IOC_CNAME, ioc->ioc_guid_str,
2174 ioc->ioc_phci_guid, 0, &pip);
2175 if (rval != MDI_SUCCESS) {
2176 IBTF_DPRINTF_L2("ibnex",
2177 "\tioc_create_pi: mdi_pi_alloc(%p, %s. %s) failed",
2178 pdip, ioc->ioc_guid_str, ioc->ioc_phci_guid);
2179 return (IBNEX_FAILURE);
2180 }
2181 cdip = mdi_pi_get_client(pip);
2182
2183 IBTF_DPRINTF_L4("ibnex", "\tioc_create_pi: IOC dip %p",
2184 cdip);
2185
2186 if (node_data->node_dip == NULL) {
2187 node_data->node_dip = cdip;
2188 ddi_set_parent_data(cdip, node_data);
2189 create_prop = 1;
2190 IBTF_DPRINTF_L4("ibnex",
2191 "\tioc_create_pi: creating prop");
2192 if ((rval = ibnex_create_ioc_node_prop(
2193 ioc_info, cdip)) != IBNEX_SUCCESS) {
2194 IBTF_DPRINTF_L4("ibnex",
2195 "\tioc_create_pi: creating prop failed");
2196 ibnex_delete_ioc_node_data(node_data);
2197 *node_valid = 0;
2198 ddi_prop_remove_all(cdip);
2199 ddi_set_parent_data(cdip, NULL);
2200
2201 (void) ibnex_offline_childdip(cdip);
2202 return (IBNEX_FAILURE);
2203 }
2204 }
2205
2206 rval = mdi_pi_online(pip, 0);
2207
2208 if (rval != MDI_SUCCESS) {
2209 IBTF_DPRINTF_L2("ibnex", "\tioc_create_pi: "
2210 "mdi_pi_online() failed ioc dip %p, rval %d",
2211 cdip, rval);
2212 rval = IBNEX_FAILURE;
2213 if (create_prop) {
2214 ddi_set_parent_data(cdip, NULL);
2215 ddi_prop_remove_all(cdip);
2216 ibnex_delete_ioc_node_data(node_data);
2217 *node_valid = 0;
2218 (void) ibnex_offline_childdip(cdip);
2219 } else
2220 (void) mdi_pi_free(pip, 0);
2221 } else
2222 rval = IBNEX_SUCCESS;
2223
2224 IBTF_DPRINTF_L4("ibnex", "\tioc_create_pi ret %x", rval);
2225 return (rval);
2226 }
2227
2228
2229 /*
2230 * ibnex_create_ioc_node_prop()
2231 * Create IOC device node properties
2232 * Returns IBNEX_SUCCESS/IBNEX_FAILURE
2233 */
2234 static int
2235 ibnex_create_ioc_node_prop(ibdm_ioc_info_t *ioc_info, dev_info_t *cdip)
2236 {
2237 uint16_t capabilities;
2238 ib_dm_ioc_ctrl_profile_t *ioc_profile = &ioc_info->ioc_profile;
2239
2240 IBTF_DPRINTF_L4("ibnex", "\tcreate_ioc_node_prop");
2241
2242 if (ibnex_create_ioc_compatible_prop(cdip,
2243 ioc_profile) != IBNEX_SUCCESS) {
2244 return (IBNEX_FAILURE);
2245 }
2246 if ((ioc_info->ioc_iou_dc_valid) &&
2247 (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "iou-diagcode",
2248 ioc_info->ioc_iou_diagcode)) != DDI_PROP_SUCCESS) {
2249 IBTF_DPRINTF_L2("ibnex",
2250 "\tcreate_ioc_node_prop: iou-diagcode create failed");
2251 return (IBNEX_FAILURE);
2252 }
2253 if ((ioc_info->ioc_diagdeviceid) && (ioc_info->ioc_dc_valid)) {
2254 if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "ioc-diagcode",
2255 ioc_info->ioc_diagcode) != DDI_PROP_SUCCESS) {
2256 IBTF_DPRINTF_L2("ibnex", "\tcreate_ioc_node_prop: "
2257 "ioc-diagcode create failed");
2258 return (IBNEX_FAILURE);
2259 }
2260 }
2261 if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "rdma-queue-depth",
2262 ioc_profile->ioc_rdma_read_qdepth) != DDI_PROP_SUCCESS) {
2263 IBTF_DPRINTF_L2("ibnex",
2264 "\tcreate_ioc_node_prop: rdma-queue-depth create failed");
2265 return (IBNEX_FAILURE);
2266 }
2267 if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "rdma-transfer-size",
2268 ioc_profile->ioc_rdma_xfer_sz) != DDI_PROP_SUCCESS) {
2269 IBTF_DPRINTF_L2("ibnex", "\tcreate_ioc_node_prop: "
2270 "rdma-transfer-size create failed");
2271 return (IBNEX_FAILURE);
2272 }
2273 if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "send-message-size",
2274 ioc_profile->ioc_send_msg_sz) != DDI_PROP_SUCCESS) {
2275 IBTF_DPRINTF_L2("ibnex",
2276 "\tcreate_ioc_node_prop: send-message-size create failed");
2277 return (IBNEX_FAILURE);
2278 }
2279 if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "send-queue-depth",
2280 ioc_profile->ioc_send_msg_qdepth) != DDI_PROP_SUCCESS) {
2281 IBTF_DPRINTF_L2("ibnex",
2282 "\tcreate_ioc_node_prop: send-queue-depth create failed");
2283 return (IBNEX_FAILURE);
2284 }
2285
2286 capabilities = (ioc_profile->ioc_ctrl_opcap_mask << 8);
2287 if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip,
2288 "capabilities", capabilities) != DDI_PROP_SUCCESS) {
2289 IBTF_DPRINTF_L2("ibnex",
2290 "\tcreate_ioc_node_prop: capabilities create failed");
2291 return (IBNEX_FAILURE);
2292 }
2293 if (ndi_prop_update_string(DDI_DEV_T_NONE, cdip, "id-string",
2294 (char *)ioc_profile->ioc_id_string) != DDI_PROP_SUCCESS) {
2295 IBTF_DPRINTF_L2("ibnex",
2296 "\tcreate_ioc_node_prop: id-string failed");
2297 return (IBNEX_FAILURE);
2298 }
2299
2300 /*
2301 * Create properties to represent all the service entries supported
2302 * by the IOC. Each service entry consists of 1) Service ID (64 bits)
2303 * and 2) Service name (40 bytes). The service entry table is
2304 * represented by two properties, service-ids and service-names. The
2305 * service-id property is a array of int64's and service names is
2306 * array of strings. The first element in the "service-ids" property
2307 * corresponds to first string in the "service-names" and so on.
2308 */
2309 if ((ioc_profile->ioc_service_entries != 0) &&
2310 (ibnex_create_ioc_srv_props(cdip, ioc_info) != IBNEX_SUCCESS))
2311 return (IBNEX_FAILURE);
2312
2313 /* Create destination port GID properties */
2314 if (ibnex_create_ioc_portgid_prop(cdip, ioc_info) != IBNEX_SUCCESS)
2315 return (IBNEX_FAILURE);
2316
2317 if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "protocol-version",
2318 ioc_profile->ioc_protocol_ver) != DDI_PROP_SUCCESS) {
2319 IBTF_DPRINTF_L2("ibnex",
2320 "\tcreate_ioc_node_prop: protocol-version create failed");
2321 return (IBNEX_FAILURE);
2322 }
2323 if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "protocol",
2324 ioc_profile->ioc_protocol) != DDI_PROP_SUCCESS) {
2325 IBTF_DPRINTF_L2("ibnex",
2326 "\tcreate_ioc_node_prop: protocol create failed");
2327 return (IBNEX_FAILURE);
2328 }
2329 if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "io-subclass",
2330 ioc_profile->ioc_io_subclass) != DDI_PROP_SUCCESS) {
2331 IBTF_DPRINTF_L2("ibnex",
2332 "\tcreate_ioc_node_prop: subclass create failed");
2333 return (IBNEX_FAILURE);
2334 }
2335 if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "io-class",
2336 ioc_profile->ioc_io_class) != DDI_PROP_SUCCESS) {
2337 IBTF_DPRINTF_L2("ibnex",
2338 "\tcreate_ioc_node_prop: class prop create failed");
2339 return (IBNEX_FAILURE);
2340 }
2341 if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "subsystem-id",
2342 ioc_profile->ioc_subsys_id) != DDI_PROP_SUCCESS) {
2343 IBTF_DPRINTF_L2("ibnex",
2344 "\tcreate_ioc_node_prop: subsys_id create failed");
2345 return (IBNEX_FAILURE);
2346 }
2347 if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "subsystem-vendor-id",
2348 ioc_profile->ioc_subsys_vendorid) != DDI_PROP_SUCCESS) {
2349 IBTF_DPRINTF_L2("ibnex",
2350 "\tcreate_ioc_node_prop: subsystem vendor create failed");
2351 return (IBNEX_FAILURE);
2352 }
2353 if (ndi_prop_update_int64(DDI_DEV_T_NONE, cdip, "ioc-guid",
2354 ioc_profile->ioc_guid) != DDI_PROP_SUCCESS) {
2355 IBTF_DPRINTF_L2("ibnex",
2356 "\tcreate_ioc_node_prop: protocol create failed");
2357 return (IBNEX_FAILURE);
2358 }
2359 if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "device-version",
2360 ioc_profile->ioc_device_ver) != DDI_PROP_SUCCESS) {
2361 IBTF_DPRINTF_L2("ibnex",
2362 "\tcreate_ioc_node_prop: product-id create failed");
2363 return (IBNEX_FAILURE);
2364 }
2365 if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "device-id",
2366 ioc_profile->ioc_deviceid) != DDI_PROP_SUCCESS) {
2367 IBTF_DPRINTF_L2("ibnex",
2368 "\tcreate_ioc_node_prop: product-id create failed");
2369 return (IBNEX_FAILURE);
2370 }
2371 if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "vendor-id",
2372 ioc_profile->ioc_vendorid) != DDI_PROP_SUCCESS) {
2373 IBTF_DPRINTF_L2("ibnex",
2374 "\tcreate_ioc_node_prop: vendor-id create failed");
2375 return (IBNEX_FAILURE);
2376 }
2377 return (IBNEX_SUCCESS);
2378 }
2379
2380
2381 /*
2382 * ibnex_create_ioc_portgid_prop()
2383 * Creates "port-entries", "port-list" properties
2384 * Returns IBNEX_SUCCESS/IBNEX_FAILURE
2385 */
2386 static int
2387 ibnex_create_ioc_portgid_prop(
2388 dev_info_t *cdip, ibdm_ioc_info_t *ioc_info)
2389 {
2390 uint64_t *port_gids;
2391 int length, ii, jj;
2392 int prop_len;
2393 ibnex_node_data_t *node_data;
2394
2395 IBTF_DPRINTF_L4("ibnex", "\tcreate_ioc_portgid_prop");
2396
2397 node_data = ddi_get_parent_data(cdip);
2398 ASSERT(node_data);
2399
2400 prop_len = (ioc_info->ioc_nportgids != 0) ?
2401 (2 * ioc_info->ioc_nportgids) : 1;
2402 length = sizeof (uint64_t) * prop_len;
2403 port_gids = kmem_zalloc(length, KM_SLEEP);
2404
2405 for (ii = 0, jj = 0; ii < ioc_info->ioc_nportgids; ii++) {
2406 port_gids[jj++] = ioc_info->ioc_gid_list[ii].gid_dgid_hi;
2407 port_gids[jj++] = ioc_info->ioc_gid_list[ii].gid_dgid_lo;
2408 }
2409 if (ndi_prop_update_int64_array(DDI_DEV_T_NONE, cdip, "port-list",
2410 (int64_t *)port_gids, prop_len) != DDI_PROP_SUCCESS) {
2411 IBTF_DPRINTF_L2("ibnex",
2412 "\tcreate_ioc_portgid_prop: port-list create failed");
2413 kmem_free(port_gids, length);
2414 return (IBNEX_FAILURE);
2415 }
2416 if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "port-entries",
2417 ioc_info->ioc_nportgids) != DDI_PROP_SUCCESS) {
2418 IBTF_DPRINTF_L2("ibnex",
2419 "\tcreate_ioc_portgid_prop: port-entries create failed");
2420 kmem_free(port_gids, length);
2421 return (IBNEX_FAILURE);
2422 }
2423
2424 kmem_free(port_gids, length);
2425 return (IBNEX_SUCCESS);
2426 }
2427
2428
2429 /*
2430 * ibnex_create_ioc_srv_props()
2431 * Creates "service-name" and "service-id" properties
2432 * Returns IBNEX_SUCCESS/IBNEX_FAILURE
2433 */
2434 static int
2435 ibnex_create_ioc_srv_props(
2436 dev_info_t *cdip, ibdm_ioc_info_t *ioc_info)
2437 {
2438 int length, ii;
2439 uint64_t *srv_id;
2440 char *temp, *srv_names[IB_DM_MAX_IOCS_IN_IOU];
2441 ib_dm_ioc_ctrl_profile_t *profile = &ioc_info->ioc_profile;
2442 ibdm_srvents_info_t *srvents = ioc_info->ioc_serv;
2443
2444 IBTF_DPRINTF_L4("ibnex", "\tcreate_ioc_srv_props");
2445
2446 length = profile->ioc_service_entries * sizeof (ib_dm_srv_t);
2447 srv_id = kmem_zalloc(length, KM_SLEEP);
2448 temp = (char *)((char *)srv_id + (8 * profile->ioc_service_entries));
2449 for (ii = 0; ii < profile->ioc_service_entries; ii++) {
2450 srv_names[ii] = (char *)temp + (ii * IB_DM_MAX_SVC_NAME_LEN);
2451 }
2452
2453 for (ii = 0; ii < profile->ioc_service_entries; ii++) {
2454 srv_id[ii] = srvents[ii].se_attr.srv_id;
2455 bcopy(srvents[ii].se_attr.srv_name,
2456 srv_names[ii], (IB_DM_MAX_SVC_NAME_LEN - 1));
2457 IBTF_DPRINTF_L4("ibnex", "\tcreate_ioc_srv_props "
2458 "Service Names : %s", srv_names[ii]);
2459 IBTF_DPRINTF_L4("ibnex", "\tcreate_ioc_srv_props "
2460 "Service ID : %llX", srv_id[ii]);
2461 }
2462
2463 if (ndi_prop_update_int64_array(DDI_DEV_T_NONE, cdip,
2464 "service-id", (int64_t *)srv_id,
2465 profile->ioc_service_entries) != DDI_PROP_SUCCESS) {
2466 IBTF_DPRINTF_L2("ibnex",
2467 "\tcreate_ioc_srv_props: service-id create failed");
2468 kmem_free(srv_id, length);
2469 return (IBNEX_FAILURE);
2470 }
2471
2472 if (ndi_prop_update_string_array(DDI_DEV_T_NONE, cdip,
2473 "service-name", (char **)srv_names,
2474 profile->ioc_service_entries) != DDI_PROP_SUCCESS) {
2475 IBTF_DPRINTF_L2("ibnex",
2476 "\tcreate_ioc_srv_props: service-name create failed");
2477 kmem_free(srv_id, length);
2478 return (IBNEX_FAILURE);
2479 }
2480 kmem_free(srv_id, length);
2481 return (IBNEX_SUCCESS);
2482 }
2483
2484
2485 /*
2486 * ibnex_create_ioc_compatible_prop()
2487 * Creates "compatible" property values
2488 * Returns IBNEX_SUCCESS/IBNEX_FAILURE
2489 */
2490 static int
2491 ibnex_create_ioc_compatible_prop(
2492 dev_info_t *cdip, ib_dm_ioc_ctrl_profile_t *ioc_profile)
2493 {
2494 char *temp;
2495 int rval, ii;
2496 char *compatible[IBNEX_MAX_COMPAT_NAMES];
2497
2498 /*
2499 * Initialize the "compatible" property string as below:
2500 * Compatible Strings :
2501 * 1. ib.V<vid>P<pid>S<subsys vid>s<subsys id>v<ver>
2502 * 2. ib.V<vid>P<pid>S<subsys vid>s<subsys id>
2503 * 3. ib.V<vid>P<pid>v<ver>
2504 * 4. ib.V<vid>P<pid>
2505 * 5. ib.C<Class>c<Subclass>p<protocol>r<protocol ver>
2506 * 6. ib.C<Class>c<Subclass>p<protocol>
2507 *
2508 * Note:
2509 * All leading zeros must be present
2510 * All numeric values must specified in hex without prefix "0x"
2511 */
2512
2513 temp = kmem_alloc(IBNEX_MAX_COMPAT_PROP_SZ, KM_SLEEP);
2514 for (ii = 0; ii < IBNEX_MAX_COMPAT_NAMES; ii++)
2515 compatible[ii] = temp + (ii * IBNEX_MAX_COMPAT_LEN);
2516
2517 (void) snprintf(compatible[0], IBNEX_MAX_COMPAT_LEN,
2518 "ib.V%06xP%08xS%06xs%08xv%04x",
2519 ioc_profile->ioc_vendorid, ioc_profile->ioc_deviceid,
2520 ioc_profile->ioc_subsys_vendorid, ioc_profile->ioc_subsys_id,
2521 ioc_profile->ioc_device_ver);
2522
2523 (void) snprintf(compatible[1], IBNEX_MAX_COMPAT_LEN,
2524 "ib.V%06xP%08xS%06xs%08x",
2525 ioc_profile->ioc_vendorid, ioc_profile->ioc_deviceid,
2526 ioc_profile->ioc_subsys_vendorid, ioc_profile->ioc_subsys_id);
2527
2528 (void) snprintf(compatible[2], IBNEX_MAX_COMPAT_LEN,
2529 "ib.V%06xP%08xv%04x",
2530 ioc_profile->ioc_vendorid, ioc_profile->ioc_deviceid,
2531 ioc_profile->ioc_device_ver);
2532
2533 (void) snprintf(compatible[3], IBNEX_MAX_COMPAT_LEN,
2534 "ib.V%06xP%08x",
2535 ioc_profile->ioc_vendorid, ioc_profile->ioc_deviceid);
2536
2537 (void) snprintf(compatible[4], IBNEX_MAX_COMPAT_LEN,
2538 "ib.C%04xc%04xp%04xr%04x",
2539 ioc_profile->ioc_io_class, ioc_profile->ioc_io_subclass,
2540 ioc_profile->ioc_protocol, ioc_profile->ioc_protocol_ver);
2541
2542 (void) snprintf(compatible[5], IBNEX_MAX_COMPAT_LEN,
2543 "ib.C%04xc%04xp%04x",
2544 ioc_profile->ioc_io_class, ioc_profile->ioc_io_subclass,
2545 ioc_profile->ioc_protocol);
2546 for (ii = 0; ii < IBNEX_MAX_COMPAT_NAMES; ii++)
2547 IBTF_DPRINTF_L4("ibnex", "\tcompatible: %s", compatible[ii]);
2548
2549 /* Create the compatible property for child cdip */
2550 rval = ndi_prop_update_string_array(DDI_DEV_T_NONE, cdip,
2551 "compatible", (char **)compatible, IBNEX_MAX_COMPAT_NAMES);
2552
2553 if (rval != DDI_PROP_SUCCESS) {
2554 IBTF_DPRINTF_L2("ibnex", "\tcompatible prop_create failed");
2555 kmem_free(temp, IBNEX_MAX_COMPAT_PROP_SZ);
2556 return (IBNEX_FAILURE);
2557 }
2558
2559 kmem_free(temp, IBNEX_MAX_COMPAT_PROP_SZ);
2560 return (IBNEX_SUCCESS);
2561 }
2562
2563
2564 static void
2565 ibnex_ioc_node_cleanup()
2566 {
2567 ibnex_node_data_t *node, *delete;
2568
2569 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
2570 for (node = ibnex.ibnex_ioc_node_head; node; ) {
2571 delete = node;
2572 node = node->node_next;
2573 mutex_exit(&ibnex.ibnex_mutex);
2574 ibnex_delete_ioc_node_data(delete);
2575 mutex_enter(&ibnex.ibnex_mutex);
2576 }
2577 }
2578
2579 /*
2580 * ibnex_delete_ioc_node_data()
2581 * Delete IOC node from the list
2582 */
2583 static void
2584 ibnex_delete_ioc_node_data(ibnex_node_data_t *node)
2585 {
2586 IBTF_DPRINTF_L4("ibnex", "\tdelete_ioc_node_data:");
2587
2588 mutex_enter(&ibnex.ibnex_mutex);
2589 if ((node->node_next == NULL) && (node->node_prev == NULL)) {
2590 ASSERT(ibnex.ibnex_ioc_node_head == node);
2591 ibnex.ibnex_ioc_node_head = NULL;
2592 } else if (node->node_next == NULL)
2593 node->node_prev->node_next = NULL;
2594 else if (node->node_prev == NULL) {
2595 node->node_next->node_prev = NULL;
2596 ibnex.ibnex_ioc_node_head = node->node_next;
2597 } else {
2598 node->node_prev->node_next = node->node_next;
2599 node->node_next->node_prev = node->node_prev;
2600 }
2601 IBTF_DPRINTF_L4("ibnex", "\tdelete_ioc_node_data: head %p",
2602 ibnex.ibnex_ioc_node_head);
2603 mutex_exit(&ibnex.ibnex_mutex);
2604 kmem_free(node, sizeof (ibnex_node_data_t));
2605 }
2606
2607
2608 /*
2609 * ibnex_dm_callback()
2610 *
2611 * This routine is registered with the IBDM during IB nexus attach. It
2612 * is called by the IBDM module when it discovers
2613 * New HCA port
2614 * HCA port removal
2615 * New HCA added
2616 * HCA removed
2617 */
2618 void
2619 ibnex_dm_callback(void *arg, ibdm_events_t flag)
2620 {
2621 char hca_guid[IBNEX_HCAGUID_STRSZ];
2622 ibdm_ioc_info_t *ioc_list, *ioc;
2623 ibnex_node_data_t *node_data;
2624 dev_info_t *phci;
2625 ib_guid_t *guid;
2626
2627 IBTF_DPRINTF_L4("ibnex", "\tdm_callback: attr %p event %x", arg, flag);
2628
2629 switch (flag) {
2630 case IBDM_EVENT_HCA_ADDED:
2631 (void) snprintf(hca_guid, IBNEX_HCAGUID_STRSZ, "%llX",
2632 (*(longlong_t *)arg));
2633 /* Create a devctl minor node for the HCA's port */
2634 if (ddi_create_minor_node(ibnex.ibnex_dip, hca_guid, S_IFCHR,
2635 ddi_get_instance(ibnex.ibnex_dip),
2636 DDI_NT_IB_ATTACHMENT_POINT, 0) != DDI_SUCCESS) {
2637 IBTF_DPRINTF_L4("ibnex", "\tdm_callback: failed to "
2638 "create minor node for port w/ guid %s", hca_guid);
2639 }
2640
2641 guid = kmem_alloc(sizeof (ib_guid_t), KM_SLEEP);
2642 *guid = *(ib_guid_t *)arg;
2643 if (ddi_taskq_dispatch(ibnex.ibnex_taskq_id,
2644 ibnex_handle_hca_attach, guid, DDI_NOSLEEP)
2645 != DDI_SUCCESS) {
2646 kmem_free(guid, sizeof (ib_guid_t));
2647 IBTF_DPRINTF_L4("ibnex", "\tdm_callback: failed to "
2648 "dispatch HCA add event for guid %s", hca_guid);
2649 }
2650
2651 break;
2652
2653 case IBDM_EVENT_HCA_REMOVED:
2654 (void) snprintf(hca_guid, IBNEX_HCAGUID_STRSZ, "%llX",
2655 (*(longlong_t *)arg));
2656 ddi_remove_minor_node(ibnex.ibnex_dip, hca_guid);
2657 break;
2658
2659 case IBDM_EVENT_IOC_PROP_UPDATE:
2660 ioc = ioc_list = (ibdm_ioc_info_t *)arg;
2661 if (ioc_list == NULL)
2662 break;
2663
2664 mutex_enter(&ibnex.ibnex_mutex);
2665 while (ioc_list) {
2666 if ((node_data = ibnex_is_node_data_present(
2667 IBNEX_IOC_NODE, ioc_list, 0, 0)) != NULL &&
2668 node_data->node_dip != NULL) {
2669 ibnex_update_prop(node_data, ioc_list);
2670 }
2671 ioc_list = ioc_list->ioc_next;
2672 }
2673 mutex_exit(&ibnex.ibnex_mutex);
2674 ibdm_ibnex_free_ioc_list(ioc);
2675 break;
2676
2677 case IBDM_EVENT_PORT_UP:
2678 case IBDM_EVENT_PORT_PKEY_CHANGE:
2679 phci = ibtl_ibnex_hcaguid2dip(*(longlong_t *)arg);
2680 (void) devfs_clean(phci, NULL, 0);
2681 break;
2682 default:
2683 break;
2684
2685 }
2686 }
2687
2688
2689 /*
2690 * ibnex_get_node_and_dip_from_guid()
2691 *
2692 * Searches the linked list of the port nodes and returns the dip for
2693 * the of the Port / Node guid requested.
2694 * Returns NULL if not found
2695 */
2696 int
2697 ibnex_get_node_and_dip_from_guid(ib_guid_t guid, int index, ib_pkey_t pkey,
2698 ibnex_node_data_t **nodep, dev_info_t **dip)
2699 {
2700 int node_index;
2701 ib_guid_t node_guid;
2702 ib_pkey_t node_pkey;
2703 ibnex_node_data_t *node_data;
2704
2705 IBTF_DPRINTF_L4("ibnex",
2706 "\tget_node_and_dip_from_guid: guid = %llX", guid);
2707
2708 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
2709 /* Search for a matching entry in internal lists */
2710 node_data = ibnex.ibnex_port_node_head;
2711 while (node_data) {
2712 node_guid = node_data->node_data.port_node.port_guid;
2713 node_index = node_data->node_data.port_node.port_commsvc_idx;
2714 node_pkey = node_data->node_data.port_node.port_pkey;
2715 if ((node_guid == guid) && (index == node_index) &&
2716 (node_pkey == pkey)) {
2717 break;
2718 }
2719 node_data = node_data->node_next;
2720 }
2721
2722 /* matching found with a valid dip */
2723 if (node_data && node_data->node_dip) {
2724 *nodep = node_data;
2725 *dip = node_data->node_dip;
2726 return (IBNEX_SUCCESS);
2727 } else if (node_data && !node_data->node_dip) { /* dip is invalid */
2728 *nodep = node_data;
2729 *dip = NULL;
2730 return (IBNEX_SUCCESS);
2731 }
2732
2733 /* no match found */
2734 *nodep = NULL;
2735 *dip = NULL;
2736 return (IBNEX_FAILURE);
2737 }
2738
2739 /*
2740 * ibnex_get_dip_from_guid()
2741 *
2742 * Searches the linked list of the port nodes and returns the dip for
2743 * the of the Port / Node guid requested.
2744 * Returns NULL if not found
2745 */
2746 int
2747 ibnex_get_dip_from_guid(ib_guid_t guid, int index, ib_pkey_t pkey,
2748 dev_info_t **dip)
2749 {
2750 int node_index;
2751 ib_guid_t node_guid;
2752 ib_pkey_t node_pkey;
2753 ibnex_node_data_t *node_data;
2754
2755 IBTF_DPRINTF_L4("ibnex",
2756 "\tget_dip_from_guid: guid = %llX", guid);
2757
2758 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
2759 /* Search for a matching entry in internal lists */
2760 node_data = ibnex.ibnex_port_node_head;
2761 while (node_data) {
2762 node_guid = node_data->node_data.port_node.port_guid;
2763 node_index = node_data->node_data.port_node.port_commsvc_idx;
2764 node_pkey = node_data->node_data.port_node.port_pkey;
2765 if ((node_guid == guid) && (index == node_index) &&
2766 (node_pkey == pkey)) {
2767 break;
2768 }
2769 node_data = node_data->node_next;
2770 }
2771
2772 /* matching found with a valid dip */
2773 if (node_data && node_data->node_dip) {
2774 *dip = node_data->node_dip;
2775 return (IBNEX_SUCCESS);
2776 } else if (node_data && !node_data->node_dip) { /* dip is invalid */
2777 *dip = NULL;
2778 return (IBNEX_SUCCESS);
2779 }
2780
2781 /* no match found */
2782 *dip = NULL;
2783 return (IBNEX_FAILURE);
2784 }
2785
2786
2787 /*
2788 * ibnex_comm_svc_init()
2789 * Read the property and cache the values in the global
2790 * structure.
2791 * Check for max allowed length (4 bytes) of service name
2792 * (each element of the property)
2793 * Returns IBNEX_SUCCESS/IBNEX_FAILURE
2794 */
2795 static ibnex_rval_t
2796 ibnex_comm_svc_init(char *property, ibnex_node_type_t type)
2797 {
2798 int i, len, count;
2799 int ncomm_svcs;
2800 char **comm_svcp;
2801 char **servicep = NULL;
2802 uint_t nservices = 0;
2803 int *valid = NULL;
2804
2805 IBTF_DPRINTF_L4("ibnex", "\tcomm_svc_init : %s property, type = %x",
2806 property, type);
2807
2808 /* lookup the string array property */
2809 if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, ibnex.ibnex_dip,
2810 DDI_PROP_DONTPASS, property, &servicep, &nservices) !=
2811 DDI_PROP_SUCCESS) {
2812 IBTF_DPRINTF_L2("ibnex", "\t%s property undefined", property);
2813 return (IBNEX_SUCCESS);
2814 }
2815
2816 if (nservices)
2817 valid = kmem_zalloc(nservices * sizeof (int), KM_SLEEP);
2818
2819
2820 /* first read the file to get a count of valid service entries */
2821 for (ncomm_svcs = 0, count = 0; count < nservices; count++) {
2822 int j;
2823
2824 len = strlen(servicep[count]);
2825 /*
2826 * ib.conf has NULL strings for port-svc-list &
2827 * hca-svc-list, by default. Do not have L2 message
2828 * for these.
2829 */
2830 if (len == 1 || len > 4) {
2831 IBTF_DPRINTF_L2("ibnex", "\tcomm_svc_init : "
2832 "Service name %s for property %s invalid : "
2833 "length %d", servicep[count], property, len);
2834 continue;
2835 } else if (len == 0) {
2836 continue;
2837 }
2838 if (ibnex_unique_svcname(servicep[count]) != IBNEX_SUCCESS) {
2839 IBTF_DPRINTF_L2("ibnex", "\tcomm_svc_init : "
2840 "Service name %s invalid : Not unique",
2841 servicep[count]);
2842 continue;
2843 }
2844
2845 /*
2846 * ibnex_unique_svcname checks for uniqueness in service names
2847 * communication services fully initialized. Check uniqueness
2848 * in service names currently initialized.
2849 */
2850 for (j = 0; j < count; j++)
2851 if (valid[j] && strncmp(servicep[count],
2852 servicep[j], 4) == 0) {
2853 IBTF_DPRINTF_L2("ibnex", "\tcomm_svc_init : "
2854 "Service name %s invalid : Not unique",
2855 servicep[count]);
2856 continue;
2857 }
2858
2859 valid[count] = 1;
2860 ncomm_svcs++;
2861 }
2862
2863 /* if no valid entries found, bailout */
2864 if (nservices == 0 || ncomm_svcs == 0) {
2865 IBTF_DPRINTF_L4("ibnex", "\tNo %s entries found", property);
2866 ddi_prop_free(servicep); /* free the property */
2867 if (valid)
2868 kmem_free(valid, nservices * sizeof (int));
2869 return (IBNEX_SUCCESS);
2870 }
2871
2872 comm_svcp = kmem_zalloc((ncomm_svcs * sizeof (char *)), KM_SLEEP);
2873 if (type == IBNEX_PORT_COMMSVC_NODE) {
2874 ibnex.ibnex_comm_svc_names = comm_svcp;
2875 ibnex.ibnex_num_comm_svcs = ncomm_svcs;
2876 } else if (type == IBNEX_VPPA_COMMSVC_NODE) {
2877 ibnex.ibnex_vppa_comm_svc_names = comm_svcp;
2878 ibnex.ibnex_nvppa_comm_svcs = ncomm_svcs;
2879 } else if (type == IBNEX_HCASVC_COMMSVC_NODE) {
2880 ibnex.ibnex_hcasvc_comm_svc_names = comm_svcp;
2881 ibnex.ibnex_nhcasvc_comm_svcs = ncomm_svcs;
2882 }
2883
2884 /* copy the services into an array of strings */
2885 for (i = 0, count = 0; count < nservices; count++) {
2886 if (valid[count] == 0) /* Skip invalid ones */
2887 continue;
2888 comm_svcp[i] = kmem_alloc(len + 1, KM_SLEEP);
2889 (void) strcpy(comm_svcp[i], servicep[count]);
2890 IBTF_DPRINTF_L4("ibnex",
2891 "\t\tService [%d]: %s", i, comm_svcp[i]);
2892 ++i;
2893 }
2894 ddi_prop_free(servicep);
2895 kmem_free(valid, nservices * sizeof (int));
2896 return (IBNEX_SUCCESS);
2897 }
2898
2899
2900 /*
2901 * ibnex_comm_svc_fini()
2902 * Deallocate all the memory allocated for the communication
2903 * service arrays.
2904 */
2905 static void
2906 ibnex_comm_svc_fini()
2907 {
2908 int index;
2909
2910 for (index = 0; index < ibnex.ibnex_num_comm_svcs; index++) {
2911 kmem_free(ibnex.ibnex_comm_svc_names[index],
2912 (strlen(ibnex.ibnex_comm_svc_names[index]) + 1));
2913 }
2914 if (ibnex.ibnex_comm_svc_names) {
2915 kmem_free(ibnex.ibnex_comm_svc_names,
2916 ibnex.ibnex_num_comm_svcs * sizeof (char *));
2917 }
2918 for (index = 0; index < ibnex.ibnex_nvppa_comm_svcs; index++) {
2919 kmem_free(ibnex.ibnex_vppa_comm_svc_names[index],
2920 strlen(ibnex.ibnex_vppa_comm_svc_names[index]) +1);
2921 }
2922 if (ibnex.ibnex_vppa_comm_svc_names) {
2923 kmem_free(ibnex.ibnex_vppa_comm_svc_names,
2924 ibnex.ibnex_nvppa_comm_svcs * sizeof (char *));
2925 }
2926 for (index = 0; index < ibnex.ibnex_nhcasvc_comm_svcs; index++) {
2927 kmem_free(ibnex.ibnex_hcasvc_comm_svc_names[index],
2928 strlen(ibnex.ibnex_hcasvc_comm_svc_names[index]) +1);
2929 }
2930 if (ibnex.ibnex_hcasvc_comm_svc_names) {
2931 kmem_free(ibnex.ibnex_hcasvc_comm_svc_names,
2932 ibnex.ibnex_nhcasvc_comm_svcs * sizeof (char *));
2933 }
2934 ibnex.ibnex_comm_svc_names = NULL;
2935 ibnex.ibnex_num_comm_svcs = 0;
2936 ibnex.ibnex_vppa_comm_svc_names = NULL;
2937 ibnex.ibnex_nvppa_comm_svcs = 0;
2938 ibnex.ibnex_hcasvc_comm_svc_names = NULL;
2939 ibnex.ibnex_nhcasvc_comm_svcs = 0;
2940 }
2941
2942
2943 /*
2944 * ibnex_commsvc_initnode()
2945 * This routine is specific to port/VPPA node creation
2946 * Creates a device node for the comm service specified by commsvc_index
2947 * Creates all the device node properties
2948 * Allocates and initializes the node specific data
2949 * Binds the device driver of the device node
2950 * Returns "dev_info_t" of the child node or NULL in case of failure
2951 * Sets IBNEX_SUCCESS/IBNEX_FAILURE/IBNEX_BUSY in "rval" to reflect
2952 * if the operation was successful, failed or was not performed.
2953 */
2954 dev_info_t *
2955 ibnex_commsvc_initnode(dev_info_t *parent, ibdm_port_attr_t *port_attr,
2956 int index, int node_type, ib_pkey_t pkey, int *rval, int flag)
2957 {
2958 int ret;
2959 char *svcname;
2960 dev_info_t *cdip;
2961 ibnex_node_data_t *node_data;
2962 ibnex_port_node_t *port_node;
2963 char devname[MAXNAMELEN];
2964 int cdip_allocated = 0;
2965
2966 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
2967
2968 *rval = IBNEX_SUCCESS;
2969
2970 /*
2971 * prevent any races
2972 * we have seen this node_data and it has been initialized
2973 * Note that node_dip is already NULL if unconfigure is in
2974 * progress.
2975 */
2976 node_data = ibnex_is_node_data_present(node_type, (void *)port_attr,
2977 index, pkey);
2978
2979 /*
2980 * If this node has been explicity unconfigured by cfgadm, then it can
2981 * be configured back again only by cfgadm configure.
2982 */
2983 if (node_data && (node_data->node_ap_state ==
2984 IBNEX_NODE_AP_UNCONFIGURED)) {
2985 *rval = IBNEX_FAILURE;
2986 return (NULL);
2987 }
2988
2989 if (node_data && node_data->node_dip) {
2990 /*
2991 * Return NULL if another configure
2992 * operation is in progress
2993 */
2994 if (node_data->node_state == IBNEX_CFGADM_CONFIGURING) {
2995 *rval = IBNEX_BUSY;
2996 return (NULL);
2997 } else {
2998 return (node_data->node_dip);
2999 }
3000 } else if (node_data == NULL) {
3001 /* allocate a new ibnex_node_data_t */
3002 node_data = ibnex_init_child_nodedata(node_type, port_attr,
3003 index, pkey);
3004 node_data->node_data.port_node.port_pdip = parent;
3005 }
3006
3007 /*
3008 * Return NULL if another unconfigure operation is in progress
3009 */
3010 if (node_data->node_state == IBNEX_CFGADM_UNCONFIGURING) {
3011 *rval = IBNEX_BUSY;
3012 return (NULL);
3013 }
3014
3015 ASSERT(node_data->node_state != IBNEX_CFGADM_CONFIGURED);
3016 node_data->node_state = IBNEX_CFGADM_CONFIGURING;
3017
3018 switch (node_type) {
3019 case IBNEX_VPPA_COMMSVC_NODE :
3020 svcname = ibnex.ibnex_vppa_comm_svc_names[index];
3021 port_node = &node_data->node_data.port_node;
3022 (void) snprintf(devname, MAXNAMELEN, "%s@%x,%x,%s",
3023 IBNEX_IBPORT_CNAME, port_node->port_num,
3024 port_node->port_pkey, svcname);
3025 break;
3026 case IBNEX_HCASVC_COMMSVC_NODE :
3027 svcname = ibnex.ibnex_hcasvc_comm_svc_names[index];
3028 port_node = &node_data->node_data.port_node;
3029 (void) snprintf(devname, MAXNAMELEN, "%s@%x,0,%s",
3030 IBNEX_IBPORT_CNAME, port_node->port_num, svcname);
3031 break;
3032 case IBNEX_PORT_COMMSVC_NODE :
3033 svcname = ibnex.ibnex_comm_svc_names[index];
3034 port_node = &node_data->node_data.port_node;
3035 (void) snprintf(devname, MAXNAMELEN, "%s@%x,0,%s",
3036 IBNEX_IBPORT_CNAME, port_node->port_num, svcname);
3037 break;
3038 default :
3039 IBTF_DPRINTF_L2("ibnex", "\tcommsvc_initnode:"
3040 "\tInvalid Node type");
3041 *rval = IBNEX_FAILURE;
3042 ibnex_delete_port_node_data(node_data);
3043 return (NULL);
3044 }
3045
3046 if ((cdip = ndi_devi_findchild(parent, devname)) != NULL) {
3047 if (i_ddi_devi_attached(cdip)) {
3048 node_data->node_dip = cdip;
3049 node_data->node_data.port_node.port_pdip = parent;
3050 node_data->node_state = IBNEX_CFGADM_CONFIGURED;
3051 ddi_set_parent_data(cdip, node_data);
3052 IBTF_DPRINTF_L4("ibnex", "\tcommsvc_initnode: found "
3053 "attached cdip 0x%p for devname %s", cdip, devname);
3054 return (cdip);
3055 }
3056 } else {
3057 ndi_devi_alloc_sleep(parent,
3058 IBNEX_IBPORT_CNAME, (pnode_t)DEVI_SID_NODEID, &cdip);
3059 cdip_allocated = 1;
3060 }
3061
3062 node_data->node_dip = cdip;
3063 ddi_set_parent_data(cdip, node_data);
3064 mutex_exit(&ibnex.ibnex_mutex);
3065
3066
3067 if (ibnex_create_port_node_prop(port_attr, cdip, svcname, pkey) ==
3068 IBNEX_SUCCESS) {
3069 if (flag == IBNEX_DEVFS_ENUMERATE)
3070 ret = ndi_devi_bind_driver(cdip, 0);
3071 else
3072 ret = ndi_devi_online(cdip, 0);
3073 if (ret == NDI_SUCCESS) {
3074 mutex_enter(&ibnex.ibnex_mutex);
3075 node_data->node_state = IBNEX_CFGADM_CONFIGURED;
3076 node_data->node_data.port_node.port_pdip = parent;
3077 return (cdip);
3078 }
3079 IBTF_DPRINTF_L4("ibnex", "\tcommsvc_initnode: BIND/ONLINE "
3080 "of cdip 0x%p for devname %s and flag %d failed", cdip,
3081 devname, flag);
3082 }
3083
3084 *rval = IBNEX_FAILURE;
3085 node_data->node_dip = NULL;
3086 ddi_set_parent_data(cdip, NULL);
3087 if (cdip_allocated)
3088 (void) ndi_devi_free(cdip);
3089 mutex_enter(&ibnex.ibnex_mutex);
3090 IBTF_DPRINTF_L4("ibnex", "\tcommsvc_initnode: failure exit");
3091 return (NULL);
3092 }
3093
3094
3095 /*
3096 * ibnex_create_port_node_prop()
3097 * Returns IBNEX_SUCCESS/IBNEX_FAILURE
3098 */
3099 static int
3100 ibnex_create_port_node_prop(ibdm_port_attr_t *port_attr,
3101 dev_info_t *child_dip, char *srvname, ib_pkey_t pkey)
3102 {
3103 if (ibnex_create_port_compatible_prop(child_dip,
3104 srvname, port_attr) != DDI_PROP_SUCCESS) {
3105 IBTF_DPRINTF_L2("ibnex",
3106 "\tcreate_port_node_prop: compatible update failed");
3107 return (IBNEX_FAILURE);
3108 }
3109 if ((pkey != 0) && (ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
3110 "port-pkey", pkey) != DDI_PROP_SUCCESS)) {
3111 IBTF_DPRINTF_L2("ibnex",
3112 "\tcreate_port_node_prop: port-num update failed");
3113 return (IBNEX_FAILURE);
3114 }
3115
3116 /*
3117 * For HCA_SVC device nodes, port_num will be 0.
3118 * Do not create the "port-number" & "port-guid" properties.
3119 */
3120 if (port_attr->pa_port_num != 0) {
3121 if (ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
3122 "port-number", port_attr->pa_port_num) !=
3123 DDI_PROP_SUCCESS) {
3124 IBTF_DPRINTF_L2("ibnex",
3125 "\tcreate_port_node_prop: port-num update failed");
3126 return (IBNEX_FAILURE);
3127 }
3128 if (ndi_prop_update_int64(DDI_DEV_T_NONE, child_dip,
3129 "port-guid", port_attr->pa_port_guid) !=
3130 DDI_PROP_SUCCESS) {
3131 IBTF_DPRINTF_L2("ibnex",
3132 "\tcreate_port_node_prop: port-guid update failed");
3133 return (IBNEX_FAILURE);
3134 }
3135 } else {
3136 ibdm_hca_list_t *hca_list;
3137
3138 /*
3139 * HCA_SVC nodes require "num-ports" & "port-guids"
3140 * properties.
3141 *
3142 * To create the num-ports & port-guids attribute :
3143 * 1. Get HCA list (ibdm_ibnex_get_hca_info_by_guid)
3144 * 2. Form the array of port GUIDs.
3145 */
3146 if ((hca_list = ibdm_ibnex_get_hca_info_by_guid(
3147 port_attr->pa_hca_guid)) == NULL) {
3148 IBTF_DPRINTF_L2("ibnex",
3149 "\tcreate_port_node_prop: hca_info_by_guid failed");
3150 return (IBNEX_FAILURE);
3151 }
3152
3153 if (hca_list->hl_nports != 0) {
3154 ib_guid_t *port_guids;
3155 uint8_t portnum;
3156
3157 ASSERT(hca_list->hl_port_attr != NULL);
3158
3159 port_guids = kmem_zalloc(
3160 hca_list->hl_nports * sizeof (ib_guid_t),
3161 KM_SLEEP);
3162
3163 for (portnum = 0; portnum < hca_list->hl_nports;
3164 portnum++) {
3165 port_guids[portnum] = (hca_list->
3166 hl_port_attr[portnum]).pa_port_guid;
3167 }
3168
3169 if (ndi_prop_update_int64_array(DDI_DEV_T_NONE,
3170 child_dip, "port-guids", (int64_t *)port_guids,
3171 hca_list->hl_nports) != DDI_PROP_SUCCESS) {
3172 IBTF_DPRINTF_L2("ibnex",
3173 "\tcreate_port_node_prop: port-guids "
3174 "create failed");
3175 kmem_free(port_guids, hca_list->hl_nports *
3176 sizeof (ib_guid_t));
3177 ibdm_ibnex_free_hca_list(hca_list);
3178 return (IBNEX_FAILURE);
3179 }
3180 kmem_free(port_guids, hca_list->hl_nports *
3181 sizeof (ib_guid_t));
3182 }
3183
3184 if (ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
3185 "num-ports", hca_list->hl_nports) != DDI_PROP_SUCCESS) {
3186 IBTF_DPRINTF_L2("ibnex",
3187 "\tcreate_port_node_prop: num-ports update failed");
3188 ibdm_ibnex_free_hca_list(hca_list);
3189 return (IBNEX_FAILURE);
3190 }
3191 ibdm_ibnex_free_hca_list(hca_list);
3192 }
3193
3194 if (ndi_prop_update_int64(DDI_DEV_T_NONE, child_dip,
3195 "hca-guid", port_attr->pa_hca_guid) != DDI_PROP_SUCCESS) {
3196 IBTF_DPRINTF_L2("ibnex",
3197 "\tcreate_port_node_prop: hca-guid update failed");
3198 return (IBNEX_FAILURE);
3199 }
3200 if (ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
3201 "product-id", port_attr->pa_productid) != DDI_PROP_SUCCESS) {
3202 IBTF_DPRINTF_L2("ibnex",
3203 "\tcreate_port_node_prop: product-id update failed");
3204 return (IBNEX_FAILURE);
3205 }
3206 if (ndi_prop_update_int(DDI_DEV_T_NONE, child_dip,
3207 "vendor-id", port_attr->pa_vendorid) != DDI_PROP_SUCCESS) {
3208 IBTF_DPRINTF_L2("ibnex",
3209 "\tcreate_port_node_prop: vendor-id update failed");
3210 return (IBNEX_FAILURE);
3211 }
3212 if (ndi_prop_update_int(DDI_DEV_T_NONE, child_dip, "device-version",
3213 port_attr->pa_dev_version) != DDI_PROP_SUCCESS) {
3214 IBTF_DPRINTF_L2("ibnex",
3215 "\tcreate_port_node_prop: device-version update failed");
3216 return (IBNEX_FAILURE);
3217 }
3218 return (IBNEX_SUCCESS);
3219 }
3220
3221
3222 /*
3223 * ibnex_str2int()
3224 * Utility function that converts a string of length "len" to
3225 * integer.
3226 * Returns IBNEX_SUCCESS/IBNEX_FAILURE
3227 */
3228 int
3229 ibnex_str2int(char *c, int len, int *ret)
3230 {
3231 int intval = 0, ii;
3232
3233 IBTF_DPRINTF_L4("ibnex", "\tstr2int: Int string %s..", c);
3234 *ret = IBNEX_SUCCESS;
3235 for (ii = 0; ii < len; ii ++) {
3236 if ((c[ii] >= '0') && (c[ii] <= '9'))
3237 intval = intval * 10 +c[ii] - '0';
3238 else {
3239 IBTF_DPRINTF_L2("ibnex",
3240 "\tstr2int: Invalid integer string %s..", c);
3241 *ret = IBNEX_FAILURE;
3242 break;
3243 }
3244 }
3245
3246 return (intval);
3247 }
3248
3249
3250 /*
3251 * ibnex_str2hex()
3252 * Utility functions that converts a string of length "len" to
3253 * hex value. Note. This function does not handle strings which
3254 * string length more than 8 bytes.
3255 *
3256 */
3257 uint64_t
3258 ibnex_str2hex(char *c, int len, int *ret)
3259 {
3260 uint64_t hex = 0, ii;
3261
3262 *ret = IBNEX_SUCCESS;
3263 for (ii = 0; ii < len; ii ++) {
3264 hex = (ii == 0) ? hex : (hex << 4);
3265 if ((c[ii] >= '0') && (c[ii] <= '9'))
3266 hex |= c[ii] - '0';
3267 else if ((c[ii] >= 'a') && (c[ii] <= 'f'))
3268 hex |= c[ii] - 'a' + 10;
3269 else if ((c[ii] >= 'A') && (c[ii] <= 'F'))
3270 hex |= c[ii] - 'A' + 10;
3271 else {
3272 IBTF_DPRINTF_L2("ibnex",
3273 "\tstr2hex: Invalid integer string");
3274 *ret = IBNEX_FAILURE;
3275 break;
3276 }
3277 }
3278
3279 return (hex);
3280 }
3281
3282
3283 /*
3284 * ibnex_create_port_compatible_prop()
3285 * Creates 'Compatibility' property for port / HCA_SVC device nodes
3286 * Returns IBNEX_SUCCESS/IBNEX_FAILURE
3287 */
3288 static int
3289 ibnex_create_port_compatible_prop(dev_info_t *child_dip,
3290 char *comm_svcp, ibdm_port_attr_t *port_attr)
3291 {
3292 int rval, i;
3293 char *temp;
3294 char *compatible[IBNEX_MAX_IBPORT_COMPAT_NAMES];
3295
3296 IBTF_DPRINTF_L4("ibnex", "\tcreate_port_compatible_prop: Begin");
3297 /*
3298 * Initialize the "compatible" property string as below:
3299 * Compatible Strings :
3300 * 1. ib.V<vid>P<pid>v<revision>.<service name>.
3301 * 2. ib.V<vid>P<pid>.<service name>.
3302 * 3. ib.<service name>
3303 * Leading zeros must be present
3304 */
3305 temp = kmem_alloc(IBNEX_MAX_IBPORT_COMPAT_PROP_SZ, KM_SLEEP);
3306 for (i = 0; i < IBNEX_MAX_IBPORT_COMPAT_NAMES; i++) {
3307 compatible[i] = temp + (i * IBNEX_MAX_COMPAT_LEN);
3308 }
3309
3310 (void) snprintf(compatible[0], IBNEX_MAX_COMPAT_LEN,
3311 "ib.V%06xP%08xv%04x.%s",
3312 port_attr->pa_vendorid, port_attr->pa_productid,
3313 port_attr->pa_dev_version, comm_svcp);
3314 (void) snprintf(compatible[1], IBNEX_MAX_COMPAT_LEN,
3315 "ib.V%06xP%08x.%s",
3316 port_attr->pa_vendorid, port_attr->pa_productid,
3317 comm_svcp);
3318 (void) snprintf(compatible[2], IBNEX_MAX_COMPAT_LEN,
3319 "ib.%s", comm_svcp);
3320
3321 for (i = 0; i < IBNEX_MAX_IBPORT_COMPAT_NAMES; i++)
3322 IBTF_DPRINTF_L4("ibnex", "\tcompatible: %s", compatible[i]);
3323
3324 rval = ndi_prop_update_string_array(DDI_DEV_T_NONE, child_dip,
3325 "compatible", (char **)compatible, IBNEX_MAX_IBPORT_COMPAT_NAMES);
3326
3327 if (rval != DDI_PROP_SUCCESS) {
3328 kmem_free(temp, IBNEX_MAX_IBPORT_COMPAT_PROP_SZ);
3329 return (IBNEX_FAILURE);
3330 }
3331 kmem_free(temp, IBNEX_MAX_IBPORT_COMPAT_PROP_SZ);
3332 return (IBNEX_SUCCESS);
3333 }
3334
3335
3336 /*
3337 * ibnex_delete_port_node_data()
3338 * Delete the parent private node data from the linked list
3339 * Deallocate the memory of the port/ioc attributes
3340 * Deallocate the memory of the node data
3341 */
3342 static void
3343 ibnex_delete_port_node_data(ibnex_node_data_t *node)
3344 {
3345 if ((node->node_next == NULL) && (node->node_prev == NULL))
3346 ibnex.ibnex_port_node_head = NULL;
3347 else if (node->node_next == NULL)
3348 node->node_prev->node_next = NULL;
3349 else if (node->node_prev == NULL) {
3350 node->node_next->node_prev = NULL;
3351 ibnex.ibnex_port_node_head = node->node_next;
3352 } else {
3353 node->node_prev->node_next = node->node_next;
3354 node->node_next->node_prev = node->node_prev;
3355 }
3356 kmem_free(node, sizeof (ibnex_node_data_t));
3357 }
3358
3359
3360 /*
3361 * ibnex_is_node_data_present()
3362 * Checks whether ibnex_node_t is created already
3363 * Returns ibnex_node_data_t if found, otherwise NULL
3364 */
3365 static ibnex_node_data_t *
3366 ibnex_is_node_data_present(ibnex_node_type_t node_type, void *attr,
3367 int index, ib_pkey_t pkey)
3368 {
3369 ibnex_node_data_t *nodep;
3370 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
3371 if (node_type == IBNEX_IOC_NODE) {
3372 ibdm_ioc_info_t *ioc_infop = (ibdm_ioc_info_t *)attr;
3373
3374 for (nodep = ibnex.ibnex_ioc_node_head; nodep != NULL;
3375 nodep = nodep->node_next) {
3376 if (nodep->node_data.ioc_node.ioc_guid ==
3377 ioc_infop->ioc_profile.ioc_guid) {
3378 return (nodep);
3379 }
3380 }
3381
3382 } else if (node_type == IBNEX_PSEUDO_NODE) {
3383 for (nodep = ibnex.ibnex_pseudo_node_head; nodep;
3384 nodep = nodep->node_next)
3385 if (strcmp(nodep->node_data.pseudo_node.
3386 pseudo_node_addr, (char *)attr) == 0)
3387 return (nodep);
3388
3389 } else {
3390 ibdm_port_attr_t *pattrp = (ibdm_port_attr_t *)attr;
3391
3392 for (nodep = ibnex.ibnex_port_node_head; nodep != NULL;
3393 nodep = nodep->node_next) {
3394 if ((nodep->node_data.port_node.port_guid ==
3395 pattrp->pa_port_guid) &&
3396 (nodep->node_data.port_node.port_commsvc_idx ==
3397 index) &&
3398 (nodep->node_data.port_node.port_pkey == pkey)) {
3399 return (nodep);
3400 }
3401 }
3402 }
3403 return (NULL);
3404 }
3405
3406 /*
3407 * ibnex_lookup_unit_address_prop:
3408 *
3409 * If property with name is found, return its value
3410 * otherwise return NULL.
3411 */
3412 static char *
3413 ibnex_lookup_named_prop(ddi_prop_t *head, char *name)
3414 {
3415 ddi_prop_t *propp;
3416
3417 /* Search the list of properties for name */
3418 for (propp = head; propp != NULL; propp = propp->prop_next) {
3419 if (strcmp(propp->prop_name, name) != 0)
3420 continue;
3421 /* named property should be valid and have a value */
3422 if (propp->prop_len <= 1)
3423 break;
3424 return ((char *)propp->prop_val);
3425 }
3426
3427 return ((char *)0);
3428 }
3429
3430
3431 /*
3432 * ibnex_pseudo_initnodes()
3433 * This routine is specific to pseudo node information handling
3434 * Creates a ibnex_node_data_t all pseudo nodes children of ibnex
3435 */
3436 void
3437 ibnex_pseudo_initnodes()
3438 {
3439 int pnam_len, len;
3440 ibnex_node_data_t *nodep;
3441 struct hwc_spec *list, *spec;
3442 char *node_addr, *temp, *unit_addr;
3443 char *node_type;
3444
3445 IBTF_DPRINTF_L4("ibnex", "\tpseudo_initnodes");
3446
3447 mutex_enter(&ibnex.ibnex_mutex);
3448 /*
3449 * get a list of all "pseudo" children of "ib".
3450 * for these children initialize/allocate an internal
3451 * ibnex_node_data_t.
3452 */
3453 list = hwc_get_child_spec(ibnex.ibnex_dip, (major_t)-1);
3454 for (spec = list; spec != NULL; spec = spec->hwc_next) {
3455 if (spec->hwc_devi_sys_prop_ptr == NULL)
3456 continue;
3457
3458 /* Check "ib-node-type" property for IOC .conf */
3459 node_type = ibnex_lookup_named_prop(
3460 spec->hwc_devi_sys_prop_ptr, "ib-node-type");
3461
3462 /* "unit-address" property should be present */
3463 temp = ibnex_lookup_named_prop(
3464 spec->hwc_devi_sys_prop_ptr, "unit-address");
3465 if (temp == NULL)
3466 continue;
3467
3468 pnam_len = strlen(spec->hwc_devi_name) + strlen(temp) + 2;
3469
3470 node_addr = kmem_zalloc(pnam_len, KM_SLEEP);
3471
3472 (void) snprintf(node_addr,
3473 pnam_len, "%s,%s", spec->hwc_devi_name, temp);
3474
3475 nodep = ibnex_is_node_data_present(
3476 IBNEX_PSEUDO_NODE, (void *)node_addr, 0, 0);
3477
3478 if (nodep) {
3479 kmem_free(node_addr, pnam_len);
3480 continue;
3481 }
3482
3483 nodep = ibnex_init_child_nodedata(IBNEX_PSEUDO_NODE,
3484 (void *)spec->hwc_devi_name, 0, 0);
3485
3486 nodep->node_data.pseudo_node.pseudo_node_addr = node_addr;
3487 (void) snprintf(nodep->node_data.
3488 pseudo_node.pseudo_node_addr, pnam_len, "%s", node_addr);
3489
3490 len = strlen(temp) + 1;
3491 unit_addr = (char *)kmem_alloc(len, KM_SLEEP);
3492 nodep->node_data.pseudo_node.pseudo_unit_addr = unit_addr;
3493 (void) snprintf(unit_addr, len, "%s", temp);
3494 nodep->node_data.pseudo_node.pseudo_unit_addr_len = len;
3495
3496 if (node_type && strcmp(node_type, "merge") == 0)
3497 nodep->node_data.pseudo_node.pseudo_merge_node = 1;
3498
3499 IBTF_DPRINTF_L3("ibnex", "\tpseudo_initnodes: unit addr = %s"
3500 " : drv name = %s", unit_addr, spec->hwc_devi_name);
3501 }
3502 hwc_free_spec_list(list);
3503 mutex_exit(&ibnex.ibnex_mutex);
3504 }
3505
3506
3507 /*
3508 * ibnex_init_child_nodedata()
3509 *
3510 * Allocate memory for the parent private data for device node
3511 * Initializes the parent private child device node data.
3512 * Returns pointer to the parent private data
3513 */
3514 static ibnex_node_data_t *
3515 ibnex_init_child_nodedata(ibnex_node_type_t node_type, void *attr, int index,
3516 ib_pkey_t pkey)
3517 {
3518 char *devi_name;
3519 ibdm_ioc_info_t *ioc_info;
3520 ibnex_ioc_node_t *ioc_node;
3521 ibnex_node_data_t *node_data;
3522 ib_dm_ioc_ctrl_profile_t *ioc_profile;
3523
3524 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
3525
3526 node_data = kmem_zalloc(sizeof (ibnex_node_data_t), KM_SLEEP);
3527 node_data->node_ap_state = IBNEX_NODE_AP_CONFIGURED;
3528 node_data->node_state = IBNEX_CFGADM_CONFIGURING;
3529 node_data->node_type = node_type;
3530
3531 if (node_type == IBNEX_IOC_NODE) {
3532 ioc_info = (ibdm_ioc_info_t *)attr;
3533 ioc_profile = &ioc_info->ioc_profile;
3534 ioc_node = &node_data->node_data.ioc_node;
3535
3536 ioc_node->iou_guid = ioc_info->ioc_iou_guid;
3537 ioc_node->ioc_guid = ioc_profile->ioc_guid;
3538 (void) strncpy(ioc_node->ioc_id_string,
3539 (char *)ioc_profile->ioc_id_string,
3540 IB_DM_IOC_ID_STRING_LEN);
3541 ioc_node->ioc_ngids = ioc_info->ioc_nportgids;
3542
3543 node_data->node_next = ibnex.ibnex_ioc_node_head;
3544 node_data->node_prev = NULL;
3545 if (ibnex.ibnex_ioc_node_head)
3546 ibnex.ibnex_ioc_node_head->node_prev = node_data;
3547 ibnex.ibnex_ioc_node_head = node_data;
3548 } else if (node_type == IBNEX_PSEUDO_NODE) {
3549 devi_name = (char *)attr;
3550 node_data->node_data.pseudo_node.pseudo_devi_name =
3551 kmem_zalloc(strlen(devi_name) + 1, KM_SLEEP);
3552 (void) strncpy(node_data->node_data.pseudo_node.
3553 pseudo_devi_name, devi_name, strlen(devi_name));
3554 node_data->node_next = ibnex.ibnex_pseudo_node_head;
3555 node_data->node_prev = NULL;
3556 if (ibnex.ibnex_pseudo_node_head)
3557 ibnex.ibnex_pseudo_node_head->node_prev = node_data;
3558 ibnex.ibnex_pseudo_node_head = node_data;
3559 } else {
3560 node_data->node_data.port_node.port_hcaguid =
3561 ((ibdm_port_attr_t *)attr)->pa_hca_guid;
3562 node_data->node_data.port_node.port_guid =
3563 ((ibdm_port_attr_t *)attr)->pa_port_guid;
3564 node_data->node_data.port_node.port_num =
3565 ((ibdm_port_attr_t *)attr)->pa_port_num;
3566 node_data->node_data.port_node.port_commsvc_idx = index;
3567 node_data->node_data.port_node.port_pkey = pkey;
3568
3569 node_data->node_next = ibnex.ibnex_port_node_head;
3570 node_data->node_prev = NULL;
3571 if (ibnex.ibnex_port_node_head)
3572 ibnex.ibnex_port_node_head->node_prev = node_data;
3573 ibnex.ibnex_port_node_head = node_data;
3574 }
3575 return (node_data);
3576 }
3577
3578 static int
3579 ibnex_get_eventcookie(dev_info_t *dip, dev_info_t *rdip,
3580 char *eventname, ddi_eventcookie_t *cookie)
3581 {
3582 int rc;
3583
3584
3585 IBTF_DPRINTF_L4("ibnex", "ibnex_get_eventcookie(%p, %p, %s, 0x%X)",
3586 dip, rdip, eventname, cookie);
3587
3588 rc = ndi_event_retrieve_cookie(ibnex.ibnex_ndi_event_hdl,
3589 rdip, eventname, cookie, NDI_EVENT_NOPASS);
3590 if (rc == NDI_SUCCESS) {
3591 mutex_enter(&ibnex.ibnex_mutex);
3592 ibnex.ibnex_prop_update_evt_cookie = *cookie;
3593 mutex_exit(&ibnex.ibnex_mutex);
3594 }
3595
3596 return (rc);
3597 }
3598
3599 static int
3600 ibnex_add_eventcall(dev_info_t *dip, dev_info_t *rdip,
3601 ddi_eventcookie_t cookie, void (*callback)(dev_info_t *dip,
3602 ddi_eventcookie_t cookie, void *arg, void *bus_impldata),
3603 void *arg, ddi_callback_id_t *cb_id)
3604 {
3605 IBTF_DPRINTF_L4("ibnex",
3606 "ibnex_add_eventcall(%p, %p, 0x%X, %p, %p, %p)",
3607 dip, rdip, cookie, callback, arg, cb_id);
3608
3609 return (ndi_event_add_callback(ibnex.ibnex_ndi_event_hdl,
3610 rdip, cookie, callback, arg, NDI_SLEEP, cb_id));
3611 }
3612
3613 static int
3614 ibnex_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id)
3615 {
3616 IBTF_DPRINTF_L4("ibnex", "ibnex_remove_eventcall(%p, 0x%X)",
3617 dip, cb_id);
3618
3619 return (ndi_event_remove_callback(ibnex.ibnex_ndi_event_hdl,
3620 cb_id));
3621 }
3622
3623 static int
3624 ibnex_post_event(dev_info_t *dip, dev_info_t *rdip,
3625 ddi_eventcookie_t cookie, void *bus_impldata)
3626 {
3627 IBTF_DPRINTF_L4("ibnex", "ibnex_post_event(%p, %p, 0x%X, %p)",
3628 dip, rdip, cookie, bus_impldata);
3629
3630 return (ndi_event_run_callbacks(ibnex.ibnex_ndi_event_hdl, rdip,
3631 cookie, bus_impldata));
3632 }
3633
3634 /*
3635 * ibnex_reprobe_ioc_dev()
3636 *
3637 * This could be called as a result of ibt_reprobe_dev request or
3638 * cfgadm command. The function is called from a taskq in case of
3639 * ibt_reprobe_dev and from user context for cfgadm command.
3640 *
3641 * This function reprobes the properties for one IOC dip.
3642 *
3643 * node_reprobe_state should be set before calling this function.
3644 */
3645 void
3646 ibnex_reprobe_ioc_dev(void *arg)
3647 {
3648 dev_info_t *dip = (dev_info_t *)arg;
3649 ibnex_node_data_t *node_data;
3650 ibnex_ioc_node_t *ioc_data;
3651 ibdm_ioc_info_t *ioc_info;
3652
3653 /* ASSERT(NO_LOCKS_HELD); */
3654 ASSERT(dip != NULL);
3655
3656 node_data = ddi_get_parent_data(dip);
3657 ASSERT(node_data);
3658
3659 if (node_data->node_dip == NULL) {
3660 IBTF_DPRINTF_L4("ibnex", "reprobe for unconfigured dip");
3661 mutex_enter(&ibnex.ibnex_mutex);
3662 ibnex_wakeup_reprobe_ioc(node_data, 0);
3663 mutex_exit(&ibnex.ibnex_mutex);
3664 return;
3665 }
3666 ioc_data = &(node_data->node_data.ioc_node);
3667
3668 /* Reprobe the IOC */
3669 ioc_info = ibdm_ibnex_probe_ioc(ioc_data->iou_guid, ioc_data->ioc_guid,
3670 1);
3671 if (ioc_info == NULL) {
3672 IBTF_DPRINTF_L2("ibnex", "Null ioc_info from reprobe");
3673 mutex_enter(&ibnex.ibnex_mutex);
3674 ibnex_wakeup_reprobe_ioc(node_data, 1);
3675 mutex_exit(&ibnex.ibnex_mutex);
3676 return;
3677 }
3678
3679 mutex_enter(&ibnex.ibnex_mutex);
3680 if (node_data->node_dip)
3681 ibnex_update_prop(node_data, ioc_info);
3682 ibnex_wakeup_reprobe_ioc(node_data, 0);
3683 mutex_exit(&ibnex.ibnex_mutex);
3684
3685 ibdm_ibnex_free_ioc_list(ioc_info);
3686 }
3687
3688 /*
3689 * ibnex_reprobe_all()
3690 *
3691 * This could be called as a result of cfgadm command. The function
3692 * is called from user context.
3693 *
3694 * This function reprobes the properties for all IOC dips.
3695 *
3696 * ibnex_reprobe_state should be set before calling this function.
3697 */
3698 void
3699 ibnex_reprobe_ioc_all()
3700 {
3701 ibnex_node_data_t *node_data;
3702 ibdm_ioc_info_t *ioc_info_list, *ioc;
3703
3704 /* ASSERT(NO_LOCKS_HELD); */
3705
3706 /* Sweep the fabric */
3707 ioc = ioc_info_list = ibdm_ibnex_get_ioc_list(
3708 IBDM_IBNEX_REPROBE_ALL);
3709 if (ioc_info_list == NULL) {
3710 mutex_enter(&ibnex.ibnex_mutex);
3711 ibnex_wakeup_reprobe_all();
3712 mutex_exit(&ibnex.ibnex_mutex);
3713 return;
3714 }
3715
3716 mutex_enter(&ibnex.ibnex_mutex);
3717 while (ioc_info_list) {
3718 if ((node_data = ibnex_is_node_data_present(IBNEX_IOC_NODE,
3719 ioc_info_list, 0, 0)) != NULL &&
3720 node_data->node_dip != NULL) {
3721 ibnex_update_prop(node_data, ioc_info_list);
3722 }
3723 ioc_info_list = ioc_info_list->ioc_next;
3724 }
3725 ibnex_wakeup_reprobe_all();
3726 mutex_exit(&ibnex.ibnex_mutex);
3727
3728 ibdm_ibnex_free_ioc_list(ioc);
3729 }
3730
3731 /*
3732 * Update the properties, if it has modified and notify IBTF client.
3733 */
3734 static void
3735 ibnex_update_prop(ibnex_node_data_t *node_data, ibdm_ioc_info_t *ioc_info)
3736 {
3737 ibt_prop_update_payload_t evt_data;
3738 dev_info_t *dip = node_data->node_dip;
3739 ddi_eventcookie_t evt_cookie;
3740 ibnex_ioc_node_t *ioc;
3741
3742 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
3743
3744 ASSERT(dip != NULL);
3745
3746 ioc = &node_data->node_data.ioc_node;
3747
3748 evt_data = ioc_info->ioc_info_updated;
3749 evt_cookie = ibnex.ibnex_prop_update_evt_cookie;
3750
3751 /*
3752 * For a disconnected IOC :
3753 * Store the ioc_profile for supplying cfgadm info
3754 * ibdm maintains no info of disconnected IOC
3755 *
3756 * For reconnected IOC :
3757 * ibdm has info of previous service entries
3758 * ioc_profile maintained by ibnexus is used to
3759 * update ib_srv_prop_updated.
3760 * Free the ibnex maintained ioc_profile
3761 */
3762 if (ioc_info->ioc_nportgids == 0) {
3763 IBTF_DPRINTF_L4("ibnex",
3764 "\tupdate_prop: IOC disconnected");
3765 ioc->ioc_profile = (ib_dm_ioc_ctrl_profile_t *)kmem_zalloc(
3766 sizeof (ib_dm_ioc_ctrl_profile_t), KM_SLEEP);
3767 bcopy(&ioc_info->ioc_profile, ioc->ioc_profile,
3768 sizeof (ib_dm_ioc_ctrl_profile_t));
3769
3770 ibnex.ibnex_num_disconnect_iocs++;
3771 } else if (ioc_info->ioc_nportgids != 0 && ioc->ioc_ngids == 0 &&
3772 ioc->ioc_profile != NULL) {
3773 IBTF_DPRINTF_L4("ibnex",
3774 "\tupdate_prop: IOC reconnected");
3775 if (ioc->ioc_profile->ioc_service_entries !=
3776 ioc_info->ioc_profile.ioc_service_entries)
3777 evt_data.ib_srv_prop_updated = 1;
3778
3779 ibnex.ibnex_num_disconnect_iocs--;
3780 kmem_free(ioc->ioc_profile, sizeof (ib_dm_ioc_ctrl_profile_t));
3781 ioc->ioc_profile = NULL;
3782 }
3783
3784 /* Update the properties that have changed */
3785 mutex_exit(&ibnex.ibnex_mutex);
3786 if (evt_data.ib_gid_prop_updated) {
3787 if (ibnex_create_ioc_portgid_prop(dip, ioc_info) !=
3788 IBNEX_SUCCESS) {
3789 mutex_enter(&ibnex.ibnex_mutex);
3790 return;
3791 }
3792 }
3793 if (evt_data.ib_srv_prop_updated) {
3794 if (ioc_info->ioc_profile.ioc_service_entries != 0 &&
3795 (ibnex_create_ioc_srv_props(dip, ioc_info) !=
3796 IBNEX_SUCCESS)) {
3797 mutex_enter(&ibnex.ibnex_mutex);
3798 return;
3799 } else if (ioc_info->ioc_profile.ioc_service_entries == 0) {
3800 (void) ndi_prop_remove(DDI_DEV_T_NONE, dip,
3801 "service-id");
3802 (void) ndi_prop_remove(DDI_DEV_T_NONE, dip,
3803 "service-name");
3804 }
3805 }
3806 mutex_enter(&ibnex.ibnex_mutex);
3807 ioc->ioc_ngids = ioc_info->ioc_nportgids;
3808
3809 /*
3810 * Post an event if :
3811 * 1. Properites have changed or NOTIFY_ALWAYS is set.
3812 * 2. child dip is configured and a valid cookie for
3813 * IB_PROP_UPDATE_EVENT.
3814 */
3815 if ((evt_data.ib_prop_updated != 0 ||
3816 (node_data->node_reprobe_state &
3817 IBNEX_NODE_REPROBE_NOTIFY_ALWAYS)) &&
3818 ((node_data->node_state == IBNEX_CFGADM_CONFIGURED) &&
3819 (evt_cookie != NULL))) {
3820 mutex_exit(&ibnex.ibnex_mutex);
3821
3822 if (ndi_post_event(ibnex.ibnex_dip, dip,
3823 evt_cookie, &evt_data) != NDI_SUCCESS)
3824 IBTF_DPRINTF_L2("ibnex",
3825 "\tndi_post_event failed\n");
3826
3827 mutex_enter(&ibnex.ibnex_mutex);
3828 }
3829
3830 /*
3831 * Cleanup node_reprobe_state, for ibt_reprobe_dev
3832 * requests, when reprobe all / node reprobe is in
3833 * progress. ibnex_reprobe_ioc_dev is not called
3834 * in this case.
3835 */
3836 if (node_data->node_reprobe_state ==
3837 IBNEX_NODE_REPROBE_NOTIFY_ALWAYS)
3838 ibnex_wakeup_reprobe_ioc(node_data, 0);
3839 }
3840
3841 static ibnex_rval_t
3842 ibnex_unique_svcname(char *svcname)
3843 {
3844 int i;
3845
3846 /* Check Port Services */
3847 for (i = 0; i < ibnex.ibnex_num_comm_svcs; i++)
3848 if (ibnex.ibnex_comm_svc_names[i] && strncmp(svcname,
3849 ibnex.ibnex_comm_svc_names[i], 4) == 0)
3850 return (IBNEX_FAILURE);
3851
3852 /* Check VPPA Services */
3853 for (i = 0; i < ibnex.ibnex_nvppa_comm_svcs; i++)
3854 if (ibnex.ibnex_vppa_comm_svc_names[i] && strncmp(svcname,
3855 ibnex.ibnex_vppa_comm_svc_names[i], 4) == 0)
3856 return (IBNEX_FAILURE);
3857
3858 /* Check HCA_SVC Services */
3859 for (i = 0; i < ibnex.ibnex_nhcasvc_comm_svcs; i++)
3860 if (ibnex.ibnex_hcasvc_comm_svc_names[i] && strncmp(svcname,
3861 ibnex.ibnex_hcasvc_comm_svc_names[i], 4) == 0)
3862 return (IBNEX_FAILURE);
3863
3864 return (IBNEX_SUCCESS);
3865 }
3866
3867 static void
3868 ibnex_handle_reprobe_dev(void *arg)
3869 {
3870 dev_info_t *dip = (dev_info_t *)arg;
3871 ibnex_node_data_t *node_data;
3872
3873 ASSERT(dip != NULL);
3874 node_data = ddi_get_parent_data(dip);
3875 ASSERT(node_data);
3876
3877 /*
3878 * Return success if:
3879 * 1. Reprobe for all nodes are in progress
3880 * 2. Reprobe for this node is in progress.
3881 * The reprobe in progress will complete eventually and
3882 * update the properties, if required.
3883 */
3884 mutex_enter(&ibnex.ibnex_mutex);
3885 if (ibnex.ibnex_reprobe_state != 0 ||
3886 node_data->node_reprobe_state != 0) {
3887 /*
3888 * Setting NOTIFY_ALWAYS to ensure that
3889 * DDI event is delivered always for
3890 * ibt_reprobe_dev
3891 */
3892 node_data->node_reprobe_state |=
3893 IBNEX_NODE_REPROBE_NOTIFY_ALWAYS;
3894 mutex_exit(&ibnex.ibnex_mutex);
3895 return;
3896 }
3897 node_data->node_reprobe_state =
3898 IBNEX_NODE_REPROBE_NOTIFY_ALWAYS;
3899 mutex_exit(&ibnex.ibnex_mutex);
3900 ibnex_reprobe_ioc_dev(arg);
3901 }
3902
3903
3904 /*
3905 * MPxIO pathmangement routines. Currently IB nexus does not support
3906 * any kind of pathmangement. So, just return success to make MPxIO
3907 * framework happy.
3908 */
3909 /*ARGSUSED*/
3910 static int
3911 ib_vhci_pi_init(dev_info_t *vdip, mdi_pathinfo_t *pip, int flag)
3912 {
3913 IBTF_DPRINTF_L4("ibnex", "\tpi_init: dip %p pip %p", vdip, pip);
3914 return (MDI_SUCCESS);
3915 }
3916
3917
3918 /*ARGSUSED*/
3919 static int
3920 ib_vhci_pi_uninit(dev_info_t *vdip, mdi_pathinfo_t *pip, int flag)
3921 {
3922 dev_info_t *cdip;
3923 ibnex_node_data_t *node_data;
3924 int clnt_num_pi;
3925 IBTF_DPRINTF_L4("ibnex", "\tpi_uninit: dip %p pip %p", vdip, pip);
3926
3927 if (pip == NULL)
3928 return (MDI_FAILURE);
3929 /*
3930 * Get the Client dev_info from the pathinfo.
3931 */
3932 cdip = mdi_pi_get_client(pip);
3933 if (cdip == NULL)
3934 return (MDI_FAILURE);
3935
3936 /*
3937 * How many PIs do we have from this cdip ?
3938 */
3939 clnt_num_pi = mdi_client_get_path_count(cdip);
3940
3941 /*
3942 * If this is the last PI that is being free'd ( called from
3943 * mdi_pi_free) we have to clean up the node data for the cdip since
3944 * the client would have been detached by mdi_devi_offline.
3945 */
3946 if (clnt_num_pi == 1) {
3947 node_data = ddi_get_parent_data(cdip);
3948 if (node_data == NULL)
3949 return (MDI_SUCCESS);
3950 if (node_data->node_dip == cdip) {
3951 node_data->node_dip = NULL;
3952 node_data->node_state = IBNEX_CFGADM_UNCONFIGURED;
3953 return (MDI_SUCCESS);
3954 }
3955 }
3956 return (MDI_SUCCESS);
3957 }
3958
3959
3960 /*ARGSUSED*/
3961 static int
3962 ib_vhci_pi_state_change(dev_info_t *vdip, mdi_pathinfo_t *pip,
3963 mdi_pathinfo_state_t state, uint32_t arg1, int arg2)
3964 {
3965 IBTF_DPRINTF_L4("ibnex",
3966 "\tpi_state_change: dip %p pip %p state %x", vdip, pip, state);
3967 return (MDI_SUCCESS);
3968 }
3969
3970
3971 /*ARGSUSED*/
3972 static int
3973 ib_vhci_failover(dev_info_t *dip1, dev_info_t *dip2, int arg)
3974 {
3975 return (MDI_SUCCESS);
3976 }
3977
3978
3979 static int
3980 ibnex_bus_power(dev_info_t *parent, void *impl_arg,
3981 pm_bus_power_op_t op, void *arg, void *result)
3982 {
3983
3984 int ret = DDI_SUCCESS;
3985
3986 IBTF_DPRINTF_L4("ibnex", "\tbus_power: begin: op = %d", op);
3987
3988 /*
3989 * Generic processing in MPxIO framework
3990 */
3991 ret = mdi_bus_power(parent, impl_arg, op, arg, result);
3992
3993 switch (ret) {
3994 case MDI_SUCCESS:
3995 ret = DDI_SUCCESS;
3996 break;
3997 case MDI_FAILURE:
3998 ret = DDI_FAILURE;
3999 break;
4000 default:
4001 break;
4002 }
4003
4004 return (ret);
4005 }
4006
4007
4008 /*
4009 * If enumerated as a child of IB Nexus / VHCI, call mdi_vhci_bus_config.
4010 * ndi_devi_enter is not held during this call. mdi_vhci_bus_config()
4011 * will have called ndi_busop_bus_config(), no need for the caller to call
4012 * ndi_busop_bus_config() again.
4013 *
4014 * If enumerated as a child of HCA device, this could be a case for
4015 * Sparc boot or device enumeration from PHCI, driven by MDI.
4016 * Hold parent lock (ndi_devi_enter). The caller will have to call
4017 * ndi_busop_bus_config() if this function returns SUCCESS.
4018 *
4019 * if the device name contains ":port", then it is the Sparc boot case.
4020 * Handle this as before.
4021 *
4022 * If the device name does *not* contain the ":port", then :
4023 * 1. ibdm to probe IOC
4024 * 2. Create a pathinfo only if the IOC is reachable from the parent dip.
4025 */
4026 int
4027 ibnex_ioc_bus_config_one(dev_info_t **pdipp, uint_t flag,
4028 ddi_bus_config_op_t op, void *devname, dev_info_t **child,
4029 int *need_bus_config)
4030 {
4031 int ret = DDI_FAILURE, circ;
4032 dev_info_t *pdip = *pdipp;
4033 ib_guid_t iou_guid, ioc_guid;
4034 char *ioc_guid_str;
4035
4036
4037 *need_bus_config = 1;
4038
4039 if (pdip == ibnex.ibnex_dip) {
4040 if (ibnex_devname_to_node_n_ioc_guids(
4041 (char *)devname, &iou_guid, &ioc_guid,
4042 &ioc_guid_str) != IBNEX_SUCCESS) {
4043 return (ret);
4044 }
4045 ret = mdi_vhci_bus_config(pdip, flag, op, devname, child,
4046 ioc_guid_str);
4047 kmem_free(ioc_guid_str, strlen(ioc_guid_str) + 1);
4048 if (ret == MDI_SUCCESS)
4049 *need_bus_config = 0;
4050 } else {
4051 mdi_devi_enter(pdip, &circ);
4052 if (strstr((char *)devname, ":port=") != NULL) {
4053 ret = ibnex_config_root_iocnode(pdip, devname);
4054 ASSERT(ibnex.ibnex_dip == NULL);
4055 *pdipp = ibnex.ibnex_dip;
4056 } else {
4057 ret = ibnex_config_ioc_node(devname, pdip);
4058 }
4059 mdi_devi_exit(pdip, circ);
4060 }
4061 return (ret);
4062 }
4063
4064 static int
4065 ibnex_is_merge_node(dev_info_t *child)
4066 {
4067 char *node;
4068 int ret = IBNEX_INVALID_NODE;
4069
4070 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, child,
4071 DDI_PROP_DONTPASS, "ib-node-type", &node) !=
4072 DDI_PROP_SUCCESS) {
4073 return (IBNEX_FAILURE);
4074 }
4075
4076 if (node != NULL && *node != 0) {
4077 if (strcmp(node, "merge") == 0)
4078 ret = IBNEX_SUCCESS;
4079 else {
4080 IBTF_DPRINTF_L4("ibnex",
4081 "\tis_merge_node: ib-node-type = %s", node);
4082 }
4083 }
4084
4085 ddi_prop_free(node);
4086 return (ret);
4087 }
4088
4089 /*
4090 * Checks if the dn_head for the driver has already
4091 * initialized by the prom tree.
4092 */
4093 void
4094 ibnex_hw_in_dev_tree(char *driver_name)
4095 {
4096 major_t major;
4097
4098 IBTF_DPRINTF_L4("ibnex", "\thw_in_dev_tree(%s)", driver_name);
4099
4100 if (devnamesp == NULL)
4101 return;
4102
4103 major = ddi_name_to_major(driver_name);
4104 if (major == -1)
4105 return;
4106
4107 if (devnamesp[major].dn_head != (dev_info_t *)NULL)
4108 ibnex_hw_status = IBNEX_HW_IN_DEVTREE;
4109 }
4110
4111 int
4112 ibnex_ioc_initnode_all_pi(ibdm_ioc_info_t *ioc_info)
4113 {
4114 ibdm_hca_list_t *hca_list;
4115 dev_info_t *hca_dip;
4116 int rc = IBNEX_FAILURE;
4117
4118 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
4119 /*
4120 * We return failure even if we fail for all HCAs
4121 */
4122 for (hca_list = ioc_info->ioc_hca_list; hca_list;
4123 hca_list = hca_list->hl_next) {
4124 hca_dip = ibtl_ibnex_hcaguid2dip(hca_list->hl_hca_guid);
4125 if (ibnex_ioc_config_from_pdip(ioc_info, hca_dip, 1) ==
4126 IBNEX_SUCCESS)
4127 rc = IBNEX_SUCCESS;
4128 }
4129 return (rc);
4130 }
4131
4132 static int
4133 ibnex_ioc_config_from_pdip(ibdm_ioc_info_t *ioc_info, dev_info_t *pdip,
4134 int pdip_reachable_checked)
4135 {
4136 ibnex_node_data_t *node_data;
4137 int create_pdip = 0;
4138 int rc = IBNEX_SUCCESS;
4139
4140
4141 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
4142 IBTF_DPRINTF_L4("ibnex",
4143 "/tioc_config_from_pdip(%p, %p, %d)", ioc_info, pdip,
4144 pdip_reachable_checked);
4145
4146 if (pdip_reachable_checked == 0) {
4147 if (ibnex_ioc_pi_reachable(ioc_info, pdip) == IBNEX_FAILURE) {
4148 IBTF_DPRINTF_L4("ibnex",
4149 "/tioc_config_from_pdip: ioc %p not reachable"
4150 "from %p", ioc_info, pdip);
4151 return (IBNEX_FAILURE);
4152 }
4153 }
4154
4155 node_data = ibnex_is_node_data_present(IBNEX_IOC_NODE,
4156 (void *)ioc_info, 0, 0);
4157
4158 if (node_data && node_data->node_ap_state ==
4159 IBNEX_NODE_AP_UNCONFIGURED) {
4160 IBTF_DPRINTF_L4("ibnex",
4161 "\tioc_config_from_pdip: Unconfigured node");
4162 return (IBNEX_FAILURE);
4163 }
4164
4165
4166 if (node_data == NULL) {
4167 ibnex_ioc_node_t *ioc;
4168
4169 create_pdip = 1;
4170
4171 node_data = ibnex_init_child_nodedata(IBNEX_IOC_NODE,
4172 ioc_info, 0, 0);
4173 ASSERT(node_data);
4174 ioc = &node_data->node_data.ioc_node;
4175 (void) snprintf(ioc->ioc_guid_str, IBNEX_IOC_GUID_LEN,
4176 "%llX",
4177 (longlong_t)ioc_info->ioc_profile.ioc_guid);
4178 (void) snprintf(ioc->ioc_phci_guid, IBNEX_PHCI_GUID_LEN,
4179 "%llX,%llX",
4180 (longlong_t)ioc_info->ioc_profile.ioc_guid,
4181 (longlong_t)ioc_info->ioc_iou_guid);
4182 } else if (ibnex_ioc_pi_exists(node_data, pdip) == IBNEX_FAILURE) {
4183 create_pdip = 1;
4184 }
4185
4186 if (create_pdip) {
4187 rc = ibnex_ioc_initnode_pdip(node_data, ioc_info, pdip);
4188 }
4189
4190 IBTF_DPRINTF_L4("ibnex", "\tioc_config_from_pdip ret %x",
4191 rc);
4192 return (rc);
4193 }
4194
4195 /*
4196 * This function checks if a pathinfo has already been created
4197 * for the HCA parent. The function returns SUCCESS if a pathinfo
4198 * has already been created, FAILURE if not.
4199 */
4200 static int
4201 ibnex_ioc_pi_exists(ibnex_node_data_t *node_data, dev_info_t *parent)
4202 {
4203 int rc;
4204 ibnex_ioc_node_t *ioc;
4205
4206 ioc = &node_data->node_data.ioc_node;
4207 if (mdi_pi_find(parent, (char *)ioc->ioc_guid_str,
4208 (char *)ioc->ioc_phci_guid) != NULL)
4209 rc = IBNEX_SUCCESS;
4210 else
4211 rc = IBNEX_FAILURE;
4212
4213 IBTF_DPRINTF_L4("ibnex", "\tioc_pi_created- client_guid %s, "
4214 "phci_guid %s, parent %p, rc %x",
4215 ioc->ioc_guid_str, ioc->ioc_phci_guid, parent, rc);
4216 return (rc);
4217 }
4218
4219 static int
4220 ibnex_ioc_pi_reachable(ibdm_ioc_info_t *ioc_info, dev_info_t *pdip)
4221 {
4222 ibdm_hca_list_t *hca_list;
4223 dev_info_t *hca_dip;
4224
4225 IBTF_DPRINTF_L4("ibnex", "\tioc_pi_reachable(%p, %p)",
4226 ioc_info, pdip);
4227 for (hca_list = ioc_info->ioc_hca_list; hca_list;
4228 hca_list = hca_list->hl_next) {
4229 hca_dip = ibtl_ibnex_hcaguid2dip(hca_list->hl_hca_guid);
4230 if (hca_dip == pdip) {
4231 IBTF_DPRINTF_L4("ibnex",
4232 "\tioc_pi_reachable FAILURE");
4233 return (IBNEX_SUCCESS);
4234 }
4235 }
4236
4237 IBTF_DPRINTF_L4("ibnex", "\tioc_pi_reachable FAILURE");
4238 return (IBNEX_FAILURE);
4239 }