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_add_32(&ss->ss_port_event_counter, -1);
1389         kmem_free(ae, sizeof (fcoei_event_t));
1390 }