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