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