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 client_fcoet.ect_fcoe_ver = FCOE_VER_NOW; 457 FCOET_LOG(__FUNCTION__, "version: %x %x", FCOE_VER_NOW, fcoe_ver_now); 458 ret = ddi_prop_get_int(DDI_DEV_T_ANY, ss->ss_dip, 459 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "mac_id", -1); 460 if (ret == -1) { 461 FCOET_LOG("fcoet_attach_init", "get mac_id failed"); 462 return (DDI_FAILURE); 463 } else { 464 client_fcoet.ect_channelid = ret; 465 } 466 FCOET_LOG("fcoet_attach_init", "channel_id is %d", 467 client_fcoet.ect_channelid); 468 469 /* 470 * It's FCoE's responsiblity to initialize eport's all elements 471 */ 472 eport = fcoe_register_client(&client_fcoet); 473 if (eport == NULL) { 474 goto fail_register_client; 475 } 476 477 /* 478 * Now it's time to register local port to FCT 479 */ 480 if (fcoet_dbuf_init(ss) != FCOE_SUCCESS) { 481 goto fail_init_dbuf; 482 } 483 484 fds = (fct_dbuf_store_t *)fct_alloc(FCT_STRUCT_DBUF_STORE, 0, 0); 485 if (fds == NULL) { 486 goto fail_alloc_dbuf; 487 } else { 488 fds->fds_alloc_data_buf = fcoet_dbuf_alloc; 489 fds->fds_free_data_buf = fcoet_dbuf_free; 490 fds->fds_fca_private = (void *)ss; 491 } 492 493 port = (fct_local_port_t *)fct_alloc(FCT_STRUCT_LOCAL_PORT, 0, 0); 494 if (port == NULL) { 495 goto fail_alloc_port; 496 } else { 497 /* 498 * Do ss's initialization now 499 */ 500 (void) snprintf(ss->ss_alias, sizeof (ss->ss_alias), "fcoet%d", 501 ss->ss_instance); 502 ret = ddi_create_minor_node(ss->ss_dip, "admin", 503 S_IFCHR, ss->ss_instance, DDI_NT_STMF_PP, 0); 504 if (ret != DDI_SUCCESS) { 505 goto fail_minor_node; 506 } 507 508 ss->ss_state = FCT_STATE_OFFLINE; 509 ss->ss_state_not_acked = 1; 510 ss->ss_flags = 0; 511 ss->ss_port = port; 512 ss->ss_eport = eport; 513 FCOE_SET_DEFAULT_FPORT_ADDR(eport->eport_efh_dst); 514 515 ss->ss_rportid_in_dereg = 0; 516 ss->ss_rport_dereg_state = 0; 517 518 ss->ss_next_sol_oxid = 0xFFFF; 519 ss->ss_next_unsol_rxid = 0xFFFF; 520 ss->ss_sol_oxid_hash = mod_hash_create_idhash( 521 "ss_sol_oxid_hash", FCOET_SOL_HASH_SIZE, 522 mod_hash_null_valdtor); 523 ss->ss_unsol_rxid_hash = mod_hash_create_idhash( 524 "ss_unsol_rxid_hash", FCOET_SOL_HASH_SIZE, 525 mod_hash_null_valdtor); 526 527 ss->ss_watch_count = 0; 528 mutex_init(&ss->ss_watch_mutex, 0, MUTEX_DRIVER, 0); 529 cv_init(&ss->ss_watch_cv, NULL, CV_DRIVER, NULL); 530 531 list_create(&ss->ss_abort_xchg_list, sizeof (fcoet_exchange_t), 532 offsetof(fcoet_exchange_t, xch_abort_node)); 533 534 ss->ss_sol_flogi = NULL; 535 ss->ss_sol_flogi_state = SFS_WAIT_LINKUP; 536 537 bzero(&ss->ss_link_info, sizeof (fct_link_info_t)); 538 539 ss->ss_ioctl_flags = 0; 540 mutex_init(&ss->ss_ioctl_mutex, 0, MUTEX_DRIVER, 0); 541 542 ss->ss_change_state_flags = 0; 543 } 544 545 /* 546 * Do port's initialization 547 * 548 * port_fct_private and port_lport have been initialized by fct_alloc 549 */ 550 port->port_fca_private = ss; 551 bcopy(ss->ss_eport->eport_nodewwn, port->port_nwwn, 8); 552 bcopy(ss->ss_eport->eport_portwwn, port->port_pwwn, 8); 553 port->port_default_alias = ss->ss_alias; 554 port->port_sym_node_name = NULL; 555 port->port_sym_port_name = NULL; 556 557 port->port_pp = fcoet_pp; 558 559 port->port_hard_address = 0; 560 port->port_max_logins = FCOET_MAX_LOGINS; 561 port->port_max_xchges = FCOET_MAX_XCHGES; 562 port->port_fca_fcp_cmd_size = sizeof (fcoet_exchange_t); 563 port->port_fca_rp_private_size = 0; 564 port->port_fca_sol_els_private_size = sizeof (fcoet_exchange_t); 565 port->port_fca_sol_ct_private_size = sizeof (fcoet_exchange_t); 566 567 port->port_fca_abort_timeout = 5 * 1000; /* 5 seconds */ 568 port->port_fds = fds; 569 570 port->port_get_link_info = fcoet_get_link_info; 571 port->port_register_remote_port = fcoet_register_remote_port; 572 port->port_deregister_remote_port = fcoet_deregister_remote_port; 573 port->port_send_cmd = fcoet_send_cmd; 574 port->port_xfer_scsi_data = fcoet_xfer_scsi_data; 575 port->port_send_cmd_response = fcoet_send_cmd_response; 576 port->port_abort_cmd = fcoet_abort_cmd; 577 port->port_ctl = fcoet_ctl; 578 port->port_flogi_xchg = fcoet_do_flogi; 579 port->port_populate_hba_details = fcoet_populate_hba_fru_details; 580 if (fct_register_local_port(port) != FCT_SUCCESS) { 581 goto fail_register_port; 582 } 583 584 /* 585 * Start watchdog thread 586 */ 587 (void) snprintf(taskq_name, 32, "stmf_fct_fcoet_%d_taskq", 588 ss->ss_instance); 589 taskq_name[31] = 0; 590 if ((ss->ss_watchdog_taskq = ddi_taskq_create(NULL, 591 taskq_name, 2, TASKQ_DEFAULTPRI, 0)) == NULL) { 592 goto fail_create_taskq; 593 } 594 595 atomic_and_32(&ss->ss_flags, ~SS_FLAG_TERMINATE_WATCHDOG); 596 (void) ddi_taskq_dispatch(ss->ss_watchdog_taskq, 597 fcoet_watchdog, ss, DDI_SLEEP); 598 while ((ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) == 0) { 599 delay(10); 600 } 601 602 ddi_report_dev(ss->ss_dip); 603 return (DDI_SUCCESS); 604 605 fail_create_taskq: 606 if (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) { 607 atomic_or_32(&ss->ss_flags, SS_FLAG_TERMINATE_WATCHDOG); 608 cv_broadcast(&ss->ss_watch_cv); 609 while (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) { 610 delay(10); 611 } 612 } 613 614 ddi_taskq_destroy(ss->ss_watchdog_taskq); 615 FCOET_LOG("fcoet_attach_init", "fail_register_port"); 616 617 fail_register_port: 618 mutex_destroy(&ss->ss_ioctl_mutex); 619 mutex_destroy(&ss->ss_watch_mutex); 620 cv_destroy(&ss->ss_watch_cv); 621 mod_hash_destroy_hash(ss->ss_sol_oxid_hash); 622 mod_hash_destroy_hash(ss->ss_unsol_rxid_hash); 623 list_destroy(&ss->ss_abort_xchg_list); 624 FCOET_LOG("fcoet_attach_init", "fail_create_taskq"); 625 626 fail_minor_node: 627 fct_free(port); 628 FCOET_LOG("fcoet_attach_init", "fail_minor_node"); 629 630 fail_alloc_port: 631 fct_free(fds); 632 FCOET_LOG("fcoet_attach_init", "fail_alloc_port"); 633 634 fail_alloc_dbuf: 635 fcoet_dbuf_destroy(ss); 636 FCOET_LOG("fcoet_attach_init", "fail_alloc_dbuf"); 637 638 fail_init_dbuf: 639 ss->ss_eport->eport_deregister_client(ss->ss_eport); 640 FCOET_LOG("fcoet_attach_init", "fail_init_dbuf"); 641 642 fail_register_client: 643 FCOET_LOG("fcoet_attach_init", "fail_register_client"); 644 return (DDI_FAILURE); 645 } 646 647 static fct_status_t 648 fcoet_detach_uninit(fcoet_soft_state_t *ss) 649 { 650 if ((ss->ss_state != FCT_STATE_OFFLINE) || 651 ss->ss_state_not_acked) { 652 return (FCOE_FAILURE); 653 } 654 655 /* 656 * Avoid modunload before running fcinfo remove-target-port 657 */ 658 if (ss->ss_eport != NULL && 659 ss->ss_eport->eport_flags & EPORT_FLAG_MAC_IN_USE) { 660 return (FCOE_FAILURE); 661 } 662 663 if (ss->ss_port == NULL) { 664 return (FCOE_SUCCESS); 665 } 666 667 ss->ss_sol_oxid_hash_empty = 1; 668 ss->ss_unsol_rxid_hash_empty = 1; 669 mod_hash_walk(ss->ss_sol_oxid_hash, fcoet_sol_oxid_hash_empty, ss); 670 mod_hash_walk(ss->ss_unsol_rxid_hash, fcoet_unsol_rxid_hash_empty, ss); 671 if ((!ss->ss_sol_oxid_hash_empty) || (!ss->ss_unsol_rxid_hash_empty)) { 672 return (FCOE_FAILURE); 673 } 674 675 /* 676 * We need offline the port manually, before we want to detach it 677 * or it will not succeed. 678 */ 679 if (fct_deregister_local_port(ss->ss_port) != FCT_SUCCESS) { 680 FCOET_LOG("fcoet_detach_uninit", 681 "fct_deregister_local_port failed"); 682 return (FCOE_FAILURE); 683 } 684 685 /* 686 * Stop watchdog 687 */ 688 if (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) { 689 atomic_or_32(&ss->ss_flags, SS_FLAG_TERMINATE_WATCHDOG); 690 cv_broadcast(&ss->ss_watch_cv); 691 while (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) { 692 delay(10); 693 } 694 } 695 696 ddi_taskq_destroy(ss->ss_watchdog_taskq); 697 698 /* 699 * Release all resources 700 */ 701 mutex_destroy(&ss->ss_ioctl_mutex); 702 mutex_destroy(&ss->ss_watch_mutex); 703 cv_destroy(&ss->ss_watch_cv); 704 mod_hash_destroy_hash(ss->ss_sol_oxid_hash); 705 mod_hash_destroy_hash(ss->ss_unsol_rxid_hash); 706 list_destroy(&ss->ss_abort_xchg_list); 707 708 fct_free(ss->ss_port->port_fds); 709 fct_free(ss->ss_port); 710 ss->ss_port = NULL; 711 712 fcoet_dbuf_destroy(ss); 713 714 if (ss->ss_eport != NULL && 715 ss->ss_eport->eport_deregister_client != NULL) { 716 ss->ss_eport->eport_deregister_client(ss->ss_eport); 717 } 718 ddi_soft_state_free(fcoet_state, ss->ss_instance); 719 return (FCOE_SUCCESS); 720 } 721 722 static void 723 fcoet_watchdog(void *arg) 724 { 725 fcoet_soft_state_t *ss = (fcoet_soft_state_t *)arg; 726 clock_t tmp_delay = 0; 727 fcoet_exchange_t *xchg, *xchg_next; 728 729 FCOET_LOG("fcoet_watchdog", "fcoet_soft_state is %p", ss); 730 731 mutex_enter(&ss->ss_watch_mutex); 732 atomic_or_32(&ss->ss_flags, SS_FLAG_WATCHDOG_RUNNING); 733 tmp_delay = STMF_SEC2TICK(1)/2; 734 735 while ((ss->ss_flags & SS_FLAG_TERMINATE_WATCHDOG) == 0) { 736 ss->ss_watch_count++; 737 738 if (ss->ss_sol_flogi_state != SFS_FLOGI_DONE) { 739 fcoet_handle_sol_flogi(ss); 740 } 741 for (xchg = list_head(&ss->ss_abort_xchg_list); xchg; ) { 742 xchg_next = list_next(&ss->ss_abort_xchg_list, xchg); 743 if (xchg->xch_ref == 0) { 744 list_remove(&ss->ss_abort_xchg_list, xchg); 745 mutex_exit(&ss->ss_watch_mutex); 746 /* xchg abort done */ 747 if (xchg->xch_dbuf_num) { 748 kmem_free((void*)xchg->xch_dbufs, 749 xchg->xch_dbuf_num * 750 sizeof (void *)); 751 xchg->xch_dbufs = NULL; 752 xchg->xch_dbuf_num = 0; 753 } 754 fct_cmd_fca_aborted(xchg->xch_cmd, 755 FCT_ABORT_SUCCESS, FCT_IOF_FCA_DONE); 756 mutex_enter(&ss->ss_watch_mutex); 757 } 758 xchg = xchg_next; 759 } 760 761 atomic_or_32(&ss->ss_flags, SS_FLAG_DOG_WAITING); 762 (void) cv_timedwait(&ss->ss_watch_cv, 763 &ss->ss_watch_mutex, ddi_get_lbolt() + 764 (clock_t)tmp_delay); 765 atomic_and_32(&ss->ss_flags, ~SS_FLAG_DOG_WAITING); 766 } 767 768 /* 769 * Ensure no ongoing FLOGI, before terminate the watchdog 770 */ 771 if (ss->ss_sol_flogi) { 772 fcoet_clear_sol_exchange(ss->ss_sol_flogi); 773 fct_free(ss->ss_sol_flogi->xch_cmd); 774 ss->ss_sol_flogi = NULL; 775 } 776 777 atomic_and_32(&ss->ss_flags, ~SS_FLAG_WATCHDOG_RUNNING); 778 mutex_exit(&ss->ss_watch_mutex); 779 } 780 781 static void 782 fcoet_handle_sol_flogi(fcoet_soft_state_t *ss) 783 { 784 clock_t twosec = STMF_SEC2TICK(2); 785 786 check_state_again: 787 if (ss->ss_flags & SS_FLAG_PORT_DISABLED) { 788 ss->ss_sol_flogi_state = SFS_WAIT_LINKUP; 789 } 790 791 switch (ss->ss_sol_flogi_state) { 792 case SFS_WAIT_LINKUP: 793 if (ss->ss_sol_flogi) { 794 if (ss->ss_sol_flogi->xch_ref == 0) { 795 fcoet_clear_sol_exchange(ss->ss_sol_flogi); 796 fct_free(ss->ss_sol_flogi->xch_cmd); 797 ss->ss_sol_flogi = NULL; 798 } 799 } 800 break; 801 802 case SFS_FLOGI_INIT: 803 if (ss->ss_sol_flogi) { 804 /* 805 * wait for the response to finish 806 */ 807 ss->ss_sol_flogi_state = SFS_CLEAR_FLOGI; 808 break; 809 } 810 fcoet_send_sol_flogi(ss); 811 ss->ss_sol_flogi_state++; 812 break; 813 814 case SFS_FLOGI_CHECK_TIMEOUT: 815 if ((ss->ss_sol_flogi->xch_start_time + twosec) < 816 ddi_get_lbolt()) { 817 ss->ss_sol_flogi_state++; 818 } 819 break; 820 821 case SFS_ABTS_INIT: 822 fcoet_send_sol_abts(ss->ss_sol_flogi); 823 ss->ss_sol_flogi_state++; 824 break; 825 826 case SFS_CLEAR_FLOGI: 827 if (ss->ss_sol_flogi) { 828 if (ss->ss_sol_flogi->xch_ref) { 829 break; 830 } 831 fcoet_clear_sol_exchange(ss->ss_sol_flogi); 832 fct_free(ss->ss_sol_flogi->xch_cmd); 833 ss->ss_sol_flogi = NULL; 834 } 835 ss->ss_sol_flogi_state = SFS_FLOGI_INIT; 836 goto check_state_again; 837 838 case SFS_FLOGI_ACC: 839 ss->ss_sol_flogi_state++; 840 goto check_state_again; 841 842 case SFS_FLOGI_DONE: 843 if (!(ss->ss_flags & SS_FLAG_PORT_DISABLED) && 844 ss->ss_sol_flogi) { 845 fcoet_clear_sol_exchange(ss->ss_sol_flogi); 846 fct_free(ss->ss_sol_flogi->xch_cmd); 847 ss->ss_sol_flogi = NULL; 848 } 849 850 /* 851 * We'd better to offline it first, and delay 0.1 seconds, 852 * before we say it's on again. 853 */ 854 fct_handle_event(ss->ss_port, 855 FCT_EVENT_LINK_DOWN, 0, NULL); 856 delay(STMF_SEC2TICK(1)/10); 857 fct_handle_event(ss->ss_port, 858 FCT_EVENT_LINK_UP, 0, NULL); 859 break; 860 861 default: 862 ASSERT(0); 863 break; 864 } 865 } 866 867 /* ARGSUSED */ 868 static int 869 fcoet_dbuf_init(fcoet_soft_state_t *ss) 870 { 871 return (FCOE_SUCCESS); 872 } 873 874 /* ARGSUSED */ 875 static void 876 fcoet_dbuf_destroy(fcoet_soft_state_t *ss) 877 { 878 879 } 880 881 /* ARGSUSED */ 882 static stmf_data_buf_t * 883 fcoet_dbuf_alloc(fct_local_port_t *port, uint32_t size, uint32_t *pminsize, 884 uint32_t flags) 885 { 886 stmf_data_buf_t *dbuf; 887 int add_size; 888 int sge_num; 889 int sge_size; 890 int idx; 891 int ii; 892 void *netb; 893 uint8_t *fc_buf; 894 fcoet_soft_state_t *ss = 895 (fcoet_soft_state_t *)port->port_fca_private; 896 897 if (size > FCOET_MAX_DBUF_LEN) { 898 if (*pminsize > FCOET_MAX_DBUF_LEN) { 899 return (NULL); 900 } 901 902 size = FCOET_MAX_DBUF_LEN; 903 } 904 905 sge_num = (size - 1) / ss->ss_fcp_data_payload_size + 1; 906 add_size = (sge_num - 1) * sizeof (struct stmf_sglist_ent) + 907 sge_num * sizeof (mblk_t *); 908 dbuf = stmf_alloc(STMF_STRUCT_DATA_BUF, add_size, 0); 909 if (dbuf == NULL) { 910 return (NULL); 911 } 912 dbuf->db_buf_size = size; 913 dbuf->db_data_size = size; 914 dbuf->db_sglist_length = 0; 915 dbuf->db_flags |= DB_DONT_REUSE; 916 FCOET_SET_SEG_NUM(dbuf, sge_num); 917 918 /* 919 * Initialize non-last sg entries 920 */ 921 for (idx = 0; idx < sge_num - 1; idx++) { 922 sge_size = ss->ss_fcp_data_payload_size; 923 netb = ss->ss_eport->eport_alloc_netb( 924 ss->ss_eport, sizeof (fcoe_fc_frame_header_t) + 925 sge_size, &fc_buf); 926 if (netb == NULL) { 927 for (ii = 0; ii < idx; ii++) { 928 ss->ss_eport->eport_free_netb( 929 FCOET_GET_NETB(dbuf, ii)); 930 } 931 stmf_free(dbuf); 932 FCOET_LOG("fcoe_dbuf_alloc", "no netb"); 933 return (NULL); 934 } 935 FCOET_SET_NETB(dbuf, idx, netb); 936 dbuf->db_sglist[idx].seg_addr = fc_buf + 937 sizeof (fcoe_fc_frame_header_t); 938 dbuf->db_sglist[idx].seg_length = sge_size; 939 } 940 941 /* 942 * Initialize the last sg entry 943 */ 944 if (size % ss->ss_fcp_data_payload_size) { 945 sge_size = P2ROUNDUP(size % ss->ss_fcp_data_payload_size, 4); 946 } else { 947 sge_size = ss->ss_fcp_data_payload_size; 948 } 949 950 netb = ss->ss_eport->eport_alloc_netb( 951 ss->ss_eport, 952 sizeof (fcoe_fc_frame_header_t) + 953 sge_size, &fc_buf); 954 if (netb == NULL) { 955 for (ii = 0; ii < idx; ii++) { 956 ss->ss_eport->eport_free_netb( 957 FCOET_GET_NETB(dbuf, ii)); 958 } 959 stmf_free(dbuf); 960 FCOET_LOG("fcoe_dbuf_alloc", "no netb"); 961 return (NULL); 962 } 963 964 FCOET_SET_NETB(dbuf, idx, netb); 965 dbuf->db_sglist[idx].seg_addr = fc_buf + 966 sizeof (fcoe_fc_frame_header_t); 967 dbuf->db_sglist[idx].seg_length = sge_size; 968 969 /* 970 * Let COMSTAR know how many sg entries we will use 971 */ 972 dbuf->db_sglist_length = idx + 1; 973 974 return (dbuf); 975 } 976 977 static void 978 fcoet_dbuf_free(fct_dbuf_store_t *fds, stmf_data_buf_t *dbuf) 979 { 980 int idx; 981 fcoet_soft_state_t *ss = 982 (fcoet_soft_state_t *)fds->fds_fca_private; 983 984 for (idx = 0; idx < FCOET_GET_SEG_NUM(dbuf); idx++) { 985 if (FCOET_GET_NETB(dbuf, idx)) { 986 ss->ss_eport->eport_free_netb( 987 FCOET_GET_NETB(dbuf, idx)); 988 } 989 } 990 991 stmf_free(dbuf); 992 } 993 994 /* 995 * We should have initialized fcoe_frame_t before 996 */ 997 void 998 fcoet_init_tfm(fcoe_frame_t *frm, fcoet_exchange_t *xch) 999 { 1000 FRM2TFM(frm)->tfm_fcoe_frame = frm; 1001 FRM2TFM(frm)->tfm_xch = xch; 1002 FRM2TFM(frm)->tfm_seq = NULL; 1003 } 1004 1005 /* ARGSUSED */ 1006 static uint_t 1007 fcoet_sol_oxid_hash_empty(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 1008 { 1009 fcoet_soft_state_t *ss = (fcoet_soft_state_t *)arg; 1010 1011 ss->ss_sol_oxid_hash_empty = 0; 1012 FCOET_LOG("fcoet_sol_oxid_hash_empty", "one ongoing xch: %p", val); 1013 return (MH_WALK_CONTINUE); 1014 } 1015 1016 /* ARGSUSED */ 1017 static uint_t 1018 fcoet_unsol_rxid_hash_empty(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 1019 { 1020 fcoet_soft_state_t *ss = (fcoet_soft_state_t *)arg; 1021 1022 ss->ss_sol_oxid_hash_empty = 0; 1023 FCOET_LOG("fcoet_unsol_rxid_hash_empty", "one ongoing xch: %p", val); 1024 return (MH_WALK_CONTINUE); 1025 } 1026 1027 /* ARGSUSED */ 1028 void 1029 fcoet_modhash_find_cb(mod_hash_key_t key, mod_hash_val_t val) 1030 { 1031 ASSERT(val != NULL); 1032 fcoet_exchange_t *xch = (fcoet_exchange_t *)val; 1033 FCOET_BUSY_XCHG(xch); 1034 } 1035