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