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) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 #include <sys/conf.h> 27 #include <sys/ddi.h> 28 #include <sys/stat.h> 29 #include <sys/pci.h> 30 #include <sys/sunddi.h> 31 #include <sys/modctl.h> 32 #include <sys/file.h> 33 #include <sys/cred.h> 34 #include <sys/byteorder.h> 35 #include <sys/atomic.h> 36 #include <sys/scsi/scsi.h> 37 #include <sys/mac_client.h> 38 #include <sys/modhash.h> 39 40 /* 41 * leadville header files 42 */ 43 #include <sys/fibre-channel/fc.h> 44 #include <sys/fibre-channel/impl/fc_fcaif.h> 45 46 /* 47 * fcoe header files 48 */ 49 #include <sys/fcoe/fcoe_common.h> 50 51 /* 52 * fcoei header files 53 */ 54 #include <fcoei.h> 55 56 /* 57 * forward declaration of stack functions 58 */ 59 static uint32_t fcoei_xch_check( 60 mod_hash_key_t key, mod_hash_val_t *val, void *arg); 61 static int fcoei_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 62 static int fcoei_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 63 static int fcoei_open(dev_t *devp, int flag, int otype, cred_t *credp); 64 static int fcoei_close(dev_t dev, int flag, int otype, cred_t *credp); 65 static int fcoei_ioctl( 66 dev_t dev, int cmd, intptr_t data, int mode, cred_t *credp, int *rval); 67 static int fcoei_attach_init(fcoei_soft_state_t *ss); 68 static int fcoei_detach_uninit(fcoei_soft_state_t *ss); 69 static void fcoei_watchdog(void *arg); 70 static void fcoei_process_events(fcoei_soft_state_t *ss); 71 static void fcoei_trigger_fp_attach(void *arg); 72 static void fcoei_abts_exchange(fcoei_exchange_t *xch); 73 static void fcoei_clear_watchdog_jobs(fcoei_soft_state_t *ss); 74 75 /* 76 * Driver identificaton stuff 77 */ 78 static struct cb_ops fcoei_cb_ops = { 79 fcoei_open, 80 fcoei_close, 81 nodev, 82 nodev, 83 nodev, 84 nodev, 85 nodev, 86 fcoei_ioctl, 87 nodev, 88 nodev, 89 nodev, 90 nochpoll, 91 ddi_prop_op, 92 0, 93 D_MP | D_NEW | D_HOTPLUG, 94 CB_REV, 95 nodev, 96 nodev 97 }; 98 99 static struct dev_ops fcoei_ops = { 100 DEVO_REV, 101 0, 102 nodev, 103 nulldev, 104 nulldev, 105 fcoei_attach, 106 fcoei_detach, 107 nodev, 108 &fcoei_cb_ops, 109 NULL, 110 ddi_power, 111 ddi_quiesce_not_needed 112 }; 113 114 static struct modldrv modldrv = { 115 &mod_driverops, 116 FCOEI_NAME_VERSION, 117 &fcoei_ops, 118 }; 119 120 static struct modlinkage modlinkage = { 121 MODREV_1, 122 { &modldrv, NULL } 123 }; 124 125 /* 126 * Driver's global variables 127 */ 128 void *fcoei_state = NULL; 129 int fcoei_use_ext_log = 0; 130 131 /* 132 * Common loadable module entry points _init, _fini, _info 133 */ 134 int 135 _init(void) 136 { 137 int ret; 138 139 ret = ddi_soft_state_init(&fcoei_state, sizeof (fcoei_soft_state_t), 0); 140 if (ret != DDI_SUCCESS) { 141 FCOEI_LOG(__FUNCTION__, "soft state init failed: %x", ret); 142 return (ret); 143 } 144 145 ret = mod_install(&modlinkage); 146 if (ret != 0) { 147 ddi_soft_state_fini(&fcoei_state); 148 FCOEI_LOG(__FUNCTION__, "fcoei mod_install failed: %x", ret); 149 return (ret); 150 } 151 152 /* 153 * Let FCTL initialize devo_bus_ops 154 */ 155 fc_fca_init(&fcoei_ops); 156 157 FCOEI_LOG(__FUNCTION__, "fcoei _init succeeded"); 158 return (ret); 159 } 160 161 int 162 _fini(void) 163 { 164 int ret; 165 166 ret = mod_remove(&modlinkage); 167 if (ret != 0) { 168 FCOEI_EXT_LOG(__FUNCTION__, "fcoei mod_remove failed: %x", ret); 169 return (ret); 170 } 171 172 ddi_soft_state_fini(&fcoei_state); 173 FCOEI_LOG(__FUNCTION__, "fcoei _fini succeeded"); 174 return (ret); 175 } 176 177 int 178 _info(struct modinfo *modinfop) 179 { 180 return (mod_info(&modlinkage, modinfop)); 181 } 182 183 /* 184 * Autoconfiguration entry points: attach, detach, getinfo 185 */ 186 187 static int 188 fcoei_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 189 { 190 int ret; 191 int fcoe_ret; 192 int instance; 193 fcoei_soft_state_t *ss; 194 195 instance = ddi_get_instance(dip); 196 FCOEI_LOG(__FUNCTION__, "instance is %d", instance); 197 switch (cmd) { 198 case DDI_ATTACH: 199 ret = ddi_soft_state_zalloc(fcoei_state, instance); 200 if (ret != DDI_SUCCESS) { 201 FCOEI_LOG(__FUNCTION__, "ss zalloc failed: %x", ret); 202 return (ret); 203 } 204 205 /* 206 * Get the soft state, and do basic initialization with dip 207 */ 208 ss = ddi_get_soft_state(fcoei_state, instance); 209 ss->ss_dip = dip; 210 211 fcoe_ret = fcoei_attach_init(ss); 212 if (fcoe_ret != FCOE_SUCCESS) { 213 ddi_soft_state_free(fcoei_state, instance); 214 FCOEI_LOG(__FUNCTION__, "fcoei_attach_init failed: " 215 "%x", fcoe_ret); 216 return (DDI_FAILURE); 217 } 218 219 ss->ss_flags |= SS_FLAG_TRIGGER_FP_ATTACH; 220 (void) timeout(fcoei_trigger_fp_attach, ss, FCOE_SEC2TICK(1)); 221 FCOEI_LOG(__FUNCTION__, "fcoei_attach succeeded: dip-%p, " 222 "cmd-%x", dip, cmd); 223 return (DDI_SUCCESS); 224 225 case DDI_RESUME: 226 return (DDI_SUCCESS); 227 228 default: 229 FCOEI_LOG(__FUNCTION__, "unsupported attach cmd-%X", cmd); 230 return (DDI_FAILURE); 231 } 232 } 233 234 static int 235 fcoei_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 236 { 237 int fcoe_ret; 238 int instance; 239 fcoei_soft_state_t *ss; 240 241 instance = ddi_get_instance(dip); 242 ss = ddi_get_soft_state(fcoei_state, instance); 243 if (ss == NULL) { 244 FCOEI_LOG(__FUNCTION__, "get ss failed: dip-%p", dip); 245 return (DDI_FAILURE); 246 } 247 248 switch (cmd) { 249 case DDI_DETACH: 250 if (ss->ss_flags & SS_FLAG_TRIGGER_FP_ATTACH) { 251 FCOEI_LOG(__FUNCTION__, "still await fp attach"); 252 return (DDI_FAILURE); 253 } 254 255 if (ss->ss_flags & SS_FLAG_LV_BOUND) { 256 FCOEI_LOG(__FUNCTION__, "fp is not detached yet"); 257 return (DDI_FAILURE); 258 } 259 260 fcoe_ret = fcoei_detach_uninit(ss); 261 if (fcoe_ret != FCOE_SUCCESS) { 262 FCOEI_LOG(__FUNCTION__, "fcoei_detach_uninit failed:" 263 " dip-%p, fcoe_ret-%d", dip, fcoe_ret); 264 return (DDI_FAILURE); 265 } 266 267 FCOEI_LOG(__FUNCTION__, "succeeded: dip-%p, cmd-%x", dip, cmd); 268 return (DDI_SUCCESS); 269 270 case DDI_SUSPEND: 271 return (DDI_SUCCESS); 272 273 default: 274 FCOEI_LOG(__FUNCTION__, "unspported detach cmd-%X", cmd); 275 return (DDI_FAILURE); 276 } 277 } 278 279 /* 280 * Device access entry points: open, close, ioctl 281 */ 282 283 static int 284 fcoei_open(dev_t *devp, int flag, int otype, cred_t *credp) 285 { 286 fcoei_soft_state_t *ss; 287 288 if (otype != OTYP_CHR) { 289 FCOEI_LOG(__FUNCTION__, "flag: %x", flag); 290 return (EINVAL); 291 } 292 293 if (drv_priv(credp)) { 294 return (EPERM); 295 } 296 297 /* 298 * First of all, get related soft state 299 */ 300 ss = ddi_get_soft_state(fcoei_state, (int)getminor(*devp)); 301 if (ss == NULL) { 302 return (ENXIO); 303 } 304 305 mutex_enter(&ss->ss_ioctl_mutex); 306 if (ss->ss_ioctl_flags & FCOEI_IOCTL_FLAG_OPEN) { 307 /* 308 * We don't support concurrent open 309 */ 310 mutex_exit(&ss->ss_ioctl_mutex); 311 return (EBUSY); 312 } 313 314 ss->ss_ioctl_flags |= FCOEI_IOCTL_FLAG_OPEN; 315 mutex_exit(&ss->ss_ioctl_mutex); 316 317 return (0); 318 } 319 320 static int 321 fcoei_close(dev_t dev, int flag, int otype, cred_t *credp) 322 { 323 fcoei_soft_state_t *ss; 324 325 if (otype != OTYP_CHR) { 326 FCOEI_LOG(__FUNCTION__, "flag: %x, %p", flag, credp); 327 return (EINVAL); 328 } 329 330 /* 331 * First of all, get related soft state 332 */ 333 ss = ddi_get_soft_state(fcoei_state, (int)getminor(dev)); 334 if (ss == NULL) { 335 return (ENXIO); 336 } 337 338 mutex_enter(&ss->ss_ioctl_mutex); 339 if (!(ss->ss_ioctl_flags & FCOEI_IOCTL_FLAG_OPEN)) { 340 /* 341 * If it's not open, we can exit 342 */ 343 344 mutex_exit(&ss->ss_ioctl_mutex); 345 return (ENODEV); 346 } 347 348 ss->ss_ioctl_flags &= ~FCOEI_IOCTL_FLAG_OPEN; 349 mutex_exit(&ss->ss_ioctl_mutex); 350 351 return (0); 352 } 353 354 static int 355 fcoei_ioctl(dev_t dev, int cmd, intptr_t data, int mode, 356 cred_t *credp, int *rval) 357 { 358 fcoei_soft_state_t *ss; 359 int ret = 0; 360 361 if (drv_priv(credp) != 0) { 362 FCOEI_LOG(__FUNCTION__, "data: %p, %x", data, mode); 363 return (EPERM); 364 } 365 366 /* 367 * Get related soft state 368 */ 369 ss = ddi_get_soft_state(fcoei_state, (int32_t)getminor(dev)); 370 if (!ss) { 371 return (ENXIO); 372 } 373 374 /* 375 * Process ioctl 376 */ 377 switch (cmd) { 378 379 default: 380 FCOEI_LOG(__FUNCTION__, "ioctl-0x%02X", cmd); 381 ret = ENOTTY; 382 } 383 384 /* 385 * Set return value 386 */ 387 *rval = ret; 388 return (ret); 389 } 390 391 /* 392 * fcoei_attach_init 393 * init related stuff of the soft state 394 * 395 * Input: 396 * ss = the soft state that will be processed 397 * 398 * Return: 399 * if it succeeded or not 400 * 401 * Comment: 402 * N/A 403 */ 404 static int 405 fcoei_attach_init(fcoei_soft_state_t *ss) 406 { 407 fcoe_port_t *eport; 408 fcoe_client_t client_fcoei; 409 char taskq_name[32]; 410 int ret; 411 la_els_logi_t *els = &ss->ss_els_logi; 412 svc_param_t *class3_param; 413 414 /* 415 * Register fcoei to FCOE as its client 416 */ 417 client_fcoei.ect_eport_flags = EPORT_FLAG_INI_MODE | 418 EPORT_FLAG_IS_DIRECT_P2P; 419 client_fcoei.ect_max_fc_frame_size = FCOE_MAX_FC_FRAME_SIZE; 420 client_fcoei.ect_private_frame_struct_size = sizeof (fcoei_frame_t); 421 fcoei_init_ect_vectors(&client_fcoei); 422 client_fcoei.ect_client_port_struct = ss; 423 client_fcoei.ect_fcoe_ver = FCOE_VER_NOW; 424 FCOEI_LOG(__FUNCTION__, "version: %x %x", FCOE_VER_NOW, fcoe_ver_now); 425 ret = ddi_prop_get_int(DDI_DEV_T_ANY, ss->ss_dip, 426 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "mac_id", -1); 427 if (ret == -1) { 428 FCOEI_LOG(__FUNCTION__, "get mac_id failed"); 429 return (DDI_FAILURE); 430 } else { 431 client_fcoei.ect_channelid = ret; 432 } 433 434 /* 435 * It's fcoe's responsiblity to initialize eport's all elements, 436 * so we needn't do eport initialization 437 */ 438 eport = fcoe_register_client(&client_fcoei); 439 if (eport == NULL) { 440 goto fail_register_client; 441 } else { 442 ss->ss_eport = eport; 443 FCOE_SET_DEFAULT_FPORT_ADDR(eport->eport_efh_dst); 444 } 445 446 /* 447 * Now it's time to register fca_tran to FCTL 448 * Remember fc_local_port is transparent to FCA (fcoei) 449 */ 450 ss->ss_fca_tran.fca_version = FCTL_FCA_MODREV_5; 451 ss->ss_fca_tran.fca_numports = 1; 452 ss->ss_fca_tran.fca_pkt_size = sizeof (fcoei_exchange_t); 453 ss->ss_fca_tran.fca_cmd_max = 2048; 454 455 /* 456 * scsi_tran_hba_setup could need these stuff 457 */ 458 ss->ss_fca_tran.fca_dma_lim = NULL; 459 ss->ss_fca_tran.fca_iblock = NULL; 460 ss->ss_fca_tran.fca_dma_attr = NULL; 461 ss->ss_fca_tran.fca_acc_attr = NULL; 462 463 /* 464 * Initialize vectors 465 */ 466 fcoei_init_fcatran_vectors(&ss->ss_fca_tran); 467 468 /* 469 * fc_fca_attach only sets driver's private, it has nothing to with 470 * common port object between fcoei and leadville. 471 * After this attach, fp_attach will be triggered, and it will call 472 * fca_bind_port to let fcoei to know about common port object. 473 */ 474 if (fc_fca_attach(ss->ss_dip, &ss->ss_fca_tran) != DDI_SUCCESS) { 475 goto fail_fca_attach; 476 } 477 478 /* 479 * It's time to do ss initialization 480 */ 481 ret = ddi_create_minor_node(ss->ss_dip, "admin", 482 S_IFCHR, ddi_get_instance(ss->ss_dip), DDI_NT_NEXUS, 0); 483 if (ret != DDI_SUCCESS) { 484 goto fail_minor_node; 485 } 486 487 ss->ss_flags = 0; 488 ss->ss_port = NULL; 489 /* 490 * ss->ss_eport has been initialized 491 */ 492 493 ss->ss_sol_oxid_hash = mod_hash_create_idhash( 494 "fcoei_sol_oxid_hash", FCOEI_SOL_HASH_SIZE, 495 mod_hash_null_valdtor); 496 ss->ss_unsol_rxid_hash = mod_hash_create_idhash( 497 "fcoei_unsol_rxid_hash", FCOEI_UNSOL_HASH_SIZE, 498 mod_hash_null_valdtor); 499 list_create(&ss->ss_comp_xch_list, sizeof (fcoei_exchange_t), 500 offsetof(fcoei_exchange_t, xch_comp_node)); 501 ss->ss_next_sol_oxid = 0xFFFF; 502 ss->ss_next_unsol_rxid = 0xFFFF; 503 504 mutex_init(&ss->ss_watchdog_mutex, 0, MUTEX_DRIVER, 0); 505 cv_init(&ss->ss_watchdog_cv, NULL, CV_DRIVER, NULL); 506 (void) snprintf(taskq_name, 32, "leadville_fcoei_%d_taskq", 507 ddi_get_instance(ss->ss_dip)); 508 taskq_name[31] = 0; 509 ss->ss_taskq = ddi_taskq_create(ss->ss_dip, 510 taskq_name, 64, TASKQ_DEFAULTPRI, DDI_SLEEP); 511 512 ss->ss_link_state = FC_STATE_OFFLINE; 513 ss->ss_link_speed = 0; 514 ss->ss_port_event_counter = 0; 515 516 list_create(&ss->ss_event_list, sizeof (fcoei_event_t), 517 offsetof(fcoei_event_t, ae_node)); 518 519 ss->ss_sol_cnt1 = 0; 520 ss->ss_sol_cnt2 = 0; 521 ss->ss_sol_cnt = &ss->ss_sol_cnt1; 522 ss->ss_unsol_cnt1 = 0; 523 ss->ss_unsol_cnt2 = 0; 524 ss->ss_unsol_cnt = &ss->ss_unsol_cnt1; 525 ss->ss_ioctl_flags = 0; 526 527 mutex_init(&ss->ss_ioctl_mutex, 0, MUTEX_DRIVER, 0); 528 529 bcopy(eport->eport_portwwn, els->nport_ww_name.raw_wwn, 8); 530 bcopy(eport->eport_nodewwn, els->node_ww_name.raw_wwn, 8); 531 els->common_service.fcph_version = 0x2008; 532 els->common_service.btob_credit = 3; 533 els->common_service.cmn_features = 0x8800; 534 els->common_service.conc_sequences = 0xff; 535 els->common_service.relative_offset = 3; 536 els->common_service.e_d_tov = 0x07d0; 537 class3_param = (svc_param_t *)&els->class_3; 538 class3_param->class_opt = 0x8800; 539 class3_param->rcv_size = els->common_service.rx_bufsize = 2048; 540 class3_param->conc_sequences = 0xff; 541 class3_param->open_seq_per_xchng = 1; 542 543 /* 544 * Fill out RNID Management Information 545 */ 546 bcopy(ss->ss_eport->eport_portwwn, ss->ss_rnid.global_id, 8); 547 ss->ss_rnid.unit_type = FCOEI_RNID_HBA; 548 ss->ss_rnid.ip_version = FCOEI_RNID_IPV4; 549 550 /* 551 * Start our watchdog 552 */ 553 (void) ddi_taskq_dispatch(ss->ss_taskq, 554 fcoei_watchdog, ss, DDI_SLEEP); 555 while (!(ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING)) { 556 delay(50); 557 } 558 559 /* 560 * Report the device to the system 561 */ 562 ddi_report_dev(ss->ss_dip); 563 return (DDI_SUCCESS); 564 565 566 fail_minor_node: 567 FCOEI_LOG(__FUNCTION__, "fail_minor_node"); 568 (void) fc_fca_detach(ss->ss_dip); 569 570 fail_fca_attach: 571 eport->eport_deregister_client(eport); 572 FCOEI_LOG(__FUNCTION__, "fail_fca_attach"); 573 574 fail_register_client: 575 FCOEI_LOG(__FUNCTION__, "fail_register_client"); 576 return (DDI_FAILURE); 577 } 578 579 /* 580 * fcoei_detach_uninit 581 * uninit related stuff of the soft state 582 * 583 * Input: 584 * ss = the soft state that will be processed 585 * 586 * Return: 587 * if it succeeded or not 588 * 589 * Comment: 590 * N/A 591 */ 592 int 593 fcoei_detach_uninit(fcoei_soft_state_t *ss) 594 { 595 /* 596 * Stop watchdog first 597 */ 598 if (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) { 599 ss->ss_flags |= SS_FLAG_TERMINATE_WATCHDOG; 600 cv_broadcast(&ss->ss_watchdog_cv); 601 } 602 603 /* 604 * Destroy the taskq 605 */ 606 ddi_taskq_wait(ss->ss_taskq); 607 ddi_taskq_destroy(ss->ss_taskq); 608 609 /* 610 * Release all allocated resources 611 */ 612 mutex_destroy(&ss->ss_ioctl_mutex); 613 mutex_destroy(&ss->ss_watchdog_mutex); 614 cv_destroy(&ss->ss_watchdog_cv); 615 mod_hash_destroy_idhash(ss->ss_sol_oxid_hash); 616 mod_hash_destroy_idhash(ss->ss_unsol_rxid_hash); 617 list_destroy(&ss->ss_event_list); 618 ss->ss_eport->eport_deregister_client(ss->ss_eport); 619 ddi_remove_minor_node(ss->ss_dip, NULL); 620 621 /* 622 * Release itself 623 */ 624 ddi_soft_state_free(fcoei_state, ddi_get_instance(ss->ss_dip)); 625 return (FCOE_SUCCESS); 626 } 627 628 /* 629 * fcoei_watchdog 630 * Perform periodic checking and routine tasks 631 * 632 * Input: 633 * arg = the soft state that will be processed 634 * 635 * Return: 636 * N/A 637 * 638 * Comment: 639 * N/A 640 */ 641 static void 642 fcoei_watchdog(void *arg) 643 { 644 fcoei_soft_state_t *ss; 645 clock_t tmp_delay; 646 clock_t start_clock; 647 clock_t last_clock; 648 649 /* 650 * For debugging 651 */ 652 ss = (fcoei_soft_state_t *)arg; 653 FCOEI_LOG(__FUNCTION__, "ss %p", ss); 654 FCOEI_LOG(__FUNCTION__, "sol_hash %p", ss->ss_sol_oxid_hash); 655 FCOEI_LOG(__FUNCTION__, "unsol_hash %p", ss->ss_unsol_rxid_hash); 656 ss->ss_flags |= SS_FLAG_WATCHDOG_RUNNING; 657 tmp_delay = FCOE_SEC2TICK(1) / 2; 658 last_clock = CURRENT_CLOCK; 659 660 /* 661 * If nobody reqeusts to terminate the watchdog, we will work forever 662 */ 663 while (!(ss->ss_flags & SS_FLAG_TERMINATE_WATCHDOG)) { 664 /* 665 * We handle all asynchronous events serially 666 */ 667 fcoei_process_events(ss); 668 669 /* 670 * To avoid to check timing too freqently, we check 671 * if we need skip timing stuff. 672 */ 673 start_clock = CURRENT_CLOCK; 674 if ((start_clock - last_clock) < tmp_delay) { 675 goto end_timing; 676 } else { 677 last_clock = start_clock; 678 } 679 680 /* 681 * It's time to do timeout checking of solicited exchanges 682 */ 683 if (ss->ss_sol_cnt == (&ss->ss_sol_cnt1)) { 684 if (ss->ss_sol_cnt2 == 0) { 685 ss->ss_sol_cnt = &ss->ss_sol_cnt2; 686 } else { 687 mod_hash_walk(ss->ss_sol_oxid_hash, 688 fcoei_xch_check, ss); 689 } 690 } else { 691 if (ss->ss_sol_cnt1 == 0) { 692 ss->ss_sol_cnt = &ss->ss_sol_cnt1; 693 } else { 694 mod_hash_walk(ss->ss_sol_oxid_hash, 695 fcoei_xch_check, ss); 696 } 697 } 698 699 /* 700 * It's time to do timeout checking of unsolicited exchange 701 */ 702 if (ss->ss_unsol_cnt == (&ss->ss_unsol_cnt1)) { 703 if (ss->ss_unsol_cnt2 == 0) { 704 ss->ss_unsol_cnt = &ss->ss_unsol_cnt2; 705 } else { 706 mod_hash_walk(ss->ss_unsol_rxid_hash, 707 fcoei_xch_check, ss); 708 } 709 } else { 710 if (ss->ss_unsol_cnt1 == 0) { 711 ss->ss_unsol_cnt = &ss->ss_unsol_cnt1; 712 } else { 713 mod_hash_walk(ss->ss_unsol_rxid_hash, 714 fcoei_xch_check, ss); 715 } 716 } 717 718 /* 719 * Check if there are exchanges which are ready to complete 720 */ 721 fcoei_handle_comp_xch_list(ss); 722 723 end_timing: 724 /* 725 * Wait for next cycle 726 */ 727 mutex_enter(&ss->ss_watchdog_mutex); 728 ss->ss_flags |= SS_FLAG_WATCHDOG_IDLE; 729 if (!list_is_empty(&ss->ss_event_list)) { 730 goto skip_wait; 731 } 732 733 (void) cv_timedwait(&ss->ss_watchdog_cv, 734 &ss->ss_watchdog_mutex, CURRENT_CLOCK + 735 (clock_t)tmp_delay); 736 skip_wait: 737 ss->ss_flags &= ~SS_FLAG_WATCHDOG_IDLE; 738 mutex_exit(&ss->ss_watchdog_mutex); 739 } 740 741 /* 742 * Do clear work before exit 743 */ 744 fcoei_clear_watchdog_jobs(ss); 745 746 /* 747 * Watchdog has stopped 748 */ 749 ss->ss_flags &= ~SS_FLAG_WATCHDOG_RUNNING; 750 } 751 752 static void 753 fcoei_clear_watchdog_jobs(fcoei_soft_state_t *ss) 754 { 755 fcoei_event_t *ae; 756 fcoe_frame_t *frm; 757 758 mutex_enter(&ss->ss_watchdog_mutex); 759 while (!list_is_empty(&ss->ss_event_list)) { 760 ae = (fcoei_event_t *)list_head(&ss->ss_event_list); 761 list_remove(&ss->ss_event_list, ae); 762 switch (ae->ae_type) { 763 case AE_EVENT_SOL_FRAME: 764 frm = (fcoe_frame_t *)ae->ae_obj; 765 frm->frm_eport->eport_release_frame(frm); 766 break; 767 768 case AE_EVENT_UNSOL_FRAME: 769 frm = (fcoe_frame_t *)ae->ae_obj; 770 frm->frm_eport->eport_free_netb(frm->frm_netb); 771 frm->frm_eport->eport_release_frame(frm); 772 break; 773 774 case AE_EVENT_PORT: 775 atomic_dec_32(&ss->ss_port_event_counter); 776 /* FALLTHROUGH */ 777 778 case AE_EVENT_RESET: 779 kmem_free(ae, sizeof (fcoei_event_t)); 780 break; 781 782 case AE_EVENT_EXCHANGE: 783 /* FALLTHROUGH */ 784 785 default: 786 break; 787 } 788 } 789 790 mod_hash_clear(ss->ss_unsol_rxid_hash); 791 mod_hash_clear(ss->ss_sol_oxid_hash); 792 793 while (!list_is_empty(&ss->ss_comp_xch_list)) { 794 (void) list_remove_head(&ss->ss_comp_xch_list); 795 } 796 mutex_exit(&ss->ss_watchdog_mutex); 797 } 798 799 /* 800 * fcoei_process_events 801 * Process the events one by one 802 * 803 * Input: 804 * ss = the soft state that will be processed 805 * 806 * Return: 807 * N/A 808 * 809 * Comment: 810 * N/A 811 */ 812 static void 813 fcoei_process_events(fcoei_soft_state_t *ss) 814 { 815 fcoei_event_t *ae = NULL; 816 817 /* 818 * It's the only place to delete node from ss_event_list, so we needn't 819 * hold mutex to check if the list is empty. 820 */ 821 ASSERT(!MUTEX_HELD(&ss->ss_watchdog_mutex)); 822 while (list_is_empty(&ss->ss_event_list) == B_FALSE) { 823 mutex_enter(&ss->ss_watchdog_mutex); 824 ae = (fcoei_event_t *)list_remove_head(&ss->ss_event_list); 825 mutex_exit(&ss->ss_watchdog_mutex); 826 827 switch (ae->ae_type) { 828 case AE_EVENT_SOL_FRAME: 829 fcoei_handle_sol_frame_done((fcoe_frame_t *)ae->ae_obj); 830 break; 831 832 case AE_EVENT_UNSOL_FRAME: 833 fcoei_process_unsol_frame((fcoe_frame_t *)ae->ae_obj); 834 break; 835 836 case AE_EVENT_EXCHANGE: 837 fcoei_process_event_exchange(ae); 838 break; 839 840 case AE_EVENT_PORT: 841 fcoei_process_event_port(ae); 842 break; 843 844 case AE_EVENT_RESET: 845 fcoei_process_event_reset(ae); 846 break; 847 848 default: 849 FCOEI_LOG(__FUNCTION__, "unsupported events"); 850 } 851 852 } 853 } 854 855 /* 856 * fcoei_handle_tmout_xch_list 857 * Complete every exchange in the timed-out xch list of the soft state 858 * 859 * Input: 860 * ss = the soft state that need be handled 861 * 862 * Return: 863 * N/A 864 * 865 * Comment: 866 * When mod_hash_walk is in progress, we can't change the hashtable. 867 * This is post-walk handling of exchange timing 868 */ 869 void 870 fcoei_handle_comp_xch_list(fcoei_soft_state_t *ss) 871 { 872 fcoei_exchange_t *xch = NULL; 873 874 while ((xch = list_remove_head(&ss->ss_comp_xch_list)) != NULL) { 875 fcoei_complete_xch(xch, NULL, xch->xch_fpkt->pkt_state, 876 xch->xch_fpkt->pkt_reason); 877 } 878 } 879 880 /* 881 * fcoei_xch_check 882 * Check if the exchange timed out or link is down 883 * 884 * Input: 885 * key = rxid of the unsolicited exchange 886 * val = the unsolicited exchange 887 * arg = the soft state 888 * 889 * Return: 890 * MH_WALK_CONTINUE = continue to walk 891 * 892 * Comment: 893 * We need send ABTS for timed-out for solicited exchange 894 * If it's solicited FLOGI, we need set SS_FLAG_FLOGI_FAILED 895 * If the link is down, we think it has timed out too. 896 */ 897 /* ARGSUSED */ 898 static uint32_t 899 fcoei_xch_check(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 900 { 901 fcoei_exchange_t *xch = (fcoei_exchange_t *)val; 902 903 ASSERT(xch->xch_ss == arg); 904 if ((xch->xch_end_tick < CURRENT_CLOCK) && 905 (xch->xch_ss->ss_link_state != FC_STATE_OFFLINE)) { 906 if (xch->xch_flags & XCH_FLAG_IN_SOL_HASH) { 907 ASSERT(xch->xch_oxid == CMHK(key)); 908 /* 909 * It's solicited exchange 910 */ 911 fcoei_abts_exchange(xch); 912 if (LA_ELS_FLOGI == ((ls_code_t *)(void *) 913 xch->xch_fpkt->pkt_cmd)->ls_code) { 914 /* 915 * It's solicited FLOGI 916 */ 917 xch->xch_ss->ss_flags |= SS_FLAG_FLOGI_FAILED; 918 } 919 } 920 921 FCOEI_LOG(__FUNCTION__, "oxid-%x/rxid-%x timed out", 922 xch->xch_oxid, xch->xch_rxid); 923 xch->xch_flags |= XCH_FLAG_TMOUT; 924 xch->xch_fpkt->pkt_state = FC_PKT_TIMEOUT; 925 xch->xch_fpkt->pkt_reason = FC_REASON_ABORTED; 926 list_insert_tail(&xch->xch_ss->ss_comp_xch_list, xch); 927 } else if (xch->xch_ss->ss_link_state == FC_STATE_OFFLINE) { 928 FCOEI_LOG(__FUNCTION__, "oxid-%x/rxid-%x offline complete", 929 xch->xch_oxid, xch->xch_rxid); 930 xch->xch_flags |= XCH_FLAG_TMOUT; 931 xch->xch_fpkt->pkt_state = FC_PKT_PORT_OFFLINE; 932 xch->xch_fpkt->pkt_reason = FC_REASON_OFFLINE; 933 list_insert_tail(&xch->xch_ss->ss_comp_xch_list, xch); 934 } 935 936 return (MH_WALK_CONTINUE); 937 } 938 939 /* 940 * fcoei_init_ifm 941 * initialize fcoei_frame 942 * 943 * Input: 944 * frm = the frame that ifm need link to 945 * xch = the exchange that ifm need link to 946 * 947 * Return: 948 * N/A 949 * 950 * Comment: 951 * For solicited frames, it's called after FC frame header initialization 952 * For unsolicited frames, it's called just after the frame enters fcoei 953 */ 954 void 955 fcoei_init_ifm(fcoe_frame_t *frm, fcoei_exchange_t *xch) 956 { 957 FRM2IFM(frm)->ifm_frm = frm; 958 FRM2IFM(frm)->ifm_xch = xch; 959 FRM2IFM(frm)->ifm_rctl = FRM_R_CTL(frm); 960 } 961 962 /* 963 * fcoei_trigger_fp_attach 964 * Trigger fp_attach for this fcoei port 965 * 966 * Input: 967 * arg = the soft state that fp will attach 968 * 969 * Return: 970 * N/A 971 * 972 * Comment: 973 * N/A 974 */ 975 static void 976 fcoei_trigger_fp_attach(void * arg) 977 { 978 fcoei_soft_state_t *ss = (fcoei_soft_state_t *)arg; 979 dev_info_t *child = NULL; 980 int rval = NDI_FAILURE; 981 982 ndi_devi_alloc_sleep(ss->ss_dip, "fp", DEVI_PSEUDO_NODEID, &child); 983 if (child == NULL) { 984 FCOEI_LOG(__FUNCTION__, "can't alloc dev_info"); 985 return; 986 } 987 988 /* 989 * fp/fctl need this property 990 */ 991 if (ddi_prop_update_string(DDI_DEV_T_NONE, child, 992 "bus-addr", "0,0") != DDI_PROP_SUCCESS) { 993 FCOEI_LOG(__FUNCTION__, "update bus-addr failed"); 994 (void) ndi_devi_free(child); 995 return; 996 } 997 998 /* 999 * If it's physical HBA, fp.conf will register the property. 1000 * fcoei is one software HBA, so we need register it manually 1001 */ 1002 if (ddi_prop_update_int(DDI_DEV_T_NONE, child, 1003 "port", 0) != DDI_PROP_SUCCESS) { 1004 FCOEI_LOG(__FUNCTION__, "update port failed"); 1005 (void) ndi_devi_free(child); 1006 return; 1007 } 1008 1009 /* 1010 * It will call fp_attach eventually 1011 */ 1012 rval = ndi_devi_online(child, NDI_ONLINE_ATTACH); 1013 ss->ss_flags &= ~SS_FLAG_TRIGGER_FP_ATTACH; 1014 if (rval != NDI_SUCCESS) { 1015 FCOEI_LOG(__FUNCTION__, "devi_online: %d", rval); 1016 } else { 1017 FCOEI_LOG(__FUNCTION__, "triggered successfully"); 1018 } 1019 } 1020 1021 /* 1022 * fcoei_abts_exchange 1023 * Send ABTS to abort solicited exchange 1024 * 1025 * Input: 1026 * xch = the exchange that will be aborted 1027 * 1028 * Return: 1029 * N/A 1030 * 1031 * Comment: 1032 * ABTS frame uses the same oxid as the exchange 1033 */ 1034 static void 1035 fcoei_abts_exchange(fcoei_exchange_t *xch) 1036 { 1037 fc_packet_t *fpkt = xch->xch_fpkt; 1038 fcoe_frame_t *frm = NULL; 1039 1040 /* 1041 * BLS_ABTS doesn't contain any other payload except FCFH 1042 */ 1043 frm = xch->xch_ss->ss_eport->eport_alloc_frame(xch->xch_ss->ss_eport, 1044 FCFH_SIZE, NULL); 1045 if (frm == NULL) { 1046 FCOEI_LOG(__FUNCTION__, "can't alloc frame: %p", xch); 1047 return; 1048 } 1049 1050 FFM_R_CTL(0x81, frm); 1051 FFM_D_ID(fpkt->pkt_cmd_fhdr.d_id, frm); 1052 FFM_S_ID(fpkt->pkt_cmd_fhdr.s_id, frm); 1053 FFM_F_CTL(0x090000, frm); 1054 FFM_SEQ_ID(0x01, frm); 1055 FFM_OXID(xch->xch_oxid, frm); 1056 FFM_RXID(xch->xch_rxid, frm); 1057 fcoei_init_ifm(frm, xch); 1058 xch->xch_ss->ss_eport->eport_tx_frame(frm); 1059 } 1060 1061 /* 1062 * fcoei_complete_xch 1063 * Complete the exchange 1064 * 1065 * Input: 1066 * xch = the exchange that will be completed 1067 * frm = newly-allocated frame that has not been submitted 1068 * pkt_state = LV fpkt state 1069 * pkt_reason = LV fpkt reason 1070 * 1071 * Return: 1072 * N/A 1073 * 1074 * Comment: 1075 * N/A 1076 */ 1077 void 1078 fcoei_complete_xch(fcoei_exchange_t *xch, fcoe_frame_t *frm, 1079 uint8_t pkt_state, uint8_t pkt_reason) 1080 { 1081 mod_hash_val_t val; 1082 1083 if (pkt_state != FC_PKT_SUCCESS) { 1084 FCOEI_LOG(__FUNCTION__, "FHDR: %x/%x/%x, %x/%x/%x", 1085 xch->xch_fpkt->pkt_cmd_fhdr.r_ctl, 1086 xch->xch_fpkt->pkt_cmd_fhdr.f_ctl, 1087 xch->xch_fpkt->pkt_cmd_fhdr.type, 1088 xch->xch_fpkt->pkt_resp_fhdr.r_ctl, 1089 xch->xch_fpkt->pkt_resp_fhdr.f_ctl, 1090 xch->xch_fpkt->pkt_resp_fhdr.type); 1091 FCOEI_LOG(__FUNCTION__, "%p/%p/%x/%x", 1092 xch, frm, pkt_state, pkt_reason); 1093 } 1094 1095 if (frm != NULL) { 1096 /* 1097 * It's newly-allocated frame , which we haven't sent out 1098 */ 1099 xch->xch_ss->ss_eport->eport_free_netb(frm->frm_netb); 1100 xch->xch_ss->ss_eport->eport_release_frame(frm); 1101 FCOEI_LOG(__FUNCTION__, "xch: %p, not submitted", xch); 1102 } 1103 1104 /* 1105 * If xch is in hash table, we need remove it 1106 */ 1107 if (xch->xch_flags & XCH_FLAG_IN_SOL_HASH) { 1108 (void) mod_hash_remove(xch->xch_ss->ss_sol_oxid_hash, 1109 FMHK(xch->xch_oxid), &val); 1110 ASSERT((fcoei_exchange_t *)val == xch); 1111 xch->xch_flags &= ~XCH_FLAG_IN_SOL_HASH; 1112 } else if (xch->xch_flags & XCH_FLAG_IN_UNSOL_HASH) { 1113 (void) mod_hash_remove(xch->xch_ss->ss_unsol_rxid_hash, 1114 FMHK(xch->xch_rxid), &val); 1115 ASSERT((fcoei_exchange_t *)val == xch); 1116 xch->xch_flags &= ~XCH_FLAG_IN_UNSOL_HASH; 1117 } else { 1118 FCOEI_LOG(__FUNCTION__, "xch not in any hash: %p", xch); 1119 } 1120 1121 xch->xch_fpkt->pkt_state = pkt_state; 1122 xch->xch_fpkt->pkt_reason = pkt_reason; 1123 if (xch->xch_fpkt->pkt_tran_flags & FC_TRAN_NO_INTR) { 1124 FCOEI_LOG(__FUNCTION__, "polled xch is done: %p", xch); 1125 sema_v(&xch->xch_sema); 1126 } else { 1127 xch->xch_fpkt->pkt_comp(xch->xch_fpkt); 1128 } 1129 }