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 /* 23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 /* 27 * The Ethernet Over Infiniband Nexus driver is a bus nexus driver 28 * that enumerates all the EoIB nodes. 29 */ 30 31 #include <sys/types.h> 32 #include <sys/conf.h> 33 #include <sys/devops.h> 34 #include <sys/kmem.h> 35 #include <sys/ksynch.h> 36 #include <sys/modctl.h> 37 #include <sys/stat.h> 38 #include <sys/ddi.h> 39 #include <sys/sunddi.h> 40 #include <sys/sunndi.h> 41 42 #include <sys/ib/clients/eoib/enx_impl.h> 43 44 /* 45 * Global per-instance EoIB Nexus data. Only one instance 46 * of EoIB Nexus is supported 47 */ 48 eibnx_t *enx_global_ss = NULL; 49 50 /* 51 * Static function declarations 52 */ 53 static int eibnx_attach(dev_info_t *, ddi_attach_cmd_t); 54 static int eibnx_detach(dev_info_t *, ddi_detach_cmd_t); 55 static int eibnx_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 56 static int eibnx_bus_ctl(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, 57 void *, void *); 58 59 static int eibnx_get_eventcookie(dev_info_t *, dev_info_t *, char *, 60 ddi_eventcookie_t *); 61 static int eibnx_add_eventcall(dev_info_t *, dev_info_t *, ddi_eventcookie_t, 62 void (*)(dev_info_t *, ddi_eventcookie_t, void *, void *), 63 void *, ddi_callback_id_t *); 64 static int eibnx_remove_eventcall(dev_info_t *, ddi_callback_id_t); 65 static int eibnx_post_event(dev_info_t *, dev_info_t *, 66 ddi_eventcookie_t, void *); 67 68 static int eibnx_bus_config(dev_info_t *, uint_t, ddi_bus_config_op_t, 69 void *, dev_info_t **); 70 static int eibnx_bus_unconfig(dev_info_t *, uint_t, ddi_bus_config_op_t, 71 void *); 72 static int eibnx_config_all_children(dev_info_t *); 73 static void eibnx_unconfig_all_children(dev_info_t *); 74 static int eibnx_config_child(char *, dev_info_t **); 75 static int eibnx_unconfig_child(char *); 76 77 /* 78 * Cbops 79 */ 80 static struct cb_ops enx_cb_ops = { 81 eibnx_devctl_open, /* cb_open */ 82 eibnx_devctl_close, /* cb_close */ 83 nodev, /* cb_strategy */ 84 nodev, /* cb_print */ 85 nodev, /* cb_dump */ 86 nodev, /* cb_read */ 87 nodev, /* cb_write */ 88 eibnx_devctl_ioctl, /* cb_ioctl */ 89 nodev, /* cb_devmap */ 90 nodev, /* cb_mmap */ 91 nodev, /* cb_segmap */ 92 nochpoll, /* cb_chpoll */ 93 ddi_prop_op, /* cb_prop_op */ 94 NULL, /* cb_str */ 95 D_MP, /* cb_flag */ 96 CB_REV, /* cb_rev */ 97 nodev, /* cb_aread */ 98 nodev /* cb_awrite */ 99 }; 100 101 /* 102 * Busops 103 */ 104 static struct bus_ops enx_bus_ops = { 105 BUSO_REV, 106 nullbusmap, /* bus_map */ 107 NULL, /* bus_get_intrspec */ 108 NULL, /* bus_add_intrspec */ 109 NULL, /* bus_remove_intrspec */ 110 i_ddi_map_fault, /* bus_map_fault */ 111 ddi_no_dma_map, /* bus_dma_map */ 112 NULL, /* bus_dma_allochdl */ 113 NULL, /* bus_dma_freehdl */ 114 NULL, /* bus_dma_bindhdl */ 115 NULL, /* bus_dma_unbindhdl */ 116 NULL, /* bus_dma_flush */ 117 NULL, /* bus_dma_win */ 118 NULL, /* bus_dma_ctl */ 119 eibnx_bus_ctl, /* bus_ctl */ 120 ddi_bus_prop_op, /* bus_prop_op */ 121 eibnx_get_eventcookie, /* bus_get_eventcookie */ 122 eibnx_add_eventcall, /* bus_add_eventcall */ 123 eibnx_remove_eventcall, /* bus_remove_eventcall */ 124 eibnx_post_event, /* bus_post_event */ 125 NULL, /* bus_intr_ctl */ 126 eibnx_bus_config, /* bus_config */ 127 eibnx_bus_unconfig, /* bus_unconfig */ 128 }; 129 130 /* 131 * Nexus ops 132 */ 133 static struct dev_ops enx_ops = { 134 DEVO_REV, /* devo_rev, */ 135 0, /* devo_refcnt */ 136 eibnx_getinfo, /* devo_info */ 137 nulldev, /* devo_identify */ 138 nulldev, /* devo_probe */ 139 eibnx_attach, /* devo_attach */ 140 eibnx_detach, /* devo_detach */ 141 nodev, /* devo_reset */ 142 &enx_cb_ops, /* devo_cb_ops */ 143 &enx_bus_ops, /* devo_bus_ops */ 144 nulldev, /* devo_power */ 145 ddi_quiesce_not_needed /* devo_quiesce */ 146 }; 147 148 /* 149 * Module linkage information for the kernel 150 */ 151 static struct modldrv enx_modldrv = { 152 &mod_driverops, /* Driver module */ 153 "EoIB Nexus", /* Driver name and version */ 154 &enx_ops, /* Driver ops */ 155 }; 156 157 static struct modlinkage enx_modlinkage = { 158 MODREV_1, (void *)&enx_modldrv, NULL 159 }; 160 161 /* 162 * EoIB NDI events 163 */ 164 static ndi_event_definition_t enx_ndi_event_defs[] = { 165 { ENX_EVENT_TAG_GW_INFO_UPDATE, EIB_NDI_EVENT_GW_INFO_UPDATE, 166 EPL_KERNEL, NDI_EVENT_POST_TO_TGT }, 167 { ENX_EVENT_TAG_GW_AVAILABLE, EIB_NDI_EVENT_GW_AVAILABLE, 168 EPL_KERNEL, NDI_EVENT_POST_TO_TGT }, 169 { ENX_EVENT_TAG_LOGIN_ACK, EIB_NDI_EVENT_LOGIN_ACK, 170 EPL_KERNEL, NDI_EVENT_POST_TO_TGT } 171 }; 172 #define ENX_NUM_NDI_EVENTS \ 173 (sizeof (enx_ndi_event_defs) / sizeof (enx_ndi_event_defs[0])) 174 175 static ndi_event_set_t enx_ndi_events = { 176 NDI_EVENTS_REV1, 177 ENX_NUM_NDI_EVENTS, 178 enx_ndi_event_defs 179 }; 180 ndi_event_hdl_t enx_ndi_event_hdl; 181 182 183 /* 184 * Common loadable module entry points _init, _fini, _info 185 */ 186 187 int 188 _init(void) 189 { 190 int ret; 191 192 if ((ret = mod_install(&enx_modlinkage)) == 0) 193 eibnx_debug_init(); 194 195 return (ret); 196 } 197 198 int 199 _fini(void) 200 { 201 int ret; 202 203 if ((ret = mod_remove(&enx_modlinkage)) == 0) 204 eibnx_debug_fini(); 205 206 return (ret); 207 } 208 209 int 210 _info(struct modinfo *modinfop) 211 { 212 return (mod_info(&enx_modlinkage, modinfop)); 213 } 214 215 /* 216 * Autoconfiguration entry points: attach, detach, getinfo 217 */ 218 219 static int 220 eibnx_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 221 { 222 eibnx_t *ss; 223 int instance; 224 225 if (cmd == DDI_RESUME) 226 return (DDI_SUCCESS); 227 else if (cmd != DDI_ATTACH) 228 return (DDI_FAILURE); 229 230 /* 231 * Don't allow more than one instance to attach 232 */ 233 if (enx_global_ss) 234 return (DDI_FAILURE); 235 236 /* 237 * Alloc this instance's softstate 238 */ 239 ss = kmem_zalloc(sizeof (eibnx_t), KM_SLEEP); 240 ss->nx_dip = dip; 241 242 enx_global_ss = ss; 243 244 /* 245 * Allocate our NDI event handle and bind our event set 246 */ 247 if (ndi_event_alloc_hdl(dip, 0, &enx_ndi_event_hdl, 248 NDI_SLEEP) != NDI_SUCCESS) { 249 ENX_DPRINTF_ERR("ndi_event_alloc_hdl(dip=0x%llx) " 250 "failed", dip); 251 252 kmem_free(enx_global_ss, sizeof (eibnx_t)); 253 enx_global_ss = NULL; 254 return (DDI_FAILURE); 255 } 256 if (ndi_event_bind_set(enx_ndi_event_hdl, &enx_ndi_events, 257 NDI_SLEEP) != NDI_SUCCESS) { 258 ENX_DPRINTF_ERR("ndi_event_bind_set(ndi_event_hdl=0x%llx) " 259 "failed", enx_ndi_event_hdl); 260 261 (void) ndi_event_free_hdl(enx_ndi_event_hdl); 262 enx_ndi_event_hdl = NULL; 263 kmem_free(enx_global_ss, sizeof (eibnx_t)); 264 enx_global_ss = NULL; 265 return (DDI_FAILURE); 266 } 267 268 /* 269 * Create "devctl" minor node for general ioctl interface to the 270 * eoib nexus. If we cannot, it isn't fatal - we'll operate without 271 * the support for devctl (but issue a warning). 272 */ 273 instance = ddi_get_instance(dip); 274 if (ddi_create_minor_node(dip, "devctl", S_IFCHR, instance, 275 DDI_NT_NEXUS, 0) != DDI_SUCCESS) { 276 ENX_DPRINTF_WARN("could not create devctl minor node " 277 "for instance %d", instance); 278 } 279 280 /* 281 * Do IBTF related initializations. If we fail, we cannot operate, 282 * so fail the attach. 283 */ 284 if (eibnx_ibt_init(ss) != ENX_E_SUCCESS) { 285 (void) ddi_remove_minor_node(dip, NULL); 286 (void) ndi_event_unbind_set(enx_ndi_event_hdl, 287 &enx_ndi_events, NDI_SLEEP); 288 (void) ndi_event_free_hdl(enx_ndi_event_hdl); 289 enx_ndi_event_hdl = NULL; 290 kmem_free(enx_global_ss, sizeof (eibnx_t)); 291 enx_global_ss = NULL; 292 return (DDI_FAILURE); 293 } 294 295 return (DDI_SUCCESS); 296 } 297 298 static int 299 eibnx_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 300 { 301 eibnx_t *ss = enx_global_ss; 302 303 if (cmd == DDI_SUSPEND) 304 return (DDI_SUCCESS); 305 else if (cmd != DDI_DETACH) 306 return (DDI_FAILURE); 307 308 /* 309 * If there's no instance of eibnx attached, fail 310 */ 311 if (ss == NULL) 312 return (DDI_FAILURE); 313 314 /* 315 * Before we do anything, we need to stop the port monitors 316 * we may have started earlier. 317 */ 318 eibnx_terminate_monitors(); 319 320 /* 321 * If eibnx_ibt_fini() fails, it could be because one of the 322 * HCA's pd could not be freed, the hca could not be closed 323 * or the IBTF detach wasn't successful. If this is the case, 324 * we have to return failure, but cannot do much about the 325 * port monitors we've already terminated. 326 */ 327 if (eibnx_ibt_fini(ss) == ENX_E_FAILURE) 328 return (DDI_FAILURE); 329 330 /* 331 * Cleanup any devctl minor node we may have created, unbind and 332 * free ndi event handle and free the instance softstate. 333 */ 334 (void) ddi_remove_minor_node(dip, NULL); 335 (void) ndi_event_unbind_set(enx_ndi_event_hdl, 336 &enx_ndi_events, NDI_SLEEP); 337 (void) ndi_event_free_hdl(enx_ndi_event_hdl); 338 enx_ndi_event_hdl = NULL; 339 kmem_free(enx_global_ss, sizeof (eibnx_t)); 340 enx_global_ss = NULL; 341 342 return (DDI_SUCCESS); 343 } 344 345 /*ARGSUSED*/ 346 static int 347 eibnx_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp) 348 { 349 eibnx_t *ss = enx_global_ss; 350 int ret; 351 352 if (cmd == DDI_INFO_DEVT2DEVINFO) { 353 *resultp = (ss) ? ss->nx_dip : NULL; 354 ret = (ss) ? DDI_SUCCESS : DDI_FAILURE; 355 } else if (cmd == DDI_INFO_DEVT2INSTANCE) { 356 *resultp = 0; 357 ret = DDI_SUCCESS; 358 } else { 359 ret = DDI_FAILURE; 360 } 361 362 return (ret); 363 } 364 365 /* 366 * Busops: bus_ctl, bus_config, bus_unconfig 367 */ 368 369 /*ARGSUSED*/ 370 static int 371 eibnx_bus_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop, 372 void *arg, void *result) 373 { 374 dev_info_t *child = arg; 375 int ret; 376 char name[MAXNAMELEN]; 377 378 switch (ctlop) { 379 case DDI_CTLOPS_REPORTDEV: 380 ENX_DPRINTF_DEBUG("EoIB device: %s@%s, %s%d", 381 ddi_node_name(rdip), ddi_get_name_addr(rdip), 382 ddi_driver_name(rdip), ddi_get_instance(rdip)); 383 /*FALLTHROUGH*/ 384 385 case DDI_CTLOPS_ATTACH: 386 case DDI_CTLOPS_DETACH: 387 case DDI_CTLOPS_POWER: 388 case DDI_CTLOPS_SIDDEV: 389 case DDI_CTLOPS_IOMIN: 390 ret = DDI_SUCCESS; 391 break; 392 393 case DDI_CTLOPS_INITCHILD: 394 if ((ret = eibnx_name_child(child, name, 395 sizeof (name))) == DDI_SUCCESS) { 396 ddi_set_name_addr(child, name); 397 } 398 break; 399 400 case DDI_CTLOPS_UNINITCHILD: 401 ddi_set_name_addr(child, NULL); 402 ret = DDI_SUCCESS; 403 break; 404 405 default: 406 ret = ddi_ctlops(dip, rdip, ctlop, arg, result); 407 break; 408 } 409 410 return (ret); 411 } 412 413 /*ARGSUSED*/ 414 static int 415 eibnx_bus_config(dev_info_t *parent, uint_t flags, 416 ddi_bus_config_op_t op, void *arg, dev_info_t **childp) 417 { 418 eibnx_t *ss = enx_global_ss; 419 int ret = NDI_SUCCESS; 420 421 switch (op) { 422 case BUS_CONFIG_ONE: 423 eibnx_busop_inprog_enter(ss); 424 ret = eibnx_config_child(arg, childp); 425 eibnx_busop_inprog_exit(ss); 426 break; 427 428 case BUS_CONFIG_ALL: 429 case BUS_CONFIG_DRIVER: 430 eibnx_busop_inprog_enter(ss); 431 if ((ss->nx_busop_flags & NX_FL_BUSCFG_COMPLETE) == 0) { 432 ret = eibnx_config_all_children(parent); 433 if (ret == NDI_SUCCESS) 434 ss->nx_busop_flags |= NX_FL_BUSCFG_COMPLETE; 435 } 436 eibnx_busop_inprog_exit(ss); 437 break; 438 439 default: 440 ret = NDI_FAILURE; 441 } 442 443 if (ret == NDI_SUCCESS) 444 ret = ndi_busop_bus_config(parent, flags, op, arg, childp, 0); 445 446 return (ret); 447 } 448 449 static int 450 eibnx_bus_unconfig(dev_info_t *parent, uint_t flags, 451 ddi_bus_config_op_t op, void *arg) 452 { 453 eibnx_t *ss = enx_global_ss; 454 int ret; 455 456 ret = ndi_busop_bus_unconfig(parent, flags, op, arg); 457 if (ret != NDI_SUCCESS) 458 return (ret); 459 460 switch (op) { 461 case BUS_UNCONFIG_ONE: 462 if (flags & (NDI_UNCONFIG | NDI_DEVI_REMOVE)) { 463 eibnx_busop_inprog_enter(ss); 464 465 if ((ret = eibnx_unconfig_child(arg)) == ENX_E_SUCCESS) 466 ss->nx_busop_flags &= (~NX_FL_BUSCFG_COMPLETE); 467 else { 468 ENX_DPRINTF_DEBUG("eibnx_bus_config: " 469 "unconfig child %s failed", (char *)arg); 470 } 471 472 eibnx_busop_inprog_exit(ss); 473 } 474 break; 475 476 case BUS_UNCONFIG_ALL: 477 case BUS_UNCONFIG_DRIVER: 478 if (flags & (NDI_UNCONFIG | NDI_DEVI_REMOVE)) { 479 eibnx_busop_inprog_enter(ss); 480 481 eibnx_unconfig_all_children(parent); 482 ss->nx_busop_flags &= (~NX_FL_BUSCFG_COMPLETE); 483 484 eibnx_busop_inprog_exit(ss); 485 } 486 break; 487 488 default: 489 break; 490 } 491 492 return (ret); 493 } 494 495 /* 496 * Event Handling: bus_get_eventcookie, bus_add_eventcall, bus_remove_eventcall 497 * and bus_post_event 498 */ 499 500 /*ARGSUSED*/ 501 static int 502 eibnx_get_eventcookie(dev_info_t *dip, dev_info_t *rdip, 503 char *name, ddi_eventcookie_t *cookiep) 504 { 505 return (ndi_event_retrieve_cookie(enx_ndi_event_hdl, rdip, name, 506 cookiep, NDI_EVENT_NOPASS)); 507 } 508 509 /*ARGSUSED*/ 510 static int 511 eibnx_add_eventcall(dev_info_t *dip, dev_info_t *rdip, ddi_eventcookie_t cookie, 512 void (*callback)(dev_info_t *cb_dip, ddi_eventcookie_t cb_cookie, 513 void *cb_arg, void *cb_impl_data), 514 void *arg, ddi_callback_id_t *cb_id) 515 { 516 return (ndi_event_add_callback(enx_ndi_event_hdl, rdip, cookie, 517 callback, arg, NDI_SLEEP, cb_id)); 518 } 519 520 /*ARGSUSED*/ 521 static int 522 eibnx_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id) 523 { 524 return (ndi_event_remove_callback(enx_ndi_event_hdl, cb_id)); 525 } 526 527 /*ARGSUSED*/ 528 static int 529 eibnx_post_event(dev_info_t *dip, dev_info_t *rdip, 530 ddi_eventcookie_t cookie, void *impl_data) 531 { 532 return (ndi_event_run_callbacks(enx_ndi_event_hdl, rdip, cookie, 533 impl_data)); 534 } 535 536 /* 537 * Routines to configure/unconfigure EoIB node(s) on a system. 538 */ 539 540 /*ARGSUSED*/ 541 static int 542 eibnx_config_all_children(dev_info_t *parent) 543 { 544 eibnx_t *ss = enx_global_ss; 545 eibnx_hca_t *hca; 546 eibnx_port_t *port; 547 eibnx_thr_info_t *ti; 548 eibnx_thr_info_t *ti_tail; 549 eibnx_gw_info_t *gwi; 550 551 /* 552 * Go through each port of each hca and create a thread to solicit, 553 * monitor, receive advertisements, create eoib nodes and attach eoib 554 * driver instances. 555 */ 556 mutex_enter(&ss->nx_lock); 557 if (!ss->nx_monitors_up) { 558 ss->nx_thr_info = ti_tail = NULL; 559 for (hca = ss->nx_hca; hca; hca = hca->hc_next) { 560 for (port = hca->hc_port; port; port = port->po_next) { 561 ti = eibnx_start_port_monitor(hca, port); 562 if (ti_tail) { 563 ti_tail->ti_next = ti; 564 } else { 565 ss->nx_thr_info = ti; 566 } 567 ti_tail = ti; 568 } 569 } 570 571 ss->nx_monitors_up = B_TRUE; 572 mutex_exit(&ss->nx_lock); 573 574 return (NDI_SUCCESS); 575 } 576 mutex_exit(&ss->nx_lock); 577 578 while (eibnx_locate_unconfigured_node(&ti, &gwi) == ENX_E_SUCCESS) 579 (void) eibnx_configure_node(ti, gwi, NULL); 580 581 return (NDI_SUCCESS); 582 } 583 584 /* 585 * Routine to unconfigure all the EoIB nodes on a system. This terminates 586 * all the per-port monitor threads and releases any resources allocated. 587 */ 588 589 /*ARGSUSED*/ 590 static void 591 eibnx_unconfig_all_children(dev_info_t *parent) 592 { 593 eibnx_t *ss = enx_global_ss; 594 eibnx_thr_info_t *ti; 595 eibnx_child_t *ch; 596 597 mutex_enter(&ss->nx_lock); 598 for (ti = ss->nx_thr_info; ti; ti = ti->ti_next) { 599 mutex_enter(&ti->ti_child_lock); 600 for (ch = ti->ti_child; ch; ch = ch->ch_next) { 601 ch->ch_dip = NULL; 602 } 603 mutex_exit(&ti->ti_child_lock); 604 } 605 mutex_exit(&ss->nx_lock); 606 } 607 608 /*ARGSUSED*/ 609 static int 610 eibnx_config_child(char *devname, dev_info_t **childp) 611 { 612 eibnx_thr_info_t *ti; 613 eibnx_gw_info_t *gwi; 614 615 if (eibnx_locate_node_name(devname, &ti, &gwi) == ENX_E_FAILURE) { 616 ENX_DPRINTF_DEBUG("eibnx_config_child: invalid eoib " 617 "nodename %s, no such address", devname); 618 return (ENX_E_FAILURE); 619 } 620 621 return (eibnx_configure_node(ti, gwi, childp)); 622 } 623 624 /*ARGSUSED*/ 625 static int 626 eibnx_unconfig_child(char *devname) 627 { 628 eibnx_thr_info_t *ti; 629 eibnx_gw_info_t *gwi; 630 631 if (eibnx_locate_node_name(devname, &ti, &gwi) == ENX_E_FAILURE) { 632 ENX_DPRINTF_DEBUG("eibnx_unconfig_child: invalid eoib " 633 "nodename %s, no such address", devname); 634 return (ENX_E_FAILURE); 635 } 636 637 return (eibnx_unconfigure_node(ti, gwi)); 638 }