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