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