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 ddi_quiesce_not_needed 156 }; 157 158 static struct modldrv modldrv = { 159 &mod_driverops, 160 FCOET_MOD_NAME, 161 &fcoet_ops, 162 }; 163 164 static struct modlinkage modlinkage = { 165 MODREV_1, &modldrv, NULL 166 }; 167 168 /* 169 * Driver's global variables 170 */ 171 static kmutex_t fcoet_mutex; 172 static void *fcoet_state = NULL; 173 174 int fcoet_use_ext_log = 1; 175 static char fcoet_provider_name[] = "fcoet"; 176 static struct stmf_port_provider *fcoet_pp = NULL; 177 178 /* 179 * Common loadable module entry points _init, _fini, _info 180 */ 181 182 int 183 _init(void) 184 { 185 int ret; 186 187 ret = ddi_soft_state_init(&fcoet_state, sizeof (fcoet_soft_state_t), 0); 188 if (ret == 0) { 189 fcoet_pp = (stmf_port_provider_t *) 190 stmf_alloc(STMF_STRUCT_PORT_PROVIDER, 0, 0); 191 fcoet_pp->pp_portif_rev = PORTIF_REV_1; 192 fcoet_pp->pp_name = fcoet_provider_name; 193 if (stmf_register_port_provider(fcoet_pp) != STMF_SUCCESS) { 194 stmf_free(fcoet_pp); 195 ddi_soft_state_fini(&fcoet_state); 196 return (EIO); 197 } 198 199 mutex_init(&fcoet_mutex, 0, MUTEX_DRIVER, 0); 200 ret = mod_install(&modlinkage); 201 if (ret) { 202 stmf_deregister_port_provider(fcoet_pp); 203 stmf_free(fcoet_pp); 204 mutex_destroy(&fcoet_mutex); 205 ddi_soft_state_fini(&fcoet_state); 206 } 207 } 208 209 FCOET_LOG("_init", "exit _init with %x", ret); 210 return (ret); 211 } 212 213 int 214 _fini(void) 215 { 216 int ret; 217 218 ret = mod_remove(&modlinkage); 219 if (ret == 0) { 220 stmf_deregister_port_provider(fcoet_pp); 221 stmf_free(fcoet_pp); 222 mutex_destroy(&fcoet_mutex); 223 ddi_soft_state_fini(&fcoet_state); 224 } 225 226 FCOET_LOG("_fini", "exit _fini with %x", ret); 227 return (ret); 228 } 229 230 int 231 _info(struct modinfo *modinfop) 232 { 233 return (mod_info(&modlinkage, modinfop)); 234 } 235 236 /* 237 * Autoconfiguration entry points: attach, detach, getinfo 238 */ 239 240 static int 241 fcoet_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 242 { 243 int ret = DDI_FAILURE; 244 int instance; 245 fcoet_soft_state_t *ss; 246 247 instance = ddi_get_instance(dip); 248 FCOET_LOG("fcoet_attach", "get instance %d", instance); 249 250 switch (cmd) { 251 case DDI_ATTACH: 252 ret = ddi_soft_state_zalloc(fcoet_state, instance); 253 if (ret != DDI_SUCCESS) { 254 return (ret); 255 } 256 257 ss = ddi_get_soft_state(fcoet_state, instance); 258 ss->ss_instance = instance; 259 ss->ss_dip = dip; 260 261 ret = fcoet_attach_init(ss); 262 if (ret != FCOE_SUCCESS) { 263 ddi_soft_state_free(fcoet_state, instance); 264 ret = DDI_FAILURE; 265 } 266 267 FCOET_LOG("fcoet_attach", "end with-%x", ret); 268 break; 269 270 case DDI_RESUME: 271 ret = DDI_SUCCESS; 272 break; 273 274 default: 275 FCOET_LOG("fcoet_attach", "unspported attach cmd-%x", cmd); 276 break; 277 } 278 279 return (ret); 280 } 281 282 static int 283 fcoet_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 284 { 285 int ret = DDI_FAILURE; 286 int fcoe_ret; 287 int instance; 288 fcoet_soft_state_t *ss; 289 290 instance = ddi_get_instance(dip); 291 ss = ddi_get_soft_state(fcoet_state, instance); 292 if (ss == NULL) { 293 return (ret); 294 } 295 296 switch (cmd) { 297 case DDI_DETACH: 298 fcoe_ret = fcoet_detach_uninit(ss); 299 if (fcoe_ret == FCOE_SUCCESS) { 300 ret = DDI_SUCCESS; 301 } 302 303 FCOET_LOG("fcoet_detach", "fcoet_detach_uninit end with-%x", 304 fcoe_ret); 305 break; 306 307 case DDI_SUSPEND: 308 ret = DDI_SUCCESS; 309 break; 310 311 default: 312 FCOET_LOG("fcoet_detach", "unsupported detach cmd-%x", cmd); 313 break; 314 } 315 316 return (ret); 317 } 318 319 /* 320 * Device access entry points 321 */ 322 static int 323 fcoet_open(dev_t *devp, int flag, int otype, cred_t *credp) 324 { 325 int instance; 326 fcoet_soft_state_t *ss; 327 328 if (otype != OTYP_CHR) { 329 return (EINVAL); 330 } 331 332 /* 333 * Since this is for debugging only, only allow root to issue ioctl now 334 */ 335 if (drv_priv(credp)) { 336 return (EPERM); 337 } 338 339 instance = (int)getminor(*devp); 340 ss = ddi_get_soft_state(fcoet_state, instance); 341 if (ss == NULL) { 342 return (ENXIO); 343 } 344 345 mutex_enter(&ss->ss_ioctl_mutex); 346 if (ss->ss_ioctl_flags & FCOET_IOCTL_FLAG_EXCL) { 347 /* 348 * It is already open for exclusive access. 349 * So shut the door on this caller. 350 */ 351 mutex_exit(&ss->ss_ioctl_mutex); 352 return (EBUSY); 353 } 354 355 if (flag & FEXCL) { 356 if (ss->ss_ioctl_flags & FCOET_IOCTL_FLAG_OPEN) { 357 /* 358 * Exclusive operation not possible 359 * as it is already opened 360 */ 361 mutex_exit(&ss->ss_ioctl_mutex); 362 return (EBUSY); 363 } 364 ss->ss_ioctl_flags |= FCOET_IOCTL_FLAG_EXCL; 365 } 366 ss->ss_ioctl_flags |= FCOET_IOCTL_FLAG_OPEN; 367 mutex_exit(&ss->ss_ioctl_mutex); 368 369 return (0); 370 } 371 372 /* ARGSUSED */ 373 static int 374 fcoet_close(dev_t dev, int flag, int otype, cred_t *credp) 375 { 376 int instance; 377 fcoet_soft_state_t *ss; 378 379 if (otype != OTYP_CHR) { 380 return (EINVAL); 381 } 382 383 instance = (int)getminor(dev); 384 ss = ddi_get_soft_state(fcoet_state, instance); 385 if (ss == NULL) { 386 return (ENXIO); 387 } 388 389 mutex_enter(&ss->ss_ioctl_mutex); 390 if ((ss->ss_ioctl_flags & FCOET_IOCTL_FLAG_OPEN) == 0) { 391 mutex_exit(&ss->ss_ioctl_mutex); 392 return (ENODEV); 393 } 394 395 /* 396 * It looks there's one hole here, maybe there could several concurrent 397 * shareed open session, but we never check this case. 398 * But it will not hurt too much, disregard it now. 399 */ 400 ss->ss_ioctl_flags &= ~FCOET_IOCTL_FLAG_MASK; 401 mutex_exit(&ss->ss_ioctl_mutex); 402 403 return (0); 404 } 405 406 /* ARGSUSED */ 407 static int 408 fcoet_ioctl(dev_t dev, int cmd, intptr_t data, int mode, 409 cred_t *credp, int *rval) 410 { 411 fcoet_soft_state_t *ss; 412 int ret = 0; 413 414 if (drv_priv(credp) != 0) { 415 return (EPERM); 416 } 417 418 ss = ddi_get_soft_state(fcoet_state, (int32_t)getminor(dev)); 419 if (ss == NULL) { 420 return (ENXIO); 421 } 422 423 switch (cmd) { 424 default: 425 FCOET_LOG("fcoet_ioctl", "ioctl-0x%02X", cmd); 426 ret = ENOTTY; 427 break; 428 } 429 430 *rval = ret; 431 return (ret); 432 } 433 434 static fct_status_t 435 fcoet_attach_init(fcoet_soft_state_t *ss) 436 { 437 fcoe_client_t client_fcoet; 438 fcoe_port_t *eport; 439 fct_local_port_t *port; 440 fct_dbuf_store_t *fds; 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_get_int(DDI_DEV_T_ANY, ss->ss_dip, 457 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "mac_id", -1); 458 if (ret == -1) { 459 FCOET_LOG("fcoet_attach_init", "get mac_id failed"); 460 return (DDI_FAILURE); 461 } else { 462 client_fcoet.ect_channelid = ret; 463 } 464 FCOET_LOG("fcoet_attach_init", "channel_id is %d", 465 client_fcoet.ect_channelid); 466 467 /* 468 * It's FCoE's responsiblity to initialize eport's all elements 469 */ 470 eport = fcoe_register_client(&client_fcoet); 471 if (eport == NULL) { 472 goto fail_register_client; 473 } 474 475 /* 476 * Now it's time to register local port to FCT 477 */ 478 if (fcoet_dbuf_init(ss) != FCOE_SUCCESS) { 479 goto fail_init_dbuf; 480 } 481 482 fds = (fct_dbuf_store_t *)fct_alloc(FCT_STRUCT_DBUF_STORE, 0, 0); 483 if (fds == NULL) { 484 goto fail_alloc_dbuf; 485 } else { 486 fds->fds_alloc_data_buf = fcoet_dbuf_alloc; 487 fds->fds_free_data_buf = fcoet_dbuf_free; 488 fds->fds_fca_private = (void *)ss; 489 } 490 491 port = (fct_local_port_t *)fct_alloc(FCT_STRUCT_LOCAL_PORT, 0, 0); 492 if (port == NULL) { 493 goto fail_alloc_port; 494 } else { 495 /* 496 * Do ss's initialization now 497 */ 498 (void) snprintf(ss->ss_alias, sizeof (ss->ss_alias), "fcoet%d", 499 ss->ss_instance); 500 ret = ddi_create_minor_node(ss->ss_dip, "admin", 501 S_IFCHR, ss->ss_instance, DDI_NT_STMF_PP, 0); 502 if (ret != DDI_SUCCESS) { 503 goto fail_minor_node; 504 } 505 506 ss->ss_state = FCT_STATE_OFFLINE; 507 ss->ss_state_not_acked = 1; 508 ss->ss_flags = 0; 509 ss->ss_port = port; 510 ss->ss_eport = eport; 511 FCOE_SET_DEFAULT_FPORT_ADDR(eport->eport_efh_dst); 512 513 ss->ss_rportid_in_dereg = 0; 514 ss->ss_rport_dereg_state = 0; 515 516 ss->ss_next_sol_oxid = 0xFFFF; 517 ss->ss_next_unsol_rxid = 0xFFFF; 518 ss->ss_sol_oxid_hash = mod_hash_create_idhash( 519 "ss_sol_oxid_hash", FCOET_SOL_HASH_SIZE, 520 mod_hash_null_valdtor); 521 ss->ss_unsol_rxid_hash = mod_hash_create_idhash( 522 "ss_unsol_rxid_hash", FCOET_SOL_HASH_SIZE, 523 mod_hash_null_valdtor); 524 525 ss->ss_watch_count = 0; 526 mutex_init(&ss->ss_watch_mutex, 0, MUTEX_DRIVER, 0); 527 cv_init(&ss->ss_watch_cv, NULL, CV_DRIVER, NULL); 528 529 list_create(&ss->ss_abort_xchg_list, sizeof (fcoet_exchange_t), 530 offsetof(fcoet_exchange_t, xch_abort_node)); 531 532 ss->ss_sol_flogi = NULL; 533 ss->ss_sol_flogi_state = SFS_WAIT_LINKUP; 534 535 bzero(&ss->ss_link_info, sizeof (fct_link_info_t)); 536 537 ss->ss_ioctl_flags = 0; 538 mutex_init(&ss->ss_ioctl_mutex, 0, MUTEX_DRIVER, 0); 539 540 ss->ss_change_state_flags = 0; 541 } 542 543 /* 544 * Do port's initialization 545 * 546 * port_fct_private and port_lport have been initialized by fct_alloc 547 */ 548 port->port_fca_private = ss; 549 bcopy(ss->ss_eport->eport_nodewwn, port->port_nwwn, 8); 550 bcopy(ss->ss_eport->eport_portwwn, port->port_pwwn, 8); 551 port->port_default_alias = ss->ss_alias; 552 port->port_sym_node_name = NULL; 553 port->port_sym_port_name = NULL; 554 555 port->port_pp = fcoet_pp; 556 557 port->port_hard_address = 0; 558 port->port_max_logins = FCOET_MAX_LOGINS; 559 port->port_max_xchges = FCOET_MAX_XCHGES; 560 port->port_fca_fcp_cmd_size = sizeof (fcoet_exchange_t); 561 port->port_fca_rp_private_size = 0; 562 port->port_fca_sol_els_private_size = sizeof (fcoet_exchange_t); 563 port->port_fca_sol_ct_private_size = sizeof (fcoet_exchange_t); 564 565 port->port_fca_abort_timeout = 5 * 1000; /* 5 seconds */ 566 port->port_fds = fds; 567 568 port->port_get_link_info = fcoet_get_link_info; 569 port->port_register_remote_port = fcoet_register_remote_port; 570 port->port_deregister_remote_port = fcoet_deregister_remote_port; 571 port->port_send_cmd = fcoet_send_cmd; 572 port->port_xfer_scsi_data = fcoet_xfer_scsi_data; 573 port->port_send_cmd_response = fcoet_send_cmd_response; 574 port->port_abort_cmd = fcoet_abort_cmd; 575 port->port_ctl = fcoet_ctl; 576 port->port_flogi_xchg = fcoet_do_flogi; 577 port->port_populate_hba_details = fcoet_populate_hba_fru_details; 578 if (fct_register_local_port(port) != FCT_SUCCESS) { 579 goto fail_register_port; 580 } 581 582 /* 583 * Start watchdog thread 584 */ 585 (void) snprintf(taskq_name, 32, "stmf_fct_fcoet_%d_taskq", 586 ss->ss_instance); 587 taskq_name[31] = 0; 588 if ((ss->ss_watchdog_taskq = ddi_taskq_create(NULL, 589 taskq_name, 2, TASKQ_DEFAULTPRI, 0)) == NULL) { 590 goto fail_create_taskq; 591 } 592 593 atomic_and_32(&ss->ss_flags, ~SS_FLAG_TERMINATE_WATCHDOG); 594 (void) ddi_taskq_dispatch(ss->ss_watchdog_taskq, 595 fcoet_watchdog, ss, DDI_SLEEP); 596 while ((ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) == 0) { 597 delay(10); 598 } 599 600 ddi_report_dev(ss->ss_dip); 601 return (DDI_SUCCESS); 602 603 fail_create_taskq: 604 if (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) { 605 atomic_or_32(&ss->ss_flags, SS_FLAG_TERMINATE_WATCHDOG); 606 cv_broadcast(&ss->ss_watch_cv); 607 while (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) { 608 delay(10); 609 } 610 } 611 612 ddi_taskq_destroy(ss->ss_watchdog_taskq); 613 FCOET_LOG("fcoet_attach_init", "fail_register_port"); 614 615 fail_register_port: 616 mutex_destroy(&ss->ss_ioctl_mutex); 617 mutex_destroy(&ss->ss_watch_mutex); 618 cv_destroy(&ss->ss_watch_cv); 619 mod_hash_destroy_hash(ss->ss_sol_oxid_hash); 620 mod_hash_destroy_hash(ss->ss_unsol_rxid_hash); 621 list_destroy(&ss->ss_abort_xchg_list); 622 FCOET_LOG("fcoet_attach_init", "fail_create_taskq"); 623 624 fail_minor_node: 625 fct_free(port); 626 FCOET_LOG("fcoet_attach_init", "fail_minor_node"); 627 628 fail_alloc_port: 629 fct_free(fds); 630 FCOET_LOG("fcoet_attach_init", "fail_alloc_port"); 631 632 fail_alloc_dbuf: 633 fcoet_dbuf_destroy(ss); 634 FCOET_LOG("fcoet_attach_init", "fail_alloc_dbuf"); 635 636 fail_init_dbuf: 637 ss->ss_eport->eport_deregister_client(ss->ss_eport); 638 FCOET_LOG("fcoet_attach_init", "fail_init_dbuf"); 639 640 fail_register_client: 641 FCOET_LOG("fcoet_attach_init", "fail_register_client"); 642 return (DDI_FAILURE); 643 } 644 645 static fct_status_t 646 fcoet_detach_uninit(fcoet_soft_state_t *ss) 647 { 648 if ((ss->ss_state != FCT_STATE_OFFLINE) || 649 ss->ss_state_not_acked) { 650 return (FCOE_FAILURE); 651 } 652 653 /* 654 * Avoid modunload before running fcinfo remove-target-port 655 */ 656 if (ss->ss_eport != NULL && 657 ss->ss_eport->eport_flags & EPORT_FLAG_MAC_IN_USE) { 658 return (FCOE_FAILURE); 659 } 660 661 if (ss->ss_port == NULL) { 662 return (FCOE_SUCCESS); 663 } 664 665 ss->ss_sol_oxid_hash_empty = 1; 666 ss->ss_unsol_rxid_hash_empty = 1; 667 mod_hash_walk(ss->ss_sol_oxid_hash, fcoet_sol_oxid_hash_empty, ss); 668 mod_hash_walk(ss->ss_unsol_rxid_hash, fcoet_unsol_rxid_hash_empty, ss); 669 if ((!ss->ss_sol_oxid_hash_empty) || (!ss->ss_unsol_rxid_hash_empty)) { 670 return (FCOE_FAILURE); 671 } 672 673 /* 674 * We need offline the port manually, before we want to detach it 675 * or it will not succeed. 676 */ 677 if (fct_deregister_local_port(ss->ss_port) != FCT_SUCCESS) { 678 FCOET_LOG("fcoet_detach_uninit", 679 "fct_deregister_local_port failed"); 680 return (FCOE_FAILURE); 681 } 682 683 /* 684 * Stop watchdog 685 */ 686 if (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) { 687 atomic_or_32(&ss->ss_flags, SS_FLAG_TERMINATE_WATCHDOG); 688 cv_broadcast(&ss->ss_watch_cv); 689 while (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) { 690 delay(10); 691 } 692 } 693 694 ddi_taskq_destroy(ss->ss_watchdog_taskq); 695 696 /* 697 * Release all resources 698 */ 699 mutex_destroy(&ss->ss_ioctl_mutex); 700 mutex_destroy(&ss->ss_watch_mutex); 701 cv_destroy(&ss->ss_watch_cv); 702 mod_hash_destroy_hash(ss->ss_sol_oxid_hash); 703 mod_hash_destroy_hash(ss->ss_unsol_rxid_hash); 704 list_destroy(&ss->ss_abort_xchg_list); 705 706 fct_free(ss->ss_port->port_fds); 707 fct_free(ss->ss_port); 708 ss->ss_port = NULL; 709 710 fcoet_dbuf_destroy(ss); 711 712 if (ss->ss_eport != NULL && 713 ss->ss_eport->eport_deregister_client != NULL) { 714 ss->ss_eport->eport_deregister_client(ss->ss_eport); 715 } 716 ddi_soft_state_free(fcoet_state, ss->ss_instance); 717 return (FCOE_SUCCESS); 718 } 719 720 static void 721 fcoet_watchdog(void *arg) 722 { 723 fcoet_soft_state_t *ss = (fcoet_soft_state_t *)arg; 724 clock_t tmp_delay = 0; 725 fcoet_exchange_t *xchg, *xchg_next; 726 727 FCOET_LOG("fcoet_watchdog", "fcoet_soft_state is %p", ss); 728 729 mutex_enter(&ss->ss_watch_mutex); 730 atomic_or_32(&ss->ss_flags, SS_FLAG_WATCHDOG_RUNNING); 731 tmp_delay = STMF_SEC2TICK(1)/2; 732 733 while ((ss->ss_flags & SS_FLAG_TERMINATE_WATCHDOG) == 0) { 734 ss->ss_watch_count++; 735 736 if (ss->ss_sol_flogi_state != SFS_FLOGI_DONE) { 737 fcoet_handle_sol_flogi(ss); 738 } 739 for (xchg = list_head(&ss->ss_abort_xchg_list); xchg; ) { 740 xchg_next = list_next(&ss->ss_abort_xchg_list, xchg); 741 if (xchg->xch_ref == 0) { 742 list_remove(&ss->ss_abort_xchg_list, xchg); 743 mutex_exit(&ss->ss_watch_mutex); 744 /* xchg abort done */ 745 if (xchg->xch_dbuf_num) { 746 kmem_free((void*)xchg->xch_dbufs, 747 xchg->xch_dbuf_num * 748 sizeof (void *)); 749 xchg->xch_dbufs = NULL; 750 xchg->xch_dbuf_num = 0; 751 } 752 fct_cmd_fca_aborted(xchg->xch_cmd, 753 FCT_ABORT_SUCCESS, FCT_IOF_FCA_DONE); 754 mutex_enter(&ss->ss_watch_mutex); 755 } 756 xchg = xchg_next; 757 } 758 759 atomic_or_32(&ss->ss_flags, SS_FLAG_DOG_WAITING); 760 (void) cv_timedwait(&ss->ss_watch_cv, 761 &ss->ss_watch_mutex, ddi_get_lbolt() + 762 (clock_t)tmp_delay); 763 atomic_and_32(&ss->ss_flags, ~SS_FLAG_DOG_WAITING); 764 } 765 766 /* 767 * Ensure no ongoing FLOGI, before terminate the watchdog 768 */ 769 if (ss->ss_sol_flogi) { 770 fcoet_clear_sol_exchange(ss->ss_sol_flogi); 771 fct_free(ss->ss_sol_flogi->xch_cmd); 772 ss->ss_sol_flogi = NULL; 773 } 774 775 atomic_and_32(&ss->ss_flags, ~SS_FLAG_WATCHDOG_RUNNING); 776 mutex_exit(&ss->ss_watch_mutex); 777 } 778 779 static void 780 fcoet_handle_sol_flogi(fcoet_soft_state_t *ss) 781 { 782 clock_t twosec = STMF_SEC2TICK(2); 783 784 check_state_again: 785 if (ss->ss_flags & SS_FLAG_PORT_DISABLED) { 786 ss->ss_sol_flogi_state = SFS_WAIT_LINKUP; 787 } 788 789 switch (ss->ss_sol_flogi_state) { 790 case SFS_WAIT_LINKUP: 791 if (ss->ss_sol_flogi) { 792 if (ss->ss_sol_flogi->xch_ref == 0) { 793 fcoet_clear_sol_exchange(ss->ss_sol_flogi); 794 fct_free(ss->ss_sol_flogi->xch_cmd); 795 ss->ss_sol_flogi = NULL; 796 } 797 } 798 break; 799 800 case SFS_FLOGI_INIT: 801 if (ss->ss_sol_flogi) { 802 /* 803 * wait for the response to finish 804 */ 805 ss->ss_sol_flogi_state = SFS_CLEAR_FLOGI; 806 break; 807 } 808 fcoet_send_sol_flogi(ss); 809 ss->ss_sol_flogi_state++; 810 break; 811 812 case SFS_FLOGI_CHECK_TIMEOUT: 813 if ((ss->ss_sol_flogi->xch_start_time + twosec) < 814 ddi_get_lbolt()) { 815 ss->ss_sol_flogi_state++; 816 } 817 break; 818 819 case SFS_ABTS_INIT: 820 fcoet_send_sol_abts(ss->ss_sol_flogi); 821 ss->ss_sol_flogi_state++; 822 break; 823 824 case SFS_CLEAR_FLOGI: 825 if (ss->ss_sol_flogi) { 826 if (ss->ss_sol_flogi->xch_ref) { 827 break; 828 } 829 fcoet_clear_sol_exchange(ss->ss_sol_flogi); 830 fct_free(ss->ss_sol_flogi->xch_cmd); 831 ss->ss_sol_flogi = NULL; 832 } 833 ss->ss_sol_flogi_state = SFS_FLOGI_INIT; 834 goto check_state_again; 835 836 case SFS_FLOGI_ACC: 837 ss->ss_sol_flogi_state++; 838 goto check_state_again; 839 840 case SFS_FLOGI_DONE: 841 if (!(ss->ss_flags & SS_FLAG_PORT_DISABLED) && 842 ss->ss_sol_flogi) { 843 fcoet_clear_sol_exchange(ss->ss_sol_flogi); 844 fct_free(ss->ss_sol_flogi->xch_cmd); 845 ss->ss_sol_flogi = NULL; 846 } 847 848 /* 849 * We'd better to offline it first, and delay 0.1 seconds, 850 * before we say it's on again. 851 */ 852 fct_handle_event(ss->ss_port, 853 FCT_EVENT_LINK_DOWN, 0, NULL); 854 delay(STMF_SEC2TICK(1)/10); 855 fct_handle_event(ss->ss_port, 856 FCT_EVENT_LINK_UP, 0, NULL); 857 break; 858 859 default: 860 ASSERT(0); 861 break; 862 } 863 } 864 865 /* ARGSUSED */ 866 static int 867 fcoet_dbuf_init(fcoet_soft_state_t *ss) 868 { 869 return (FCOE_SUCCESS); 870 } 871 872 /* ARGSUSED */ 873 static void 874 fcoet_dbuf_destroy(fcoet_soft_state_t *ss) 875 { 876 877 } 878 879 /* ARGSUSED */ 880 static stmf_data_buf_t * 881 fcoet_dbuf_alloc(fct_local_port_t *port, uint32_t size, uint32_t *pminsize, 882 uint32_t flags) 883 { 884 stmf_data_buf_t *dbuf; 885 int add_size; 886 int sge_num; 887 int sge_size; 888 int idx; 889 int ii; 890 void *netb; 891 uint8_t *fc_buf; 892 fcoet_soft_state_t *ss = 893 (fcoet_soft_state_t *)port->port_fca_private; 894 895 if (size > FCOET_MAX_DBUF_LEN) { 896 if (*pminsize > FCOET_MAX_DBUF_LEN) { 897 return (NULL); 898 } 899 900 size = FCOET_MAX_DBUF_LEN; 901 } 902 903 sge_num = (size - 1) / ss->ss_fcp_data_payload_size + 1; 904 add_size = (sge_num - 1) * sizeof (struct stmf_sglist_ent) + 905 sge_num * sizeof (mblk_t *); 906 dbuf = stmf_alloc(STMF_STRUCT_DATA_BUF, add_size, 0); 907 if (dbuf == NULL) { 908 return (NULL); 909 } 910 dbuf->db_buf_size = size; 911 dbuf->db_data_size = size; 912 dbuf->db_sglist_length = 0; 913 dbuf->db_flags |= DB_DONT_REUSE; 914 FCOET_SET_SEG_NUM(dbuf, sge_num); 915 916 /* 917 * Initialize non-last sg entries 918 */ 919 for (idx = 0; idx < sge_num - 1; idx++) { 920 sge_size = ss->ss_fcp_data_payload_size; 921 netb = ss->ss_eport->eport_alloc_netb( 922 ss->ss_eport, sizeof (fcoe_fc_frame_header_t) + 923 sge_size, &fc_buf); 924 if (netb == NULL) { 925 for (ii = 0; ii < idx; ii++) { 926 ss->ss_eport->eport_free_netb( 927 FCOET_GET_NETB(dbuf, ii)); 928 } 929 stmf_free(dbuf); 930 FCOET_LOG("fcoe_dbuf_alloc", "no netb"); 931 return (NULL); 932 } 933 FCOET_SET_NETB(dbuf, idx, netb); 934 dbuf->db_sglist[idx].seg_addr = fc_buf + 935 sizeof (fcoe_fc_frame_header_t); 936 dbuf->db_sglist[idx].seg_length = sge_size; 937 } 938 939 /* 940 * Initialize the last sg entry 941 */ 942 if (size % ss->ss_fcp_data_payload_size) { 943 sge_size = P2ROUNDUP(size % ss->ss_fcp_data_payload_size, 4); 944 } else { 945 sge_size = ss->ss_fcp_data_payload_size; 946 } 947 948 netb = ss->ss_eport->eport_alloc_netb( 949 ss->ss_eport, 950 sizeof (fcoe_fc_frame_header_t) + 951 sge_size, &fc_buf); 952 if (netb == NULL) { 953 for (ii = 0; ii < idx; ii++) { 954 ss->ss_eport->eport_free_netb( 955 FCOET_GET_NETB(dbuf, ii)); 956 } 957 stmf_free(dbuf); 958 FCOET_LOG("fcoe_dbuf_alloc", "no netb"); 959 return (NULL); 960 } 961 962 FCOET_SET_NETB(dbuf, idx, netb); 963 dbuf->db_sglist[idx].seg_addr = fc_buf + 964 sizeof (fcoe_fc_frame_header_t); 965 dbuf->db_sglist[idx].seg_length = sge_size; 966 967 /* 968 * Let COMSTAR know how many sg entries we will use 969 */ 970 dbuf->db_sglist_length = idx + 1; 971 972 return (dbuf); 973 } 974 975 static void 976 fcoet_dbuf_free(fct_dbuf_store_t *fds, stmf_data_buf_t *dbuf) 977 { 978 int idx; 979 fcoet_soft_state_t *ss = 980 (fcoet_soft_state_t *)fds->fds_fca_private; 981 982 for (idx = 0; idx < FCOET_GET_SEG_NUM(dbuf); idx++) { 983 if (FCOET_GET_NETB(dbuf, idx)) { 984 ss->ss_eport->eport_free_netb( 985 FCOET_GET_NETB(dbuf, idx)); 986 } 987 } 988 989 stmf_free(dbuf); 990 } 991 992 /* 993 * We should have initialized fcoe_frame_t before 994 */ 995 void 996 fcoet_init_tfm(fcoe_frame_t *frm, fcoet_exchange_t *xch) 997 { 998 FRM2TFM(frm)->tfm_fcoe_frame = frm; 999 FRM2TFM(frm)->tfm_xch = xch; 1000 FRM2TFM(frm)->tfm_seq = NULL; 1001 } 1002 1003 /* ARGSUSED */ 1004 static uint_t 1005 fcoet_sol_oxid_hash_empty(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 1006 { 1007 fcoet_soft_state_t *ss = (fcoet_soft_state_t *)arg; 1008 1009 ss->ss_sol_oxid_hash_empty = 0; 1010 FCOET_LOG("fcoet_sol_oxid_hash_empty", "one ongoing xch: %p", val); 1011 return (MH_WALK_CONTINUE); 1012 } 1013 1014 /* ARGSUSED */ 1015 static uint_t 1016 fcoet_unsol_rxid_hash_empty(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 1017 { 1018 fcoet_soft_state_t *ss = (fcoet_soft_state_t *)arg; 1019 1020 ss->ss_sol_oxid_hash_empty = 0; 1021 FCOET_LOG("fcoet_unsol_rxid_hash_empty", "one ongoing xch: %p", val); 1022 return (MH_WALK_CONTINUE); 1023 } 1024 1025 /* ARGSUSED */ 1026 void 1027 fcoet_modhash_find_cb(mod_hash_key_t key, mod_hash_val_t val) 1028 { 1029 ASSERT(val != NULL); 1030 fcoet_exchange_t *xch = (fcoet_exchange_t *)val; 1031 FCOET_BUSY_XCHG(xch); 1032 } 1033