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 * The following notice accompanied the original version of this file: 24 * 25 * BSD LICENSE 26 * 27 * Copyright(c) 2007 Intel Corporation. All rights reserved. 28 * All rights reserved. 29 * 30 * Redistribution and use in source and binary forms, with or without 31 * modification, are permitted provided that the following conditions 32 * are met: 33 * 34 * * Redistributions of source code must retain the above copyright 35 * notice, this list of conditions and the following disclaimer. 36 * * Redistributions in binary form must reproduce the above copyright 37 * notice, this list of conditions and the following disclaimer in 38 * the documentation and/or other materials provided with the 39 * distribution. 40 * * Neither the name of Intel Corporation nor the names of its 41 * contributors may be used to endorse or promote products derived 42 * from this software without specific prior written permission. 43 * 44 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 45 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 46 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 47 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 48 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 49 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 50 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 51 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 52 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 53 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 54 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 55 */ 56 57 /* 58 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 59 */ 60 61 /* 62 * This file defines interface functions between fcoe and fcoei driver. 63 */ 64 65 #include <sys/conf.h> 66 #include <sys/ddi.h> 67 #include <sys/stat.h> 68 #include <sys/pci.h> 69 #include <sys/sunddi.h> 70 #include <sys/modctl.h> 71 #include <sys/file.h> 72 #include <sys/cred.h> 73 #include <sys/byteorder.h> 74 #include <sys/atomic.h> 75 #include <sys/scsi/scsi.h> 76 #include <sys/mac_client.h> 77 #include <sys/modhash.h> 78 79 /* 80 * LEADVILLE header files 81 */ 82 #include <sys/fibre-channel/fc.h> 83 #include <sys/fibre-channel/impl/fc_fcaif.h> 84 85 /* 86 * COMSTAR header files 87 */ 88 #include <sys/stmf_defines.h> 89 90 /* 91 * FCOE header files 92 */ 93 #include <sys/fcoe/fcoe_common.h> 94 95 /* 96 * Driver's own header files 97 */ 98 #include <fcoei.h> 99 100 /* 101 * Forward declaration of internal functions 102 */ 103 static void fcoei_process_unsol_els_req(fcoe_frame_t *frm); 104 static void fcoei_process_sol_els_rsp(fcoe_frame_t *frm); 105 static void fcoei_process_unsol_abts_req(fcoe_frame_t *frame); 106 static void fcoei_process_sol_abts_acc(fcoe_frame_t *frame); 107 static void fcoei_process_sol_abts_rjt(fcoe_frame_t *frame); 108 static void fcoei_process_sol_ct_rsp(fcoe_frame_t *frame); 109 static void fcoei_process_unsol_xfer_rdy(fcoe_frame_t *frame); 110 static void fcoei_process_sol_fcp_resp(fcoe_frame_t *frm); 111 112 static void fcoei_fill_fcp_resp(uint8_t *src, uint8_t *dest, int size); 113 static void fcoei_fill_els_fpkt_resp(fcoe_frame_t *frm, fcoei_exchange_t *xch, 114 int size); 115 116 /* 117 * fcoei_rx_frame 118 * Unsolicited frame is received 119 * 120 * Input: 121 * frame = unsolicited frame that is received 122 * 123 * Return: 124 * N/A 125 * 126 * Comment: 127 * N/A 128 */ 129 static void 130 fcoei_rx_frame(fcoe_frame_t *frm) 131 { 132 if (!(FRM2SS(frm)->ss_flags & SS_FLAG_LV_BOUND)) { 133 /* 134 * Release the frame and netb 135 */ 136 FCOEI_LOG(__FUNCTION__, "not bound now"); 137 frm->frm_eport->eport_free_netb(frm->frm_netb); 138 frm->frm_eport->eport_release_frame(frm); 139 return; 140 } 141 142 FRM2IFM(frm)->ifm_ae.ae_type = AE_EVENT_UNSOL_FRAME; 143 FRM2IFM(frm)->ifm_ae.ae_obj = frm; 144 145 mutex_enter(&FRM2SS(frm)->ss_watchdog_mutex); 146 list_insert_tail(&FRM2SS(frm)->ss_event_list, &FRM2IFM(frm)->ifm_ae); 147 if (FRM2SS(frm)->ss_flags & SS_FLAG_WATCHDOG_IDLE) { 148 cv_signal(&FRM2SS(frm)->ss_watchdog_cv); 149 } 150 mutex_exit(&FRM2SS(frm)->ss_watchdog_mutex); 151 } 152 153 /* 154 * fcoei_release_sol_frame 155 * Release the solicited frame that has just been sent out 156 * 157 * Input: 158 * frame = solicited frame that has been sent out 159 * 160 * Returns: 161 * N/A 162 * 163 * Comments: 164 * After FCOE sends solicited frames out, it will call this to notify 165 * FCOEI of the completion. 166 */ 167 static void 168 fcoei_release_sol_frame(fcoe_frame_t *frm) 169 { 170 /* 171 * For request-type frames, it's safe to be handled out of 172 * watchdog, because it needn't update anything 173 */ 174 switch (FRM2IFM(frm)->ifm_rctl) { 175 case R_CTL_SOLICITED_DATA: 176 case R_CTL_COMMAND: 177 case R_CTL_ELS_REQ: 178 case R_CTL_UNSOL_CONTROL: 179 case R_CTL_LS_ABTS: 180 FRM2SS(frm)->ss_eport->eport_release_frame(frm); 181 break; 182 183 default: 184 FRM2IFM(frm)->ifm_ae.ae_type = AE_EVENT_SOL_FRAME; 185 FRM2IFM(frm)->ifm_ae.ae_obj = frm; 186 187 mutex_enter(&FRM2SS(frm)->ss_watchdog_mutex); 188 list_insert_tail(&FRM2SS(frm)->ss_event_list, 189 &FRM2IFM(frm)->ifm_ae); 190 if (FRM2SS(frm)->ss_flags & SS_FLAG_WATCHDOG_IDLE) { 191 cv_signal(&FRM2SS(frm)->ss_watchdog_cv); 192 } 193 mutex_exit(&FRM2SS(frm)->ss_watchdog_mutex); 194 break; 195 } 196 } 197 198 /* 199 * fcoei_process_unsol_xfer_rdy 200 * XFER_RDY is received 201 * 202 * Input: 203 * frm = XFER_RDY frame 204 * 205 * Returns: 206 * N/A 207 * 208 * Comments: 209 * N/A 210 */ 211 static void 212 fcoei_process_unsol_xfer_rdy(fcoe_frame_t *frm) 213 { 214 uint16_t sol_oxid; 215 fcoei_exchange_t *xch; 216 int rcv_buf_size; 217 int offset; 218 int left_size; 219 int data_size; 220 int frm_num; 221 int idx; 222 fcoe_frame_t *nfrm; 223 224 sol_oxid = FRM_OXID(frm); 225 if (mod_hash_find(FRM2SS(frm)->ss_sol_oxid_hash, 226 FMHK(sol_oxid), (mod_hash_val_t *)&xch) != 0) { 227 return; 228 } 229 230 /* 231 * rcv_buf_size is the total size of data that should be transferred 232 * in this sequence. 233 * offset is based on the exchange not the sequence. 234 */ 235 xch->xch_rxid = FRM_RXID(frm); 236 rcv_buf_size = FCOE_B2V_4(frm->frm_payload + 4); 237 offset = FCOE_B2V_4(frm->frm_payload); 238 ASSERT(xch->xch_resid >= rcv_buf_size); 239 240 /* 241 * Local variables initialization 242 */ 243 left_size = rcv_buf_size; 244 data_size = FRM2SS(frm)->ss_fcp_data_payload_size; 245 frm_num = (rcv_buf_size + data_size - 1) / data_size; 246 247 for (idx = 0; idx < frm_num - 1; idx++) { 248 /* 249 * The first (frm_num -1) frames are always full 250 */ 251 nfrm = FRM2SS(frm)->ss_eport->eport_alloc_frame( 252 FRM2SS(frm)->ss_eport, data_size + FCFH_SIZE, NULL); 253 if (nfrm == NULL) { 254 FCOEI_LOG(__FUNCTION__, "can't alloc frame"); 255 return; 256 } 257 258 /* 259 * Copy the data payload that will be transferred 260 */ 261 bcopy(offset + (uint8_t *)xch->xch_fpkt->pkt_data, 262 nfrm->frm_payload, nfrm->frm_payload_size); 263 264 FFM_R_CTL(R_CTL_SOLICITED_DATA, nfrm); 265 FFM_TYPE(FC_TYPE_SCSI_FCP, nfrm); 266 FFM_F_CTL(0x010008, nfrm); 267 FFM_OXID(xch->xch_oxid, nfrm); 268 FFM_RXID(xch->xch_rxid, nfrm); 269 FFM_S_ID(FRM_D_ID(frm), nfrm); 270 FFM_D_ID(FRM_S_ID(frm), nfrm); 271 FFM_SEQ_CNT(idx, nfrm); 272 FFM_PARAM(offset, nfrm); 273 fcoei_init_ifm(nfrm, xch); 274 275 /* 276 * Submit the frame 277 */ 278 xch->xch_ss->ss_eport->eport_tx_frame(nfrm); 279 280 /* 281 * Update offset and left_size 282 */ 283 offset += data_size; 284 left_size -= data_size; 285 } 286 287 /* 288 * Send the last data frame of this sequence 289 */ 290 data_size = left_size; 291 nfrm = xch->xch_ss->ss_eport->eport_alloc_frame( 292 xch->xch_ss->ss_eport, data_size + FCFH_SIZE, NULL); 293 if (nfrm != NULL) { 294 fcoei_init_ifm(nfrm, xch); 295 } else { 296 ASSERT(0); 297 return; 298 } 299 300 /* 301 * Copy the data payload that will be transferred 302 */ 303 bcopy(offset + (uint8_t *)xch->xch_fpkt->pkt_data, 304 nfrm->frm_payload, nfrm->frm_payload_size); 305 306 /* 307 * Set ifm_rctl for fcoei_handle_sol_frame_done 308 */ 309 FRM2IFM(nfrm)->ifm_rctl = R_CTL_SOLICITED_DATA; 310 311 /* 312 * FFM 313 */ 314 FFM_R_CTL(R_CTL_SOLICITED_DATA, nfrm); 315 FFM_TYPE(FC_TYPE_SCSI_FCP, nfrm); 316 FFM_F_CTL(0x090008, nfrm); 317 FFM_OXID(xch->xch_oxid, nfrm); 318 FFM_RXID(xch->xch_rxid, nfrm); 319 FFM_S_ID(FRM_D_ID(frm), nfrm); 320 FFM_D_ID(FRM_S_ID(frm), nfrm); 321 FFM_SEQ_CNT(idx, nfrm); 322 FFM_PARAM(offset, nfrm); 323 324 /* 325 * Submit the frame 326 */ 327 xch->xch_ss->ss_eport->eport_tx_frame(nfrm); 328 329 /* 330 * Sequence is a transaction, so we need only update 331 * xch_remained_bytes in the end. 332 */ 333 xch->xch_resid -= rcv_buf_size; 334 } 335 336 /* 337 * fcoei_process_unsol_els_req 338 * els req frame is received 339 * 340 * Input: 341 * frm = ELS request frame 342 * 343 * Returns: 344 * N/A 345 * 346 * Comments: 347 * We will not create exchange data structure at this time, 348 * and we should create unsolicited buffer, which will only 349 * contain the exchange's request payload. 350 */ 351 static void 352 fcoei_process_unsol_els_req(fcoe_frame_t *frm) 353 { 354 fc_unsol_buf_t *ub; 355 fc_rscn_t *rscn; 356 uint32_t offset; 357 fcoei_exchange_t *xch_tmp; 358 359 /* 360 * Get the unsol rxid first 361 */ 362 FCOEI_SET_UNSOL_FRM_RXID(frm, xch_tmp); 363 364 /* 365 * Do proper ub initialization 366 */ 367 ub = (fc_unsol_buf_t *)kmem_zalloc(sizeof (fc_unsol_buf_t), KM_SLEEP); 368 ub->ub_class = FC_TRAN_CLASS3; 369 ub->ub_bufsize = frm->frm_payload_size; 370 ub->ub_buffer = kmem_alloc(frm->frm_payload_size, KM_SLEEP); 371 ub->ub_port_handle = FRM2SS(frm); 372 ub->ub_token = (uint64_t)(long)ub; 373 374 /* 375 * header conversion 376 * Caution: ub_buffer is big endian, but ub_frame should be host-format 377 * RSCN is one exception. 378 */ 379 FCOEI_FRM2FHDR(frm, &ub->ub_frame); 380 381 /* 382 * If it's FLOGI, and our FLOGI failed last time, 383 * then we post online event 384 */ 385 if ((FRM2SS(frm)->ss_flags & SS_FLAG_FLOGI_FAILED) && 386 (frm->frm_payload[0] == LA_ELS_FLOGI)) { 387 frm->frm_eport->eport_flags |= 388 EPORT_FLAG_IS_DIRECT_P2P; 389 FRM2SS(frm)->ss_bind_info.port_statec_cb(FRM2SS(frm)->ss_port, 390 FC_STATE_ONLINE); 391 } 392 393 switch (frm->frm_payload[0]) { 394 case LA_ELS_RSCN: 395 /* 396 * Only RSCN need byte swapping 397 */ 398 rscn = (fc_rscn_t *)(void *)ub->ub_buffer; 399 rscn->rscn_code = frm->frm_payload[0]; 400 rscn->rscn_len = frm->frm_payload[1]; 401 rscn->rscn_payload_len = 402 FCOE_B2V_2(frm->frm_payload + 2); 403 404 offset = 4; 405 for (int i = 0; i < rscn->rscn_payload_len - 4; i += 4) { 406 *(uint32_t *)((intptr_t)(uint8_t *)ub->ub_buffer + 407 offset) = FCOE_B2V_4(frm->frm_payload + offset); 408 offset += 4; 409 } 410 break; 411 412 default: 413 bcopy(frm->frm_payload, ub->ub_buffer, frm->frm_payload_size); 414 break; 415 } 416 417 /* 418 * Pass this unsol ELS up to Leadville 419 */ 420 FRM2SS(frm)->ss_bind_info.port_unsol_cb(FRM2SS(frm)->ss_port, ub, 0); 421 } 422 423 /* 424 * fcoei_search_abort_xch 425 * Find the exchange that should be aborted 426 * 427 * Input: 428 * key = oxid of the exchange 429 * val = the exchange 430 * arg = the soft state 431 * 432 * Returns: 433 * MH_WALK_TERMINATE = found it, terminate the walk 434 * MH_WALK_CONTINUE = not found, continue the walk 435 * 436 * Comments: 437 * N/A 438 */ 439 /* ARGSUSED */ 440 static uint32_t 441 fcoei_search_abort_xch(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 442 { 443 fcoei_walk_arg_t *wa = (fcoei_walk_arg_t *)arg; 444 fcoei_exchange_t *xch = (fcoei_exchange_t *)val; 445 446 if (xch->xch_oxid == wa->wa_oxid) { 447 wa->wa_xch = xch; 448 ASSERT(xch->xch_oxid == CMHK(key)); 449 return (MH_WALK_TERMINATE); 450 } 451 452 return (MH_WALK_CONTINUE); 453 } 454 455 /* 456 * fcoei_process_unsol_abts_req 457 * ABTS request is received 458 * 459 * Input: 460 * frm = ABTS request frame 461 * 462 * Returns: 463 * N/A 464 * 465 * Comments: 466 * The remote side wants to abort one unsolicited exchange. 467 */ 468 static void 469 fcoei_process_unsol_abts_req(fcoe_frame_t *frm) 470 { 471 fcoei_exchange_t *xch = NULL; 472 fcoe_frame_t *nfrm; 473 int payload_size; 474 fcoei_walk_arg_t walk_arg; 475 476 /* 477 * According to spec, the responder could want to ABTS xch too 478 */ 479 if (FRM_SENDER_IS_XCH_RESPONDER(frm)) { 480 uint16_t sol_oxid = FRM_OXID(frm); 481 (void) mod_hash_find(FRM2SS(frm)->ss_sol_oxid_hash, 482 FMHK(sol_oxid), (mod_hash_val_t *)&xch); 483 } else { 484 /* 485 * it's a unsolicited exchange, and we need find it out from 486 * unsolicited hash table. But at this time, RXID in frame could 487 * still be 0xFFFF in most cases, so we need do exaustive search 488 */ 489 walk_arg.wa_xch = NULL; 490 walk_arg.wa_oxid = FRM_OXID(frm); 491 mod_hash_walk(FRM2SS(frm)->ss_unsol_rxid_hash, 492 fcoei_search_abort_xch, &walk_arg); 493 xch = walk_arg.wa_xch; 494 } 495 496 if (xch == NULL) { 497 payload_size = 4; 498 nfrm = FRM2SS(frm)->ss_eport->eport_alloc_frame( 499 FRM2SS(frm)->ss_eport, 500 payload_size + FCFH_SIZE, NULL); 501 if (nfrm == NULL) { 502 FCOEI_LOG(__FUNCTION__, "can't alloc frame"); 503 return; 504 } 505 506 bzero(nfrm->frm_payload, nfrm->frm_payload_size); 507 nfrm->frm_payload[1] = 0x05; 508 nfrm->frm_payload[3] = 0xAA; 509 FFM_R_CTL(R_CTL_LS_BA_RJT, nfrm); 510 fcoei_init_ifm(nfrm, xch); 511 } else { 512 /* 513 * We should complete the exchange with frm as NULL, 514 * and we don't care its success or failure 515 */ 516 fcoei_complete_xch(xch, NULL, FC_PKT_FAILURE, FC_REASON_ABTX); 517 518 /* 519 * Construct ABTS ACC frame 520 */ 521 payload_size = 12; 522 nfrm = FRM2SS(frm)->ss_eport->eport_alloc_frame( 523 FRM2SS(frm)->ss_eport, payload_size + FCFH_SIZE, NULL); 524 if (nfrm == NULL) { 525 FCOEI_LOG(__FUNCTION__, "can't alloc frame"); 526 return; 527 } 528 529 bzero(nfrm->frm_payload, nfrm->frm_payload_size); 530 nfrm->frm_payload[4] = 0xFF & (xch->xch_oxid >> 8); 531 nfrm->frm_payload[5] = 0xFF & (xch->xch_oxid); 532 nfrm->frm_payload[6] = 0xFF & (xch->xch_rxid >> 8); 533 nfrm->frm_payload[7] = 0xFF & (xch->xch_rxid); 534 nfrm->frm_payload[10] = 0xFF; 535 nfrm->frm_payload[11] = 0xFF; 536 537 FFM_R_CTL(R_CTL_LS_BA_ACC, nfrm); 538 fcoei_init_ifm(nfrm, xch); 539 } 540 541 FFM_D_ID(FRM_S_ID(frm), nfrm); 542 FFM_S_ID(FRM_D_ID(frm), nfrm); 543 FFM_TYPE(FRM_TYPE(frm), nfrm); 544 FFM_F_CTL(FRM_F_CTL(frm), nfrm); 545 FFM_OXID(FRM_OXID(frm), nfrm); 546 FFM_RXID(FRM_RXID(frm), nfrm); 547 FRM2SS(frm)->ss_eport->eport_tx_frame(nfrm); 548 } 549 550 /* 551 * fcoei_process_sol_fcp_resp 552 * FCP response is received 553 * 554 * Input: 555 * frm = FCP response frame 556 * 557 * Returns: 558 * N/A 559 * 560 * Comments: 561 * N/A 562 */ 563 static void 564 fcoei_process_sol_fcp_resp(fcoe_frame_t *frm) 565 { 566 uint16_t sol_oxid; 567 uint32_t actual_size; 568 fcoei_exchange_t *xch = NULL; 569 fc_packet_t *fpkt = NULL; 570 mod_hash_val_t val; 571 uint32_t i_fcp_status; 572 573 /* 574 * Firstly, we search the related exchange 575 */ 576 sol_oxid = FRM_OXID(frm); 577 if (mod_hash_find(FRM2SS(frm)->ss_sol_oxid_hash, 578 FMHK(sol_oxid), (mod_hash_val_t *)&xch) != 0) { 579 PRT_FRM_HDR(__FUNCTION__, frm); 580 FCOEI_LOG(__FUNCTION__, "can't find the corresponding xch: " 581 "oxid/%x %lu - %lu", sol_oxid, 582 CURRENT_CLOCK, frm->frm_clock); 583 return; 584 } else { 585 fpkt = xch->xch_fpkt; 586 } 587 588 /* 589 * Decide the actual response length 590 */ 591 actual_size = fpkt->pkt_rsplen; 592 if (actual_size > frm->frm_payload_size) { 593 actual_size = frm->frm_payload_size; 594 } 595 596 /* 597 * Update the exchange and hash table 598 */ 599 (void) mod_hash_remove(FRM2SS(frm)->ss_sol_oxid_hash, 600 FMHK(xch->xch_oxid), &val); 601 ASSERT((fcoei_exchange_t *)val == xch); 602 xch->xch_flags &= ~XCH_FLAG_IN_SOL_HASH; 603 604 /* 605 * Upate fpkt related elements 606 */ 607 FCOEI_FRM2FHDR(frm, &fpkt->pkt_resp_fhdr); 608 609 /* 610 * we should set pkt_reason and pkt_state carefully 611 */ 612 fpkt->pkt_state = FC_PKT_SUCCESS; 613 fpkt->pkt_reason = 0; 614 615 /* 616 * First we zero the first 12 byte of dest 617 */ 618 bzero(xch->xch_fpkt->pkt_resp, 12); 619 i_fcp_status = BE_IN32(frm->frm_payload + 8); 620 if (i_fcp_status != 0) { 621 fcoei_fill_fcp_resp(frm->frm_payload, 622 (uint8_t *)xch->xch_fpkt->pkt_resp, actual_size); 623 } 624 625 /* 626 * Update pkt_resp_resid 627 */ 628 fpkt->pkt_data_resid = xch->xch_resid; 629 if ((xch->xch_resid != 0) && ((xch->xch_resid % 0x200) == 0) && 630 ((xch->xch_fpkt->pkt_datalen % 0x200) == 0) && 631 (i_fcp_status == 0)) { 632 FCOEI_LOG(__FUNCTION__, "frame lost no pause ? %x/%x", 633 xch->xch_resid, xch->xch_fpkt->pkt_datalen); 634 fpkt->pkt_state = FC_PKT_LOCAL_RJT; 635 fpkt->pkt_reason = FC_REASON_UNDERRUN; 636 } 637 638 /* 639 * Notify LV it's over 640 */ 641 if (fpkt->pkt_tran_flags & FC_TRAN_NO_INTR) { 642 FCOEI_LOG(__FUNCTION__, "BEFORE WAKEUP: %p-%p", fpkt, xch); 643 sema_v(&xch->xch_sema); 644 FCOEI_LOG(__FUNCTION__, "AFTERE WAKEUP: %p-%p", fpkt, xch); 645 } else { 646 xch->xch_fpkt->pkt_comp(xch->xch_fpkt); 647 } 648 } 649 650 /* 651 * fcoei_process_sol_els_rsp 652 * ELS response is received 653 * 654 * Input: 655 * frm = ELS response frame 656 * 657 * Returns: 658 * N/A 659 * 660 * Comments: 661 * N/A 662 */ 663 static void 664 fcoei_process_sol_els_rsp(fcoe_frame_t *frm) 665 { 666 uint16_t sol_oxid = 0; 667 uint32_t actual_size = 0; 668 fcoei_exchange_t *xch; 669 fc_packet_t *fpkt; 670 671 /* 672 * Look for the related exchange 673 */ 674 xch = NULL; 675 fpkt = NULL; 676 sol_oxid = FRM_OXID(frm); 677 if (mod_hash_find(FRM2SS(frm)->ss_sol_oxid_hash, 678 FMHK(sol_oxid), (mod_hash_val_t *)&xch) != 0) { 679 PRT_FRM_HDR(__FUNCTION__, frm); 680 FCOEI_LOG(__FUNCTION__, "can't find the " 681 "corresponding xch: oxid/%x", sol_oxid); 682 return; 683 } 684 685 xch->xch_rxid = FRM_RXID(frm); 686 fpkt = xch->xch_fpkt; 687 688 /* 689 * Decide the actual response length 690 */ 691 actual_size = frm->frm_payload_size; 692 if (actual_size > fpkt->pkt_rsplen) { 693 FCOEI_LOG(__FUNCTION__, "pkt_rsplen is smaller" 694 "0x(%x - %x)", actual_size, fpkt->pkt_rsplen); 695 actual_size = fpkt->pkt_rsplen; 696 } 697 698 /* 699 * Upate fpkt related elements 700 */ 701 FCOEI_FRM2FHDR(frm, &fpkt->pkt_resp_fhdr); 702 fcoei_fill_els_fpkt_resp(frm, xch, actual_size); 703 704 /* 705 * we should set pkt_reason and pkt_state carefully now 706 * Need to analyze pkt_reason according to the response. 707 * Leave it untouched now. 708 */ 709 if (((ls_code_t *)(void *)xch->xch_fpkt->pkt_resp)->ls_code == 710 LA_ELS_RJT) { 711 fcoei_complete_xch(xch, NULL, FC_PKT_FABRIC_RJT, 712 FC_REASON_INVALID_PARAM); 713 } else { 714 fcoei_complete_xch(xch, NULL, FC_PKT_SUCCESS, 0); 715 } 716 } 717 718 /* 719 * fcoei_process_sol_ct_rsp 720 * CT response is received 721 * 722 * Input: 723 * frm = CT response frame 724 * 725 * Returns: 726 * N/A 727 * 728 * Comments: 729 * N/A 730 */ 731 static void 732 fcoei_process_sol_ct_rsp(fcoe_frame_t *frm) 733 { 734 uint16_t sol_oxid = 0; 735 uint32_t actual_size = 0; 736 fcoei_exchange_t *xch; 737 fc_packet_t *fpkt; 738 739 /* 740 * Look for the related exchange 741 */ 742 xch = NULL; 743 fpkt = NULL; 744 sol_oxid = FRM_OXID(frm); 745 if (mod_hash_find(FRM2SS(frm)->ss_sol_oxid_hash, 746 FMHK(sol_oxid), (mod_hash_val_t *)&xch) != 0) { 747 FCOEI_LOG(__FUNCTION__, "can't find the " 748 "corresponding xch: oxid/%x", sol_oxid); 749 return; 750 } 751 752 xch->xch_rxid = FRM_RXID(frm); 753 fpkt = xch->xch_fpkt; 754 755 /* 756 * Decide the actual response length 757 */ 758 actual_size = fpkt->pkt_rsplen; 759 if (actual_size > frm->frm_payload_size) { 760 FCOEI_LOG(__FUNCTION__, "payload is smaller" 761 "0x(%x - %x)", actual_size, frm->frm_payload_size); 762 actual_size = frm->frm_payload_size; 763 } 764 765 /* 766 * Update fpkt related elements 767 * Caution: we needn't do byte swapping for CT response 768 */ 769 FCOEI_FRM2FHDR(frm, &fpkt->pkt_resp_fhdr); 770 bcopy(FPLD, (uint8_t *)xch->xch_fpkt->pkt_resp, actual_size); 771 772 /* 773 * Complete it with frm as NULL 774 */ 775 fcoei_complete_xch(xch, NULL, FC_PKT_SUCCESS, 0); 776 } 777 778 /* 779 * fcoei_process_sol_abts_acc 780 * ABTS accpet is received 781 * 782 * Input: 783 * frm = ABTS accept frame 784 * 785 * Returns: 786 * N/A 787 * 788 * Comments: 789 * We will always finish the abortion of solicited exchanges, 790 * so we will not depend on the response from the remote side. 791 * We just log one message. 792 */ 793 static void 794 fcoei_process_sol_abts_acc(fcoe_frame_t *frm) 795 { 796 FCOEI_LOG(__FUNCTION__, "the remote side has agreed to " 797 "abort the exchange: oxid-%x, rxid-%x", 798 FCOE_B2V_2(frm->frm_payload + 4), 799 FCOE_B2V_2(frm->frm_payload + 6)); 800 } 801 802 /* 803 * fcoei_process_sol_abts_rjt 804 * ABTS reject is received 805 * 806 * Input: 807 * frm = ABTS reject frame 808 * 809 * Returns: 810 * N/A 811 * 812 * Comments: 813 * We will alwayas finish the abortion of solicited exchanges, 814 * so we will not depend on the response from the remote side. 815 * We just log one message. 816 */ 817 static void 818 fcoei_process_sol_abts_rjt(fcoe_frame_t *frm) 819 { 820 FCOEI_LOG(__FUNCTION__, "the remote side rejected " 821 "our request to abort one exchange.: %p", frm); 822 } 823 824 /* 825 * fcoei_fill_els_fpkt_resp 826 * Fill fpkt ELS response in host format according frm payload 827 * 828 * Input: 829 * src = frm payload in link format 830 * dest = fpkt ELS response in host format 831 * size = Maximum conversion size 832 * els_op = ELS opcode 833 * 834 * Returns: 835 * N/A 836 * 837 * Comments: 838 * fpkt->pkt_resp must be mapped to one data structure, and it's 839 * different from the content in the raw frame 840 */ 841 static void 842 fcoei_fill_els_fpkt_resp(fcoe_frame_t *frm, fcoei_exchange_t *xch, int size) 843 { 844 uint8_t *src = frm->frm_payload; 845 uint8_t *dest = (uint8_t *)xch->xch_fpkt->pkt_resp; 846 ls_code_t *els_code = (ls_code_t *)(void *)dest; 847 la_els_logi_t *els_logi = (la_els_logi_t *)(void *)dest; 848 la_els_adisc_t *els_adisc = (la_els_adisc_t *)(void *)dest; 849 la_els_rls_acc_t *els_rls; 850 la_els_rnid_acc_t *els_rnid; 851 struct fcp_prli_acc *prli_acc; 852 int offset; 853 854 els_code->ls_code = FCOE_B2V_1(src); 855 if (els_code->ls_code == LA_ELS_RJT) { 856 FCOEI_LOG(__FUNCTION__, "size :%d", size); 857 return; 858 } 859 860 switch (((ls_code_t *)(void *)xch->xch_fpkt->pkt_cmd)->ls_code) { 861 case LA_ELS_FLOGI: 862 bcopy((char *)frm->frm_hdr - 22, 863 frm->frm_eport->eport_efh_dst, ETHERADDRL); 864 if (frm->frm_payload[8] & 0x10) { 865 /* 866 * We are in fabric p2p mode 867 */ 868 uint8_t src_addr[ETHERADDRL]; 869 frm->frm_eport->eport_flags &= 870 ~EPORT_FLAG_IS_DIRECT_P2P; 871 FCOE_SET_DEFAULT_OUI(src_addr); 872 bcopy(frm->frm_hdr->hdr_d_id, src_addr + 3, 3); 873 frm->frm_eport->eport_set_mac_address( 874 frm->frm_eport, src_addr, 1); 875 } else { 876 /* 877 * We are in direct p2p mode 878 */ 879 frm->frm_eport->eport_flags |= 880 EPORT_FLAG_IS_DIRECT_P2P; 881 } 882 883 if (!(FRM2SS(frm)->ss_eport->eport_flags & 884 EPORT_FLAG_IS_DIRECT_P2P)) { 885 FRM2SS(frm)->ss_p2p_info.fca_d_id = FRM_D_ID(frm); 886 } 887 888 /* FALLTHROUGH */ 889 890 case LA_ELS_PLOGI: 891 if (FRM2SS(frm)->ss_eport->eport_flags & 892 EPORT_FLAG_IS_DIRECT_P2P) { 893 FRM2SS(frm)->ss_p2p_info.fca_d_id = FRM_D_ID(frm); 894 FRM2SS(frm)->ss_p2p_info.d_id = FRM_S_ID(frm); 895 } 896 897 offset = offsetof(la_els_logi_t, common_service); 898 els_logi->common_service.fcph_version = FCOE_B2V_2(src + 899 offset); 900 offset += 2; 901 els_logi->common_service.btob_credit = FCOE_B2V_2(src + 902 offset); 903 offset += 2; 904 els_logi->common_service.cmn_features = FCOE_B2V_2(src + 905 offset); 906 offset += 2; 907 els_logi->common_service.rx_bufsize = FCOE_B2V_2(src + 908 offset); 909 offset += 2; 910 els_logi->common_service.conc_sequences = FCOE_B2V_2(src + 911 offset); 912 offset += 2; 913 els_logi->common_service.relative_offset = FCOE_B2V_2(src + 914 offset); 915 offset += 2; 916 els_logi->common_service.e_d_tov = FCOE_B2V_4(src + 917 offset); 918 919 /* 920 * port/node WWN 921 */ 922 offset = offsetof(la_els_logi_t, nport_ww_name); 923 bcopy(src + offset, &els_logi->nport_ww_name, 8); 924 offset = offsetof(la_els_logi_t, node_ww_name); 925 bcopy(src + offset, &els_logi->node_ww_name, 8); 926 927 /* 928 * class_3 929 */ 930 offset = offsetof(la_els_logi_t, class_3); 931 els_logi->class_3.class_opt = FCOE_B2V_2(src + offset); 932 offset += 2; 933 els_logi->class_3.initiator_ctl = FCOE_B2V_2(src + offset); 934 offset += 2; 935 els_logi->class_3.recipient_ctl = FCOE_B2V_2(src + offset); 936 offset += 2; 937 els_logi->class_3.rcv_size = FCOE_B2V_2(src + offset); 938 offset += 2; 939 els_logi->class_3.conc_sequences = FCOE_B2V_2(src + offset); 940 offset += 2; 941 els_logi->class_3.n_port_e_to_e_credit = FCOE_B2V_2(src + 942 offset); 943 offset += 2; 944 els_logi->class_3.open_seq_per_xchng = FCOE_B2V_2(src + offset); 945 946 break; 947 948 case LA_ELS_PRLI: 949 /* 950 * PRLI service parameter response page 951 * 952 * fcp_prli_acc doesn't include ls_code, don't use offsetof 953 */ 954 offset = 4; 955 prli_acc = (struct fcp_prli_acc *)(void *)(dest + offset); 956 prli_acc->type = FCOE_B2V_1(src + offset); 957 /* 958 * Type code extension 959 */ 960 offset += 1; 961 /* 962 * PRLI response flags 963 */ 964 offset += 1; 965 prli_acc->orig_process_assoc_valid = 966 (FCOE_B2V_2(src + offset) & BIT_15) ? 1 : 0; 967 prli_acc->resp_process_assoc_valid = 968 (FCOE_B2V_2(src + offset) & BIT_14) ? 1 : 0; 969 prli_acc->image_pair_established = 970 (FCOE_B2V_2(src + offset) & BIT_13) ? 1 : 0; 971 prli_acc->accept_response_code = 972 (FCOE_B2V_2(src + offset) & 0x0F00) >> 8; 973 /* 974 * process associator 975 */ 976 offset += 2; 977 prli_acc->orig_process_associator = FCOE_B2V_4(src + offset); 978 offset += 4; 979 prli_acc->resp_process_associator = FCOE_B2V_4(src + offset); 980 /* 981 * FC-4 type 982 */ 983 offset += 4; 984 prli_acc->initiator_fn = 985 (FCOE_B2V_4(src + offset) & BIT_5) ? 1 : 0; 986 prli_acc->target_fn = 987 (FCOE_B2V_4(src + offset) & BIT_4) ? 1 : 0; 988 prli_acc->cmd_data_mixed = 989 (FCOE_B2V_4(src + offset) & BIT_3) ? 1 : 0; 990 prli_acc->data_resp_mixed = 991 (FCOE_B2V_4(src + offset) & BIT_2) ? 1 : 0; 992 prli_acc->read_xfer_rdy_disabled = 993 (FCOE_B2V_4(src + offset) & BIT_1) ? 1 : 0; 994 prli_acc->write_xfer_rdy_disabled = 995 (FCOE_B2V_4(src + offset) & BIT_0) ? 1 : 0; 996 997 break; 998 999 case LA_ELS_LOGO: 1000 /* 1001 * could only be LS_ACC, no additional information 1002 */ 1003 els_code->ls_code = FCOE_B2V_1(src); 1004 break; 1005 1006 case LA_ELS_SCR: 1007 /* 1008 * LS_ACC/LS_RJT, no additional information 1009 */ 1010 els_code->ls_code = FCOE_B2V_1(src); 1011 break; 1012 1013 case LA_ELS_ADISC: 1014 offset = 5; 1015 els_adisc->hard_addr.hard_addr = FCOE_B2V_3(src + offset); 1016 offset = offsetof(la_els_adisc_t, port_wwn); 1017 bcopy(src + offset, &els_adisc->port_wwn, 8); 1018 offset = offsetof(la_els_adisc_t, node_wwn); 1019 bcopy(src + offset, &els_adisc->node_wwn, 8); 1020 offset += 9; 1021 els_adisc->nport_id.port_id = FCOE_B2V_3(src + offset); 1022 break; 1023 case LA_ELS_RLS: 1024 els_rls = (la_els_rls_acc_t *)(void *)dest; 1025 els_rls->ls_code.ls_code = FCOE_B2V_1(src); 1026 offset = 4; 1027 els_rls->rls_link_params.rls_link_fail = 1028 FCOE_B2V_4(src + offset); 1029 offset = 8; 1030 els_rls->rls_link_params.rls_sync_loss = 1031 FCOE_B2V_4(src + offset); 1032 offset = 12; 1033 els_rls->rls_link_params.rls_sig_loss = 1034 FCOE_B2V_4(src + offset); 1035 offset = 16; 1036 els_rls->rls_link_params.rls_prim_seq_err = 1037 FCOE_B2V_4(src + offset); 1038 offset = 20; 1039 els_rls->rls_link_params.rls_invalid_word = 1040 FCOE_B2V_4(src + offset); 1041 offset = 24; 1042 els_rls->rls_link_params.rls_invalid_crc = 1043 FCOE_B2V_4(src + offset); 1044 break; 1045 case LA_ELS_RNID: 1046 els_rnid = (la_els_rnid_acc_t *)(void *)dest; 1047 els_rnid->ls_code.ls_code = FCOE_B2V_1(src); 1048 offset = 4; 1049 bcopy(src + offset, &els_rnid->hdr.data_format, 1); 1050 offset = 5; 1051 bcopy(src + offset, &els_rnid->hdr.cmn_len, 1); 1052 offset = 7; 1053 bcopy(src + offset, &els_rnid->hdr.specific_len, 1); 1054 offset = 8; 1055 bcopy(src + offset, els_rnid->data, FCIO_RNID_MAX_DATA_LEN); 1056 break; 1057 default: 1058 FCOEI_LOG(__FUNCTION__, "unsupported R_CTL"); 1059 break; 1060 } 1061 } 1062 1063 /* 1064 * fcoei_fill_fcp_resp 1065 * Fill fpkt FCP response in host format according to frm payload 1066 * 1067 * Input: 1068 * src - frm payload in link format 1069 * dest - fpkt FCP response in host format 1070 * size - Maximum conversion size 1071 * 1072 * Returns: 1073 * N/A 1074 * 1075 * Comments: 1076 * This is called only for SCSI response with non good status 1077 */ 1078 static void 1079 fcoei_fill_fcp_resp(uint8_t *src, uint8_t *dest, int size) 1080 { 1081 fcp_rsp_t *fcp_rsp_iu = (fcp_rsp_t *)(void *)dest; 1082 int offset; 1083 1084 /* 1085 * set fcp_status 1086 */ 1087 offset = offsetof(fcp_rsp_t, fcp_u); 1088 offset += 2; 1089 fcp_rsp_iu->fcp_u.fcp_status.resid_under = 1090 (FCOE_B2V_1(src + offset) & BIT_3) ? 1 : 0; 1091 fcp_rsp_iu->fcp_u.fcp_status.resid_over = 1092 (FCOE_B2V_1(src + offset) & BIT_2) ? 1 : 0; 1093 fcp_rsp_iu->fcp_u.fcp_status.sense_len_set = 1094 (FCOE_B2V_1(src + offset) & BIT_1) ? 1 : 0; 1095 fcp_rsp_iu->fcp_u.fcp_status.rsp_len_set = 1096 (FCOE_B2V_1(src + offset) & BIT_0) ? 1 : 0; 1097 offset += 1; 1098 fcp_rsp_iu->fcp_u.fcp_status.scsi_status = FCOE_B2V_1(src + offset); 1099 /* 1100 * fcp_resid/fcp_sense_len/fcp_response_len 1101 */ 1102 offset = offsetof(fcp_rsp_t, fcp_resid); 1103 fcp_rsp_iu->fcp_resid = FCOE_B2V_4(src + offset); 1104 offset = offsetof(fcp_rsp_t, fcp_sense_len); 1105 fcp_rsp_iu->fcp_sense_len = FCOE_B2V_4(src + offset); 1106 offset = offsetof(fcp_rsp_t, fcp_response_len); 1107 fcp_rsp_iu->fcp_response_len = FCOE_B2V_4(src + offset); 1108 /* 1109 * sense or response 1110 */ 1111 offset += 4; 1112 if (fcp_rsp_iu->fcp_sense_len) { 1113 if ((offset + fcp_rsp_iu->fcp_sense_len) > size) { 1114 FCOEI_LOG(__FUNCTION__, "buffer too small - sens"); 1115 return; 1116 } 1117 bcopy(src + offset, dest + offset, fcp_rsp_iu->fcp_sense_len); 1118 offset += fcp_rsp_iu->fcp_sense_len; 1119 } 1120 1121 if (fcp_rsp_iu->fcp_response_len) { 1122 if ((offset + fcp_rsp_iu->fcp_response_len) > size) { 1123 FCOEI_LOG(__FUNCTION__, "buffer too small - resp"); 1124 return; 1125 } 1126 bcopy(src + offset, dest + offset, 1127 fcp_rsp_iu->fcp_response_len); 1128 } 1129 } 1130 1131 void 1132 fcoei_init_ect_vectors(fcoe_client_t *ect) 1133 { 1134 ect->ect_rx_frame = fcoei_rx_frame; 1135 ect->ect_port_event = fcoei_port_event; 1136 ect->ect_release_sol_frame = fcoei_release_sol_frame; 1137 } 1138 1139 /* 1140 * fcoei_process_unsol_frame 1141 * Unsolicited frame is received 1142 * 1143 * Input: 1144 * frame = unsolicited frame that is received 1145 * 1146 * Returns: 1147 * N/A 1148 * 1149 * Comments: 1150 * watchdog will call this to process unsolicited frames that we 1151 * just received fcoei_process_xx is used to handle different 1152 * unsolicited frames 1153 */ 1154 void 1155 fcoei_process_unsol_frame(fcoe_frame_t *frm) 1156 { 1157 fcoei_exchange_t *xch; 1158 uint16_t sol_oxid; 1159 1160 switch (FRM_R_CTL(frm)) { 1161 case R_CTL_SOLICITED_DATA: 1162 /* 1163 * READ data phase frame 1164 * Find the associated exchange 1165 */ 1166 sol_oxid = FRM_OXID(frm); 1167 if (mod_hash_find(FRM2SS(frm)->ss_sol_oxid_hash, 1168 FMHK(sol_oxid), (mod_hash_val_t *)&xch) != 0) { 1169 PRT_FRM_HDR(__FUNCTION__, frm); 1170 FCOEI_LOG(__FUNCTION__, "associated xch not found: " 1171 "oxid/%x %lu - %lu", sol_oxid, 1172 CURRENT_CLOCK, frm->frm_clock); 1173 break; 1174 } 1175 1176 /* 1177 * Copy data into fpkt data buffer, and update the counter 1178 */ 1179 bcopy(frm->frm_payload, (uint8_t *)xch->xch_fpkt->pkt_data + 1180 FRM_PARAM(frm), frm->frm_payload_size); 1181 xch->xch_resid -= frm->frm_payload_size; 1182 xch->xch_rxid = FRM_RXID(frm); 1183 break; 1184 1185 case R_CTL_XFER_RDY: 1186 fcoei_process_unsol_xfer_rdy(frm); 1187 break; 1188 1189 case R_CTL_STATUS: 1190 fcoei_process_sol_fcp_resp(frm); 1191 break; 1192 1193 case R_CTL_ELS_REQ: 1194 fcoei_process_unsol_els_req(frm); 1195 break; 1196 1197 case R_CTL_LS_ABTS: 1198 fcoei_process_unsol_abts_req(frm); 1199 break; 1200 1201 case R_CTL_ELS_RSP: 1202 fcoei_process_sol_els_rsp(frm); 1203 break; 1204 1205 case R_CTL_SOLICITED_CONTROL: 1206 fcoei_process_sol_ct_rsp(frm); 1207 break; 1208 1209 case R_CTL_LS_BA_ACC: 1210 fcoei_process_sol_abts_acc(frm); 1211 break; 1212 1213 case R_CTL_LS_BA_RJT: 1214 fcoei_process_sol_abts_rjt(frm); 1215 break; 1216 1217 default: 1218 /* 1219 * Unsupported frame 1220 */ 1221 PRT_FRM_HDR("Unsupported unsol frame: ", frm); 1222 } 1223 1224 /* 1225 * Release the frame and netb 1226 */ 1227 frm->frm_eport->eport_free_netb(frm->frm_netb); 1228 frm->frm_eport->eport_release_frame(frm); 1229 } 1230 1231 /* 1232 * fcoei_handle_sol_frame_done 1233 * solicited frame is just sent out 1234 * 1235 * Input: 1236 * frame = solicited frame that has been sent out 1237 * 1238 * Returns: 1239 * N/A 1240 * 1241 * Comments: 1242 * watchdog will call this to handle solicited frames that FCOEI 1243 * has sent out Non-request frame post handling 1244 */ 1245 void 1246 fcoei_handle_sol_frame_done(fcoe_frame_t *frm) 1247 { 1248 /* 1249 * the corresponding xch could be NULL at this time 1250 */ 1251 fcoei_exchange_t *xch = FRM2IFM(frm)->ifm_xch; 1252 1253 switch (FRM2IFM(frm)->ifm_rctl) { 1254 case R_CTL_ELS_RSP: 1255 /* 1256 * Complete it with frm as NULL 1257 */ 1258 fcoei_complete_xch(xch, NULL, FC_PKT_SUCCESS, 0); 1259 break; 1260 1261 case R_CTL_LS_BA_ACC: 1262 FCOEI_LOG(__FUNCTION__, "BA_ACC out: xch-%p, frm-%p", 1263 xch, frm); 1264 PRT_FRM_HDR("LS_BA_ACC", frm); 1265 break; 1266 1267 case R_CTL_LS_BA_RJT: 1268 FCOEI_LOG(__FUNCTION__, "BA_RJT out: xch-%p, frm-%p", 1269 xch, frm); 1270 PRT_FRM_HDR("LS_BA_RJT", frm); 1271 break; 1272 1273 default: 1274 /* 1275 * Unsupported frame 1276 */ 1277 PRT_FRM_HDR("Unsupported sol frame: ", frm); 1278 } 1279 1280 /* 1281 * We should release only the frame, and we don't care its netb 1282 */ 1283 FRM2SS(frm)->ss_eport->eport_release_frame(frm); 1284 } 1285 1286 /* 1287 * fcoei_port_event 1288 * link/port state changed 1289 * 1290 * Input: 1291 * eport = to indicate which port has changed 1292 * event = what change 1293 * 1294 * Returns: 1295 * N/A 1296 * 1297 * Comments: 1298 * refer fctl.h for ss_link_state value 1299 */ 1300 void 1301 fcoei_port_event(fcoe_port_t *eport, uint32_t event) 1302 { 1303 fcoei_event_t *ae; 1304 1305 if (!(EPORT2SS(eport)->ss_flags & SS_FLAG_LV_BOUND)) { 1306 FCOEI_LOG(__FUNCTION__, "not bound now"); 1307 return; 1308 } 1309 1310 mutex_enter(&EPORT2SS(eport)->ss_watchdog_mutex); 1311 switch (event) { 1312 case FCOE_NOTIFY_EPORT_LINK_DOWN: 1313 EPORT2SS(eport)->ss_link_state = FC_STATE_OFFLINE; 1314 cmn_err(CE_NOTE, "%02x%02x%02x%02x%02x%02x%02x%02x Link down", 1315 eport->eport_portwwn[0], eport->eport_portwwn[1], 1316 eport->eport_portwwn[2], eport->eport_portwwn[3], 1317 eport->eport_portwwn[4], eport->eport_portwwn[5], 1318 eport->eport_portwwn[6], eport->eport_portwwn[7]); 1319 break; 1320 1321 case FCOE_NOTIFY_EPORT_LINK_UP: 1322 if (eport->eport_mtu >= 2200) { 1323 EPORT2SS(eport)->ss_fcp_data_payload_size = 1324 FCOE_DEFAULT_FCP_DATA_PAYLOAD_SIZE; 1325 } else { 1326 FCOEI_LOG(__FUNCTION__, "fcoei: MTU is not big enough. " 1327 "we will use 1K frames in FCP data phase."); 1328 EPORT2SS(eport)->ss_fcp_data_payload_size = 1329 FCOE_MIN_FCP_DATA_PAYLOAD_SIZE; 1330 } 1331 1332 cmn_err(CE_NOTE, "%02x%02x%02x%02x%02x%02x%02x%02x Link up", 1333 eport->eport_portwwn[0], eport->eport_portwwn[1], 1334 eport->eport_portwwn[2], eport->eport_portwwn[3], 1335 eport->eport_portwwn[4], eport->eport_portwwn[5], 1336 eport->eport_portwwn[6], eport->eport_portwwn[7]); 1337 EPORT2SS(eport)->ss_link_state = FC_STATE_ONLINE; 1338 break; 1339 1340 default: 1341 FCOEI_LOG(__FUNCTION__, "unsupported event"); 1342 mutex_exit(&EPORT2SS(eport)->ss_watchdog_mutex); 1343 1344 return; 1345 } 1346 1347 EPORT2SS(eport)->ss_port_event_counter++; 1348 ae = (fcoei_event_t *)kmem_zalloc(sizeof (fcoei_event_t), KM_SLEEP); 1349 ae->ae_type = AE_EVENT_PORT; 1350 ae->ae_obj = EPORT2SS(eport); 1351 ae->ae_specific = EPORT2SS(eport)->ss_link_state; 1352 list_insert_tail(&EPORT2SS(eport)->ss_event_list, ae); 1353 mutex_exit(&EPORT2SS(eport)->ss_watchdog_mutex); 1354 } 1355 1356 /* 1357 * fcoei_process_event_port 1358 * link/port state changed 1359 * 1360 * Input: 1361 * ae = link fcoei_event 1362 * 1363 * Returns: 1364 * N/A 1365 * 1366 * Comments: 1367 * asynchronous events from FCOE 1368 */ 1369 void 1370 fcoei_process_event_port(fcoei_event_t *ae) 1371 { 1372 fcoei_soft_state_t *ss = (fcoei_soft_state_t *)ae->ae_obj; 1373 1374 if (ss->ss_eport->eport_link_speed == FCOE_PORT_SPEED_1G) { 1375 ae->ae_specific |= FC_STATE_1GBIT_SPEED; 1376 } else if (ss->ss_eport->eport_link_speed == 1377 FCOE_PORT_SPEED_10G) { 1378 ae->ae_specific |= FC_STATE_10GBIT_SPEED; 1379 } 1380 1381 if (ss->ss_flags & SS_FLAG_LV_BOUND) { 1382 ss->ss_bind_info.port_statec_cb(ss->ss_port, 1383 (uint32_t)ae->ae_specific); 1384 } else { 1385 FCOEI_LOG(__FUNCTION__, "ss %p not bound now", ss); 1386 } 1387 1388 atomic_dec_32(&ss->ss_port_event_counter); 1389 kmem_free(ae, sizeof (fcoei_event_t)); 1390 } 1391