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