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