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_SLAVEONLY: 909 case DDI_CTLOPS_AFFINITY: 910 case DDI_CTLOPS_POKE: 911 case DDI_CTLOPS_PEEK: 912 IBTF_DPRINTF_L2("ibnex", 913 "%s%d: invalid op (%d) from %s inst%d", 914 ddi_get_name(dip), ddi_get_instance(dip), 915 ctlop, ddi_get_name(rdip), ddi_get_instance(rdip)); 916 return (DDI_FAILURE); 917 918 /* 919 * Everything else (PTOB/BTOP/BTOPR/DVMAPAGESIZE requests) we 920 * pass up 921 */ 922 default: 923 return (ddi_ctlops(dip, rdip, ctlop, arg, result)); 924 } 925 } 926 927 928 /* 929 * ibnex_init_child() 930 * 931 * Initialize a child device node. This is called for the DDI_CTLOPS_INITCHILD 932 * entry. Function returns DDI_SUCCESS, DDI_FAILURE or DDI_NOT_WELL_FORMED. 933 */ 934 static int 935 ibnex_init_child(dev_info_t *child) 936 { 937 int ret; 938 char name[MAXNAMELEN]; 939 940 IBTF_DPRINTF_L4("ibnex", "\tinit_child: child = %p", child); 941 942 /* Handle Pseudo nodes of client children */ 943 if (ndi_dev_is_persistent_node(child) == 0) { 944 if (ibnex_name_pseudo_child(child, name) != DDI_SUCCESS) 945 return (DDI_FAILURE); 946 947 ddi_set_name_addr(child, name); 948 /* 949 * Merge the .conf node 950 */ 951 if (ndi_merge_node(child, 952 ibnex_name_child) == DDI_SUCCESS) { 953 ddi_set_name_addr(child, NULL); 954 return (DDI_FAILURE); 955 } 956 return (DDI_NOT_WELL_FORMED); 957 958 } 959 960 if ((ret = ibnex_name_child(child, name, 0)) != DDI_SUCCESS) 961 return (ret); 962 963 ddi_set_name_addr(child, name); 964 965 return (DDI_SUCCESS); 966 } 967 968 969 int 970 ibnex_name_pseudo_child(dev_info_t *child, char *name) 971 { 972 char **unit_addr; 973 uint_t n; 974 if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child, 975 DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) != 976 DDI_PROP_SUCCESS) { 977 cmn_err(CE_WARN, 978 "cannot find unit-address in %s.conf", 979 ddi_get_name(child)); 980 return (DDI_FAILURE); 981 } 982 if (n != 1 || *unit_addr == NULL || **unit_addr == 0) { 983 cmn_err(CE_WARN, "unit-address property in %s.conf" 984 " not well-formed", ddi_get_name(child)); 985 ddi_prop_free(unit_addr); 986 return (DDI_FAILURE); 987 } 988 (void) snprintf(name, MAXNAMELEN, "%s", *unit_addr); 989 ddi_prop_free(unit_addr); 990 return (DDI_SUCCESS); 991 } 992 993 994 /*ARGSUSED*/ 995 int 996 ibnex_name_child(dev_info_t *child, char *name, int flag) 997 { 998 ibnex_pseudo_node_t *pseudo; 999 ibnex_node_data_t *node_datap; 1000 ibnex_port_node_t *port_node; 1001 ibnex_ioc_node_t *ioc; 1002 1003 node_datap = ddi_get_parent_data(child); 1004 if (node_datap == NULL) { 1005 IBTF_DPRINTF_L2("ibnex", "\tname_child: Node data is NULL"); 1006 return (DDI_NOT_WELL_FORMED); 1007 } 1008 IBTF_DPRINTF_L4("ibnex", "\tname_sid_child: Node data %p" 1009 "Node type %x", node_datap, node_datap->node_type); 1010 switch (node_datap->node_type) { 1011 case IBNEX_PORT_COMMSVC_NODE: 1012 port_node = &node_datap->node_data.port_node; 1013 (void) snprintf(name, IBNEX_MAX_NODEADDR_SZ, "%x,0,%s", 1014 port_node->port_num, 1015 ibnex.ibnex_comm_svc_names[port_node->port_commsvc_idx]); 1016 break; 1017 case IBNEX_VPPA_COMMSVC_NODE: 1018 port_node = &node_datap->node_data.port_node; 1019 (void) snprintf(name, IBNEX_MAX_NODEADDR_SZ, "%x,%x,%s", 1020 port_node->port_num, port_node->port_pkey, ibnex. 1021 ibnex_vppa_comm_svc_names[port_node->port_commsvc_idx]); 1022 break; 1023 case IBNEX_HCASVC_COMMSVC_NODE: 1024 port_node = &node_datap->node_data.port_node; 1025 (void) snprintf(name, IBNEX_MAX_NODEADDR_SZ, "%x,0,%s", 1026 port_node->port_num, 1027 ibnex.ibnex_hcasvc_comm_svc_names[port_node-> 1028 port_commsvc_idx]); 1029 break; 1030 case IBNEX_IOC_NODE: 1031 ioc = &node_datap->node_data.ioc_node; 1032 (void) snprintf(name, IBNEX_MAX_NODEADDR_SZ, "%llX,%llX", 1033 (longlong_t)ioc->ioc_guid, (longlong_t)ioc->iou_guid); 1034 break; 1035 case IBNEX_PSEUDO_NODE: 1036 pseudo = &node_datap->node_data.pseudo_node; 1037 (void) snprintf(name, 1038 IBNEX_MAX_NODEADDR_SZ, pseudo->pseudo_unit_addr); 1039 break; 1040 default: 1041 IBTF_DPRINTF_L2("ibnex", "\name_child: Not well formed"); 1042 return (DDI_NOT_WELL_FORMED); 1043 } 1044 1045 return (DDI_SUCCESS); 1046 } 1047 1048 1049 /* 1050 * ibnex_bus_config() 1051 * 1052 * BUS_CONFIG_ONE: 1053 * Enumerate the exact instance of the driver. Use the device node name 1054 * to locate the exact instance. 1055 * Query IBDM to find whether the hardware exits for the instance of the 1056 * driver. If exists, create a device node and return NDI_SUCCESS. 1057 * 1058 * BUS_CONFIG_ALL: 1059 * Enumerate all the instances of all the possible children (seen before 1060 * and never seen before). 1061 * 1062 * BUS_CONFIG_DRIVER: 1063 * Enumerate all the instances of a particular driver. 1064 */ 1065 static int 1066 ibnex_bus_config(dev_info_t *parent, uint_t flag, 1067 ddi_bus_config_op_t op, void *devname, dev_info_t **child) 1068 { 1069 int ret = IBNEX_SUCCESS, len, circ; 1070 char *device_name, *cname = NULL, *caddr = NULL; 1071 char *srvname, nameaddr[MAXNAMELEN]; 1072 dev_info_t *cdip, *pdip = NULL; 1073 ibnex_node_data_t *node_data; 1074 ibnex_port_node_t *port_node; 1075 1076 ndi_devi_enter(parent, &circ); 1077 1078 switch (op) { 1079 case BUS_CONFIG_ONE: 1080 IBTF_DPRINTF_L4("ibnex", "\tbus_config: CONFIG_ONE"); 1081 1082 len = strlen((char *)devname) + 1; 1083 device_name = i_ddi_strdup(devname, KM_SLEEP); 1084 i_ddi_parse_name(device_name, &cname, &caddr, NULL); 1085 1086 if (caddr == NULL || (strlen(caddr) == 0)) { 1087 kmem_free(device_name, len); 1088 ndi_devi_exit(parent, circ); 1089 return (NDI_FAILURE); 1090 } 1091 1092 IBTF_DPRINTF_L4("ibnex", 1093 "\tbus_config: cname %s addr %s", cname, caddr); 1094 1095 cdip = ndi_devi_findchild(parent, device_name); 1096 if (cdip == NULL) { 1097 /* Node is not present */ 1098 if (strncmp(cname, IBNEX_IOC_CNAME, 3) == 0) { 1099 if (parent == ibnex.ibnex_dip) 1100 ret = ibnex_config_ioc_node(devname); 1101 else { 1102 ret = ibnex_config_root_iocnode( 1103 parent, devname); 1104 if (ibnex.ibnex_dip) 1105 pdip = ibnex.ibnex_dip; 1106 else 1107 ret = IBNEX_FAILURE; 1108 } 1109 } else if ((strncmp(cname, 1110 IBNEX_IBPORT_CNAME, 6) == 0) && 1111 (parent != ibnex.ibnex_dip)) { /* parent is HCA */ 1112 cdip = ibnex_config_port_node(parent, devname); 1113 if (cdip) 1114 ret = IBNEX_SUCCESS; 1115 else 1116 ret = IBNEX_FAILURE; 1117 /* Allows enumeration under PHCI */ 1118 flag |= NDI_MDI_FALLBACK; 1119 } else if (parent == ibnex.ibnex_dip) { 1120 /* 1121 * if not IOC or PORT device then always 1122 * assume a Pseudo child 1123 */ 1124 ret = IBNEX_SUCCESS; 1125 ibnex_pseudo_initnodes(); 1126 mutex_enter(&ibnex.ibnex_mutex); 1127 ret = ibnex_pseudo_config_one( 1128 NULL, cname, caddr); 1129 mutex_exit(&ibnex.ibnex_mutex); 1130 } else 1131 ret = IBNEX_FAILURE; 1132 } 1133 kmem_free(device_name, len); 1134 break; 1135 1136 case BUS_CONFIG_OBP_ARGS: 1137 cdip = ibnex_config_obp_args(parent, devname); 1138 if (cdip) { 1139 /* 1140 * Boot case. 1141 * Special handling because the "devname" 1142 * format for the enumerated device is 1143 * different. 1144 */ 1145 node_data = ddi_get_parent_data(cdip); 1146 port_node = &node_data->node_data.port_node; 1147 if (node_data->node_type == 1148 IBNEX_VPPA_COMMSVC_NODE) { 1149 srvname = 1150 ibnex.ibnex_vppa_comm_svc_names[ 1151 port_node->port_commsvc_idx]; 1152 (void) snprintf(nameaddr, MAXNAMELEN, 1153 "ibport@%x,%x,%s", 1154 port_node->port_num, 1155 port_node->port_pkey, srvname); 1156 } 1157 devname = (void *)nameaddr; 1158 } else { 1159 IBTF_DPRINTF_L2("ibnex", 1160 "\tbus_config: CONFIG_OBP_ARGS : invalid state!!"); 1161 1162 ret = IBNEX_FAILURE; 1163 } 1164 break; 1165 case BUS_CONFIG_ALL: 1166 IBTF_DPRINTF_L4("ibnex", "\tbus_config: CONFIG_ALL"); 1167 ibnex_config_all_children(parent); 1168 break; 1169 1170 case BUS_CONFIG_DRIVER: 1171 IBTF_DPRINTF_L4("ibnex", "\tbus_config: CONFIG_DRIVER"); 1172 ibnex_config_all_children(parent); 1173 break; 1174 1175 default: 1176 IBTF_DPRINTF_L4("ibnex", "\tbus_config: error"); 1177 ret = IBNEX_FAILURE; 1178 break; 1179 } 1180 ndi_devi_exit(parent, circ); 1181 if (ret == IBNEX_SUCCESS) { 1182 if (op == BUS_CONFIG_OBP_ARGS) 1183 op = BUS_CONFIG_ONE; 1184 1185 if (pdip == NULL) 1186 pdip = parent; 1187 1188 ret = ndi_busop_bus_config( 1189 pdip, flag, op, devname, child, 0); 1190 IBTF_DPRINTF_L4("ibnex", "\tbus_config:" 1191 "ndi_busop_bus_config : retval %d", ret); 1192 return (ret); 1193 } 1194 1195 IBTF_DPRINTF_L2("ibnex", "\tbus_config: Failure End"); 1196 return (NDI_FAILURE); 1197 } 1198 1199 1200 /* 1201 * ibnex_config_root_iocnode() 1202 * Configures one particular instance of the IOC driver. 1203 * Returns IBNEX_SUCCESS/IBNEX_FAILURE 1204 */ 1205 static int 1206 ibnex_config_root_iocnode(dev_info_t *parent, char *device_name) 1207 { 1208 int ret, port = 0, iter = 0; 1209 boolean_t displayed = B_FALSE; 1210 char *portstr; 1211 ib_guid_t hca_guid, iou_guid, ioc_guid; 1212 ibdm_ioc_info_t *ioc_info; 1213 ibdm_port_attr_t *port_attr; 1214 1215 IBTF_DPRINTF_L4("ibnex", 1216 "\tconfig_root_iocnode: name %s", device_name); 1217 1218 portstr = strstr(device_name, ":port="); 1219 if (portstr == NULL) { 1220 return (IBNEX_FAILURE); 1221 } 1222 1223 portstr[0] = 0; portstr++; 1224 if (ibnex_devname2port(portstr, &port)) { 1225 IBTF_DPRINTF_L4("ibnex", "\tconfig_root_iocnode: invalid port"); 1226 return (IBNEX_FAILURE); 1227 } 1228 1229 if (ibnex_devname_to_node_n_ioc_guids( 1230 device_name, &iou_guid, &ioc_guid) != IBNEX_SUCCESS) { 1231 return (IBNEX_FAILURE); 1232 } 1233 1234 (void) snprintf(device_name, (IBNEX_MAX_NODEADDR_SZ + 4), 1235 "ioc@%llX,%llX", (longlong_t)ioc_guid, (longlong_t)iou_guid); 1236 1237 hca_guid = ibtl_ibnex_hcadip2guid(parent); 1238 if ((port_attr = ibdm_ibnex_probe_hcaport(hca_guid, port)) == NULL) { 1239 IBTF_DPRINTF_L2("ibnex", 1240 "\tconfig_root_iocnode: Port does not exist"); 1241 return (IBNEX_FAILURE); 1242 } 1243 1244 /* Wait until "port is up" */ 1245 while (port_attr->pa_state != IBT_PORT_ACTIVE) { 1246 ibdm_ibnex_free_port_attr(port_attr); 1247 delay(drv_usectohz(10000)); 1248 if ((port_attr = ibdm_ibnex_probe_hcaport( 1249 hca_guid, port)) == NULL) { 1250 return (IBNEX_FAILURE); 1251 } 1252 1253 if (iter++ == 400) { 1254 if (displayed == B_FALSE) { 1255 cmn_err(CE_NOTE, "\tWaiting for Port %d " 1256 "initialization", port_attr->pa_port_num); 1257 displayed = B_TRUE; 1258 } 1259 } 1260 } 1261 ibdm_ibnex_free_port_attr(port_attr); 1262 IBTF_DPRINTF_L4("ibnex", "\tconfig_rootioc_node:" 1263 "Port is initialized"); 1264 1265 if ((ioc_info = ibdm_ibnex_probe_ioc(iou_guid, ioc_guid, 0)) == NULL) { 1266 ibdm_ibnex_free_ioc_list(ioc_info); 1267 return (IBNEX_FAILURE); 1268 } 1269 mutex_enter(&ibnex.ibnex_mutex); 1270 if (ibnex_is_ioc_present(ioc_guid) == IBNEX_SUCCESS) { 1271 IBTF_DPRINTF_L4("ibnex", "\tconfig_root_iocnode: IOC present"); 1272 ret = IBNEX_SUCCESS; 1273 } else 1274 ret = ibnex_ioc_initnode(ioc_info, IBNEX_DEVFS_ENUMERATE); 1275 mutex_exit(&ibnex.ibnex_mutex); 1276 ibdm_ibnex_free_ioc_list(ioc_info); 1277 return (ret); 1278 } 1279 1280 1281 static int 1282 ibnex_devname2port(char *portstr, int *port) 1283 { 1284 char *temp; 1285 int ret = IBNEX_FAILURE; 1286 1287 IBTF_DPRINTF_L4("ibnex", "\tdevname2port: Begin"); 1288 1289 temp = strchr(portstr, '='); 1290 if (temp != NULL) { 1291 temp++; 1292 *port = ibnex_str2int(temp, strlen(temp), &ret); 1293 } 1294 return (ret); 1295 } 1296 1297 1298 /* 1299 * ibnex_config_all_children() 1300 * Wait for lata SM initialization case before enumerating the nodes 1301 * Get list of HCA's and HCA port information 1302 * Create device device nodes and its node properties 1303 * for port nodes and VPPA nodes 1304 * Get list of all the IOC node information 1305 * Create device nodes and its properties for all the IOCs 1306 * if not created already 1307 * Bind drivers for all the newly created device nodes 1308 * Support Pseudo nodes enumerated using their .conf file 1309 */ 1310 static void 1311 ibnex_config_all_children(dev_info_t *parent) 1312 { 1313 int ii; 1314 time_t wait_time; 1315 ibdm_ioc_info_t *ioc_list, *ioc; 1316 ibdm_hca_list_t *hca_list; 1317 ib_guid_t hca_guid; 1318 1319 IBTF_DPRINTF_L4("ibnex", "\tconfig_all_children: Begin"); 1320 1321 if (parent != ibnex.ibnex_dip) { 1322 /* 1323 * Parent is a HCA node. Enumerate only children of 1324 * this HCA, port nodes, VPPA & HCA_SVC nodes 1325 */ 1326 hca_guid = ibtl_ibnex_hcadip2guid(parent); 1327 wait_time = ibdm_ibnex_get_waittime( 1328 hca_guid, &ibnex_port_settling_time); 1329 if (wait_time) { 1330 delay(drv_usectohz(wait_time * 1000000)); 1331 } 1332 hca_list = ibdm_ibnex_get_hca_info_by_guid(hca_guid); 1333 if (hca_list == NULL) 1334 return; 1335 ibnex_create_hcasvc_nodes(parent, hca_list->hl_hca_port_attr); 1336 for (ii = 0; ii < hca_list->hl_nports; ii++) { 1337 ibnex_create_port_nodes( 1338 parent, &hca_list->hl_port_attr[ii]); 1339 ibnex_create_vppa_nodes( 1340 parent, &hca_list->hl_port_attr[ii]); 1341 } 1342 ibdm_ibnex_free_hca_list(hca_list); 1343 } else { 1344 1345 ibnex_pseudo_initnodes(); 1346 1347 /* Parent is a IB nexus. Enumerate all the IOC's */ 1348 wait_time = ibdm_ibnex_get_waittime( 1349 0, &ibnex_port_settling_time); 1350 if (wait_time) 1351 delay(drv_usectohz(wait_time * 1000000)); 1352 1353 1354 ioc_list = ibdm_ibnex_get_ioc_list(IBDM_IBNEX_NORMAL_PROBE); 1355 ioc = ioc_list; 1356 1357 mutex_enter(&ibnex.ibnex_mutex); 1358 1359 while (ioc_list) { 1360 if (ibnex_is_ioc_present( 1361 ioc_list->ioc_profile.ioc_guid) != IBNEX_SUCCESS) { 1362 (void) ibnex_ioc_initnode(ioc_list, 1363 IBNEX_DEVFS_ENUMERATE); 1364 } 1365 ioc_list = ioc_list->ioc_next; 1366 } 1367 ibnex_config_pseudo_all(); 1368 mutex_exit(&ibnex.ibnex_mutex); 1369 ibdm_ibnex_free_ioc_list(ioc); 1370 } 1371 IBTF_DPRINTF_L4("ibnex", "\tconfig_all_children: End"); 1372 } 1373 1374 1375 /* 1376 * ibnex_create_port_nodes: 1377 * Creates a device node per each communication service defined 1378 * in the "port-commsvc-list" property per HCA port 1379 */ 1380 static void 1381 ibnex_create_port_nodes(dev_info_t *parent, ibdm_port_attr_t *port_attr) 1382 { 1383 int idx; 1384 dev_info_t *dip; 1385 int rval; 1386 1387 mutex_enter(&ibnex.ibnex_mutex); 1388 for (idx = 0; idx < ibnex.ibnex_num_comm_svcs; idx++) { 1389 rval = ibnex_get_dip_from_guid(port_attr->pa_port_guid, 1390 idx, 0, &dip); 1391 if (rval != IBNEX_SUCCESS) { 1392 (void) ibnex_commsvc_initnode(parent, port_attr, idx, 1393 IBNEX_PORT_COMMSVC_NODE, 0, &rval, 1394 IBNEX_DEVFS_ENUMERATE); 1395 } 1396 } 1397 mutex_exit(&ibnex.ibnex_mutex); 1398 } 1399 1400 1401 /* 1402 * ibnex_create_vppa_nodes: 1403 * Creates a device node per each communication service defined 1404 * in the "vppa-commsvc-list" property and per each PKEY that 1405 * this particular port supports and per HCA port 1406 */ 1407 static void 1408 ibnex_create_vppa_nodes(dev_info_t *parent, ibdm_port_attr_t *port_attr) 1409 { 1410 int idx, ii; 1411 int rval; 1412 ib_pkey_t pkey; 1413 dev_info_t *dip; 1414 1415 IBTF_DPRINTF_L4("ibnex", "\tcreate_vppa_nodes: Begin"); 1416 1417 mutex_enter(&ibnex.ibnex_mutex); 1418 if (port_attr->pa_state != IBT_PORT_ACTIVE) { 1419 IBTF_DPRINTF_L4("ibnex", "\tcreate_vppa_nodes: " 1420 "Port %d is down", port_attr->pa_port_num); 1421 mutex_exit(&ibnex.ibnex_mutex); 1422 return; 1423 } 1424 for (idx = 0; idx < ibnex.ibnex_nvppa_comm_svcs; idx++) { 1425 for (ii = 0; ii < port_attr->pa_npkeys; ii++) { 1426 pkey = port_attr->pa_pkey_tbl[ii].pt_pkey; 1427 1428 if (IBNEX_INVALID_PKEY(pkey)) { 1429 continue; 1430 } 1431 rval = ibnex_get_dip_from_guid( 1432 port_attr->pa_port_guid, idx, pkey, &dip); 1433 if (rval != IBNEX_SUCCESS) { 1434 (void) ibnex_commsvc_initnode(parent, port_attr, 1435 idx, IBNEX_VPPA_COMMSVC_NODE, 1436 pkey, &rval, IBNEX_CFGADM_ENUMERATE); 1437 IBTF_DPRINTF_L5("ibnex", "\tcreate_vppa_nodes: " 1438 "commsvc_initnode failed rval %x", rval); 1439 } 1440 } 1441 } 1442 mutex_exit(&ibnex.ibnex_mutex); 1443 } 1444 1445 1446 /* 1447 * ibnex_create_hcasvc_nodes: 1448 * Creates a device node per each communication service defined 1449 * in the "port-commsvc-list" property per HCA port 1450 */ 1451 static void 1452 ibnex_create_hcasvc_nodes(dev_info_t *parent, ibdm_port_attr_t *port_attr) 1453 { 1454 int idx; 1455 dev_info_t *dip; 1456 int rval; 1457 1458 mutex_enter(&ibnex.ibnex_mutex); 1459 for (idx = 0; idx < ibnex.ibnex_nhcasvc_comm_svcs; idx++) { 1460 rval = ibnex_get_dip_from_guid(port_attr->pa_port_guid, 1461 idx, 0, &dip); 1462 if (rval != IBNEX_SUCCESS) { 1463 (void) ibnex_commsvc_initnode(parent, port_attr, idx, 1464 IBNEX_HCASVC_COMMSVC_NODE, 0, &rval, 1465 IBNEX_DEVFS_ENUMERATE); 1466 IBTF_DPRINTF_L5("ibnex", "create_hcasvc_nodes: " 1467 "commsvc_initnode failed, rval %x", rval); 1468 } 1469 } 1470 mutex_exit(&ibnex.ibnex_mutex); 1471 } 1472 1473 /* 1474 * ibnex_is_ioc_present() 1475 * Returns IBNEX_SUCCESS if an entry found in the global linked list 1476 * Returns IBNEX_FAILURE, if no match found 1477 */ 1478 static int 1479 ibnex_is_ioc_present(ib_guid_t ioc_guid) 1480 { 1481 ibnex_node_data_t *head; 1482 ibnex_ioc_node_t *ioc; 1483 int ret = IBNEX_FAILURE; 1484 1485 IBTF_DPRINTF_L4("ibnex", "\tis_ioc_present: Begin"); 1486 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex)); 1487 1488 head = ibnex.ibnex_ioc_node_head; 1489 while (head) { 1490 ioc = &head->node_data.ioc_node; 1491 if (ioc->ioc_guid == ioc_guid) 1492 break; 1493 head = head->node_next; 1494 } 1495 if (head) 1496 ret = IBNEX_SUCCESS; 1497 1498 return (ret); 1499 } 1500 1501 1502 /* 1503 * ibnex_bus_unconfig() 1504 * 1505 * Unconfigure a particular device node or all instance of a device 1506 * driver device or all children of IBnex 1507 */ 1508 static int 1509 ibnex_bus_unconfig(dev_info_t *parent, 1510 uint_t flag, ddi_bus_config_op_t op, void *device_name) 1511 { 1512 return (ndi_busop_bus_unconfig(parent, flag, op, device_name)); 1513 } 1514 1515 1516 /* 1517 * ibnex_config_port_node() 1518 * 1519 * Configures a particular port / HCA node for a particular 1520 * communication service. 1521 * The format of the device_name is 1522 * ibport@<Port#>,<pkey>,<service name> 1523 * where pkey = 0 for port communication service nodes 1524 * Port# = 0 for HCA_SVC communication service nodes 1525 * Returns "dev_info_t" of the "child" node just created 1526 * NULL when failed to enumerate the child node 1527 */ 1528 static dev_info_t * 1529 ibnex_config_port_node(dev_info_t *parent, char *devname) 1530 { 1531 int ii, index; 1532 int rval; 1533 time_t wait_time; 1534 uint8_t port_num; 1535 ib_guid_t hca_guid, port_guid; 1536 ib_pkey_t pkey; 1537 dev_info_t *cdip; 1538 ibdm_port_attr_t *port_attr; 1539 ibdm_hca_list_t *hca_list; 1540 1541 IBTF_DPRINTF_L4("ibnex", "\tconfig_port_node: %s", devname); 1542 1543 if (ibnex_get_pkey_commsvc_index_portnum(devname, 1544 &index, &pkey, &port_num) != IBNEX_SUCCESS) { 1545 IBTF_DPRINTF_L2("ibnex", 1546 "\tconfig_port_node: Invalid Service Name"); 1547 return (NULL); 1548 } 1549 1550 hca_guid = ibtl_ibnex_hcadip2guid(parent); 1551 if (port_num == 0) { 1552 /* 1553 * Use the dummy port attribute for HCA node in hca_list 1554 * Note : pa_state is always IBT_PORT_ACTIVE. 1555 */ 1556 hca_list = ibdm_ibnex_get_hca_info_by_guid(hca_guid); 1557 ASSERT(hca_list != NULL); 1558 port_attr = hca_list->hl_hca_port_attr; 1559 } else { 1560 if ((port_attr = ibdm_ibnex_probe_hcaport( 1561 hca_guid, port_num)) == NULL) { 1562 IBTF_DPRINTF_L2("ibnex", 1563 "\tconfig_port_node: Port does not exist"); 1564 return (NULL); 1565 } 1566 1567 if (port_attr->pa_state != IBT_PORT_ACTIVE) { 1568 wait_time = ibdm_ibnex_get_waittime( 1569 hca_guid, &ibnex_port_settling_time); 1570 if (wait_time) { 1571 delay(drv_usectohz(wait_time * 1000000)); 1572 } 1573 ibdm_ibnex_free_port_attr(port_attr); 1574 if ((port_attr = ibdm_ibnex_probe_hcaport( 1575 hca_guid, port_num)) == NULL) { 1576 return (NULL); 1577 } 1578 } 1579 } 1580 1581 port_guid = port_attr->pa_port_guid; 1582 mutex_enter(&ibnex.ibnex_mutex); 1583 if ((rval = ibnex_get_dip_from_guid(port_guid, index, pkey, 1584 &cdip)) == IBNEX_SUCCESS) { 1585 IBTF_DPRINTF_L4("ibnex", "\tconfig_port_node: Node exists"); 1586 mutex_exit(&ibnex.ibnex_mutex); 1587 if (port_num != 0) 1588 ibdm_ibnex_free_port_attr(port_attr); 1589 else 1590 ibdm_ibnex_free_hca_list(hca_list); 1591 return (cdip); 1592 } 1593 1594 if (pkey == 0 && port_num != 0) { 1595 cdip = ibnex_commsvc_initnode(parent, 1596 port_attr, index, IBNEX_PORT_COMMSVC_NODE, pkey, &rval, 1597 IBNEX_DEVFS_ENUMERATE); 1598 IBTF_DPRINTF_L5("ibnex", 1599 "\t ibnex_commsvc_initnode rval %x", rval); 1600 } else if (pkey == 0 && port_num == 0) { 1601 cdip = ibnex_commsvc_initnode(parent, 1602 port_attr, index, IBNEX_HCASVC_COMMSVC_NODE, pkey, &rval, 1603 IBNEX_DEVFS_ENUMERATE); 1604 IBTF_DPRINTF_L5("ibnex", 1605 "\t ibnex_commsvc_initnode rval %x", rval); 1606 } else { 1607 if (port_attr->pa_state != IBT_PORT_ACTIVE) { 1608 IBTF_DPRINTF_L4("ibnex", "\tconfig_port_nodes: " 1609 "Port %d is down", port_attr->pa_port_num); 1610 ibdm_ibnex_free_port_attr(port_attr); 1611 mutex_exit(&ibnex.ibnex_mutex); 1612 return (NULL); 1613 } 1614 for (ii = 0; ii < port_attr->pa_npkeys; ii++) { 1615 if (pkey == port_attr->pa_pkey_tbl[ii].pt_pkey) { 1616 cdip = ibnex_commsvc_initnode(parent, port_attr, 1617 index, IBNEX_VPPA_COMMSVC_NODE, 1618 pkey, &rval, IBNEX_CFGADM_ENUMERATE); 1619 IBTF_DPRINTF_L5("ibnex", 1620 "\t ibnex_commsvc_initnode rval %x", rval); 1621 break; 1622 } 1623 } 1624 } 1625 mutex_exit(&ibnex.ibnex_mutex); 1626 if (port_num != 0) 1627 ibdm_ibnex_free_port_attr(port_attr); 1628 else 1629 ibdm_ibnex_free_hca_list(hca_list); 1630 return (cdip); 1631 } 1632 1633 1634 /* 1635 * ibnex_config_obp_args() 1636 * Configures a particular port node for a IP over IB communication 1637 * service. 1638 * The format of the input string "devname" is 1639 * port=x,pkey=y,protocol=ip,<wanboot options> 1640 * Thr format of the node name created here is 1641 * ibport@<Port#>,<pkey>,<service name> 1642 * where pkey = 0 for port communication service nodes 1643 * Returns "dev_info_t" of the "child" node just created 1644 * NULL when failed to enumerate the child node 1645 * 1646 */ 1647 static dev_info_t * 1648 ibnex_config_obp_args(dev_info_t *parent, char *devname) 1649 { 1650 int ii, index; 1651 int rval, iter = 0; 1652 char *temp; 1653 uint8_t port_num; 1654 ib_guid_t hca_guid, port_guid; 1655 ib_pkey_t pkey; 1656 dev_info_t *cdip; 1657 boolean_t displayed = B_FALSE; 1658 ibdm_port_attr_t *port_attr; 1659 1660 IBTF_DPRINTF_L4("ibnex", "\tconfig_obp_args: %s", devname); 1661 1662 /* Is this OBP node for IPoIB ? */ 1663 temp = devname; 1664 do { 1665 temp = strstr(temp, ",protocol=ip"); 1666 if (temp == NULL) 1667 break; 1668 1669 if (strlen(devname) > (int)((temp - devname) + 12)) { 1670 if (temp[12] == ',') 1671 break; 1672 } else { 1673 break; 1674 } 1675 temp++; 1676 } while (temp); 1677 1678 if (temp == NULL) 1679 return (NULL); 1680 if (ibnex_prom_devname_to_pkey_n_portnum( 1681 devname, &pkey, &port_num) != IBNEX_SUCCESS) { 1682 return (NULL); 1683 } 1684 for (index = 0; index < ibnex.ibnex_nvppa_comm_svcs; index++) { 1685 if (strcmp(ibnex.ibnex_vppa_comm_svc_names[index], 1686 "ipib") == 0) { 1687 break; 1688 } 1689 } 1690 1691 hca_guid = ibtl_ibnex_hcadip2guid(parent); 1692 if ((port_attr = ibdm_ibnex_probe_hcaport( 1693 hca_guid, port_num)) == NULL) { 1694 IBTF_DPRINTF_L2("ibnex", 1695 "\tconfig_port_node: Port does not exist"); 1696 return (NULL); 1697 } 1698 1699 /* Wait until "port is up" */ 1700 while (port_attr->pa_state != IBT_PORT_ACTIVE) { 1701 ibdm_ibnex_free_port_attr(port_attr); 1702 delay(drv_usectohz(10000)); 1703 if ((port_attr = ibdm_ibnex_probe_hcaport( 1704 hca_guid, port_num)) == NULL) { 1705 return (NULL); 1706 } 1707 if (iter++ == 400) { 1708 if (displayed == B_FALSE) { 1709 cmn_err(CE_NOTE, "\tWaiting for Port %d " 1710 "initialization", port_attr->pa_port_num); 1711 displayed = B_TRUE; 1712 } 1713 } 1714 } 1715 IBTF_DPRINTF_L4("ibnex", "\tPort is initialized"); 1716 1717 mutex_enter(&ibnex.ibnex_mutex); 1718 port_guid = port_attr->pa_port_guid; 1719 if ((rval = ibnex_get_dip_from_guid(port_guid, index, pkey, 1720 &cdip)) == IBNEX_SUCCESS) { 1721 IBTF_DPRINTF_L4("ibnex", "\tconfig_port_node: Node exists"); 1722 mutex_exit(&ibnex.ibnex_mutex); 1723 ibdm_ibnex_free_port_attr(port_attr); 1724 return (cdip); 1725 } 1726 for (ii = 0; ii < port_attr->pa_npkeys; ii++) { 1727 if (pkey == port_attr->pa_pkey_tbl[ii].pt_pkey) { 1728 cdip = ibnex_commsvc_initnode(parent, port_attr, 1729 index, IBNEX_VPPA_COMMSVC_NODE, pkey, &rval, 1730 IBNEX_CFGADM_ENUMERATE); 1731 IBTF_DPRINTF_L5("ibnex", 1732 "\t ibnex_commsvc_initnode rval %x", rval); 1733 break; 1734 } 1735 } 1736 mutex_exit(&ibnex.ibnex_mutex); 1737 1738 ibdm_ibnex_free_port_attr(port_attr); 1739 return (cdip); 1740 } 1741 1742 1743 /* 1744 * ibnex_prom_devname_to_pkey_n_portnum() 1745 * Parses the device node name and extracts "PKEY" and "port#" 1746 * Returns IBNEX_SUCCESS/IBNEX_FAILURE 1747 */ 1748 static int 1749 ibnex_prom_devname_to_pkey_n_portnum( 1750 char *devname, ib_pkey_t *pkey, uint8_t *port) 1751 { 1752 int ret = IBNEX_SUCCESS; 1753 char *tmp, *tmp1; 1754 1755 if ((tmp = strstr(devname, "port=")) != NULL) { 1756 if ((tmp = strchr(++tmp, '=')) != NULL) 1757 if ((tmp1 = strchr(++tmp, ',')) != NULL) 1758 *port = ibnex_str2int(tmp, (tmp1 - tmp), &ret); 1759 } else 1760 ret = IBNEX_FAILURE; 1761 1762 if ((ret == IBNEX_SUCCESS) && 1763 (tmp = strstr(devname, "pkey=")) != NULL) { 1764 if ((tmp = strchr(++tmp, '=')) != NULL) 1765 if ((tmp1 = strchr(++tmp, ',')) != NULL) 1766 *pkey = ibnex_str2hex(tmp, (tmp1 - tmp), &ret); 1767 } else 1768 ret = IBNEX_FAILURE; 1769 1770 return (ret); 1771 } 1772 1773 1774 /* 1775 * ibnex_get_pkey_commsvc_index_portnum() 1776 * Parses the device node name and extracts PKEY, communication 1777 * service index & Port #. 1778 * Returns IBNEX_SUCCESS/IBNEX_FAILURE 1779 */ 1780 static int 1781 ibnex_get_pkey_commsvc_index_portnum(char *device_name, int *index, 1782 ib_pkey_t *pkey, uint8_t *port_num) 1783 { 1784 char *srv, **service_name, *temp; 1785 int ii, ncommsvcs, ret; 1786 1787 if (ibnex_devname_to_portnum(device_name, port_num) != 1788 IBNEX_SUCCESS) { 1789 IBTF_DPRINTF_L2("ibnex", 1790 "\tget_pkey_commsvc_index_portnum: Invalid PortGuid"); 1791 return (NULL); 1792 } 1793 srv = strchr(device_name, ','); 1794 if (srv == 0) 1795 return (IBNEX_FAILURE); 1796 1797 srv++; 1798 temp = strchr(srv, ','); 1799 if (temp == 0) 1800 return (IBNEX_FAILURE); 1801 temp++; 1802 *pkey = ibnex_str2hex(srv, (temp - srv - 1), &ret); 1803 if (ret != IBNEX_SUCCESS) 1804 return (ret); 1805 1806 if (*pkey == 0 && *port_num != 0) { 1807 service_name = ibnex.ibnex_comm_svc_names; 1808 ncommsvcs = ibnex.ibnex_num_comm_svcs; 1809 } else if (*pkey == 0 && *port_num == 0) { 1810 service_name = ibnex.ibnex_hcasvc_comm_svc_names; 1811 ncommsvcs = ibnex.ibnex_nhcasvc_comm_svcs; 1812 } else { 1813 service_name = ibnex.ibnex_vppa_comm_svc_names; 1814 ncommsvcs = ibnex.ibnex_nvppa_comm_svcs; 1815 } 1816 1817 for (ii = 0; ii < ncommsvcs; ii++) { 1818 if (strcmp(service_name[ii], temp) == 0) { 1819 break; 1820 } 1821 } 1822 if (ii == ncommsvcs) 1823 return (IBNEX_FAILURE); 1824 1825 *index = ii; 1826 return (IBNEX_SUCCESS); 1827 } 1828 1829 1830 /* 1831 * ibnex_devname_to_portnum() 1832 * Get portguid from device name 1833 * Returns IBNEX_SUCCESS/IBNEX_FAILURE 1834 */ 1835 static int 1836 ibnex_devname_to_portnum(char *device_name, uint8_t *portnum) 1837 { 1838 int ret; 1839 char *temp1, *temp2; 1840 1841 temp1 = strchr(device_name, '@'); 1842 if (temp1 == NULL) { 1843 return (IBNEX_FAILURE); 1844 } 1845 temp2 = strchr(temp1, ','); 1846 if (temp2 == NULL) 1847 return (IBNEX_FAILURE); 1848 temp1++; 1849 *portnum = ibnex_str2hex(temp1, (temp2 - temp1), &ret); 1850 return (ret); 1851 } 1852 1853 1854 /* 1855 * ibnex_config_ioc_node() 1856 * Configures one particular instance of the IOC driver. 1857 * Returns IBNEX_SUCCESS/IBNEX_FAILURE 1858 */ 1859 static int 1860 ibnex_config_ioc_node(char *device_name) 1861 { 1862 int ret; 1863 time_t wait_time; 1864 ib_guid_t iou_guid, ioc_guid; 1865 ibdm_ioc_info_t *ioc_info; 1866 1867 IBTF_DPRINTF_L4("ibnex", "\tconfig_ioc_node: Begin"); 1868 1869 if (ibnex_devname_to_node_n_ioc_guids( 1870 device_name, &iou_guid, &ioc_guid) != IBNEX_SUCCESS) { 1871 return (IBNEX_FAILURE); 1872 } 1873 1874 wait_time = ibdm_ibnex_get_waittime(0, &ibnex_port_settling_time); 1875 if (wait_time) 1876 delay(drv_usectohz(wait_time * 1000000)); 1877 1878 if ((ioc_info = ibdm_ibnex_probe_ioc(iou_guid, ioc_guid, 0)) == 1879 NULL) { 1880 ibdm_ibnex_free_ioc_list(ioc_info); 1881 return (IBNEX_FAILURE); 1882 } 1883 mutex_enter(&ibnex.ibnex_mutex); 1884 if (ibnex_is_ioc_present(ioc_guid) == IBNEX_SUCCESS) { 1885 IBTF_DPRINTF_L4("ibnex", "\tconfig_ioc_node: IOC present"); 1886 ret = IBNEX_SUCCESS; 1887 } else 1888 ret = ibnex_ioc_initnode(ioc_info, IBNEX_DEVFS_ENUMERATE); 1889 mutex_exit(&ibnex.ibnex_mutex); 1890 ibdm_ibnex_free_ioc_list(ioc_info); 1891 return (ret); 1892 } 1893 1894 1895 /* 1896 * ibnex_devname_to_node_n_ioc_guids() 1897 * Get node guid and ioc guid from the device name 1898 * Format of the device node name is: 1899 * ioc@<IOC GUID>,<IOU GUID> 1900 * Returns IBNEX_SUCCESS/IBNEX_FAILURE 1901 */ 1902 static int 1903 ibnex_devname_to_node_n_ioc_guids( 1904 char *device_name, ib_guid_t *iou_guid, ib_guid_t *ioc_guid) 1905 { 1906 char *temp1, *temp; 1907 int len, ret; 1908 1909 IBTF_DPRINTF_L4("ibnex", "\tdevname_to_node_n_ioc_guids:" 1910 "Device Name %s", device_name); 1911 1912 if ((temp = strchr(device_name, '@')) == NULL) { 1913 return (IBNEX_FAILURE); 1914 } 1915 if ((temp1 = strchr(++temp, ',')) == NULL) { 1916 return (IBNEX_FAILURE); 1917 } 1918 *ioc_guid = ibnex_str2hex(temp, (temp1 - temp), &ret); 1919 if (ret == IBNEX_SUCCESS) { 1920 len = device_name + strlen(device_name) - ++temp1; 1921 *iou_guid = ibnex_str2hex(temp1, len, &ret); 1922 } 1923 return (ret); 1924 } 1925 1926 1927 /*ARGSUSED*/ 1928 /* 1929 * ibnex_ioc_initnode() 1930 * Allocate a pathinfo node for the IOC 1931 * Initialize the device node 1932 * Bind driver to the node 1933 * Update IBnex global data 1934 * Returns IBNEX_SUCCESS/IBNEX_FAILURE/IBNEX_BUSY 1935 */ 1936 int 1937 ibnex_ioc_initnode(ibdm_ioc_info_t *ioc_info, int flag) 1938 { 1939 int rval; 1940 ibnex_node_data_t *node_data; 1941 1942 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex)); 1943 1944 node_data = ibnex_is_node_data_present(IBNEX_IOC_NODE, 1945 (void *)ioc_info, 0, 0); 1946 1947 /* 1948 * prevent any races 1949 * we have seen this node_data and it has been initialized 1950 * Note that node_dip is already NULL if unconfigure is in 1951 * progress. 1952 */ 1953 if (node_data && node_data->node_dip) { 1954 return ((node_data->node_state == IBNEX_CFGADM_CONFIGURING) ? 1955 IBNEX_BUSY : IBNEX_SUCCESS); 1956 } else if (node_data == NULL) { 1957 node_data = ibnex_init_child_nodedata(IBNEX_IOC_NODE, 1958 ioc_info, 0, 0); 1959 } 1960 1961 /* 1962 * Return EBUSY if another configure/unconfigure 1963 * operation is in progress 1964 */ 1965 if (node_data->node_state == IBNEX_CFGADM_UNCONFIGURING) { 1966 return (IBNEX_BUSY); 1967 } 1968 1969 ASSERT(node_data->node_state != IBNEX_CFGADM_CONFIGURED); 1970 node_data->node_state = IBNEX_CFGADM_CONFIGURING; 1971 1972 1973 mutex_exit(&ibnex.ibnex_mutex); 1974 1975 rval = ibnex_ioc_create_pi(ioc_info, node_data); 1976 1977 mutex_enter(&ibnex.ibnex_mutex); 1978 if (rval == IBNEX_SUCCESS) 1979 node_data->node_state = IBNEX_CFGADM_CONFIGURED; 1980 1981 return (rval); 1982 } 1983 1984 1985 /* 1986 * ibnex_config_pseudo_all() 1987 * Configure all the pseudo nodes 1988 */ 1989 static void 1990 ibnex_config_pseudo_all(void) 1991 { 1992 ibnex_node_data_t *nodep; 1993 1994 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex)); 1995 1996 for (nodep = ibnex.ibnex_pseudo_node_head; 1997 nodep; nodep = nodep->node_next) { 1998 (void) ibnex_pseudo_config_one(nodep, NULL, NULL); 1999 } 2000 } 2001 2002 2003 /* 2004 * ibnex_pseudo_config_one() 2005 */ 2006 int 2007 ibnex_pseudo_config_one(ibnex_node_data_t *node_data, char *cname, char *caddr) 2008 { 2009 int rval, len; 2010 char *node_addr; 2011 2012 IBTF_DPRINTF_L4("ibnex", "\tpseudo_config_one:Begin"); 2013 2014 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex)); 2015 2016 if (node_data == NULL) { 2017 IBTF_DPRINTF_L4("ibnex", "\tpseudo_config_one:" 2018 "cname = %s caddr = %s", cname, caddr); 2019 2020 len = strlen(cname) + strlen(caddr) + 2; 2021 node_addr = (char *)kmem_alloc(len, KM_SLEEP); 2022 2023 (void) snprintf(node_addr, len, "%s,%s", cname, caddr); 2024 node_data = ibnex_is_node_data_present(IBNEX_PSEUDO_NODE, 2025 (void *)node_addr, 0, 0); 2026 kmem_free(node_addr, len); 2027 } 2028 2029 /* 2030 * prevent any races 2031 * we have seen this node_data and it has been initialized 2032 * Note that node_dip is already NULL if unconfigure is in 2033 * progress. 2034 */ 2035 if (node_data && node_data->node_dip) { 2036 return ((node_data->node_state == IBNEX_CFGADM_CONFIGURING) ? 2037 IBNEX_BUSY : IBNEX_SUCCESS); 2038 } else if (node_data == NULL) { 2039 IBTF_DPRINTF_L2("ibnex", "\tpseudo_config_one: Invalid node"); 2040 return (IBNEX_FAILURE); 2041 } 2042 2043 /* 2044 * Return EBUSY if another configure/unconfigure 2045 * operation is in progress 2046 */ 2047 if (node_data->node_state == IBNEX_CFGADM_UNCONFIGURING) { 2048 return (IBNEX_BUSY); 2049 } 2050 2051 if (node_data->node_state == IBNEX_CFGADM_CONFIGURED) 2052 return (IBNEX_SUCCESS); 2053 2054 /* 2055 * Prevent configuring pseudo nodes specifically unconfigured 2056 * by cfgadm. This is done by checking if this is a newly 2057 * created node, not yet configured by BUS_CONFIG or cfgadm 2058 */ 2059 if (node_data->node_data.pseudo_node.pseudo_new_node != 1) 2060 return (IBNEX_FAILURE); 2061 node_data->node_data.pseudo_node.pseudo_new_node = 0; 2062 2063 node_data->node_state = IBNEX_CFGADM_CONFIGURING; 2064 2065 mutex_exit(&ibnex.ibnex_mutex); 2066 rval = ibnex_pseudo_create_pi(node_data); 2067 mutex_enter(&ibnex.ibnex_mutex); 2068 2069 if (rval == IBNEX_SUCCESS) 2070 node_data->node_state = IBNEX_CFGADM_CONFIGURED; 2071 else { 2072 node_data->node_dip = NULL; 2073 node_data->node_state = IBNEX_CFGADM_UNCONFIGURED; 2074 node_data->node_data.pseudo_node.pseudo_new_node = 1; 2075 } 2076 2077 return (rval); 2078 } 2079 2080 2081 /* 2082 * ibnex_pseudo_create_pi() 2083 * Create a path info node for each pseudo entry 2084 */ 2085 int 2086 ibnex_pseudo_create_pi(ibnex_node_data_t *nodep) 2087 { 2088 mdi_pathinfo_t *pip; 2089 int rval, hcacnt; 2090 dev_info_t *hca_dip, *cdip = NULL; 2091 ibdm_hca_list_t *hca_list, *head; 2092 ibnex_pseudo_node_t *pseudo; 2093 2094 IBTF_DPRINTF_L4("ibnex", "\tibnex_pseudo_create_pi: %p", nodep); 2095 2096 pseudo = &nodep->node_data.pseudo_node; 2097 2098 ibdm_ibnex_get_hca_list(&hca_list, &hcacnt); 2099 2100 head = hca_list; 2101 2102 for (; hca_list != NULL; hca_list = hca_list->hl_next) { 2103 2104 hca_dip = ibtl_ibnex_hcaguid2dip(hca_list->hl_hca_guid); 2105 2106 rval = mdi_pi_alloc(hca_dip, 2107 pseudo->pseudo_devi_name, pseudo->pseudo_node_addr, 2108 pseudo->pseudo_node_addr, 0, &pip); 2109 2110 if (rval != MDI_SUCCESS) { 2111 (void) ibnex_offline_childdip(cdip); 2112 return (IBNEX_FAILURE); 2113 } 2114 cdip = mdi_pi_get_client(pip); 2115 2116 IBTF_DPRINTF_L4("ibnex", 2117 "\tpseudo_create_pi: New dip %p", cdip); 2118 2119 nodep->node_dip = cdip; 2120 ddi_set_parent_data(cdip, nodep); 2121 2122 rval = mdi_pi_online(pip, 0); 2123 2124 if (rval != MDI_SUCCESS) { 2125 ddi_set_parent_data(cdip, NULL); 2126 IBTF_DPRINTF_L2("ibnex", "\tpseudo_create_pi:" 2127 "mdi_pi_online: failed for pseudo dip %p," 2128 " rval %d", cdip, rval); 2129 (void) ibnex_offline_childdip(cdip); 2130 rval = IBNEX_FAILURE; 2131 break; 2132 } else 2133 rval = IBNEX_SUCCESS; 2134 } 2135 if (head) 2136 ibdm_ibnex_free_hca_list(head); 2137 return (rval); 2138 } 2139 2140 2141 /* 2142 * ibnex_ioc_create_pi() 2143 * Create a pathinfo node for the ioc node 2144 */ 2145 static int 2146 ibnex_ioc_create_pi(ibdm_ioc_info_t *ioc_info, ibnex_node_data_t *node_data) 2147 { 2148 char ioc_guid[33], iou_guid[33]; 2149 mdi_pathinfo_t *pip; 2150 int rval; 2151 dev_info_t *hca_dip, *cdip = NULL; 2152 int flag = 1; 2153 ibdm_hca_list_t *hca_list; 2154 2155 IBTF_DPRINTF_L4("ibnex", "\tibnex_ioc_create_pi Begin"); 2156 2157 (void) snprintf(ioc_guid, 33, "%llx", 2158 (longlong_t)ioc_info->ioc_profile.ioc_guid); 2159 (void) snprintf(iou_guid, 33, "%llx", 2160 (longlong_t)ioc_info->ioc_iou_guid); 2161 2162 hca_list = ioc_info->ioc_hca_list; 2163 2164 for (; hca_list != NULL; hca_list = hca_list->hl_next) { 2165 2166 hca_dip = ibtl_ibnex_hcaguid2dip(hca_list->hl_hca_guid); 2167 2168 IBTF_DPRINTF_L4("ibnex", "\tioc_create_pi " 2169 "hca guid %llx", hca_list->hl_hca_guid); 2170 2171 rval = mdi_pi_alloc(hca_dip, 2172 IBNEX_IOC_CNAME, ioc_guid, iou_guid, 0, &pip); 2173 if (rval != MDI_SUCCESS) { 2174 (void) ibnex_offline_childdip(cdip); 2175 return (IBNEX_FAILURE); 2176 } 2177 cdip = mdi_pi_get_client(pip); 2178 2179 IBTF_DPRINTF_L4("ibnex", 2180 "\tioc_create_pi: New IOC dip %p", cdip); 2181 2182 node_data->node_dip = cdip; 2183 ddi_set_parent_data(cdip, node_data); 2184 2185 if (flag) { 2186 if ((rval = ibnex_create_ioc_node_prop( 2187 ioc_info, cdip)) != IBNEX_SUCCESS) { 2188 ibnex_delete_ioc_node_data(node_data); 2189 ddi_prop_remove_all(cdip); 2190 ddi_set_parent_data(cdip, NULL); 2191 2192 (void) ibnex_offline_childdip(cdip); 2193 return (IBNEX_FAILURE); 2194 } 2195 flag = 0; 2196 } 2197 2198 rval = mdi_pi_online(pip, 0); 2199 2200 if (rval != MDI_SUCCESS) { 2201 ibnex_delete_ioc_node_data(node_data); 2202 ddi_prop_remove_all(cdip); 2203 ddi_set_parent_data(cdip, NULL); 2204 IBTF_DPRINTF_L2("ibnex", "\tioc_create_pi: " 2205 "mdi_pi_online() failed ioc dip %p, rval %d", 2206 cdip, rval); 2207 (void) ibnex_offline_childdip(cdip); 2208 rval = IBNEX_FAILURE; 2209 break; 2210 } else 2211 rval = IBNEX_SUCCESS; 2212 } 2213 return (rval); 2214 } 2215 2216 2217 /* 2218 * ibnex_create_ioc_node_prop() 2219 * Create IOC device node properties 2220 * Returns IBNEX_SUCCESS/IBNEX_FAILURE 2221 */ 2222 static int 2223 ibnex_create_ioc_node_prop(ibdm_ioc_info_t *ioc_info, dev_info_t *cdip) 2224 { 2225 uint16_t capabilities; 2226 ib_dm_ioc_ctrl_profile_t *ioc_profile = &ioc_info->ioc_profile; 2227 2228 IBTF_DPRINTF_L4("ibnex", "\tcreate_ioc_node_prop"); 2229 2230 if (ibnex_create_ioc_compatible_prop(cdip, 2231 ioc_profile) != IBNEX_SUCCESS) { 2232 return (IBNEX_FAILURE); 2233 } 2234 if ((ioc_info->ioc_iou_dc_valid) && 2235 (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "iou-diagcode", 2236 ioc_info->ioc_iou_diagcode)) != DDI_PROP_SUCCESS) { 2237 IBTF_DPRINTF_L2("ibnex", 2238 "\tcreate_ioc_node_prop: iou-diagcode create failed"); 2239 return (IBNEX_FAILURE); 2240 } 2241 if ((ioc_info->ioc_diagdeviceid) && (ioc_info->ioc_dc_valid)) { 2242 if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "ioc-diagcode", 2243 ioc_info->ioc_diagcode) != DDI_PROP_SUCCESS) { 2244 IBTF_DPRINTF_L2("ibnex", "\tcreate_ioc_node_prop: " 2245 "ioc-diagcode create failed"); 2246 return (IBNEX_FAILURE); 2247 } 2248 } 2249 if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "rdma-queue-depth", 2250 ioc_profile->ioc_rdma_read_qdepth) != DDI_PROP_SUCCESS) { 2251 IBTF_DPRINTF_L2("ibnex", 2252 "\tcreate_ioc_node_prop: rdma-queue-depth create failed"); 2253 return (IBNEX_FAILURE); 2254 } 2255 if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "rdma-transfer-size", 2256 ioc_profile->ioc_rdma_xfer_sz) != DDI_PROP_SUCCESS) { 2257 IBTF_DPRINTF_L2("ibnex", "\tcreate_ioc_node_prop: " 2258 "rdma-transfer-size create failed"); 2259 return (IBNEX_FAILURE); 2260 } 2261 if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "send-message-size", 2262 ioc_profile->ioc_send_msg_sz) != DDI_PROP_SUCCESS) { 2263 IBTF_DPRINTF_L2("ibnex", 2264 "\tcreate_ioc_node_prop: send-message-size create failed"); 2265 return (IBNEX_FAILURE); 2266 } 2267 if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "send-queue-depth", 2268 ioc_profile->ioc_send_msg_qdepth) != DDI_PROP_SUCCESS) { 2269 IBTF_DPRINTF_L2("ibnex", 2270 "\tcreate_ioc_node_prop: send-queue-depth create failed"); 2271 return (IBNEX_FAILURE); 2272 } 2273 2274 capabilities = (ioc_profile->ioc_ctrl_opcap_mask << 8); 2275 if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, 2276 "capabilities", capabilities) != DDI_PROP_SUCCESS) { 2277 IBTF_DPRINTF_L2("ibnex", 2278 "\tcreate_ioc_node_prop: capabilities create failed"); 2279 return (IBNEX_FAILURE); 2280 } 2281 if (ndi_prop_update_string(DDI_DEV_T_NONE, cdip, "id-string", 2282 (char *)ioc_profile->ioc_id_string) != DDI_PROP_SUCCESS) { 2283 IBTF_DPRINTF_L2("ibnex", 2284 "\tcreate_ioc_node_prop: id-string failed"); 2285 return (IBNEX_FAILURE); 2286 } 2287 2288 /* 2289 * Create properties to represent all the service entries supported 2290 * by the IOC. Each service entry consists of 1) Service ID (64 bits) 2291 * and 2) Service name (40 bytes). The service entry table is 2292 * represented by two properties, service-ids and service-names. The 2293 * service-id property is a array of int64's and service names is 2294 * array of strings. The first element in the "service-ids" property 2295 * corresponds to first string in the "service-names" and so on. 2296 */ 2297 if ((ioc_profile->ioc_service_entries != 0) && 2298 (ibnex_create_ioc_srv_props(cdip, ioc_info) != IBNEX_SUCCESS)) 2299 return (IBNEX_FAILURE); 2300 2301 /* Create destination port GID properties */ 2302 if (ibnex_create_ioc_portgid_prop(cdip, ioc_info) != IBNEX_SUCCESS) 2303 return (IBNEX_FAILURE); 2304 2305 if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "protocol-version", 2306 ioc_profile->ioc_protocol_ver) != DDI_PROP_SUCCESS) { 2307 IBTF_DPRINTF_L2("ibnex", 2308 "\tcreate_ioc_node_prop: protocol-version create failed"); 2309 return (IBNEX_FAILURE); 2310 } 2311 if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "protocol", 2312 ioc_profile->ioc_protocol) != DDI_PROP_SUCCESS) { 2313 IBTF_DPRINTF_L2("ibnex", 2314 "\tcreate_ioc_node_prop: protocol create failed"); 2315 return (IBNEX_FAILURE); 2316 } 2317 if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "io-subclass", 2318 ioc_profile->ioc_io_subclass) != DDI_PROP_SUCCESS) { 2319 IBTF_DPRINTF_L2("ibnex", 2320 "\tcreate_ioc_node_prop: subclass create failed"); 2321 return (IBNEX_FAILURE); 2322 } 2323 if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "io-class", 2324 ioc_profile->ioc_io_class) != DDI_PROP_SUCCESS) { 2325 IBTF_DPRINTF_L2("ibnex", 2326 "\tcreate_ioc_node_prop: class prop create failed"); 2327 return (IBNEX_FAILURE); 2328 } 2329 if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "subsystem-id", 2330 ioc_profile->ioc_subsys_id) != DDI_PROP_SUCCESS) { 2331 IBTF_DPRINTF_L2("ibnex", 2332 "\tcreate_ioc_node_prop: subsys_id create failed"); 2333 return (IBNEX_FAILURE); 2334 } 2335 if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "subsystem-vendor-id", 2336 ioc_profile->ioc_subsys_vendorid) != DDI_PROP_SUCCESS) { 2337 IBTF_DPRINTF_L2("ibnex", 2338 "\tcreate_ioc_node_prop: subsystem vendor create failed"); 2339 return (IBNEX_FAILURE); 2340 } 2341 if (ndi_prop_update_int64(DDI_DEV_T_NONE, cdip, "ioc-guid", 2342 ioc_profile->ioc_guid) != DDI_PROP_SUCCESS) { 2343 IBTF_DPRINTF_L2("ibnex", 2344 "\tcreate_ioc_node_prop: protocol create failed"); 2345 return (IBNEX_FAILURE); 2346 } 2347 if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "device-version", 2348 ioc_profile->ioc_device_ver) != DDI_PROP_SUCCESS) { 2349 IBTF_DPRINTF_L2("ibnex", 2350 "\tcreate_ioc_node_prop: product-id create failed"); 2351 return (IBNEX_FAILURE); 2352 } 2353 if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "device-id", 2354 ioc_profile->ioc_deviceid) != DDI_PROP_SUCCESS) { 2355 IBTF_DPRINTF_L2("ibnex", 2356 "\tcreate_ioc_node_prop: product-id create failed"); 2357 return (IBNEX_FAILURE); 2358 } 2359 if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "vendor-id", 2360 ioc_profile->ioc_vendorid) != DDI_PROP_SUCCESS) { 2361 IBTF_DPRINTF_L2("ibnex", 2362 "\tcreate_ioc_node_prop: vendor-id create failed"); 2363 return (IBNEX_FAILURE); 2364 } 2365 return (IBNEX_SUCCESS); 2366 } 2367 2368 2369 /* 2370 * ibnex_create_ioc_portgid_prop() 2371 * Creates "port-entries", "port-list" properties 2372 * Returns IBNEX_SUCCESS/IBNEX_FAILURE 2373 */ 2374 static int 2375 ibnex_create_ioc_portgid_prop( 2376 dev_info_t *cdip, ibdm_ioc_info_t *ioc_info) 2377 { 2378 uint64_t *port_gids; 2379 int length, ii, jj; 2380 int prop_len; 2381 ibnex_node_data_t *node_data; 2382 2383 IBTF_DPRINTF_L4("ibnex", "\tcreate_ioc_portgid_prop"); 2384 2385 node_data = ddi_get_parent_data(cdip); 2386 ASSERT(node_data); 2387 2388 prop_len = (ioc_info->ioc_nportgids != 0) ? 2389 (2 * ioc_info->ioc_nportgids) : 1; 2390 length = sizeof (uint64_t) * prop_len; 2391 port_gids = kmem_zalloc(length, KM_SLEEP); 2392 2393 for (ii = 0, jj = 0; ii < ioc_info->ioc_nportgids; ii++) { 2394 port_gids[jj++] = ioc_info->ioc_gid_list[ii].gid_dgid_hi; 2395 port_gids[jj++] = ioc_info->ioc_gid_list[ii].gid_dgid_lo; 2396 } 2397 if (ndi_prop_update_int64_array(DDI_DEV_T_NONE, cdip, "port-list", 2398 (int64_t *)port_gids, prop_len) != DDI_PROP_SUCCESS) { 2399 IBTF_DPRINTF_L2("ibnex", 2400 "\tcreate_ioc_portgid_prop: port-list create failed"); 2401 kmem_free(port_gids, length); 2402 return (IBNEX_FAILURE); 2403 } 2404 if (ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "port-entries", 2405 ioc_info->ioc_nportgids) != DDI_PROP_SUCCESS) { 2406 IBTF_DPRINTF_L2("ibnex", 2407 "\tcreate_ioc_portgid_prop: port-entries create failed"); 2408 kmem_free(port_gids, length); 2409 return (IBNEX_FAILURE); 2410 } 2411 2412 kmem_free(port_gids, length); 2413 return (IBNEX_SUCCESS); 2414 } 2415 2416 2417 /* 2418 * ibnex_create_ioc_srv_props() 2419 * Creates "service-name" and "service-id" properties 2420 * Returns IBNEX_SUCCESS/IBNEX_FAILURE 2421 */ 2422 static int 2423 ibnex_create_ioc_srv_props( 2424 dev_info_t *cdip, ibdm_ioc_info_t *ioc_info) 2425 { 2426 int length, ii; 2427 uint64_t *srv_id; 2428 char *temp, *srv_names[IB_DM_MAX_IOCS_IN_IOU]; 2429 ib_dm_ioc_ctrl_profile_t *profile = &ioc_info->ioc_profile; 2430 ibdm_srvents_info_t *srvents = ioc_info->ioc_serv; 2431 2432 IBTF_DPRINTF_L4("ibnex", "\tcreate_ioc_srv_props"); 2433 2434 length = profile->ioc_service_entries * sizeof (ib_dm_srv_t); 2435 srv_id = kmem_zalloc(length, KM_SLEEP); 2436 temp = (char *)((char *)srv_id + (8 * profile->ioc_service_entries)); 2437 for (ii = 0; ii < profile->ioc_service_entries; ii++) { 2438 srv_names[ii] = (char *)temp + (ii * IB_DM_MAX_SVC_NAME_LEN); 2439 } 2440 2441 for (ii = 0; ii < profile->ioc_service_entries; ii++) { 2442 srv_id[ii] = srvents[ii].se_attr.srv_id; 2443 bcopy(srvents[ii].se_attr.srv_name, 2444 srv_names[ii], (IB_DM_MAX_SVC_NAME_LEN - 1)); 2445 IBTF_DPRINTF_L4("ibnex", "\tcreate_ioc_srv_props " 2446 "Service Names : %s", srv_names[ii]); 2447 IBTF_DPRINTF_L4("ibnex", "\tcreate_ioc_srv_props " 2448 "Service ID : %llx", srv_id[ii]); 2449 } 2450 2451 if (ndi_prop_update_int64_array(DDI_DEV_T_NONE, cdip, 2452 "service-id", (int64_t *)srv_id, 2453 profile->ioc_service_entries) != DDI_PROP_SUCCESS) { 2454 IBTF_DPRINTF_L2("ibnex", 2455 "\tcreate_ioc_srv_props: service-id create failed"); 2456 kmem_free(srv_id, length); 2457 return (IBNEX_FAILURE); 2458 } 2459 2460 if (ndi_prop_update_string_array(DDI_DEV_T_NONE, cdip, 2461 "service-name", (char **)srv_names, 2462 profile->ioc_service_entries) != DDI_PROP_SUCCESS) { 2463 IBTF_DPRINTF_L2("ibnex", 2464 "\tcreate_ioc_srv_props: service-name create failed"); 2465 kmem_free(srv_id, length); 2466 return (IBNEX_FAILURE); 2467 } 2468 kmem_free(srv_id, length); 2469 return (IBNEX_SUCCESS); 2470 } 2471 2472 2473 /* 2474 * ibnex_create_ioc_compatible_prop() 2475 * Creates "compatible" property values 2476 * Returns IBNEX_SUCCESS/IBNEX_FAILURE 2477 */ 2478 static int 2479 ibnex_create_ioc_compatible_prop( 2480 dev_info_t *cdip, ib_dm_ioc_ctrl_profile_t *ioc_profile) 2481 { 2482 char *temp; 2483 int rval, ii; 2484 char *compatible[IBNEX_MAX_COMPAT_NAMES]; 2485 2486 /* 2487 * Initialize the "compatible" property string as below: 2488 * Compatible Strings : 2489 * 1. ib.V<vid>P<pid>S<subsys vid>s<subsys id>v<ver> 2490 * 2. ib.V<vid>P<pid>S<subsys vid>s<subsys id> 2491 * 3. ib.V<vid>P<pid>v<ver> 2492 * 4. ib.V<vid>P<pid> 2493 * 5. ib.C<Class>c<Subclass>p<protocol>r<protocol ver> 2494 * 6. ib.C<Class>c<Subclass>p<protocol> 2495 * 2496 * Note: 2497 * All leading zeros must be present 2498 * All numeric values must specified in hex without prefix "0x" 2499 */ 2500 2501 temp = kmem_alloc(IBNEX_MAX_COMPAT_PROP_SZ, KM_SLEEP); 2502 for (ii = 0; ii < IBNEX_MAX_COMPAT_NAMES; ii++) 2503 compatible[ii] = temp + (ii * IBNEX_MAX_COMPAT_LEN); 2504 2505 (void) snprintf(compatible[0], IBNEX_MAX_COMPAT_LEN, 2506 "ib.V%06xP%08xS%06xs%08xv%04x", 2507 ioc_profile->ioc_vendorid, ioc_profile->ioc_deviceid, 2508 ioc_profile->ioc_subsys_vendorid, ioc_profile->ioc_subsys_id, 2509 ioc_profile->ioc_device_ver); 2510 2511 (void) snprintf(compatible[1], IBNEX_MAX_COMPAT_LEN, 2512 "ib.V%06xP%08xS%06xs%08x", 2513 ioc_profile->ioc_vendorid, ioc_profile->ioc_deviceid, 2514 ioc_profile->ioc_subsys_vendorid, ioc_profile->ioc_subsys_id); 2515 2516 (void) snprintf(compatible[2], IBNEX_MAX_COMPAT_LEN, 2517 "ib.V%06xP%08xv%04x", 2518 ioc_profile->ioc_vendorid, ioc_profile->ioc_deviceid, 2519 ioc_profile->ioc_device_ver); 2520 2521 (void) snprintf(compatible[3], IBNEX_MAX_COMPAT_LEN, 2522 "ib.V%06xP%08x", 2523 ioc_profile->ioc_vendorid, ioc_profile->ioc_deviceid); 2524 2525 (void) snprintf(compatible[4], IBNEX_MAX_COMPAT_LEN, 2526 "ib.C%04xc%04xp%04xr%04x", 2527 ioc_profile->ioc_io_class, ioc_profile->ioc_io_subclass, 2528 ioc_profile->ioc_protocol, ioc_profile->ioc_protocol_ver); 2529 2530 (void) snprintf(compatible[5], IBNEX_MAX_COMPAT_LEN, 2531 "ib.C%04xc%04xp%04x", 2532 ioc_profile->ioc_io_class, ioc_profile->ioc_io_subclass, 2533 ioc_profile->ioc_protocol); 2534 for (ii = 0; ii < IBNEX_MAX_COMPAT_NAMES; ii++) 2535 IBTF_DPRINTF_L4("ibnex", "\tcompatible: %s", compatible[ii]); 2536 2537 /* Create the compatible property for child cdip */ 2538 rval = ndi_prop_update_string_array(DDI_DEV_T_NONE, cdip, 2539 "compatible", (char **)compatible, IBNEX_MAX_COMPAT_NAMES); 2540 2541 if (rval != DDI_PROP_SUCCESS) { 2542 IBTF_DPRINTF_L2("ibnex", "\tcompatible prop_create failed"); 2543 kmem_free(temp, IBNEX_MAX_COMPAT_PROP_SZ); 2544 return (IBNEX_FAILURE); 2545 } 2546 2547 kmem_free(temp, IBNEX_MAX_COMPAT_PROP_SZ); 2548 return (IBNEX_SUCCESS); 2549 } 2550 2551 2552 static void 2553 ibnex_ioc_node_cleanup() 2554 { 2555 ibnex_node_data_t *node, *delete; 2556 2557 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex)); 2558 for (node = ibnex.ibnex_ioc_node_head; node; ) { 2559 delete = node; 2560 node = node->node_next; 2561 mutex_exit(&ibnex.ibnex_mutex); 2562 ibnex_delete_ioc_node_data(delete); 2563 mutex_enter(&ibnex.ibnex_mutex); 2564 } 2565 } 2566 2567 /* 2568 * ibnex_delete_ioc_node_data() 2569 * Delete IOC node from the list 2570 */ 2571 static void 2572 ibnex_delete_ioc_node_data(ibnex_node_data_t *node) 2573 { 2574 IBTF_DPRINTF_L4("ibnex", "\tdelete_ioc_node_data:"); 2575 2576 mutex_enter(&ibnex.ibnex_mutex); 2577 if ((node->node_next == NULL) && (node->node_prev == NULL)) { 2578 ASSERT(ibnex.ibnex_ioc_node_head == node); 2579 ibnex.ibnex_ioc_node_head = NULL; 2580 } else if (node->node_next == NULL) 2581 node->node_prev->node_next = NULL; 2582 else if (node->node_prev == NULL) { 2583 node->node_next->node_prev = NULL; 2584 ibnex.ibnex_ioc_node_head = node->node_next; 2585 } else { 2586 node->node_prev->node_next = node->node_next; 2587 node->node_next->node_prev = node->node_prev; 2588 } 2589 IBTF_DPRINTF_L4("ibnex", "\tdelete_ioc_node_data: head %p", 2590 ibnex.ibnex_ioc_node_head); 2591 mutex_exit(&ibnex.ibnex_mutex); 2592 kmem_free(node, sizeof (ibnex_node_data_t)); 2593 } 2594 2595 2596 /* 2597 * ibnex_dm_callback() 2598 * 2599 * This routine is registered with the IBDM during IB nexus attach. It 2600 * is called by the IBDM module when it discovers 2601 * New HCA port 2602 * HCA port removal 2603 * New HCA added 2604 * HCA removed 2605 */ 2606 void 2607 ibnex_dm_callback(void *arg, ibdm_events_t flag) 2608 { 2609 char hca_guid[IBNEX_HCAGUID_STRSZ]; 2610 ibdm_ioc_info_t *ioc_list, *ioc; 2611 ibnex_node_data_t *node_data; 2612 2613 IBTF_DPRINTF_L4("ibnex", "\tdm_callback: attr %p event %x", arg, flag); 2614 2615 switch (flag) { 2616 case IBDM_EVENT_HCA_ADDED: 2617 (void) snprintf(hca_guid, IBNEX_HCAGUID_STRSZ, "%llX", 2618 (*(longlong_t *)arg)); 2619 /* Create a devctl minor node for the HCA's port */ 2620 if (ddi_create_minor_node(ibnex.ibnex_dip, hca_guid, S_IFCHR, 2621 ddi_get_instance(ibnex.ibnex_dip), 2622 DDI_NT_IB_ATTACHMENT_POINT, 0) != DDI_SUCCESS) { 2623 IBTF_DPRINTF_L4("ibnex", "\tdm_callback: failed to " 2624 "create minor node for port w/ guid %s", hca_guid); 2625 } 2626 2627 break; 2628 2629 case IBDM_EVENT_HCA_REMOVED: 2630 (void) snprintf(hca_guid, IBNEX_HCAGUID_STRSZ, "%llX", 2631 (*(longlong_t *)arg)); 2632 ddi_remove_minor_node(ibnex.ibnex_dip, hca_guid); 2633 break; 2634 2635 case IBDM_EVENT_IOC_PROP_UPDATE: 2636 ioc = ioc_list = (ibdm_ioc_info_t *)arg; 2637 if (ioc_list == NULL) 2638 break; 2639 2640 mutex_enter(&ibnex.ibnex_mutex); 2641 while (ioc_list) { 2642 if ((node_data = ibnex_is_node_data_present( 2643 IBNEX_IOC_NODE, ioc_list, 0, 0)) != NULL && 2644 node_data->node_dip != NULL) { 2645 ibnex_update_prop(node_data, ioc_list); 2646 } 2647 ioc_list = ioc_list->ioc_next; 2648 } 2649 mutex_exit(&ibnex.ibnex_mutex); 2650 ibdm_ibnex_free_ioc_list(ioc); 2651 } 2652 } 2653 2654 2655 /* 2656 * ibnex_get_dip_from_guid() 2657 * 2658 * Searches the linked list of the port nodes and returns the dip for 2659 * the of the Port / Node guid requested. 2660 * Returns NULL if not found 2661 */ 2662 int 2663 ibnex_get_dip_from_guid(ib_guid_t guid, int index, ib_pkey_t pkey, 2664 dev_info_t **dip) 2665 { 2666 int node_index; 2667 ib_guid_t node_guid; 2668 ib_pkey_t node_pkey; 2669 ibnex_node_data_t *node_data; 2670 2671 IBTF_DPRINTF_L4("ibnex", 2672 "\tget_dip_from_guid: guid = %llx", guid); 2673 2674 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex)); 2675 /* Search for a matching entry in internal lists */ 2676 node_data = ibnex.ibnex_port_node_head; 2677 while (node_data) { 2678 node_guid = node_data->node_data.port_node.port_guid; 2679 node_index = node_data->node_data.port_node.port_commsvc_idx; 2680 node_pkey = node_data->node_data.port_node.port_pkey; 2681 if ((node_guid == guid) && (index == node_index) && 2682 (node_pkey == pkey)) { 2683 break; 2684 } 2685 node_data = node_data->node_next; 2686 } 2687 2688 /* matching found with a valid dip */ 2689 if (node_data && node_data->node_dip) { 2690 *dip = node_data->node_dip; 2691 return (IBNEX_SUCCESS); 2692 } else if (node_data && !node_data->node_dip) { /* dip is invalid */ 2693 *dip = NULL; 2694 return (IBNEX_SUCCESS); 2695 } 2696 2697 /* no match found */ 2698 *dip = NULL; 2699 return (IBNEX_FAILURE); 2700 } 2701 2702 2703 /* 2704 * ibnex_comm_svc_init() 2705 * Read the property and cache the values in the global 2706 * structure. 2707 * Check for max allowed length (4 bytes) of service name 2708 * (each element of the property) 2709 * Returns IBNEX_SUCCESS/IBNEX_FAILURE 2710 */ 2711 static ibnex_rval_t 2712 ibnex_comm_svc_init(char *property, ibnex_node_type_t type) 2713 { 2714 int i, len, count; 2715 int ncomm_svcs; 2716 char **comm_svcp; 2717 char **servicep = NULL; 2718 uint_t nservices = 0; 2719 int *valid = NULL; 2720 2721 IBTF_DPRINTF_L4("ibnex", "\tcomm_svc_init : %s property, type = %x", 2722 property, type); 2723 2724 /* lookup the string array property */ 2725 if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, ibnex.ibnex_dip, 2726 DDI_PROP_DONTPASS, property, &servicep, &nservices) != 2727 DDI_PROP_SUCCESS) { 2728 IBTF_DPRINTF_L2("ibnex", "\t%s property undefined", property); 2729 return (IBNEX_SUCCESS); 2730 } 2731 2732 if (nservices) 2733 valid = kmem_zalloc(nservices * sizeof (int), KM_SLEEP); 2734 2735 2736 /* first read the file to get a count of valid service entries */ 2737 for (ncomm_svcs = 0, count = 0; count < nservices; count++) { 2738 int j; 2739 2740 len = strlen(servicep[count]); 2741 if (len == 0 || len > 4) { 2742 IBTF_DPRINTF_L2("ibnex", "\tcomm_svc_init : " 2743 "Service name %s invalid : length %d", 2744 servicep[count], len); 2745 continue; 2746 } 2747 if (ibnex_unique_svcname(servicep[count]) != IBNEX_SUCCESS) { 2748 IBTF_DPRINTF_L2("ibnex", "\tcomm_svc_init : " 2749 "Service name %s invalid : Not unique", 2750 servicep[count]); 2751 continue; 2752 } 2753 2754 /* 2755 * ibnex_unique_svcname checks for uniqueness in service names 2756 * communication services fully initialized. Check uniqueness 2757 * in service names currently initialized. 2758 */ 2759 for (j = 0; j < count; j++) 2760 if (valid[j] && strncmp(servicep[count], 2761 servicep[j], 4) == 0) { 2762 IBTF_DPRINTF_L2("ibnex", "\tcomm_svc_init : " 2763 "Service name %s invalid : Not unique", 2764 servicep[count]); 2765 continue; 2766 } 2767 2768 valid[count] = 1; 2769 ncomm_svcs++; 2770 } 2771 2772 /* if no valid entries found, bailout */ 2773 if (nservices == 0 || ncomm_svcs == 0) { 2774 IBTF_DPRINTF_L4("ibnex", "\tNo %s entries found", property); 2775 ddi_prop_free(servicep); /* free the property */ 2776 if (valid) 2777 kmem_free(valid, nservices * sizeof (int)); 2778 return (IBNEX_SUCCESS); 2779 } 2780 2781 comm_svcp = kmem_zalloc((ncomm_svcs * sizeof (char *)), KM_SLEEP); 2782 if (type == IBNEX_PORT_COMMSVC_NODE) { 2783 ibnex.ibnex_comm_svc_names = comm_svcp; 2784 ibnex.ibnex_num_comm_svcs = ncomm_svcs; 2785 } else if (type == IBNEX_VPPA_COMMSVC_NODE) { 2786 ibnex.ibnex_vppa_comm_svc_names = comm_svcp; 2787 ibnex.ibnex_nvppa_comm_svcs = ncomm_svcs; 2788 } else if (type == IBNEX_HCASVC_COMMSVC_NODE) { 2789 ibnex.ibnex_hcasvc_comm_svc_names = comm_svcp; 2790 ibnex.ibnex_nhcasvc_comm_svcs = ncomm_svcs; 2791 } 2792 2793 /* copy the services into an array of strings */ 2794 for (i = 0, count = 0; count < nservices; count++) { 2795 if (valid[count] == 0) /* Skip invalid ones */ 2796 continue; 2797 comm_svcp[i] = kmem_alloc(len + 1, KM_SLEEP); 2798 (void) strcpy(comm_svcp[i], servicep[count]); 2799 IBTF_DPRINTF_L4("ibnex", 2800 "\t\tService [%d]: %s", i, comm_svcp[i]); 2801 ++i; 2802 } 2803 ddi_prop_free(servicep); 2804 kmem_free(valid, nservices * sizeof (int)); 2805 return (IBNEX_SUCCESS); 2806 } 2807 2808 2809 /* 2810 * ibnex_comm_svc_fini() 2811 * Deallocate all the memory allocated for the communication 2812 * service arrays. 2813 */ 2814 static void 2815 ibnex_comm_svc_fini() 2816 { 2817 int index; 2818 2819 for (index = 0; index < ibnex.ibnex_num_comm_svcs; index++) { 2820 kmem_free(ibnex.ibnex_comm_svc_names[index], 2821 (strlen(ibnex.ibnex_comm_svc_names[index]) + 1)); 2822 } 2823 if (ibnex.ibnex_comm_svc_names) { 2824 kmem_free(ibnex.ibnex_comm_svc_names, 2825 ibnex.ibnex_num_comm_svcs * sizeof (char *)); 2826 } 2827 for (index = 0; index < ibnex.ibnex_nvppa_comm_svcs; index++) { 2828 kmem_free(ibnex.ibnex_vppa_comm_svc_names[index], 2829 strlen(ibnex.ibnex_vppa_comm_svc_names[index]) +1); 2830 } 2831 if (ibnex.ibnex_vppa_comm_svc_names) { 2832 kmem_free(ibnex.ibnex_vppa_comm_svc_names, 2833 ibnex.ibnex_nvppa_comm_svcs * sizeof (char *)); 2834 } 2835 for (index = 0; index < ibnex.ibnex_nhcasvc_comm_svcs; index++) { 2836 kmem_free(ibnex.ibnex_hcasvc_comm_svc_names[index], 2837 strlen(ibnex.ibnex_hcasvc_comm_svc_names[index]) +1); 2838 } 2839 if (ibnex.ibnex_hcasvc_comm_svc_names) { 2840 kmem_free(ibnex.ibnex_hcasvc_comm_svc_names, 2841 ibnex.ibnex_nhcasvc_comm_svcs * sizeof (char *)); 2842 } 2843 ibnex.ibnex_comm_svc_names = NULL; 2844 ibnex.ibnex_num_comm_svcs = 0; 2845 ibnex.ibnex_vppa_comm_svc_names = NULL; 2846 ibnex.ibnex_nvppa_comm_svcs = 0; 2847 ibnex.ibnex_hcasvc_comm_svc_names = NULL; 2848 ibnex.ibnex_nhcasvc_comm_svcs = 0; 2849 } 2850 2851 2852 /* 2853 * ibnex_commsvc_initnode() 2854 * This routine is specific to port/VPPA node creation 2855 * Creates a device node for the comm service specified by commsvc_index 2856 * Creates all the device node properties 2857 * Allocates and initializes the node specific data 2858 * Binds the device driver of the device node 2859 * Returns "dev_info_t" of the child node or NULL in case of failure 2860 * Sets IBNEX_SUCCESS/IBNEX_FAILURE/IBNEX_BUSY in "rval" to reflect 2861 * if the operation was successful, failed or was not performed. 2862 */ 2863 dev_info_t * 2864 ibnex_commsvc_initnode(dev_info_t *parent, ibdm_port_attr_t *port_attr, 2865 int index, int node_type, ib_pkey_t pkey, int *rval, int flag) 2866 { 2867 int ret; 2868 char *svcname; 2869 dev_info_t *cdip; 2870 ibnex_node_data_t *node_data; 2871 2872 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex)); 2873 2874 *rval = IBNEX_SUCCESS; 2875 2876 /* 2877 * prevent any races 2878 * we have seen this node_data and it has been initialized 2879 * Note that node_dip is already NULL if unconfigure is in 2880 * progress. 2881 */ 2882 node_data = ibnex_is_node_data_present(node_type, (void *)port_attr, 2883 index, pkey); 2884 if (node_data && node_data->node_dip) { 2885 /* 2886 * Return NULL if another configure 2887 * operation is in progress 2888 */ 2889 if (node_data->node_state == IBNEX_CFGADM_CONFIGURING) { 2890 *rval = IBNEX_BUSY; 2891 return (NULL); 2892 } else { 2893 return (node_data->node_dip); 2894 } 2895 } else if (node_data == NULL) { 2896 /* allocate a new ibnex_node_data_t */ 2897 node_data = ibnex_init_child_nodedata(node_type, port_attr, 2898 index, pkey); 2899 } 2900 2901 /* 2902 * Return NULL if another unconfigure operation is in progress 2903 */ 2904 if (node_data->node_state == IBNEX_CFGADM_UNCONFIGURING) { 2905 *rval = IBNEX_BUSY; 2906 return (NULL); 2907 } 2908 2909 ASSERT(node_data->node_state != IBNEX_CFGADM_CONFIGURED); 2910 node_data->node_state = IBNEX_CFGADM_CONFIGURING; 2911 2912 ndi_devi_alloc_sleep(parent, 2913 IBNEX_IBPORT_CNAME, (pnode_t)DEVI_SID_NODEID, &cdip); 2914 2915 node_data->node_dip = cdip; 2916 ddi_set_parent_data(cdip, node_data); 2917 mutex_exit(&ibnex.ibnex_mutex); 2918 2919 switch (node_type) { 2920 case IBNEX_VPPA_COMMSVC_NODE : 2921 svcname = ibnex.ibnex_vppa_comm_svc_names[index]; 2922 break; 2923 case IBNEX_HCASVC_COMMSVC_NODE : 2924 svcname = ibnex.ibnex_hcasvc_comm_svc_names[index]; 2925 break; 2926 case IBNEX_PORT_COMMSVC_NODE : 2927 svcname = ibnex.ibnex_comm_svc_names[index]; 2928 break; 2929 default : 2930 IBTF_DPRINTF_L2("ibnex", "\tcommsvc_initnode:" 2931 "\tInvalid Node type"); 2932 *rval = IBNEX_FAILURE; 2933 ibnex_delete_port_node_data(node_data); 2934 ddi_prop_remove_all(cdip); 2935 ddi_set_parent_data(cdip, NULL); 2936 (void) ndi_devi_free(cdip); 2937 mutex_enter(&ibnex.ibnex_mutex); 2938 return (NULL); 2939 } 2940 2941 if (ibnex_create_port_node_prop(port_attr, cdip, svcname, pkey) == 2942 IBNEX_SUCCESS) { 2943 if (flag == IBNEX_DEVFS_ENUMERATE) 2944 ret = ndi_devi_bind_driver(cdip, 0); 2945 else 2946 ret = ndi_devi_online(cdip, 0); 2947 if (ret == NDI_SUCCESS) { 2948 mutex_enter(&ibnex.ibnex_mutex); 2949 node_data->node_state = IBNEX_CFGADM_CONFIGURED; 2950 return (cdip); 2951 } 2952 } 2953 *rval = IBNEX_FAILURE; 2954 ibnex_delete_port_node_data(node_data); 2955 ddi_prop_remove_all(cdip); 2956 ddi_set_parent_data(cdip, NULL); 2957 (void) ndi_devi_free(cdip); 2958 mutex_enter(&ibnex.ibnex_mutex); 2959 IBTF_DPRINTF_L4("ibnex", "\tcommsvc_initnode: failure exit"); 2960 return (NULL); 2961 } 2962 2963 2964 /* 2965 * ibnex_create_port_node_prop() 2966 * Returns IBNEX_SUCCESS/IBNEX_FAILURE 2967 */ 2968 static int 2969 ibnex_create_port_node_prop(ibdm_port_attr_t *port_attr, 2970 dev_info_t *child_dip, char *srvname, ib_pkey_t pkey) 2971 { 2972 if (ibnex_create_port_compatible_prop(child_dip, 2973 srvname, port_attr) != DDI_PROP_SUCCESS) { 2974 IBTF_DPRINTF_L2("ibnex", 2975 "\tcreate_port_node_prop: compatible update failed"); 2976 return (IBNEX_FAILURE); 2977 } 2978 if ((pkey != 0) && (ndi_prop_update_int(DDI_DEV_T_NONE, child_dip, 2979 "port-pkey", pkey) != DDI_PROP_SUCCESS)) { 2980 IBTF_DPRINTF_L2("ibnex", 2981 "\tcreate_port_node_prop: port-num update failed"); 2982 return (IBNEX_FAILURE); 2983 } 2984 2985 /* 2986 * For HCA_SVC device nodes, port_num will be 0. 2987 * Do not create the "port-number" & "port-guid" properties. 2988 */ 2989 if (port_attr->pa_port_num != 0) { 2990 if (ndi_prop_update_int(DDI_DEV_T_NONE, child_dip, 2991 "port-number", port_attr->pa_port_num) != 2992 DDI_PROP_SUCCESS) { 2993 IBTF_DPRINTF_L2("ibnex", 2994 "\tcreate_port_node_prop: port-num update failed"); 2995 return (IBNEX_FAILURE); 2996 } 2997 if (ndi_prop_update_int64(DDI_DEV_T_NONE, child_dip, 2998 "port-guid", port_attr->pa_port_guid) != 2999 DDI_PROP_SUCCESS) { 3000 IBTF_DPRINTF_L2("ibnex", 3001 "\tcreate_port_node_prop: port-guid update failed"); 3002 return (IBNEX_FAILURE); 3003 } 3004 } else { 3005 ibdm_hca_list_t *hca_list; 3006 3007 /* 3008 * HCA_SVC nodes require "num-ports" & "port-guids" 3009 * properties. 3010 * 3011 * To create the num-ports & port-guids attribute : 3012 * 1. Get HCA list (ibdm_ibnex_get_hca_info_by_guid) 3013 * 2. Form the array of port GUIDs. 3014 */ 3015 if ((hca_list = ibdm_ibnex_get_hca_info_by_guid( 3016 port_attr->pa_hca_guid)) == NULL) { 3017 IBTF_DPRINTF_L2("ibnex", 3018 "\tcreate_port_node_prop: hca_info_by_guid failed"); 3019 return (IBNEX_FAILURE); 3020 } 3021 3022 if (hca_list->hl_nports != 0) { 3023 ib_guid_t *port_guids; 3024 uint8_t portnum; 3025 3026 ASSERT(hca_list->hl_port_attr != NULL); 3027 3028 port_guids = kmem_zalloc( 3029 hca_list->hl_nports * sizeof (ib_guid_t), 3030 KM_SLEEP); 3031 3032 for (portnum = 0; portnum < hca_list->hl_nports; 3033 portnum++) { 3034 port_guids[portnum] = (hca_list-> 3035 hl_port_attr[portnum]).pa_port_guid; 3036 } 3037 3038 if (ndi_prop_update_int64_array(DDI_DEV_T_NONE, 3039 child_dip, "port-guids", (int64_t *)port_guids, 3040 hca_list->hl_nports) != DDI_PROP_SUCCESS) { 3041 IBTF_DPRINTF_L2("ibnex", 3042 "\tcreate_port_node_prop: port-guids " 3043 "create failed"); 3044 kmem_free(port_guids, hca_list->hl_nports * 3045 sizeof (ib_guid_t)); 3046 ibdm_ibnex_free_hca_list(hca_list); 3047 return (IBNEX_FAILURE); 3048 } 3049 kmem_free(port_guids, hca_list->hl_nports * 3050 sizeof (ib_guid_t)); 3051 } 3052 3053 if (ndi_prop_update_int(DDI_DEV_T_NONE, child_dip, 3054 "num-ports", hca_list->hl_nports) != DDI_PROP_SUCCESS) { 3055 IBTF_DPRINTF_L2("ibnex", 3056 "\tcreate_port_node_prop: num-ports update failed"); 3057 ibdm_ibnex_free_hca_list(hca_list); 3058 return (IBNEX_FAILURE); 3059 } 3060 ibdm_ibnex_free_hca_list(hca_list); 3061 } 3062 3063 if (ndi_prop_update_int64(DDI_DEV_T_NONE, child_dip, 3064 "hca-guid", port_attr->pa_hca_guid) != DDI_PROP_SUCCESS) { 3065 IBTF_DPRINTF_L2("ibnex", 3066 "\tcreate_port_node_prop: hca-guid update failed"); 3067 return (IBNEX_FAILURE); 3068 } 3069 if (ndi_prop_update_int(DDI_DEV_T_NONE, child_dip, 3070 "product-id", port_attr->pa_productid) != DDI_PROP_SUCCESS) { 3071 IBTF_DPRINTF_L2("ibnex", 3072 "\tcreate_port_node_prop: product-id update failed"); 3073 return (IBNEX_FAILURE); 3074 } 3075 if (ndi_prop_update_int(DDI_DEV_T_NONE, child_dip, 3076 "vendor-id", port_attr->pa_vendorid) != DDI_PROP_SUCCESS) { 3077 IBTF_DPRINTF_L2("ibnex", 3078 "\tcreate_port_node_prop: vendor-id update failed"); 3079 return (IBNEX_FAILURE); 3080 } 3081 if (ndi_prop_update_int(DDI_DEV_T_NONE, child_dip, "device-version", 3082 port_attr->pa_dev_version) != DDI_PROP_SUCCESS) { 3083 IBTF_DPRINTF_L2("ibnex", 3084 "\tcreate_port_node_prop: device-version update failed"); 3085 return (IBNEX_FAILURE); 3086 } 3087 return (IBNEX_SUCCESS); 3088 } 3089 3090 3091 /* 3092 * ibnex_str2int() 3093 * Utility function that converts a string of length "len" to 3094 * integer. 3095 * Returns IBNEX_SUCCESS/IBNEX_FAILURE 3096 */ 3097 static int 3098 ibnex_str2int(char *c, int len, int *ret) 3099 { 3100 int intval = 0, ii; 3101 3102 IBTF_DPRINTF_L4("ibnex", "\tstr2int: Int string %s..", c); 3103 *ret = IBNEX_SUCCESS; 3104 for (ii = 0; ii < len; ii ++) { 3105 if ((c[ii] >= '0') && (c[ii] <= '9')) 3106 intval = intval * 10 +c[ii] - '0'; 3107 else { 3108 IBTF_DPRINTF_L2("ibnex", 3109 "\tstr2int: Invalid integer string %s..", c); 3110 *ret = IBNEX_FAILURE; 3111 break; 3112 } 3113 } 3114 3115 return (intval); 3116 } 3117 3118 3119 /* 3120 * ibnex_str2hex() 3121 * Utility functions that converts a string of length "len" to 3122 * hex value. Note. This function does not handle strings which 3123 * string length more than 8 bytes. 3124 * 3125 */ 3126 uint64_t 3127 ibnex_str2hex(char *c, int len, int *ret) 3128 { 3129 uint64_t hex = 0, ii; 3130 3131 *ret = IBNEX_SUCCESS; 3132 for (ii = 0; ii < len; ii ++) { 3133 hex = (ii == 0) ? hex : (hex << 4); 3134 if ((c[ii] >= '0') && (c[ii] <= '9')) 3135 hex |= c[ii] - '0'; 3136 else if ((c[ii] >= 'a') && (c[ii] <= 'f')) 3137 hex |= c[ii] - 'a' + 10; 3138 else if ((c[ii] >= 'A') && (c[ii] <= 'F')) 3139 hex |= c[ii] - 'A' + 10; 3140 else { 3141 IBTF_DPRINTF_L2("ibnex", 3142 "\tstr2hex: Invalid integer string"); 3143 *ret = IBNEX_FAILURE; 3144 break; 3145 } 3146 } 3147 3148 return (hex); 3149 } 3150 3151 3152 /* 3153 * ibnex_create_port_compatible_prop() 3154 * Creates 'Compatibility' property for port / HCA_SVC device nodes 3155 * Returns IBNEX_SUCCESS/IBNEX_FAILURE 3156 */ 3157 static int 3158 ibnex_create_port_compatible_prop(dev_info_t *child_dip, 3159 char *comm_svcp, ibdm_port_attr_t *port_attr) 3160 { 3161 int rval, i; 3162 char *temp; 3163 char *compatible[IBNEX_MAX_IBPORT_COMPAT_NAMES]; 3164 3165 IBTF_DPRINTF_L4("ibnex", "\tcreate_port_compatible_prop: Begin"); 3166 /* 3167 * Initialize the "compatible" property string as below: 3168 * Compatible Strings : 3169 * 1. ib.V<vid>P<pid>v<revision>.<service name>. 3170 * 2. ib.V<vid>P<pid>.<service name>. 3171 * 3. ib.<service name> 3172 * Leading zeros must be present 3173 */ 3174 temp = kmem_alloc(IBNEX_MAX_IBPORT_COMPAT_PROP_SZ, KM_SLEEP); 3175 for (i = 0; i < IBNEX_MAX_IBPORT_COMPAT_NAMES; i++) { 3176 compatible[i] = temp + (i * IBNEX_MAX_COMPAT_LEN); 3177 } 3178 3179 (void) snprintf(compatible[0], IBNEX_MAX_COMPAT_LEN, 3180 "ib.V%06xP%08xv%04x.%s", 3181 port_attr->pa_vendorid, port_attr->pa_productid, 3182 port_attr->pa_dev_version, comm_svcp); 3183 (void) snprintf(compatible[1], IBNEX_MAX_COMPAT_LEN, 3184 "ib.V%06xP%08x.%s", 3185 port_attr->pa_vendorid, port_attr->pa_productid, 3186 comm_svcp); 3187 (void) snprintf(compatible[2], IBNEX_MAX_COMPAT_LEN, 3188 "ib.%s", comm_svcp); 3189 3190 for (i = 0; i < IBNEX_MAX_IBPORT_COMPAT_NAMES; i++) 3191 IBTF_DPRINTF_L4("ibnex", "\tcompatible: %s", compatible[i]); 3192 3193 rval = ndi_prop_update_string_array(DDI_DEV_T_NONE, child_dip, 3194 "compatible", (char **)compatible, IBNEX_MAX_IBPORT_COMPAT_NAMES); 3195 3196 if (rval != DDI_PROP_SUCCESS) { 3197 kmem_free(temp, IBNEX_MAX_IBPORT_COMPAT_PROP_SZ); 3198 return (IBNEX_FAILURE); 3199 } 3200 kmem_free(temp, IBNEX_MAX_IBPORT_COMPAT_PROP_SZ); 3201 return (IBNEX_SUCCESS); 3202 } 3203 3204 3205 /* 3206 * ibnex_delete_port_node_data() 3207 * Delete the parent private node data from the linked list 3208 * Deallocate the memory of the port/ioc attributes 3209 * Deallocate the memory of the node data 3210 */ 3211 static void 3212 ibnex_delete_port_node_data(ibnex_node_data_t *node) 3213 { 3214 mutex_enter(&ibnex.ibnex_mutex); 3215 if ((node->node_next == NULL) && (node->node_prev == NULL)) 3216 ibnex.ibnex_port_node_head = NULL; 3217 else if (node->node_next == NULL) 3218 node->node_prev->node_next = NULL; 3219 else if (node->node_prev == NULL) { 3220 node->node_next->node_prev = NULL; 3221 ibnex.ibnex_port_node_head = node->node_next; 3222 } else { 3223 node->node_prev->node_next = node->node_next; 3224 node->node_next->node_prev = node->node_prev; 3225 } 3226 mutex_exit(&ibnex.ibnex_mutex); 3227 kmem_free(node, sizeof (ibnex_node_data_t)); 3228 } 3229 3230 3231 /* 3232 * ibnex_is_node_data_present() 3233 * Checks whether ibnex_node_t is created already 3234 * Returns ibnex_node_data_t if found, otherwise NULL 3235 */ 3236 static ibnex_node_data_t * 3237 ibnex_is_node_data_present(ibnex_node_type_t node_type, void *attr, 3238 int index, ib_pkey_t pkey) 3239 { 3240 ibnex_node_data_t *nodep; 3241 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex)); 3242 if (node_type == IBNEX_IOC_NODE) { 3243 ibdm_ioc_info_t *ioc_infop = (ibdm_ioc_info_t *)attr; 3244 3245 for (nodep = ibnex.ibnex_ioc_node_head; nodep != NULL; 3246 nodep = nodep->node_next) { 3247 if (nodep->node_data.ioc_node.ioc_guid == 3248 ioc_infop->ioc_profile.ioc_guid) { 3249 return (nodep); 3250 } 3251 } 3252 3253 } else if (node_type == IBNEX_PSEUDO_NODE) { 3254 for (nodep = ibnex.ibnex_pseudo_node_head; nodep; 3255 nodep = nodep->node_next) 3256 if (strcmp(nodep->node_data.pseudo_node. 3257 pseudo_node_addr, (char *)attr) == 0) 3258 return (nodep); 3259 3260 } else { 3261 ibdm_port_attr_t *pattrp = (ibdm_port_attr_t *)attr; 3262 3263 for (nodep = ibnex.ibnex_port_node_head; nodep != NULL; 3264 nodep = nodep->node_next) { 3265 if ((nodep->node_data.port_node.port_guid == 3266 pattrp->pa_port_guid) && 3267 (nodep->node_data.port_node.port_commsvc_idx == 3268 index) && 3269 (nodep->node_data.port_node.port_pkey == pkey)) { 3270 return (nodep); 3271 } 3272 } 3273 } 3274 return (NULL); 3275 } 3276 3277 /* 3278 * ibnex_lookup_unit_address_prop: 3279 * 3280 * If "unit-address" property is found, return its value 3281 * otherwise return NULL. 3282 */ 3283 static char * 3284 ibnex_lookup_unit_address_prop(ddi_prop_t *head) 3285 { 3286 ddi_prop_t *propp; 3287 3288 /* Search the list of properties for "unit-address" */ 3289 for (propp = head; propp != NULL; propp = propp->prop_next) { 3290 if (strcmp(propp->prop_name, "unit-address") != 0) 3291 continue; 3292 /* "unit-address" property should be valid and have a value */ 3293 if (propp->prop_len <= 1) 3294 break; 3295 return ((char *)propp->prop_val); 3296 } 3297 3298 return ((char *)0); 3299 } 3300 3301 3302 /* 3303 * ibnex_pseudo_initnodes() 3304 * This routine is specific to pseudo node information handling 3305 * Creates a ibnex_node_data_t all pseudo nodes children of ibnex 3306 */ 3307 void 3308 ibnex_pseudo_initnodes() 3309 { 3310 int pnam_len, len; 3311 ibnex_node_data_t *nodep; 3312 struct hwc_spec *list, *spec; 3313 char *node_addr, *temp, *unit_addr; 3314 3315 IBTF_DPRINTF_L4("ibnex", "\tpseudo_initnodes"); 3316 3317 mutex_enter(&ibnex.ibnex_mutex); 3318 /* 3319 * get a list of all "pseudo" children of "ib". 3320 * for these children initialize/allocate an internal 3321 * ibnex_node_data_t. 3322 */ 3323 list = hwc_get_child_spec(ibnex.ibnex_dip, (major_t)-1); 3324 for (spec = list; spec != NULL; spec = spec->hwc_next) { 3325 if (spec->hwc_devi_sys_prop_ptr == NULL) 3326 continue; 3327 3328 /* "unit-address" property should be present */ 3329 temp = ibnex_lookup_unit_address_prop( 3330 spec->hwc_devi_sys_prop_ptr); 3331 if (temp == NULL) 3332 continue; 3333 3334 pnam_len = strlen(spec->hwc_devi_name) + strlen(temp) + 2; 3335 3336 node_addr = kmem_zalloc(pnam_len, KM_SLEEP); 3337 3338 (void) snprintf(node_addr, 3339 pnam_len, "%s,%s", spec->hwc_devi_name, temp); 3340 3341 nodep = ibnex_is_node_data_present( 3342 IBNEX_PSEUDO_NODE, (void *)node_addr, 0, 0); 3343 3344 if (nodep) { 3345 kmem_free(node_addr, pnam_len); 3346 continue; 3347 } 3348 3349 nodep = ibnex_init_child_nodedata(IBNEX_PSEUDO_NODE, 3350 (void *)spec->hwc_devi_name, 0, 0); 3351 3352 nodep->node_data.pseudo_node.pseudo_node_addr = node_addr; 3353 (void) snprintf(nodep->node_data. 3354 pseudo_node.pseudo_node_addr, pnam_len, "%s", node_addr); 3355 3356 len = strlen(temp) + 1; 3357 unit_addr = (char *)kmem_alloc(len, KM_SLEEP); 3358 nodep->node_data.pseudo_node.pseudo_unit_addr = unit_addr; 3359 (void) snprintf(unit_addr, len, "%s", temp); 3360 nodep->node_data.pseudo_node.pseudo_unit_addr_len = len; 3361 3362 /* Mark this as a new psuedo node */ 3363 nodep->node_data.pseudo_node.pseudo_new_node = 1; 3364 3365 IBTF_DPRINTF_L3("ibnex", "\tpseudo_initnodes: unit addr = %s" 3366 " : drv name = %s", unit_addr, spec->hwc_devi_name); 3367 } 3368 hwc_free_spec_list(list); 3369 mutex_exit(&ibnex.ibnex_mutex); 3370 } 3371 3372 3373 /* 3374 * ibnex_init_child_nodedata() 3375 * 3376 * Allocate memory for the parent private data for device node 3377 * Initializes the parent private child device node data. 3378 * Returns pointer to the parent private data 3379 */ 3380 static ibnex_node_data_t * 3381 ibnex_init_child_nodedata(ibnex_node_type_t node_type, void *attr, int index, 3382 ib_pkey_t pkey) 3383 { 3384 char *devi_name; 3385 ibdm_ioc_info_t *ioc_info; 3386 ibnex_ioc_node_t *ioc_node; 3387 ibnex_node_data_t *node_data; 3388 ib_dm_ioc_ctrl_profile_t *ioc_profile; 3389 3390 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex)); 3391 3392 node_data = kmem_zalloc(sizeof (ibnex_node_data_t), KM_SLEEP); 3393 node_data->node_state = IBNEX_CFGADM_CONFIGURING; 3394 node_data->node_type = node_type; 3395 3396 if (node_type == IBNEX_IOC_NODE) { 3397 ioc_info = (ibdm_ioc_info_t *)attr; 3398 ioc_profile = &ioc_info->ioc_profile; 3399 ioc_node = &node_data->node_data.ioc_node; 3400 3401 ioc_node->iou_guid = ioc_info->ioc_iou_guid; 3402 ioc_node->ioc_guid = ioc_profile->ioc_guid; 3403 (void) strncpy(ioc_node->ioc_id_string, 3404 (char *)ioc_profile->ioc_id_string, 3405 IB_DM_IOC_ID_STRING_LEN); 3406 ioc_node->ioc_ngids = ioc_info->ioc_nportgids; 3407 3408 node_data->node_next = ibnex.ibnex_ioc_node_head; 3409 node_data->node_prev = NULL; 3410 if (ibnex.ibnex_ioc_node_head) 3411 ibnex.ibnex_ioc_node_head->node_prev = node_data; 3412 ibnex.ibnex_ioc_node_head = node_data; 3413 } else if (node_type == IBNEX_PSEUDO_NODE) { 3414 devi_name = (char *)attr; 3415 node_data->node_data.pseudo_node.pseudo_devi_name = 3416 kmem_zalloc(strlen(devi_name) + 1, KM_SLEEP); 3417 (void) strncpy(node_data->node_data.pseudo_node. 3418 pseudo_devi_name, devi_name, strlen(devi_name)); 3419 node_data->node_next = ibnex.ibnex_pseudo_node_head; 3420 node_data->node_prev = NULL; 3421 if (ibnex.ibnex_pseudo_node_head) 3422 ibnex.ibnex_pseudo_node_head->node_prev = node_data; 3423 ibnex.ibnex_pseudo_node_head = node_data; 3424 } else { 3425 node_data->node_data.port_node.port_hcaguid = 3426 ((ibdm_port_attr_t *)attr)->pa_hca_guid; 3427 node_data->node_data.port_node.port_guid = 3428 ((ibdm_port_attr_t *)attr)->pa_port_guid; 3429 node_data->node_data.port_node.port_num = 3430 ((ibdm_port_attr_t *)attr)->pa_port_num; 3431 node_data->node_data.port_node.port_commsvc_idx = index; 3432 node_data->node_data.port_node.port_pkey = pkey; 3433 3434 node_data->node_next = ibnex.ibnex_port_node_head; 3435 node_data->node_prev = NULL; 3436 if (ibnex.ibnex_port_node_head) 3437 ibnex.ibnex_port_node_head->node_prev = node_data; 3438 ibnex.ibnex_port_node_head = node_data; 3439 } 3440 return (node_data); 3441 } 3442 3443 static int 3444 ibnex_get_eventcookie(dev_info_t *dip, dev_info_t *rdip, 3445 char *eventname, ddi_eventcookie_t *cookie) 3446 { 3447 int rc; 3448 3449 3450 IBTF_DPRINTF_L4("ibnex", "ibnex_get_eventcookie(%p, %p, %s, 0x%X)", 3451 dip, rdip, eventname, cookie); 3452 3453 rc = ndi_event_retrieve_cookie(ibnex.ibnex_ndi_event_hdl, 3454 rdip, eventname, cookie, NDI_EVENT_NOPASS); 3455 if (rc == NDI_SUCCESS) { 3456 mutex_enter(&ibnex.ibnex_mutex); 3457 ibnex.ibnex_prop_update_evt_cookie = *cookie; 3458 mutex_exit(&ibnex.ibnex_mutex); 3459 } 3460 3461 return (rc); 3462 } 3463 3464 static int 3465 ibnex_add_eventcall(dev_info_t *dip, dev_info_t *rdip, 3466 ddi_eventcookie_t cookie, void (*callback)(dev_info_t *dip, 3467 ddi_eventcookie_t cookie, void *arg, void *bus_impldata), 3468 void *arg, ddi_callback_id_t *cb_id) 3469 { 3470 IBTF_DPRINTF_L4("ibnex", 3471 "ibnex_add_eventcall(%p, %p, 0x%X, %p, %p, %p)", 3472 dip, rdip, cookie, callback, arg, cb_id); 3473 3474 return (ndi_event_add_callback(ibnex.ibnex_ndi_event_hdl, 3475 rdip, cookie, callback, arg, NDI_SLEEP, cb_id)); 3476 } 3477 3478 static int 3479 ibnex_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id) 3480 { 3481 IBTF_DPRINTF_L4("ibnex", "ibnex_remove_eventcall(%p, 0x%X)", 3482 dip, cb_id); 3483 3484 return (ndi_event_remove_callback(ibnex.ibnex_ndi_event_hdl, 3485 cb_id)); 3486 } 3487 3488 static int 3489 ibnex_post_event(dev_info_t *dip, dev_info_t *rdip, 3490 ddi_eventcookie_t cookie, void *bus_impldata) 3491 { 3492 IBTF_DPRINTF_L4("ibnex", "ibnex_post_event(%p, %p, 0x%X, %p)", 3493 dip, rdip, cookie, bus_impldata); 3494 3495 return (ndi_event_run_callbacks(ibnex.ibnex_ndi_event_hdl, rdip, 3496 cookie, bus_impldata)); 3497 } 3498 3499 /* 3500 * ibnex_reprobe_ioc_dev() 3501 * 3502 * This could be called as a result of ibt_reprobe_dev request or 3503 * cfgadm command. The function is called from a taskq in case of 3504 * ibt_reprobe_dev and from user context for cfgadm command. 3505 * 3506 * This function reprobes the properties for one IOC dip. 3507 * 3508 * node_reprobe_state should be set before calling this function. 3509 */ 3510 void 3511 ibnex_reprobe_ioc_dev(void *arg) 3512 { 3513 dev_info_t *dip = (dev_info_t *)arg; 3514 ibnex_node_data_t *node_data; 3515 ibnex_ioc_node_t *ioc_data; 3516 ibdm_ioc_info_t *ioc_info; 3517 3518 /* ASSERT(NO_LOCKS_HELD); */ 3519 ASSERT(dip != NULL); 3520 3521 node_data = ddi_get_parent_data(dip); 3522 ASSERT(node_data); 3523 3524 if (node_data->node_dip == NULL) { 3525 IBTF_DPRINTF_L4("ibnex", "reprobe for unconfigured dip"); 3526 mutex_enter(&ibnex.ibnex_mutex); 3527 ibnex_wakeup_reprobe_ioc(node_data, 0); 3528 mutex_exit(&ibnex.ibnex_mutex); 3529 return; 3530 } 3531 ioc_data = &(node_data->node_data.ioc_node); 3532 3533 /* Reprobe the IOC */ 3534 ioc_info = ibdm_ibnex_probe_ioc(ioc_data->iou_guid, ioc_data->ioc_guid, 3535 1); 3536 if (ioc_info == NULL) { 3537 IBTF_DPRINTF_L2("ibnex", "Null ioc_info from reprobe"); 3538 mutex_enter(&ibnex.ibnex_mutex); 3539 ibnex_wakeup_reprobe_ioc(node_data, 1); 3540 mutex_exit(&ibnex.ibnex_mutex); 3541 return; 3542 } 3543 3544 mutex_enter(&ibnex.ibnex_mutex); 3545 if (node_data->node_dip) 3546 ibnex_update_prop(node_data, ioc_info); 3547 ibnex_wakeup_reprobe_ioc(node_data, 0); 3548 mutex_exit(&ibnex.ibnex_mutex); 3549 3550 ibdm_ibnex_free_ioc_list(ioc_info); 3551 } 3552 3553 /* 3554 * ibnex_reprobe_all() 3555 * 3556 * This could be called as a result of cfgadm command. The function 3557 * is called from user context. 3558 * 3559 * This function reprobes the properties for all IOC dips. 3560 * 3561 * ibnex_reprobe_state should be set before calling this function. 3562 */ 3563 void 3564 ibnex_reprobe_ioc_all() 3565 { 3566 ibnex_node_data_t *node_data; 3567 ibdm_ioc_info_t *ioc_info_list, *ioc; 3568 3569 /* ASSERT(NO_LOCKS_HELD); */ 3570 3571 /* Sweep the fabric */ 3572 ioc = ioc_info_list = ibdm_ibnex_get_ioc_list( 3573 IBDM_IBNEX_REPROBE_ALL); 3574 if (ioc_info_list == NULL) { 3575 mutex_enter(&ibnex.ibnex_mutex); 3576 ibnex_wakeup_reprobe_all(); 3577 mutex_exit(&ibnex.ibnex_mutex); 3578 return; 3579 } 3580 3581 mutex_enter(&ibnex.ibnex_mutex); 3582 while (ioc_info_list) { 3583 if ((node_data = ibnex_is_node_data_present(IBNEX_IOC_NODE, 3584 ioc_info_list, 0, 0)) != NULL && 3585 node_data->node_dip != NULL) { 3586 ibnex_update_prop(node_data, ioc_info_list); 3587 } 3588 ioc_info_list = ioc_info_list->ioc_next; 3589 } 3590 ibnex_wakeup_reprobe_all(); 3591 mutex_exit(&ibnex.ibnex_mutex); 3592 3593 ibdm_ibnex_free_ioc_list(ioc); 3594 } 3595 3596 /* 3597 * Update the properties, if it has modified and notify IBTF client. 3598 */ 3599 static void 3600 ibnex_update_prop(ibnex_node_data_t *node_data, ibdm_ioc_info_t *ioc_info) 3601 { 3602 ibt_prop_update_payload_t evt_data; 3603 dev_info_t *dip = node_data->node_dip; 3604 ddi_eventcookie_t evt_cookie; 3605 ibnex_ioc_node_t *ioc; 3606 3607 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex)); 3608 3609 ASSERT(dip != NULL); 3610 3611 ioc = &node_data->node_data.ioc_node; 3612 3613 evt_data = ioc_info->ioc_info_updated; 3614 evt_cookie = ibnex.ibnex_prop_update_evt_cookie; 3615 3616 /* 3617 * For a disconnected IOC : 3618 * Store the ioc_profile for supplying cfgadm info 3619 * ibdm maintains no info of disconnected IOC 3620 * 3621 * For reconnected IOC : 3622 * ibdm has info of previous service entries 3623 * ioc_profile maintained by ibnexus is used to 3624 * update ib_srv_prop_updated. 3625 * Free the ibnex maintained ioc_profile 3626 */ 3627 if (ioc_info->ioc_nportgids == 0) { 3628 IBTF_DPRINTF_L4("ibnex", 3629 "\tupdate_prop: IOC disconnected"); 3630 ioc->ioc_profile = (ib_dm_ioc_ctrl_profile_t *)kmem_zalloc( 3631 sizeof (ib_dm_ioc_ctrl_profile_t), KM_SLEEP); 3632 bcopy(&ioc_info->ioc_profile, ioc->ioc_profile, 3633 sizeof (ib_dm_ioc_ctrl_profile_t)); 3634 3635 ibnex.ibnex_num_disconnect_iocs++; 3636 } else if (ioc_info->ioc_nportgids != 0 && ioc->ioc_ngids == 0 && 3637 ioc->ioc_profile != NULL) { 3638 IBTF_DPRINTF_L4("ibnex", 3639 "\tupdate_prop: IOC reconnected"); 3640 if (ioc->ioc_profile->ioc_service_entries != 3641 ioc_info->ioc_profile.ioc_service_entries) 3642 evt_data.ib_srv_prop_updated = 1; 3643 3644 ibnex.ibnex_num_disconnect_iocs--; 3645 kmem_free(ioc->ioc_profile, sizeof (ib_dm_ioc_ctrl_profile_t)); 3646 ioc->ioc_profile = NULL; 3647 } 3648 3649 /* Update the properties that have changed */ 3650 mutex_exit(&ibnex.ibnex_mutex); 3651 if (evt_data.ib_gid_prop_updated) { 3652 if (ibnex_create_ioc_portgid_prop(dip, ioc_info) != 3653 IBNEX_SUCCESS) { 3654 mutex_enter(&ibnex.ibnex_mutex); 3655 return; 3656 } 3657 } 3658 if (evt_data.ib_srv_prop_updated) { 3659 if (ioc_info->ioc_profile.ioc_service_entries != 0 && 3660 (ibnex_create_ioc_srv_props(dip, ioc_info) != 3661 IBNEX_SUCCESS)) { 3662 mutex_enter(&ibnex.ibnex_mutex); 3663 return; 3664 } else if (ioc_info->ioc_profile.ioc_service_entries == 0) { 3665 (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, 3666 "service-id"); 3667 (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, 3668 "service-name"); 3669 } 3670 } 3671 mutex_enter(&ibnex.ibnex_mutex); 3672 ioc->ioc_ngids = ioc_info->ioc_nportgids; 3673 3674 /* 3675 * Post an event if : 3676 * 1. Properites have changed or NOTIFY_ALWAYS is set. 3677 * 2. child dip is configured and a valid cookie for 3678 * IB_PROP_UPDATE_EVENT. 3679 */ 3680 if ((evt_data.ib_prop_updated != 0 || 3681 (node_data->node_reprobe_state & 3682 IBNEX_NODE_REPROBE_NOTIFY_ALWAYS)) && 3683 ((node_data->node_state == IBNEX_CFGADM_CONFIGURED) && 3684 (evt_cookie != NULL))) { 3685 mutex_exit(&ibnex.ibnex_mutex); 3686 3687 if (ndi_post_event(ibnex.ibnex_dip, dip, 3688 evt_cookie, &evt_data) != NDI_SUCCESS) 3689 IBTF_DPRINTF_L2("ibnex", 3690 "\tndi_post_event failed\n"); 3691 3692 mutex_enter(&ibnex.ibnex_mutex); 3693 } 3694 3695 /* 3696 * Cleanup node_reprobe_state, for ibt_reprobe_dev 3697 * requests, when reprobe all / node reprobe is in 3698 * progress. ibnex_reprobe_ioc_dev is not called 3699 * in this case. 3700 */ 3701 if (node_data->node_reprobe_state == 3702 IBNEX_NODE_REPROBE_NOTIFY_ALWAYS) 3703 ibnex_wakeup_reprobe_ioc(node_data, 0); 3704 } 3705 3706 static ibnex_rval_t 3707 ibnex_unique_svcname(char *svcname) 3708 { 3709 int i; 3710 3711 /* Check Port Services */ 3712 for (i = 0; i < ibnex.ibnex_num_comm_svcs; i++) 3713 if (ibnex.ibnex_comm_svc_names[i] && strncmp(svcname, 3714 ibnex.ibnex_comm_svc_names[i], 4) == 0) 3715 return (IBNEX_FAILURE); 3716 3717 /* Check VPPA Services */ 3718 for (i = 0; i < ibnex.ibnex_nvppa_comm_svcs; i++) 3719 if (ibnex.ibnex_vppa_comm_svc_names[i] && strncmp(svcname, 3720 ibnex.ibnex_vppa_comm_svc_names[i], 4) == 0) 3721 return (IBNEX_FAILURE); 3722 3723 /* Check HCA_SVC Services */ 3724 for (i = 0; i < ibnex.ibnex_nhcasvc_comm_svcs; i++) 3725 if (ibnex.ibnex_hcasvc_comm_svc_names[i] && strncmp(svcname, 3726 ibnex.ibnex_hcasvc_comm_svc_names[i], 4) == 0) 3727 return (IBNEX_FAILURE); 3728 3729 return (IBNEX_SUCCESS); 3730 } 3731 3732 static void 3733 ibnex_handle_reprobe_dev(void *arg) 3734 { 3735 dev_info_t *dip = (dev_info_t *)arg; 3736 ibnex_node_data_t *node_data; 3737 3738 ASSERT(dip != NULL); 3739 node_data = ddi_get_parent_data(dip); 3740 ASSERT(node_data); 3741 3742 /* 3743 * Return success if: 3744 * 1. Reprobe for all nodes are in progress 3745 * 2. Reprobe for this node is in progress. 3746 * The reprobe in progress will complete eventually and 3747 * update the properties, if required. 3748 */ 3749 mutex_enter(&ibnex.ibnex_mutex); 3750 if (ibnex.ibnex_reprobe_state != 0 || 3751 node_data->node_reprobe_state != 0) { 3752 /* 3753 * Setting NOTIFY_ALWAYS to ensure that 3754 * DDI event is delivered always for 3755 * ibt_reprobe_dev 3756 */ 3757 node_data->node_reprobe_state |= 3758 IBNEX_NODE_REPROBE_NOTIFY_ALWAYS; 3759 mutex_exit(&ibnex.ibnex_mutex); 3760 return; 3761 } 3762 node_data->node_reprobe_state = 3763 IBNEX_NODE_REPROBE_NOTIFY_ALWAYS; 3764 mutex_exit(&ibnex.ibnex_mutex); 3765 ibnex_reprobe_ioc_dev(arg); 3766 } 3767 3768 3769 /* 3770 * MPxIO pathmangement routines. Currently IB nexus does not support 3771 * any kind of pathmangement. So, just return success to make MPxIO 3772 * framework happy. 3773 */ 3774 /*ARGSUSED*/ 3775 static int 3776 ib_vhci_pi_init(dev_info_t *dip, mdi_pathinfo_t *pip, int flag) 3777 { 3778 IBTF_DPRINTF_L4("ibnex", "\tpi_init: dip %p pip %p", dip, pip); 3779 return (MDI_SUCCESS); 3780 } 3781 3782 3783 /*ARGSUSED*/ 3784 static int 3785 ib_vhci_pi_uninit(dev_info_t *dip, mdi_pathinfo_t *pip, int flag) 3786 { 3787 IBTF_DPRINTF_L4("ibnex", "\tpi_uninit: dip %p pip %p", dip, pip); 3788 return (MDI_SUCCESS); 3789 } 3790 3791 3792 /*ARGSUSED*/ 3793 static int 3794 ib_vhci_pi_state_change(dev_info_t *dip, mdi_pathinfo_t *pip, 3795 mdi_pathinfo_state_t state, uint32_t arg1, int arg2) 3796 { 3797 IBTF_DPRINTF_L4("ibnex", 3798 "\tpi_state_change: dip %p pip %p state %x", dip, pip, state); 3799 return (MDI_SUCCESS); 3800 } 3801 3802 3803 /*ARGSUSED*/ 3804 static int 3805 ib_vhci_failover(dev_info_t *dip1, dev_info_t *dip2, int arg) 3806 { 3807 return (MDI_SUCCESS); 3808 } 3809 3810 3811 static int 3812 ibnex_bus_power(dev_info_t *parent, void *impl_arg, 3813 pm_bus_power_op_t op, void *arg, void *result) 3814 { 3815 3816 int ret = DDI_SUCCESS; 3817 3818 IBTF_DPRINTF_L4("ibnex", "\tbus_power: begin: op = %d", op); 3819 3820 /* 3821 * Generic processing in MPxIO framework 3822 */ 3823 ret = mdi_bus_power(parent, impl_arg, op, arg, result); 3824 3825 switch (ret) { 3826 case MDI_SUCCESS: 3827 ret = DDI_SUCCESS; 3828 break; 3829 case MDI_FAILURE: 3830 ret = DDI_FAILURE; 3831 break; 3832 default: 3833 break; 3834 } 3835 3836 return (ret); 3837 } 3838