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