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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * The following notice accompanied the original version of this file: 28 * 29 * BSD LICENSE 30 * 31 * Copyright(c) 2007 Intel Corporation. All rights reserved. 32 * All rights reserved. 33 * 34 * Redistribution and use in source and binary forms, with or without 35 * modification, are permitted provided that the following conditions 36 * are met: 37 * 38 * * Redistributions of source code must retain the above copyright 39 * notice, this list of conditions and the following disclaimer. 40 * * Redistributions in binary form must reproduce the above copyright 41 * notice, this list of conditions and the following disclaimer in 42 * the documentation and/or other materials provided with the 43 * distribution. 44 * * Neither the name of Intel Corporation nor the names of its 45 * contributors may be used to endorse or promote products derived 46 * from this software without specific prior written permission. 47 * 48 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 49 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 50 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 51 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 52 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 53 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 54 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 55 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 56 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 57 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 58 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 59 */ 60 61 /* 62 * Driver kernel header files 63 */ 64 #include <sys/conf.h> 65 #include <sys/ddi.h> 66 #include <sys/stat.h> 67 #include <sys/pci.h> 68 #include <sys/sunddi.h> 69 #include <sys/modctl.h> 70 #include <sys/file.h> 71 #include <sys/cred.h> 72 #include <sys/byteorder.h> 73 #include <sys/atomic.h> 74 #include <sys/modhash.h> 75 #include <sys/scsi/scsi.h> 76 #include <sys/ethernet.h> 77 78 /* 79 * COMSTAR header files 80 */ 81 #include <sys/stmf_defines.h> 82 #include <sys/fct_defines.h> 83 #include <sys/stmf.h> 84 #include <sys/portif.h> 85 #include <sys/fct.h> 86 87 /* 88 * FCoE header files 89 */ 90 #include <sys/fcoe/fcoe_common.h> 91 92 /* 93 * Driver's own header files 94 */ 95 #include <fcoet.h> 96 #include <fcoet_eth.h> 97 #include <fcoet_fc.h> 98 99 /* 100 * static function forward declaration 101 */ 102 static int fcoet_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 103 static int fcoet_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 104 static int fcoet_open(dev_t *devp, int flag, int otype, cred_t *credp); 105 static int fcoet_close(dev_t dev, int flag, int otype, cred_t *credp); 106 static int fcoet_ioctl(dev_t dev, int cmd, intptr_t data, int mode, 107 cred_t *credp, int *rval); 108 static fct_status_t fcoet_attach_init(fcoet_soft_state_t *ss); 109 static fct_status_t fcoet_detach_uninit(fcoet_soft_state_t *ss); 110 static void fcoet_watchdog(void *arg); 111 static void fcoet_handle_sol_flogi(fcoet_soft_state_t *ss); 112 static stmf_data_buf_t *fcoet_dbuf_alloc(fct_local_port_t *port, 113 uint32_t size, uint32_t *pminsize, uint32_t flags); 114 static void fcoet_dbuf_free(fct_dbuf_store_t *fds, stmf_data_buf_t *dbuf); 115 static int fcoet_dbuf_init(fcoet_soft_state_t *ss); 116 static void fcoet_dbuf_destroy(fcoet_soft_state_t *ss); 117 static uint_t 118 fcoet_sol_oxid_hash_empty(mod_hash_key_t key, mod_hash_val_t *val, void *arg); 119 static uint_t 120 fcoet_unsol_rxid_hash_empty(mod_hash_key_t key, mod_hash_val_t *val, void *arg); 121 122 /* 123 * Driver identificaton stuff 124 */ 125 static struct cb_ops fcoet_cb_ops = { 126 fcoet_open, 127 fcoet_close, 128 nodev, 129 nodev, 130 nodev, 131 nodev, 132 nodev, 133 fcoet_ioctl, 134 nodev, 135 nodev, 136 nodev, 137 nochpoll, 138 ddi_prop_op, 139 0, 140 D_MP | D_NEW 141 }; 142 143 static struct dev_ops fcoet_ops = { 144 DEVO_REV, 145 0, 146 nodev, 147 nulldev, 148 nulldev, 149 fcoet_attach, 150 fcoet_detach, 151 nodev, 152 &fcoet_cb_ops, 153 NULL, 154 ddi_power 155 }; 156 157 static struct modldrv modldrv = { 158 &mod_driverops, 159 FCOET_MOD_NAME, 160 &fcoet_ops, 161 }; 162 163 static struct modlinkage modlinkage = { 164 MODREV_1, &modldrv, NULL 165 }; 166 167 /* 168 * Driver's global variables 169 */ 170 static kmutex_t fcoet_mutex; 171 static void *fcoet_state = NULL; 172 173 int fcoet_use_ext_log = 1; 174 static char fcoet_provider_name[] = "fcoet"; 175 static struct stmf_port_provider *fcoet_pp = NULL; 176 177 /* 178 * Common loadable module entry points _init, _fini, _info 179 */ 180 181 int 182 _init(void) 183 { 184 int ret; 185 186 ret = ddi_soft_state_init(&fcoet_state, sizeof (fcoet_soft_state_t), 0); 187 if (ret == 0) { 188 fcoet_pp = (stmf_port_provider_t *) 189 stmf_alloc(STMF_STRUCT_PORT_PROVIDER, 0, 0); 190 fcoet_pp->pp_portif_rev = PORTIF_REV_1; 191 fcoet_pp->pp_name = fcoet_provider_name; 192 if (stmf_register_port_provider(fcoet_pp) != STMF_SUCCESS) { 193 stmf_free(fcoet_pp); 194 ddi_soft_state_fini(&fcoet_state); 195 return (EIO); 196 } 197 198 mutex_init(&fcoet_mutex, 0, MUTEX_DRIVER, 0); 199 ret = mod_install(&modlinkage); 200 if (ret) { 201 stmf_deregister_port_provider(fcoet_pp); 202 stmf_free(fcoet_pp); 203 mutex_destroy(&fcoet_mutex); 204 ddi_soft_state_fini(&fcoet_state); 205 } 206 } 207 208 FCOET_LOG("_init", "exit _init with %x", ret); 209 return (ret); 210 } 211 212 int 213 _fini(void) 214 { 215 int ret; 216 217 ret = mod_remove(&modlinkage); 218 if (ret == 0) { 219 stmf_deregister_port_provider(fcoet_pp); 220 stmf_free(fcoet_pp); 221 mutex_destroy(&fcoet_mutex); 222 ddi_soft_state_fini(&fcoet_state); 223 } 224 225 FCOET_LOG("_fini", "exit _fini with %x", ret); 226 return (ret); 227 } 228 229 int 230 _info(struct modinfo *modinfop) 231 { 232 return (mod_info(&modlinkage, modinfop)); 233 } 234 235 /* 236 * Autoconfiguration entry points: attach, detach, getinfo 237 */ 238 239 static int 240 fcoet_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 241 { 242 int ret = DDI_FAILURE; 243 int instance; 244 fcoet_soft_state_t *ss; 245 246 instance = ddi_get_instance(dip); 247 FCOET_LOG("fcoet_attach", "get instance %d", instance); 248 249 switch (cmd) { 250 case DDI_ATTACH: 251 ret = ddi_soft_state_zalloc(fcoet_state, instance); 252 if (ret != DDI_SUCCESS) { 253 return (ret); 254 } 255 256 ss = ddi_get_soft_state(fcoet_state, instance); 257 ss->ss_instance = instance; 258 ss->ss_dip = dip; 259 260 ret = fcoet_attach_init(ss); 261 if (ret != FCOE_SUCCESS) { 262 ddi_soft_state_free(fcoet_state, instance); 263 ret = DDI_FAILURE; 264 } 265 266 FCOET_LOG("fcoet_attach", "end with-%x", ret); 267 break; 268 269 case DDI_RESUME: 270 ret = DDI_SUCCESS; 271 break; 272 273 default: 274 FCOET_LOG("fcoet_attach", "unspported attach cmd-%x", cmd); 275 break; 276 } 277 278 return (ret); 279 } 280 281 static int 282 fcoet_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 283 { 284 int ret = DDI_FAILURE; 285 int fcoe_ret; 286 int instance; 287 fcoet_soft_state_t *ss; 288 289 instance = ddi_get_instance(dip); 290 ss = ddi_get_soft_state(fcoet_state, instance); 291 if (ss == NULL) { 292 return (ret); 293 } 294 295 switch (cmd) { 296 case DDI_DETACH: 297 fcoe_ret = fcoet_detach_uninit(ss); 298 if (fcoe_ret == FCOE_SUCCESS) { 299 ret = DDI_SUCCESS; 300 } 301 302 FCOET_LOG("fcoet_detach", "fcoet_detach_uninit end with-%x", 303 fcoe_ret); 304 break; 305 306 case DDI_SUSPEND: 307 ret = DDI_SUCCESS; 308 break; 309 310 default: 311 FCOET_LOG("fcoet_detach", "unsupported detach cmd-%x", cmd); 312 break; 313 } 314 315 return (ret); 316 } 317 318 /* 319 * Device access entry points 320 */ 321 static int 322 fcoet_open(dev_t *devp, int flag, int otype, cred_t *credp) 323 { 324 int instance; 325 fcoet_soft_state_t *ss; 326 327 if (otype != OTYP_CHR) { 328 return (EINVAL); 329 } 330 331 /* 332 * Since this is for debugging only, only allow root to issue ioctl now 333 */ 334 if (drv_priv(credp)) { 335 return (EPERM); 336 } 337 338 instance = (int)getminor(*devp); 339 ss = ddi_get_soft_state(fcoet_state, instance); 340 if (ss == NULL) { 341 return (ENXIO); 342 } 343 344 mutex_enter(&ss->ss_ioctl_mutex); 345 if (ss->ss_ioctl_flags & FCOET_IOCTL_FLAG_EXCL) { 346 /* 347 * It is already open for exclusive access. 348 * So shut the door on this caller. 349 */ 350 mutex_exit(&ss->ss_ioctl_mutex); 351 return (EBUSY); 352 } 353 354 if (flag & FEXCL) { 355 if (ss->ss_ioctl_flags & FCOET_IOCTL_FLAG_OPEN) { 356 /* 357 * Exclusive operation not possible 358 * as it is already opened 359 */ 360 mutex_exit(&ss->ss_ioctl_mutex); 361 return (EBUSY); 362 } 363 ss->ss_ioctl_flags |= FCOET_IOCTL_FLAG_EXCL; 364 } 365 ss->ss_ioctl_flags |= FCOET_IOCTL_FLAG_OPEN; 366 mutex_exit(&ss->ss_ioctl_mutex); 367 368 return (0); 369 } 370 371 /* ARGSUSED */ 372 static int 373 fcoet_close(dev_t dev, int flag, int otype, cred_t *credp) 374 { 375 int instance; 376 fcoet_soft_state_t *ss; 377 378 if (otype != OTYP_CHR) { 379 return (EINVAL); 380 } 381 382 instance = (int)getminor(dev); 383 ss = ddi_get_soft_state(fcoet_state, instance); 384 if (ss == NULL) { 385 return (ENXIO); 386 } 387 388 mutex_enter(&ss->ss_ioctl_mutex); 389 if ((ss->ss_ioctl_flags & FCOET_IOCTL_FLAG_OPEN) == 0) { 390 mutex_exit(&ss->ss_ioctl_mutex); 391 return (ENODEV); 392 } 393 394 /* 395 * It looks there's one hole here, maybe there could several concurrent 396 * shareed open session, but we never check this case. 397 * But it will not hurt too much, disregard it now. 398 */ 399 ss->ss_ioctl_flags &= ~FCOET_IOCTL_FLAG_MASK; 400 mutex_exit(&ss->ss_ioctl_mutex); 401 402 return (0); 403 } 404 405 /* ARGSUSED */ 406 static int 407 fcoet_ioctl(dev_t dev, int cmd, intptr_t data, int mode, 408 cred_t *credp, int *rval) 409 { 410 fcoet_soft_state_t *ss; 411 int ret = 0; 412 413 if (drv_priv(credp) != 0) { 414 return (EPERM); 415 } 416 417 ss = ddi_get_soft_state(fcoet_state, (int32_t)getminor(dev)); 418 if (ss == NULL) { 419 return (ENXIO); 420 } 421 422 switch (cmd) { 423 default: 424 FCOET_LOG("fcoet_ioctl", "ioctl-0x%02X", cmd); 425 ret = ENOTTY; 426 break; 427 } 428 429 *rval = ret; 430 return (ret); 431 } 432 433 static fct_status_t 434 fcoet_attach_init(fcoet_soft_state_t *ss) 435 { 436 fcoe_client_t client_fcoet; 437 fcoe_port_t *eport; 438 fct_local_port_t *port; 439 fct_dbuf_store_t *fds; 440 char *mac_name; 441 char taskq_name[32]; 442 int ret; 443 444 /* 445 * FCoE (fcoe is fcoet's dependent driver) 446 * First we need register fcoet to FCoE as one client 447 */ 448 client_fcoet.ect_eport_flags = EPORT_FLAG_TGT_MODE | 449 EPORT_FLAG_IS_DIRECT_P2P; 450 client_fcoet.ect_max_fc_frame_size = 2136; 451 client_fcoet.ect_private_frame_struct_size = sizeof (fcoet_frame_t); 452 client_fcoet.ect_rx_frame = fcoet_rx_frame; 453 client_fcoet.ect_port_event = fcoet_port_event; 454 client_fcoet.ect_release_sol_frame = fcoet_release_sol_frame; 455 client_fcoet.ect_client_port_struct = ss; 456 ret = ddi_prop_lookup_string(DDI_DEV_T_ANY, ss->ss_dip, 457 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "mac_name", &mac_name); 458 if (ret != DDI_PROP_SUCCESS) { 459 FCOET_LOG("fcoet_attach_init", "lookup_string failed"); 460 return (DDI_FAILURE); 461 } else { 462 bcopy(mac_name, client_fcoet.ect_channel_name, 463 strlen(mac_name)); 464 client_fcoet.ect_channel_name[strlen(mac_name)] = 0; 465 ddi_prop_free(mac_name); 466 } 467 FCOET_LOG("fcoet_attach_init", "channel_name is %s", 468 client_fcoet.ect_channel_name); 469 470 /* 471 * It's FCoE's responsiblity to initialize eport's all elements 472 */ 473 eport = fcoe_register_client(&client_fcoet); 474 if (eport == NULL) { 475 goto fail_register_client; 476 } 477 478 /* 479 * Now it's time to register local port to FCT 480 */ 481 if (fcoet_dbuf_init(ss) != FCOE_SUCCESS) { 482 goto fail_init_dbuf; 483 } 484 485 fds = (fct_dbuf_store_t *)fct_alloc(FCT_STRUCT_DBUF_STORE, 0, 0); 486 if (fds == NULL) { 487 goto fail_alloc_dbuf; 488 } else { 489 fds->fds_alloc_data_buf = fcoet_dbuf_alloc; 490 fds->fds_free_data_buf = fcoet_dbuf_free; 491 fds->fds_fca_private = (void *)ss; 492 } 493 494 port = (fct_local_port_t *)fct_alloc(FCT_STRUCT_LOCAL_PORT, 0, 0); 495 if (port == NULL) { 496 goto fail_alloc_port; 497 } else { 498 /* 499 * Do ss's initialization now 500 */ 501 (void) snprintf(ss->ss_alias, sizeof (ss->ss_alias), "fcoet%d", 502 ss->ss_instance); 503 ret = ddi_create_minor_node(ss->ss_dip, "admin", 504 S_IFCHR, ss->ss_instance, DDI_NT_STMF_PP, 0); 505 if (ret != DDI_SUCCESS) { 506 goto fail_minor_node; 507 } 508 509 ss->ss_state = FCT_STATE_OFFLINE; 510 ss->ss_state_not_acked = 1; 511 ss->ss_flags = 0; 512 ss->ss_port = port; 513 ss->ss_eport = eport; 514 FCOE_SET_DEFAULT_FPORT_ADDR(eport->eport_efh_dst); 515 516 ss->ss_rportid_in_dereg = 0; 517 ss->ss_rport_dereg_state = 0; 518 519 ss->ss_next_sol_oxid = 0xFFFF; 520 ss->ss_next_unsol_rxid = 0xFFFF; 521 ss->ss_sol_oxid_hash = mod_hash_create_idhash( 522 "ss_sol_oxid_hash", FCOET_SOL_HASH_SIZE, 523 mod_hash_null_valdtor); 524 ss->ss_unsol_rxid_hash = mod_hash_create_idhash( 525 "ss_unsol_rxid_hash", FCOET_SOL_HASH_SIZE, 526 mod_hash_null_valdtor); 527 528 ss->ss_watch_count = 0; 529 mutex_init(&ss->ss_watch_mutex, 0, MUTEX_DRIVER, 0); 530 cv_init(&ss->ss_watch_cv, NULL, CV_DRIVER, NULL); 531 532 list_create(&ss->ss_abort_xchg_list, sizeof (fcoet_exchange_t), 533 offsetof(fcoet_exchange_t, xch_abort_node)); 534 535 ss->ss_sol_flogi = NULL; 536 ss->ss_sol_flogi_state = SFS_WAIT_LINKUP; 537 538 bzero(&ss->ss_link_info, sizeof (fct_link_info_t)); 539 540 ss->ss_ioctl_flags = 0; 541 mutex_init(&ss->ss_ioctl_mutex, 0, MUTEX_DRIVER, 0); 542 543 ss->ss_change_state_flags = 0; 544 } 545 546 /* 547 * Do port's initialization 548 * 549 * port_fct_private and port_lport have been initialized by fct_alloc 550 */ 551 port->port_fca_private = ss; 552 bcopy(ss->ss_eport->eport_nodewwn, port->port_nwwn, 8); 553 bcopy(ss->ss_eport->eport_portwwn, port->port_pwwn, 8); 554 port->port_default_alias = ss->ss_alias; 555 port->port_sym_node_name = NULL; 556 port->port_sym_port_name = NULL; 557 558 port->port_pp = fcoet_pp; 559 560 port->port_hard_address = 0; 561 port->port_max_logins = FCOET_MAX_LOGINS; 562 port->port_max_xchges = FCOET_MAX_XCHGES; 563 port->port_fca_fcp_cmd_size = sizeof (fcoet_exchange_t); 564 port->port_fca_rp_private_size = 0; 565 port->port_fca_sol_els_private_size = sizeof (fcoet_exchange_t); 566 port->port_fca_sol_ct_private_size = sizeof (fcoet_exchange_t); 567 568 port->port_fca_abort_timeout = 5 * 1000; /* 5 seconds */ 569 port->port_fds = fds; 570 571 port->port_get_link_info = fcoet_get_link_info; 572 port->port_register_remote_port = fcoet_register_remote_port; 573 port->port_deregister_remote_port = fcoet_deregister_remote_port; 574 port->port_send_cmd = fcoet_send_cmd; 575 port->port_xfer_scsi_data = fcoet_xfer_scsi_data; 576 port->port_send_cmd_response = fcoet_send_cmd_response; 577 port->port_abort_cmd = fcoet_abort_cmd; 578 port->port_ctl = fcoet_ctl; 579 port->port_flogi_xchg = fcoet_do_flogi; 580 port->port_populate_hba_details = fcoet_populate_hba_fru_details; 581 if (fct_register_local_port(port) != FCT_SUCCESS) { 582 goto fail_register_port; 583 } 584 585 /* 586 * Start watchdog thread 587 */ 588 (void) snprintf(taskq_name, 32, "stmf_fct_fcoet_%d_taskq", 589 ss->ss_instance); 590 taskq_name[31] = 0; 591 if ((ss->ss_watchdog_taskq = ddi_taskq_create(NULL, 592 taskq_name, 2, TASKQ_DEFAULTPRI, 0)) == NULL) { 593 goto fail_create_taskq; 594 } 595 596 atomic_and_32(&ss->ss_flags, ~SS_FLAG_TERMINATE_WATCHDOG); 597 (void) ddi_taskq_dispatch(ss->ss_watchdog_taskq, 598 fcoet_watchdog, ss, DDI_SLEEP); 599 while ((ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) == 0) { 600 delay(10); 601 } 602 603 ddi_report_dev(ss->ss_dip); 604 return (DDI_SUCCESS); 605 606 fail_create_taskq: 607 if (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) { 608 atomic_or_32(&ss->ss_flags, SS_FLAG_TERMINATE_WATCHDOG); 609 cv_broadcast(&ss->ss_watch_cv); 610 while (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) { 611 delay(10); 612 } 613 } 614 615 ddi_taskq_destroy(ss->ss_watchdog_taskq); 616 FCOET_LOG("fcoet_attach_init", "fail_register_port"); 617 618 fail_register_port: 619 mutex_destroy(&ss->ss_ioctl_mutex); 620 mutex_destroy(&ss->ss_watch_mutex); 621 cv_destroy(&ss->ss_watch_cv); 622 mod_hash_destroy_hash(ss->ss_sol_oxid_hash); 623 mod_hash_destroy_hash(ss->ss_unsol_rxid_hash); 624 list_destroy(&ss->ss_abort_xchg_list); 625 FCOET_LOG("fcoet_attach_init", "fail_create_taskq"); 626 627 fail_minor_node: 628 fct_free(port); 629 FCOET_LOG("fcoet_attach_init", "fail_minor_node"); 630 631 fail_alloc_port: 632 fct_free(fds); 633 FCOET_LOG("fcoet_attach_init", "fail_alloc_port"); 634 635 fail_alloc_dbuf: 636 fcoet_dbuf_destroy(ss); 637 FCOET_LOG("fcoet_attach_init", "fail_alloc_dbuf"); 638 639 fail_init_dbuf: 640 ss->ss_eport->eport_deregister_client(ss->ss_eport); 641 FCOET_LOG("fcoet_attach_init", "fail_init_dbuf"); 642 643 fail_register_client: 644 FCOET_LOG("fcoet_attach_init", "fail_register_client"); 645 return (DDI_FAILURE); 646 } 647 648 static fct_status_t 649 fcoet_detach_uninit(fcoet_soft_state_t *ss) 650 { 651 if ((ss->ss_state != FCT_STATE_OFFLINE) || 652 ss->ss_state_not_acked) { 653 return (FCOE_FAILURE); 654 } 655 656 /* 657 * Avoid modunload before running fcinfo remove-target-port 658 */ 659 if (ss->ss_eport != NULL && 660 ss->ss_eport->eport_flags & EPORT_FLAG_MAC_IN_USE) { 661 return (FCOE_FAILURE); 662 } 663 664 if (ss->ss_port == NULL) { 665 return (FCOE_SUCCESS); 666 } 667 668 ss->ss_sol_oxid_hash_empty = 1; 669 ss->ss_unsol_rxid_hash_empty = 1; 670 mod_hash_walk(ss->ss_sol_oxid_hash, fcoet_sol_oxid_hash_empty, ss); 671 mod_hash_walk(ss->ss_unsol_rxid_hash, fcoet_unsol_rxid_hash_empty, ss); 672 if ((!ss->ss_sol_oxid_hash_empty) || (!ss->ss_unsol_rxid_hash_empty)) { 673 return (FCOE_FAILURE); 674 } 675 676 /* 677 * We need offline the port manually, before we want to detach it 678 * or it will not succeed. 679 */ 680 if (fct_deregister_local_port(ss->ss_port) != FCT_SUCCESS) { 681 FCOET_LOG("fcoet_detach_uninit", 682 "fct_deregister_local_port failed"); 683 return (FCOE_FAILURE); 684 } 685 686 /* 687 * Stop watchdog 688 */ 689 if (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) { 690 atomic_or_32(&ss->ss_flags, SS_FLAG_TERMINATE_WATCHDOG); 691 cv_broadcast(&ss->ss_watch_cv); 692 while (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) { 693 delay(10); 694 } 695 } 696 697 ddi_taskq_destroy(ss->ss_watchdog_taskq); 698 699 /* 700 * Release all resources 701 */ 702 mutex_destroy(&ss->ss_ioctl_mutex); 703 mutex_destroy(&ss->ss_watch_mutex); 704 cv_destroy(&ss->ss_watch_cv); 705 mod_hash_destroy_hash(ss->ss_sol_oxid_hash); 706 mod_hash_destroy_hash(ss->ss_unsol_rxid_hash); 707 list_destroy(&ss->ss_abort_xchg_list); 708 709 fct_free(ss->ss_port->port_fds); 710 fct_free(ss->ss_port); 711 ss->ss_port = NULL; 712 713 fcoet_dbuf_destroy(ss); 714 715 if (ss->ss_eport != NULL && 716 ss->ss_eport->eport_deregister_client != NULL) { 717 ss->ss_eport->eport_deregister_client(ss->ss_eport); 718 } 719 ddi_soft_state_free(fcoet_state, ss->ss_instance); 720 return (FCOE_SUCCESS); 721 } 722 723 static void 724 fcoet_watchdog(void *arg) 725 { 726 fcoet_soft_state_t *ss = (fcoet_soft_state_t *)arg; 727 clock_t tmp_delay = 0; 728 fcoet_exchange_t *xchg, *xchg_next; 729 730 FCOET_LOG("fcoet_watchdog", "fcoet_soft_state is %p", ss); 731 732 mutex_enter(&ss->ss_watch_mutex); 733 atomic_or_32(&ss->ss_flags, SS_FLAG_WATCHDOG_RUNNING); 734 tmp_delay = STMF_SEC2TICK(1)/2; 735 736 while ((ss->ss_flags & SS_FLAG_TERMINATE_WATCHDOG) == 0) { 737 ss->ss_watch_count++; 738 739 if (ss->ss_sol_flogi_state != SFS_FLOGI_DONE) { 740 fcoet_handle_sol_flogi(ss); 741 } 742 for (xchg = list_head(&ss->ss_abort_xchg_list); xchg; ) { 743 xchg_next = list_next(&ss->ss_abort_xchg_list, xchg); 744 if (xchg->xch_ref == 0) { 745 list_remove(&ss->ss_abort_xchg_list, xchg); 746 mutex_exit(&ss->ss_watch_mutex); 747 /* xchg abort done */ 748 if (xchg->xch_dbuf_num) { 749 kmem_free((void*)xchg->xch_dbufs, 750 xchg->xch_dbuf_num * 751 sizeof (void *)); 752 xchg->xch_dbufs = NULL; 753 xchg->xch_dbuf_num = 0; 754 } 755 fct_cmd_fca_aborted(xchg->xch_cmd, 756 FCT_ABORT_SUCCESS, FCT_IOF_FCA_DONE); 757 mutex_enter(&ss->ss_watch_mutex); 758 } 759 xchg = xchg_next; 760 } 761 762 atomic_or_32(&ss->ss_flags, SS_FLAG_DOG_WAITING); 763 (void) cv_timedwait(&ss->ss_watch_cv, 764 &ss->ss_watch_mutex, ddi_get_lbolt() + 765 (clock_t)tmp_delay); 766 atomic_and_32(&ss->ss_flags, ~SS_FLAG_DOG_WAITING); 767 } 768 769 /* 770 * Ensure no ongoing FLOGI, before terminate the watchdog 771 */ 772 if (ss->ss_sol_flogi) { 773 fcoet_clear_sol_exchange(ss->ss_sol_flogi); 774 fct_free(ss->ss_sol_flogi->xch_cmd); 775 ss->ss_sol_flogi = NULL; 776 } 777 778 atomic_and_32(&ss->ss_flags, ~SS_FLAG_WATCHDOG_RUNNING); 779 mutex_exit(&ss->ss_watch_mutex); 780 } 781 782 static void 783 fcoet_handle_sol_flogi(fcoet_soft_state_t *ss) 784 { 785 clock_t twosec = STMF_SEC2TICK(2); 786 787 check_state_again: 788 if (ss->ss_flags & SS_FLAG_PORT_DISABLED) { 789 ss->ss_sol_flogi_state = SFS_WAIT_LINKUP; 790 } 791 792 switch (ss->ss_sol_flogi_state) { 793 case SFS_WAIT_LINKUP: 794 if (ss->ss_sol_flogi) { 795 if (ss->ss_sol_flogi->xch_ref == 0) { 796 fcoet_clear_sol_exchange(ss->ss_sol_flogi); 797 fct_free(ss->ss_sol_flogi->xch_cmd); 798 ss->ss_sol_flogi = NULL; 799 } 800 } 801 break; 802 803 case SFS_FLOGI_INIT: 804 if (ss->ss_sol_flogi) { 805 /* 806 * wait for the response to finish 807 */ 808 ss->ss_sol_flogi_state = SFS_CLEAR_FLOGI; 809 break; 810 } 811 fcoet_send_sol_flogi(ss); 812 ss->ss_sol_flogi_state++; 813 break; 814 815 case SFS_FLOGI_CHECK_TIMEOUT: 816 if ((ss->ss_sol_flogi->xch_start_time + twosec) < 817 ddi_get_lbolt()) { 818 ss->ss_sol_flogi_state++; 819 } 820 break; 821 822 case SFS_ABTS_INIT: 823 fcoet_send_sol_abts(ss->ss_sol_flogi); 824 ss->ss_sol_flogi_state++; 825 break; 826 827 case SFS_CLEAR_FLOGI: 828 if (ss->ss_sol_flogi) { 829 if (ss->ss_sol_flogi->xch_ref) { 830 break; 831 } 832 fcoet_clear_sol_exchange(ss->ss_sol_flogi); 833 fct_free(ss->ss_sol_flogi->xch_cmd); 834 ss->ss_sol_flogi = NULL; 835 } 836 ss->ss_sol_flogi_state = SFS_FLOGI_INIT; 837 goto check_state_again; 838 839 case SFS_FLOGI_ACC: 840 ss->ss_sol_flogi_state++; 841 goto check_state_again; 842 843 case SFS_FLOGI_DONE: 844 if (!(ss->ss_flags & SS_FLAG_PORT_DISABLED) && 845 ss->ss_sol_flogi) { 846 fcoet_clear_sol_exchange(ss->ss_sol_flogi); 847 fct_free(ss->ss_sol_flogi->xch_cmd); 848 ss->ss_sol_flogi = NULL; 849 } 850 851 /* 852 * We'd better to offline it first, and delay 0.1 seconds, 853 * before we say it's on again. 854 */ 855 fct_handle_event(ss->ss_port, 856 FCT_EVENT_LINK_DOWN, 0, NULL); 857 delay(STMF_SEC2TICK(1)/10); 858 fct_handle_event(ss->ss_port, 859 FCT_EVENT_LINK_UP, 0, NULL); 860 break; 861 862 default: 863 ASSERT(0); 864 break; 865 } 866 } 867 868 /* ARGSUSED */ 869 static int 870 fcoet_dbuf_init(fcoet_soft_state_t *ss) 871 { 872 return (FCOE_SUCCESS); 873 } 874 875 /* ARGSUSED */ 876 static void 877 fcoet_dbuf_destroy(fcoet_soft_state_t *ss) 878 { 879 880 } 881 882 /* ARGSUSED */ 883 static stmf_data_buf_t * 884 fcoet_dbuf_alloc(fct_local_port_t *port, uint32_t size, uint32_t *pminsize, 885 uint32_t flags) 886 { 887 stmf_data_buf_t *dbuf; 888 int add_size; 889 int sge_num; 890 int sge_size; 891 int idx; 892 int ii; 893 void *netb; 894 uint8_t *fc_buf; 895 fcoet_soft_state_t *ss = 896 (fcoet_soft_state_t *)port->port_fca_private; 897 898 if (size > FCOET_MAX_DBUF_LEN) { 899 if (*pminsize > FCOET_MAX_DBUF_LEN) { 900 return (NULL); 901 } 902 903 size = FCOET_MAX_DBUF_LEN; 904 } 905 906 sge_num = (size - 1) / ss->ss_fcp_data_payload_size + 1; 907 add_size = (sge_num - 1) * sizeof (struct stmf_sglist_ent) + 908 sge_num * sizeof (mblk_t *); 909 dbuf = stmf_alloc(STMF_STRUCT_DATA_BUF, add_size, 0); 910 if (dbuf == NULL) { 911 return (NULL); 912 } 913 dbuf->db_buf_size = size; 914 dbuf->db_data_size = size; 915 dbuf->db_sglist_length = 0; 916 dbuf->db_flags |= DB_DONT_REUSE; 917 FCOET_SET_SEG_NUM(dbuf, sge_num); 918 919 /* 920 * Initialize non-last sg entries 921 */ 922 for (idx = 0; idx < sge_num - 1; idx++) { 923 sge_size = ss->ss_fcp_data_payload_size; 924 netb = ss->ss_eport->eport_alloc_netb( 925 ss->ss_eport, sizeof (fcoe_fc_frame_header_t) + 926 sge_size, &fc_buf); 927 if (netb == NULL) { 928 for (ii = 0; ii < idx; ii++) { 929 ss->ss_eport->eport_free_netb( 930 FCOET_GET_NETB(dbuf, ii)); 931 } 932 stmf_free(dbuf); 933 FCOET_LOG("fcoe_dbuf_alloc", "no netb"); 934 return (NULL); 935 } 936 FCOET_SET_NETB(dbuf, idx, netb); 937 dbuf->db_sglist[idx].seg_addr = fc_buf + 938 sizeof (fcoe_fc_frame_header_t); 939 dbuf->db_sglist[idx].seg_length = sge_size; 940 } 941 942 /* 943 * Initialize the last sg entry 944 */ 945 if (size % ss->ss_fcp_data_payload_size) { 946 sge_size = P2ROUNDUP(size % ss->ss_fcp_data_payload_size, 4); 947 } else { 948 sge_size = ss->ss_fcp_data_payload_size; 949 } 950 951 netb = ss->ss_eport->eport_alloc_netb( 952 ss->ss_eport, 953 sizeof (fcoe_fc_frame_header_t) + 954 sge_size, &fc_buf); 955 if (netb == NULL) { 956 for (ii = 0; ii < idx; ii++) { 957 ss->ss_eport->eport_free_netb( 958 FCOET_GET_NETB(dbuf, ii)); 959 } 960 stmf_free(dbuf); 961 FCOET_LOG("fcoe_dbuf_alloc", "no netb"); 962 return (NULL); 963 } 964 965 FCOET_SET_NETB(dbuf, idx, netb); 966 dbuf->db_sglist[idx].seg_addr = fc_buf + 967 sizeof (fcoe_fc_frame_header_t); 968 dbuf->db_sglist[idx].seg_length = sge_size; 969 970 /* 971 * Let COMSTAR know how many sg entries we will use 972 */ 973 dbuf->db_sglist_length = idx + 1; 974 975 return (dbuf); 976 } 977 978 static void 979 fcoet_dbuf_free(fct_dbuf_store_t *fds, stmf_data_buf_t *dbuf) 980 { 981 int idx; 982 fcoet_soft_state_t *ss = 983 (fcoet_soft_state_t *)fds->fds_fca_private; 984 985 for (idx = 0; idx < FCOET_GET_SEG_NUM(dbuf); idx++) { 986 if (FCOET_GET_NETB(dbuf, idx)) { 987 ss->ss_eport->eport_free_netb( 988 FCOET_GET_NETB(dbuf, idx)); 989 } 990 } 991 992 stmf_free(dbuf); 993 } 994 995 /* 996 * We should have initialized fcoe_frame_t before 997 */ 998 void 999 fcoet_init_tfm(fcoe_frame_t *frm, fcoet_exchange_t *xch) 1000 { 1001 FRM2TFM(frm)->tfm_fcoe_frame = frm; 1002 FRM2TFM(frm)->tfm_xch = xch; 1003 FRM2TFM(frm)->tfm_seq = NULL; 1004 } 1005 1006 /* ARGSUSED */ 1007 static uint_t 1008 fcoet_sol_oxid_hash_empty(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 1009 { 1010 fcoet_soft_state_t *ss = (fcoet_soft_state_t *)arg; 1011 1012 ss->ss_sol_oxid_hash_empty = 0; 1013 FCOET_LOG("fcoet_sol_oxid_hash_empty", "one ongoing xch: %p", val); 1014 return (MH_WALK_CONTINUE); 1015 } 1016 1017 /* ARGSUSED */ 1018 static uint_t 1019 fcoet_unsol_rxid_hash_empty(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 1020 { 1021 fcoet_soft_state_t *ss = (fcoet_soft_state_t *)arg; 1022 1023 ss->ss_sol_oxid_hash_empty = 0; 1024 FCOET_LOG("fcoet_unsol_rxid_hash_empty", "one ongoing xch: %p", val); 1025 return (MH_WALK_CONTINUE); 1026 } 1027 1028 /* ARGSUSED */ 1029 void 1030 fcoet_modhash_find_cb(mod_hash_key_t key, mod_hash_val_t val) 1031 { 1032 ASSERT(val != NULL); 1033 fcoet_exchange_t *xch = (fcoet_exchange_t *)val; 1034 FCOET_BUSY_XCHG(xch); 1035 } 1036