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