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