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