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