1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  24  */
  25 
  26 /*
  27  * This file defines interfaces between FCOE and LEADVILLE
  28  */
  29 
  30 /*
  31  * Driver kernel header files
  32  */
  33 #include <sys/conf.h>
  34 #include <sys/ddi.h>
  35 #include <sys/stat.h>
  36 #include <sys/pci.h>
  37 #include <sys/sunddi.h>
  38 #include <sys/modctl.h>
  39 #include <sys/file.h>
  40 #include <sys/cred.h>
  41 #include <sys/byteorder.h>
  42 #include <sys/atomic.h>
  43 #include <sys/scsi/scsi.h>
  44 #include <sys/mac_client.h>
  45 #include <sys/modhash.h>
  46 
  47 /*
  48  * LEADVILLE header files
  49  */
  50 #include <sys/fibre-channel/fc.h>
  51 #include <sys/fibre-channel/impl/fc_fcaif.h>
  52 
  53 /*
  54  * COMSTAR head files (BIT_* macro)
  55  */
  56 #include <sys/stmf_defines.h>
  57 
  58 /*
  59  * FCOE header files
  60  */
  61 #include <sys/fcoe/fcoe_common.h>
  62 
  63 /*
  64  * Driver's own header files
  65  */
  66 #include <fcoei.h>
  67 
  68 /*
  69  * forward declaration of static functions
  70  */
  71 static void fcoei_port_enabled(void *arg);
  72 
  73 static void fcoei_populate_hba_fru_details(fcoei_soft_state_t *ss,
  74     fc_fca_port_info_t *port_info);
  75 
  76 static void fcoei_initiate_ct_req(fcoei_exchange_t *xch);
  77 static void fcoei_initiate_fcp_cmd(fcoei_exchange_t *xch);
  78 static void fcoei_initiate_els_req(fcoei_exchange_t *xch);
  79 static void fcoei_initiate_els_resp(fcoei_exchange_t *xch);
  80 
  81 static void fcoei_fill_els_logi_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm);
  82 static void fcoei_fill_els_prli_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm);
  83 static void fcoei_fill_els_logo_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm);
  84 static void fcoei_fill_els_scr_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm);
  85 static void fcoei_fill_els_adisc_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm);
  86 static void fcoei_fill_els_linit_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm);
  87 static void fcoei_fill_els_rls_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm);
  88 static void fcoei_fill_els_rnid_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm);
  89 
  90 static void fcoei_fill_els_acc_resp(fc_packet_t *fpkt, fcoe_frame_t *frm);
  91 static void fcoei_fill_els_rjt_resp(fc_packet_t *fpkt, fcoe_frame_t *frm);
  92 static void fcoei_fill_els_logi_resp(fc_packet_t *fpkt, fcoe_frame_t *frm);
  93 static void fcoei_fill_els_prli_resp(fc_packet_t *fpkt, fcoe_frame_t *frm);
  94 static void fcoei_fill_els_logo_resp(fc_packet_t *fpkt, fcoe_frame_t *frm);
  95 static void fcoei_fill_els_adisc_resp(fc_packet_t *fpkt, fcoe_frame_t *frm);
  96 
  97 static void fcoei_logo_peer(void *arg);
  98 static void fcoei_fpkt_comp(fc_packet_t *fpkt);
  99 
 100 static uint32_t
 101 fcoei_xch_abort(mod_hash_key_t key, mod_hash_val_t *val, void *arg);
 102 
 103 
 104 /*
 105  * fcoei_bind_port
 106  *      Bind LV port instance with fcoei soft state
 107  *
 108  * Input:
 109  *      dip = dev info of fcoei soft state
 110  *      port_info = fcoei specific parameters about LV port
 111  *      bind_info = LV specific parameters about fcoei soft state
 112  *
 113  * Returns:
 114  *      The pointer to fcoei soft state
 115  *
 116  * Comments:
 117  *      Unpon the completion of this call, the port must be offline.
 118  *      fcoei_port_enabled could trigger it to online
 119  */
 120 static void *
 121 fcoei_bind_port(dev_info_t *dip, fc_fca_port_info_t *port_info,
 122     fc_fca_bind_info_t *bind_info)
 123 {
 124         fcoei_soft_state_t      *ss;
 125 
 126         /*
 127          * get state info based on the dip
 128          */
 129         ss = (fcoei_soft_state_t *)
 130             ddi_get_soft_state(fcoei_state, ddi_get_instance(dip));
 131         if (!ss) {
 132                 FCOEI_LOG(__FUNCTION__, "ss is NULL");
 133                 return (NULL);
 134         }
 135 
 136         /*
 137          * make sure this port isn't bound
 138          */
 139         if (ss->ss_flags & SS_FLAG_LV_BOUND) {
 140                 port_info->pi_error = FC_ALREADY;
 141                 FCOEI_LOG(__FUNCTION__, "ss has been bound");
 142                 return (NULL);
 143         }
 144 
 145         if (bind_info->port_num) {
 146                 /*
 147                  * make sure request is in bounds
 148                  */
 149                 port_info->pi_error = FC_OUTOFBOUNDS;
 150                 FCOEI_LOG(__FUNCTION__, "port_num is not 0");
 151                 return (NULL);
 152         }
 153 
 154         /*
 155          * stash the ss_bind_info supplied by the FC Transport
 156          */
 157         bcopy(bind_info, &ss->ss_bind_info, sizeof (fc_fca_bind_info_t));
 158         ss->ss_port = bind_info->port_handle;
 159 
 160         /*
 161          * RNID parameter
 162          */
 163         port_info->pi_rnid_params.status = FC_FAILURE;
 164 
 165         /*
 166          * populate T11 FC-HBA details
 167          */
 168         fcoei_populate_hba_fru_details(ss, port_info);
 169 
 170         /*
 171          * set port's current state, and it is always offline before binding
 172          *
 173          * We hack pi_port_state to tell LV if it's NODMA_FCA
 174          */
 175         port_info->pi_port_state = FC_STATE_FCA_IS_NODMA;
 176 
 177         /*
 178          * copy login param
 179          */
 180         bcopy(&ss->ss_els_logi, &port_info->pi_login_params,
 181             sizeof (la_els_logi_t));
 182 
 183         /*
 184          * Mark it as bound
 185          */
 186         atomic_or_32(&ss->ss_flags, SS_FLAG_LV_BOUND);
 187 
 188         /*
 189          * Let fcoe to report the link status
 190          */
 191         fcoei_port_enabled((void *)ss);
 192 
 193         FCOEI_LOG(__FUNCTION__, "Exit fcoei_bind_port: %p", ss);
 194         return (ss);
 195 }
 196 
 197 /*
 198  * fcoei_unbind_port
 199  *      Un-bind the fcoei port
 200  *
 201  * Input:
 202  *      fca_handle = fcoei soft state set in fcoei_bind_port
 203  *
 204  * Returns:
 205  *      N/A
 206  *
 207  * Comments:
 208  *      Clear binding flag
 209  */
 210 static void
 211 fcoei_unbind_port(void *fca_handle)
 212 {
 213         fcoei_soft_state_t *ss = (fcoei_soft_state_t *)fca_handle;
 214 
 215         atomic_and_32(&ss->ss_flags, ~SS_FLAG_LV_BOUND);
 216         ss->ss_eport->eport_ctl(ss->ss_eport, FCOE_CMD_PORT_OFFLINE, NULL);
 217         FCOEI_LOG(__FUNCTION__, "Exit fcoei_unbind_port: %p", ss);
 218 }
 219 
 220 /*
 221  * fcoei_init_pkt
 222  *      Initialize fcoei related part of fc_packet
 223  *
 224  * Input:
 225  *      fca_handle = fcoei soft state set in fcoei_bind_port
 226  *      fpkt = The pointer to fc_packet
 227  *      sleep = This call can sleep or not
 228  *
 229  * Returns:
 230  *      FC_SUCCESS - Initialization completed successfully
 231  *
 232  * Comments:
 233  *      Link the exchange elements with proper objects
 234  */
 235 /* ARGSUSED */
 236 static int
 237 fcoei_init_pkt(void *fca_handle, fc_packet_t *fpkt, int sleep)
 238 {
 239         fcoei_soft_state_t      *ss  = (fcoei_soft_state_t *)fca_handle;
 240         fcoei_exchange_t        *xch = FPKT2XCH(fpkt);
 241 
 242         ASSERT(sleep + 1);
 243         xch->xch_ss = ss;
 244         xch->xch_fpkt = fpkt;
 245         xch->xch_flags = 0;
 246         return (FC_SUCCESS);
 247 }
 248 
 249 /*
 250  * fcoei_un_init_pkt
 251  *      Uninitialize fcoei related part of fc_packet
 252  *
 253  * Input:
 254  *      fca_handle = fcoei soft state set in fcoei_bind_port
 255  *      fpkt = The pointer to fc_packet
 256  *
 257  * Returns:
 258  *      FC_SUCCESS - Uninitialize successfully
 259  *
 260  * Comments:
 261  *      Very simple, just return successfully
 262  */
 263 /* ARGSUSED */
 264 static int
 265 fcoei_un_init_pkt(void *fca_handle, fc_packet_t *fpkt)
 266 {
 267         ASSERT(fca_handle && fpkt);
 268         return (FC_SUCCESS);
 269 }
 270 
 271 /*
 272  * fcoei_get_cap
 273  *      Export FCA hardware and software capability.
 274  *
 275  * Input:
 276  *      fca_handle = fcoei soft state set in fcoei_bind_port
 277  *      cap = pointer to the capability string
 278  *      ptr = buffer pointer for returning capability
 279  *
 280  * Returns:
 281  *      FC_CAP_ERROR - no such capability
 282  *      FC_CAP_FOUND - the capability was returned and cannot be set
 283  *
 284  * Comments:
 285  *      FC_CAP_UNSOL_BUF is one important capability, it will affect the
 286  *      implementation of fcoei_ub_alloc/free.
 287  */
 288 static int
 289 fcoei_get_cap(void * fca_handle, char *cap, void *ptr)
 290 {
 291         fcoei_soft_state_t      *ss   = (fcoei_soft_state_t *)fca_handle;
 292         uint32_t                *rptr = (uint32_t *)ptr;
 293         int                      rval = FC_CAP_FOUND;
 294 
 295         ASSERT(fca_handle);
 296         FCOEI_LOG(__FUNCTION__, "cap: %s", cap);
 297         if (strcmp(cap, FC_NODE_WWN) == 0) {
 298                 bcopy(&ss->ss_els_logi.node_ww_name.raw_wwn[0], ptr, 8);
 299         } else if (strcmp(cap, FC_LOGIN_PARAMS) == 0) {
 300                 bcopy((void *)&ss->ss_els_logi, ptr, sizeof (la_els_logi_t));
 301         } else if (strcmp(cap, FC_CAP_UNSOL_BUF) == 0) {
 302                 *rptr = (uint32_t)0;
 303         } else if (strcmp(cap, FC_CAP_NOSTREAM_ON_UNALIGN_BUF) == 0) {
 304                 *rptr = (uint32_t)FC_ALLOW_STREAMING;
 305         } else if (strcmp(cap, FC_CAP_PAYLOAD_SIZE) == 0) {
 306                 *rptr = (uint32_t)2136;
 307         } else if (strcmp(cap, FC_CAP_POST_RESET_BEHAVIOR) == 0) {
 308                 *rptr = FC_RESET_RETURN_ALL;
 309         } else if (strcmp(cap, FC_CAP_FCP_DMA) == 0) {
 310                 *rptr = FC_NO_DVMA_SPACE;
 311         } else {
 312                 rval = FC_CAP_ERROR;
 313                 FCOEI_LOG(__FUNCTION__, "not supported");
 314         }
 315 
 316         return (rval);
 317 }
 318 
 319 /*
 320  * fcoei_set_cap
 321  *      Allow the FC Transport to set FCA capabilities if possible
 322  *
 323  * Input:
 324  *      fca_handle = fcoei soft state set in fcoei_bind_port
 325  *      cap = pointer to the capabilities string.
 326  *      ptr = buffer pointer for capability.
 327  *
 328  * Returns:
 329  *      FC_CAP_ERROR - no such capability
 330  *
 331  * Comments:
 332  *      Currently, all capabilities can't be changed.
 333  */
 334 static int
 335 fcoei_set_cap(void * fca_handle, char *cap, void *ptr)
 336 {
 337         FCOEI_LOG(__FUNCTION__, "cap: %s, %p, %p", cap, fca_handle, ptr);
 338         return (FC_CAP_ERROR);
 339 }
 340 
 341 /*
 342  * fcoei_getmap
 343  *      Get lilp map
 344  *
 345  * Input:
 346  *      fca_handle = fcoei soft state set in fcoei_bind_port
 347  *      mapbuf = the buffer to store lilp map
 348  *
 349  * Returns:
 350  *      FC_FAILURE - Can't get the lilp map
 351  *
 352  * Comments:
 353  *      fcoei can't work in loop topology, so it should never get called
 354  */
 355 static int
 356 fcoei_getmap(void * fca_handle, fc_lilpmap_t *mapbuf)
 357 {
 358         FCOEI_LOG(__FUNCTION__, "not: %p-%p", fca_handle, mapbuf);
 359         return (FC_FAILURE);
 360 }
 361 
 362 /*
 363  * fcoei_ub_alloc
 364  *      Pre-allocate unsolicited buffers at the request of LV
 365  *
 366  * Input:
 367  *      fca_handle = fcoei soft state set in fcoei_bind_port
 368  *      tokens = token array for each buffer.
 369  *      size = number of tokens
 370  *      count = the acutual number of allocated unsolicited buffers
 371  *      type = unsolicited buffer type
 372  *
 373  * Returns:
 374  *      FC_SUCCESS - The requested buffers have been freeed
 375  *
 376  * Comments:
 377  *      fcoei_get_cap will set UNSOL_BUF to 0, so it should never get called.
 378  */
 379 static int
 380 fcoei_ub_alloc(void * fca_handle, uint64_t tokens[], uint32_t size,
 381     uint32_t *count, uint32_t type)
 382 {
 383         FCOEI_LOG(__FUNCTION__, "not: %p-%p-%x-%p-%x", fca_handle, tokens,
 384             size, count, type);
 385         return (FC_SUCCESS);
 386 }
 387 
 388 /*
 389  * fcoei_ub_free
 390  *      Free the pre-allocated unsolicited buffers at the request of LV
 391  *
 392  * Input:
 393  *      fca_handle = fcoei soft state set in fcoei_bind_port
 394  *      count = number of buffers.
 395  *      tokens = token array for each buffer.
 396  *
 397  * Returns:
 398  *      FC_SUCCESS - The requested buffers have been freeed
 399  *
 400  * Comments:
 401  *      fcoei_get_cap will set UNSOL_BUF to 0, so it should never get called.
 402  */
 403 static int
 404 fcoei_ub_free(void * fca_handle, uint32_t count, uint64_t tokens[])
 405 {
 406         FCOEI_EXT_LOG(__FUNCTION__, "not: %p-%x-%p", fca_handle, count, tokens);
 407         return (FC_SUCCESS);
 408 }
 409 
 410 /*
 411  * fcoei_ub_release
 412  *      Release unsolicited buffers from FC Transport to FCA for future use
 413  *
 414  * Input:
 415  *      fca_handle = fcoei soft state set in fcoei_bind_port
 416  *      count = number of buffers.
 417  *      tokens = token array for each buffer.
 418  *
 419  * Returns:
 420  *      FC_SUCCESS - The requested buffers have been released.
 421  *      FC_FAILURE - The requested buffers have not been released.
 422  *
 423  * Comments:
 424  *      It will always succeed. It has nothing to do with fcoei_ub_alloc/free.
 425  */
 426 static int
 427 fcoei_ub_release(void * fca_handle, uint32_t count, uint64_t tokens[])
 428 {
 429         fc_unsol_buf_t *ub = *((fc_unsol_buf_t **)tokens);
 430 
 431         if (count != 1) {
 432                 FCOEI_LOG(__FUNCTION__, "count is not 1: %p", fca_handle);
 433                 return (FC_FAILURE);
 434         }
 435 
 436         kmem_free(ub->ub_buffer, ub->ub_bufsize);
 437         kmem_free(ub, sizeof (fc_unsol_buf_t));
 438         FCOEI_EXT_LOG(__FUNCTION__, "ub is freeed");
 439         return (FC_SUCCESS);
 440 }
 441 
 442 /*
 443  * fcoei_abort
 444  *      Direct FCA driver to abort an outstanding exchange associated with a
 445  *      specified fc_packet_t struct
 446  *
 447  * Input:
 448  *      fca_handle - fcoei soft state set in fcoei_bind_port
 449  *      fpkt - A pointer to the fc_packet_t for the exchange to be aborted.
 450  *      flags - Set to KM_SLEEP if the function may sleep, or KM_NOSLEEP if
 451  *              the function may not sleep.
 452  *
 453  * Returns:
 454  *      FC_ABORTED - The specified exchange was successfully aborted.
 455  *      FC_ABORTING - The specified exchange is being aborted.
 456  *      FC_ABORT_FAILED - The specified exchange could not be aborted.
 457  *      FC_TRANSPORT_ERROR - A transport error occurred while attempting to
 458  *              abort the specified exchange.
 459  *      FC_BADEXCHANGE - The specified exchange does not exist.
 460  *
 461  * Comments:
 462  *      After the exchange is aborted, the FCA driver must update the relevant
 463  *      fields in the fc_packet_t struct as per normal exchange completion and
 464  *      call the pkt_comp function to return the fc_packet_t struct to the FC
 465  *      Transport.
 466  *      When an exchange is successfully aborted, the FCA driver must set the
 467  *      pkt_reason field in the fc_packet_t to FC_REASON_ABORTED and the
 468  *      pkt_state field in the fc_packet_t to FC_PKT_LOCAL_RJT before returning
 469  *      the fc_packet_t to the FC Transport.
 470  *
 471  *      Unfortunately, LV doesn't conform to the spec. It will take all these
 472  *      legal return value as failure to abort.
 473  */
 474 static int
 475 fcoei_abort(void * fca_handle, fc_packet_t *fpkt, int flags)
 476 {
 477         FCOEI_LOG(__FUNCTION__, "not: %p-%p-%x", fca_handle, fpkt, flags);
 478         return (FC_SUCCESS);
 479 }
 480 
 481 /*
 482  * fcoei_reset
 483  *      Reset link or hardware
 484  *
 485  * Input:
 486  *      fca_handle = fcoei soft state set in fcoei_bind_port
 487  *      cmd = reset type command
 488  *
 489  * Returns:
 490  *      FC_SUCCESS - Reset has completed successfully
 491  *      FC_FAILURE - Reset has failed
 492  *
 493  * Comments:
 494  *      N/A
 495  */
 496 static int
 497 fcoei_reset(void * fca_handle, uint32_t cmd)
 498 {
 499         int                      rval = FC_SUCCESS;
 500         fcoei_soft_state_t      *ss   = (fcoei_soft_state_t *)fca_handle;
 501         fcoei_event_t *ae;
 502 
 503         switch (cmd) {
 504         case FC_FCA_LINK_RESET:
 505                 if (ss->ss_link_state != FC_STATE_ONLINE) {
 506                         FCOEI_LOG(__FUNCTION__, "not online now: ss-%p", ss);
 507                         rval = FC_FAILURE;
 508                         break;
 509                 }
 510 
 511                 /*
 512                  * This is linkreset phase I
 513                  */
 514                 fcoei_logo_peer(ss);
 515                 delay(FCOE_SEC2TICK(1) / 10);
 516                 ss->ss_eport->eport_ctl(ss->ss_eport, FCOE_CMD_PORT_OFFLINE, 0);
 517                 fcoei_port_event(ss->ss_eport, FCOE_NOTIFY_EPORT_LINK_DOWN);
 518 
 519                 /*
 520                  * Perpare linkreset phase II
 521                  */
 522                 ae = kmem_zalloc(sizeof (*ae), KM_SLEEP);
 523                 ae->ae_type = AE_EVENT_RESET;
 524                 ae->ae_obj = ss;
 525 
 526                 mutex_enter(&ss->ss_watchdog_mutex);
 527                 list_insert_tail(&ss->ss_event_list, ae);
 528                 mutex_exit(&ss->ss_watchdog_mutex);
 529                 break;
 530 
 531         case FC_FCA_RESET:
 532                 break;
 533 
 534         case FC_FCA_CORE:
 535                 break;
 536 
 537         case FC_FCA_RESET_CORE:
 538                 break;
 539 
 540         default:
 541                 rval = FC_FAILURE;
 542                 FCOEI_LOG(__FUNCTION__, "cmd-%x not supported", cmd);
 543                 break;
 544         }
 545 
 546         return (rval);
 547 }
 548 
 549 /*
 550  * fcoei_port_manage
 551  *      Perform various port management operations at the request of LV
 552  *
 553  * Input:
 554  *      fca_handle = fcoei soft state set in fcoei_bind_port
 555  *      pm = the pointer to the struct specifying the port management operation
 556  *
 557  * Returns:
 558  *      FC_SUCCESS - The request completed successfully
 559  *      FC_FAILURE - The request did not complete successfully
 560  *
 561  * Comments:
 562  *      N/A
 563  */
 564 static int
 565 fcoei_port_manage(void * fca_handle, fc_fca_pm_t *pm)
 566 {
 567         int     rval = FC_FAILURE;
 568         fcoei_soft_state_t      *ss = (fcoei_soft_state_t *)fca_handle;
 569 
 570         if (fca_handle == NULL || pm == NULL) {
 571                 return (rval);
 572         }
 573 
 574         FCOEI_LOG(__FUNCTION__, "code0x%x, %p", pm->pm_cmd_code, fca_handle);
 575         switch (pm->pm_cmd_code) {
 576 
 577         case FC_PORT_GET_NODE_ID:
 578         {
 579                 if (pm->pm_data_len < sizeof (fc_rnid_t)) {
 580                         rval = FC_NOMEM;
 581                         break;
 582                 }
 583                 ss->ss_rnid.port_id = ss->ss_p2p_info.fca_d_id;
 584                 bcopy((void *)&ss->ss_rnid,
 585                     pm->pm_data_buf, sizeof (fc_rnid_t));
 586                 rval = FC_SUCCESS;
 587                 break;
 588         }
 589 
 590         case FC_PORT_SET_NODE_ID:
 591         {
 592                 if (pm->pm_data_len < sizeof (fc_rnid_t)) {
 593                         rval = FC_NOMEM;
 594                         break;
 595                 }
 596                 bcopy(pm->pm_data_buf,
 597                     (void *)&ss->ss_rnid, sizeof (fc_rnid_t));
 598                 rval = FC_SUCCESS;
 599                 break;
 600         }
 601 
 602         default:
 603                 FCOEI_LOG(__FUNCTION__, "unsupported cmd-%x", pm->pm_cmd_code);
 604                 rval = FC_INVALID_REQUEST;
 605                 break;
 606         }
 607 
 608         return (rval);
 609 }
 610 
 611 /*
 612  * fcoei_get_device
 613  *      Get fcoei remote port with FCID of d_id
 614  *
 615  * Input:
 616  *      fca_handle = fcoei soft state set in fcoei_bind_port
 617  *      d_id = 24-bit FCID of remote port
 618  *
 619  * Returns:
 620  *      The pointer to fcoei remote port
 621  *
 622  * Comments:
 623  *      fcoei has no remote port device
 624  */
 625 static void *
 626 fcoei_get_device(void *fca_handle, fc_portid_t d_id)
 627 {
 628         FCOEI_EXT_LOG(__FUNCTION__, "not supported: %p-%x", fca_handle, d_id);
 629         return (NULL);
 630 }
 631 
 632 /*
 633  * fcoei_notify
 634  *      Notify the change of target device
 635  *
 636  * Input:
 637  *      fca_handle = fcoei soft state set in fcoei_bind_port
 638  *      cmd = detailed cmd
 639  *
 640  * Returns:
 641  *      FC_SUCCESS - Notification completed successfully
 642  *
 643  * Comments:
 644  *      It's only needed to support non-COMSTAR FC target, so it should
 645  *      never get called.
 646  */
 647 static int
 648 fcoei_notify(void *fca_handle, uint32_t cmd)
 649 {
 650         FCOEI_LOG(__FUNCTION__, "not supported: %p-%x", fca_handle, cmd);
 651         return (FC_SUCCESS);
 652 }
 653 
 654 /*
 655  * fcoei_transport
 656  *      Submit FCP/CT requests
 657  *
 658  * Input:
 659  *      fca_handle - fcoei soft state set in fcoei_bind_port
 660  *      fpkt - LV fc_packet
 661  *
 662  * Returns:
 663  *      N/A
 664  *
 665  * Comments:
 666  *      N/A
 667  */
 668 static int
 669 fcoei_transport(void *fca_handle, fc_packet_t *fpkt)
 670 {
 671         fcoei_soft_state_t      *ss  = (fcoei_soft_state_t *)fca_handle;
 672         fcoei_exchange_t        *xch = FPKT2XCH(fpkt);
 673         uint16_t                 pkt_tran_flags = fpkt->pkt_tran_flags;
 674 
 675         xch->xch_start_tick = ddi_get_lbolt();
 676         xch->xch_end_tick = xch->xch_start_tick +
 677             FCOE_SEC2TICK(fpkt->pkt_timeout);
 678         xch->xch_ae.ae_type = AE_EVENT_EXCHANGE;
 679         xch->xch_ae.ae_obj = xch;
 680 
 681         if (pkt_tran_flags & FC_TRAN_NO_INTR) {
 682                 FCOEI_LOG(__FUNCTION__, "AaA polling: %p-%p", fpkt, xch);
 683                 sema_init(&xch->xch_sema, 0, NULL, SEMA_DRIVER, NULL);
 684         }
 685 
 686         mutex_enter(&ss->ss_watchdog_mutex);
 687         list_insert_tail(&ss->ss_event_list, &xch->xch_ae);
 688         if (ss->ss_flags & SS_FLAG_WATCHDOG_IDLE) {
 689                 cv_signal(&ss->ss_watchdog_cv);
 690         }
 691         mutex_exit(&ss->ss_watchdog_mutex);
 692 
 693         if (pkt_tran_flags & FC_TRAN_NO_INTR) {
 694                 FCOEI_LOG(__FUNCTION__, "BaB polling: %p-%p", fpkt, xch);
 695                 sema_p(&xch->xch_sema);
 696                 sema_destroy(&xch->xch_sema);
 697                 FCOEI_LOG(__FUNCTION__, "after polling: %p-%p", fpkt, xch);
 698         }
 699 
 700         return (FC_SUCCESS);
 701 }
 702 
 703 /*
 704  * fcoei_els_send
 705  *      Submit ELS request or response
 706  *
 707  * Input:
 708  *      fca_handle - fcoei soft state set in fcoei_bind_port
 709  *      fpkt = LV fc_packet
 710  *
 711  * Returns:
 712  *      N/A
 713  *
 714  * Comments:
 715  *      N/A
 716  */
 717 static int
 718 fcoei_els_send(void *fca_handle, fc_packet_t *fpkt)
 719 {
 720         fcoei_soft_state_t      *ss  = (fcoei_soft_state_t *)fca_handle;
 721         fcoei_exchange_t        *xch = FPKT2XCH(fpkt);
 722 
 723         if (fpkt->pkt_tran_flags & FC_TRAN_NO_INTR) {
 724                 FCOEI_LOG(__FUNCTION__, "ELS poll mode is not supported");
 725                 return (FC_BADPACKET);
 726         }
 727 
 728         xch->xch_start_tick = ddi_get_lbolt();
 729         xch->xch_end_tick = xch->xch_start_tick +
 730             FCOE_SEC2TICK(fpkt->pkt_timeout);
 731         xch->xch_ae.ae_type = AE_EVENT_EXCHANGE;
 732         xch->xch_ae.ae_obj = xch;
 733 
 734         /*
 735          * LV could release ub after this call, so we must save the ub type
 736          * for later use
 737          */
 738         if (fpkt->pkt_cmd_fhdr.r_ctl == R_CTL_ELS_RSP) {
 739                 ((uint8_t *)&fpkt->pkt_fca_rsvd1)[0] =
 740                     ((fc_unsol_buf_t *)fpkt->pkt_ub_resp_token)->ub_buffer[0];
 741         }
 742 
 743         mutex_enter(&ss->ss_watchdog_mutex);
 744         list_insert_tail(&ss->ss_event_list, &xch->xch_ae);
 745         if (ss->ss_flags & SS_FLAG_WATCHDOG_IDLE) {
 746                 cv_signal(&ss->ss_watchdog_cv);
 747         }
 748         mutex_exit(&ss->ss_watchdog_mutex);
 749 
 750         return (FC_SUCCESS);
 751 }
 752 
 753 /*
 754  * fcoei_populate_hba_fru_details
 755  *      Fill detailed information about HBA
 756  *
 757  * Input:
 758  *      ss - fcoei soft state
 759  *      port_info = fc_fca_port_info_t that need be updated
 760  *
 761  * Returns:
 762  *      N/A
 763  *
 764  * Comments:
 765  *      N/A
 766  */
 767 static void
 768 fcoei_populate_hba_fru_details(fcoei_soft_state_t *ss,
 769     fc_fca_port_info_t *port_info)
 770 {
 771         fca_port_attrs_t *port_attrs = &(port_info->pi_attrs);
 772         int     instance;
 773 
 774         ASSERT(ss != NULL);
 775         (void) snprintf(port_attrs->manufacturer, FCHBA_MANUFACTURER_LEN,
 776             "Sun Microsystems, Inc.");
 777         (void) snprintf(port_attrs->driver_name, FCHBA_DRIVER_NAME_LEN,
 778             "%s", FCOEI_NAME_VERSION);
 779         (void) snprintf(port_attrs->driver_version, FCHBA_DRIVER_VERSION_LEN,
 780             "%s", FCOEI_VERSION);
 781         (void) strcpy(port_attrs->serial_number, "N/A");
 782         (void) strcpy(port_attrs->hardware_version, "N/A");
 783         (void) strcpy(port_attrs->model, "FCoE Virtual FC HBA");
 784         (void) strcpy(port_attrs->model_description, "N/A");
 785         (void) strcpy(port_attrs->firmware_version, "N/A");
 786         (void) strcpy(port_attrs->option_rom_version, "N/A");
 787 
 788         port_attrs->vendor_specific_id = 0xFC0E;
 789         port_attrs->max_frame_size = FCOE_MAX_FC_FRAME_SIZE;
 790         port_attrs->supported_cos = 0x10000000;
 791         port_attrs->supported_speed = FC_HBA_PORTSPEED_1GBIT |
 792             FC_HBA_PORTSPEED_10GBIT;
 793         instance = ddi_get_instance(ss->ss_dip);
 794         port_attrs->hba_fru_details.high =
 795             (short)((instance & 0xffff0000) >> 16);
 796         port_attrs->hba_fru_details.low =
 797             (short)(instance & 0x0000ffff);
 798 }
 799 
 800 /*
 801  * fcoei_port_enabled
 802  *      Notify fcoe that the port has been enabled
 803  *
 804  * Input:
 805  *      arg = the related soft state
 806  *
 807  * Returns:
 808  *      N/A
 809  *
 810  * Comments:
 811  *      Only after this, fcoe will report the link status to us
 812  */
 813 static void
 814 fcoei_port_enabled(void *arg)
 815 {
 816         fcoei_soft_state_t      *ss  = (fcoei_soft_state_t *)arg;
 817 
 818         ss->ss_eport->eport_ctl(ss->ss_eport, FCOE_CMD_PORT_ONLINE, NULL);
 819 }
 820 
 821 
 822 /*
 823  * fcoei_initiate_ct_req
 824  *      Fill and submit CT request
 825  *
 826  * Input:
 827  *      xch - the exchange that will be initiated
 828  *
 829  * Returns:
 830  *      N/A
 831  *
 832  * Comments:
 833  *      N/A
 834  */
 835 static void
 836 fcoei_initiate_ct_req(fcoei_exchange_t *xch)
 837 {
 838         fc_packet_t     *fpkt    = xch->xch_fpkt;
 839         fc_ct_header_t  *ct      = (fc_ct_header_t *)(void *)fpkt->pkt_cmd;
 840         uint8_t         *bp      = (uint8_t *)fpkt->pkt_cmd;
 841         fcoe_frame_t    *frm;
 842         int              offset;
 843         int              idx;
 844         uint32_t         cmd_len = fpkt->pkt_cmdlen;
 845 
 846         /*
 847          * Ensure it's 4-byte aligned
 848          */
 849         cmd_len = P2ROUNDUP(cmd_len, 4);
 850 
 851         /*
 852          * Allocate CT request frame
 853          */
 854         frm = xch->xch_ss->ss_eport->eport_alloc_frame(xch->xch_ss->ss_eport,
 855             cmd_len + FCFH_SIZE, NULL);
 856         if (frm == NULL) {
 857                 FCOEI_LOG(__FUNCTION__, "failed to alloc: %p", xch);
 858                 return;
 859         }
 860 
 861         bzero(frm->frm_payload, cmd_len);
 862         xch->xch_cnt = xch->xch_ss->ss_sol_cnt;
 863         atomic_add_32(xch->xch_cnt, 1);
 864 
 865         FFM_R_CTL(fpkt->pkt_cmd_fhdr.r_ctl, frm);
 866         FFM_D_ID(fpkt->pkt_cmd_fhdr.d_id, frm);
 867         FFM_S_ID(fpkt->pkt_cmd_fhdr.s_id, frm);
 868         FFM_TYPE(fpkt->pkt_cmd_fhdr.type, frm);
 869         FFM_F_CTL(fpkt->pkt_cmd_fhdr.f_ctl, frm);
 870         FFM_OXID(xch->xch_oxid, frm);
 871         FFM_RXID(xch->xch_rxid, frm);
 872         fcoei_init_ifm(frm, xch);
 873 
 874         /*
 875          * CT header (FC payload)
 876          */
 877         offset = 0;
 878         FCOE_V2B_1(ct->ct_rev, FPLD + offset);
 879 
 880         offset = 1;
 881         FCOE_V2B_3(ct->ct_inid, FPLD + offset);
 882 
 883         offset = 4;
 884         FCOE_V2B_1(ct->ct_fcstype, FPLD + offset);
 885 
 886         offset = 5;
 887         FCOE_V2B_1(ct->ct_fcssubtype, FPLD + offset);
 888 
 889         offset = 6;
 890         FCOE_V2B_1(ct->ct_options, FPLD + offset);
 891 
 892         offset = 8;
 893         FCOE_V2B_2(ct->ct_cmdrsp, FPLD + offset);
 894 
 895         offset = 10;
 896         FCOE_V2B_2(ct->ct_aiusize, FPLD + offset);
 897 
 898         offset = 13;
 899         FCOE_V2B_1(ct->ct_reason, FPLD + offset);
 900 
 901         offset = 14;
 902         FCOE_V2B_1(ct->ct_expln, FPLD + offset);
 903 
 904         offset = 15;
 905         FCOE_V2B_1(ct->ct_vendor, FPLD + offset);
 906 
 907         /*
 908          * CT payload (FC payload)
 909          */
 910         switch (ct->ct_fcstype) {
 911         case FCSTYPE_DIRECTORY:
 912                 switch (ct->ct_cmdrsp) {
 913                 case NS_GA_NXT:
 914                 case NS_GPN_ID:
 915                 case NS_GNN_ID:
 916                 case NS_GCS_ID:
 917                 case NS_GFT_ID:
 918                 case NS_GSPN_ID:
 919                 case NS_GPT_ID:
 920                 case NS_GID_FT:
 921                 case NS_GID_PT:
 922                 case NS_DA_ID:
 923                         offset = 16;
 924                         FCOE_V2B_4(((uint32_t *)(intptr_t)(bp + offset))[0],
 925                             FPLD + offset);
 926                         break;
 927 
 928                 case NS_GID_PN:
 929                         offset = 16;
 930                         bcopy(bp + offset, FPLD + offset, 8);
 931                         break;
 932 
 933                 case NS_RNN_ID:
 934                 case NS_RPN_ID:
 935                         offset = 16;
 936                         FCOE_V2B_4(((uint32_t *)(intptr_t)(bp + offset))[0],
 937                             FPLD + offset);
 938 
 939                         offset = 20;
 940                         bcopy(bp + offset, FPLD + offset, 8);
 941                         break;
 942 
 943                 case NS_RSPN_ID:
 944                         offset = 16;
 945                         FCOE_V2B_4(((uint32_t *)(intptr_t)(bp + offset))[0],
 946                             FPLD + offset);
 947 
 948                         offset = 20;
 949                         bcopy(bp + offset, FPLD + offset, bp[20] + 1);
 950                         break;
 951 
 952                 case NS_RSNN_NN:
 953                         offset = 16;
 954                         bcopy(bp + offset, FPLD + offset, 8);
 955 
 956                         offset = 24;
 957                         bcopy(bp + offset, FPLD + offset, bp[24] + 1);
 958                         break;
 959 
 960                 case NS_RFT_ID:
 961                         offset = 16;
 962                         FCOE_V2B_4(((uint32_t *)(intptr_t)(bp + offset))[0],
 963                             FPLD + offset);
 964 
 965                         /*
 966                          * fp use bcopy to copy fp_fc4_types,
 967                          * we need to swap order for each integer
 968                          */
 969                         offset = 20;
 970                         for (idx = 0; idx < 8; idx++) {
 971                                 FCOE_V2B_4(
 972                                     ((uint32_t *)(intptr_t)(bp + offset))[0],
 973                                     FPLD + offset);
 974                                 offset += 4;
 975                         }
 976                         break;
 977 
 978                 case NS_RCS_ID:
 979                 case NS_RPT_ID:
 980                         offset = 16;
 981                         FCOE_V2B_4(((uint32_t *)(intptr_t)(bp + offset))[0],
 982                             FPLD + offset);
 983 
 984                         offset = 20;
 985                         FCOE_V2B_4(((uint32_t *)(intptr_t)(bp + offset))[0],
 986                             FPLD + offset);
 987                         break;
 988 
 989                 case NS_RIP_NN:
 990                         offset = 16;
 991                         bcopy(bp + offset, FPLD + offset, 24);
 992                         break;
 993 
 994                 default:
 995                         fcoei_complete_xch(xch, frm, FC_PKT_FAILURE,
 996                             FC_REASON_CMD_UNSUPPORTED);
 997                         break;
 998                 }
 999                 break; /* FCSTYPE_DIRECTORY */
1000 
1001         case FCSTYPE_MGMTSERVICE:
1002                 switch (ct->ct_cmdrsp) {
1003                 case MS_GIEL:
1004                         FCOEI_LOG(__FUNCTION__,
1005                             "MS_GIEL ct_fcstype %x, ct_cmdrsp: %x",
1006                             ct->ct_fcstype, ct->ct_cmdrsp);
1007                         break;
1008 
1009                 default:
1010                         fcoei_complete_xch(xch, frm, FC_PKT_FAILURE,
1011                             FC_REASON_CMD_UNSUPPORTED);
1012                         break;
1013                 }
1014                 break; /* FCSTYPE_MGMTSERVICE */
1015 
1016         default:
1017                 fcoei_complete_xch(xch, frm, FC_PKT_FAILURE,
1018                     FC_REASON_CMD_UNSUPPORTED);
1019                 break;
1020         }
1021         xch->xch_ss->ss_eport->eport_tx_frame(frm);
1022 }
1023 
1024 /*
1025  * fcoei_initiate_fcp_cmd
1026  *      Submit FCP command
1027  *
1028  * Input:
1029  *      xch - the exchange to be submitted
1030  *
1031  * Returns:
1032  *      N/A
1033  *
1034  * Comments:
1035  *      N/A
1036  */
1037 static void
1038 fcoei_initiate_fcp_cmd(fcoei_exchange_t *xch)
1039 {
1040         fc_packet_t     *fpkt = xch->xch_fpkt;
1041         fcoe_frame_t    *frm;
1042         fcp_cmd_t       *fcp_cmd_iu = (fcp_cmd_t *)(void *)fpkt->pkt_cmd;
1043         int              offset = 0;
1044 
1045         ASSERT((fpkt->pkt_cmdlen % 4) == 0);
1046         frm = xch->xch_ss->ss_eport->eport_alloc_frame(xch->xch_ss->ss_eport,
1047             fpkt->pkt_cmdlen + FCFH_SIZE, NULL);
1048         if (!frm) {
1049                 ASSERT(0);
1050         } else {
1051                 fcoei_init_ifm(frm, xch);
1052                 bzero(frm->frm_payload, fpkt->pkt_cmdlen);
1053         }
1054 
1055         /*
1056          * This will affect timing check
1057          */
1058         xch->xch_cnt = xch->xch_ss->ss_sol_cnt;
1059         atomic_add_32(xch->xch_cnt, 1);
1060 
1061         /*
1062          * Set exchange residual bytes
1063          */
1064         xch->xch_resid = (int)fpkt->pkt_datalen;
1065 
1066         /*
1067          * Fill FCP command IU
1068          *
1069          * fcp_ent_addr
1070          */
1071         FCOE_V2B_2(fcp_cmd_iu->fcp_ent_addr.ent_addr_0,
1072             frm->frm_payload + offset);
1073         offset += 2;
1074         FCOE_V2B_2(fcp_cmd_iu->fcp_ent_addr.ent_addr_1,
1075             frm->frm_payload + offset);
1076         offset += 2;
1077         FCOE_V2B_2(fcp_cmd_iu->fcp_ent_addr.ent_addr_2,
1078             frm->frm_payload + offset);
1079         offset += 2;
1080         FCOE_V2B_2(fcp_cmd_iu->fcp_ent_addr.ent_addr_3,
1081             frm->frm_payload + offset);
1082         /*
1083          * fcp_cntl
1084          */
1085         offset = offsetof(fcp_cmd_t, fcp_cntl);
1086         frm->frm_payload[offset] = 0;
1087 
1088         offset += 1;
1089         frm->frm_payload[offset] = fcp_cmd_iu->fcp_cntl.cntl_qtype & 0x07;
1090         offset += 1;
1091         frm->frm_payload[offset] =
1092             (fcp_cmd_iu->fcp_cntl.cntl_kill_tsk << 7) |
1093             (fcp_cmd_iu->fcp_cntl.cntl_clr_aca << 6) |
1094             (fcp_cmd_iu->fcp_cntl.cntl_reset_tgt << 5) |
1095             (fcp_cmd_iu->fcp_cntl.cntl_reset_lun << 4) |
1096             (fcp_cmd_iu->fcp_cntl.cntl_clr_tsk << 2) |
1097             (fcp_cmd_iu->fcp_cntl.cntl_abort_tsk << 1);
1098         offset += 1;
1099         frm->frm_payload[offset] =
1100             (fcp_cmd_iu->fcp_cntl.cntl_read_data << 1) |
1101             (fcp_cmd_iu->fcp_cntl.cntl_write_data);
1102         /*
1103          * fcp_cdb
1104          */
1105         offset = offsetof(fcp_cmd_t, fcp_cdb);
1106         bcopy(fcp_cmd_iu->fcp_cdb, frm->frm_payload + offset, FCP_CDB_SIZE);
1107         /*
1108          * fcp_data_len
1109          */
1110         offset += FCP_CDB_SIZE;
1111         FCOE_V2B_4(fcp_cmd_iu->fcp_data_len, frm->frm_payload + offset);
1112 
1113         /*
1114          * FC frame header
1115          */
1116         FRM2IFM(frm)->ifm_rctl = fpkt->pkt_cmd_fhdr.r_ctl;
1117 
1118         FFM_R_CTL(fpkt->pkt_cmd_fhdr.r_ctl, frm);
1119         FFM_D_ID(fpkt->pkt_cmd_fhdr.d_id, frm);
1120         FFM_S_ID(fpkt->pkt_cmd_fhdr.s_id, frm);
1121         FFM_TYPE(fpkt->pkt_cmd_fhdr.type, frm);
1122         FFM_F_CTL(0x290000, frm);
1123         FFM_OXID(xch->xch_oxid, frm);
1124         FFM_RXID(xch->xch_rxid, frm);
1125 
1126         xch->xch_ss->ss_eport->eport_tx_frame(frm);
1127 }
1128 
1129 /*
1130  * fcoei_initiate_els_req
1131  *      Initiate ELS request
1132  *
1133  * Input:
1134  *      xch = the exchange that will be initiated
1135  *
1136  * Returns:
1137  *      N/A
1138  *
1139  * Comments:
1140  *      N/A
1141  */
1142 static void
1143 fcoei_initiate_els_req(fcoei_exchange_t *xch)
1144 {
1145         fc_packet_t     *fpkt = xch->xch_fpkt;
1146         fcoe_frame_t    *frm;
1147         ls_code_t       *els_code;
1148 
1149         ASSERT((fpkt->pkt_cmdlen % 4) == 0);
1150         frm = xch->xch_ss->ss_eport->eport_alloc_frame(xch->xch_ss->ss_eport,
1151             fpkt->pkt_cmdlen + FCFH_SIZE, NULL);
1152         if (!frm) {
1153                 ASSERT(0);
1154         } else {
1155                 fcoei_init_ifm(frm, xch);
1156                 bzero(frm->frm_payload, fpkt->pkt_cmdlen);
1157         }
1158 
1159         /*
1160          * This will affect timing check
1161          */
1162         xch->xch_cnt = xch->xch_ss->ss_sol_cnt;
1163         atomic_add_32(xch->xch_cnt, 1);
1164 
1165         els_code = (ls_code_t *)(void *)fpkt->pkt_cmd;
1166         switch (els_code->ls_code) {
1167         case LA_ELS_FLOGI:
1168                 /*
1169                  * For FLOGI, we expect response within E_D_TOV
1170                  */
1171                 xch->xch_start_tick = ddi_get_lbolt();
1172                 xch->xch_end_tick = xch->xch_start_tick +
1173                     FCOE_SEC2TICK(2);
1174                 xch->xch_ss->ss_flags &= ~SS_FLAG_FLOGI_FAILED;
1175                 /* FALLTHROUGH */
1176 
1177         case LA_ELS_PLOGI:
1178                 fcoei_fill_els_logi_cmd(fpkt, frm);
1179                 break;
1180 
1181         case LA_ELS_PRLI:
1182                 fcoei_fill_els_prli_cmd(fpkt, frm);
1183                 break;
1184 
1185         case LA_ELS_SCR:
1186                 fcoei_fill_els_scr_cmd(fpkt, frm);
1187                 break;
1188 
1189         case LA_ELS_LINIT:
1190                 fcoei_fill_els_linit_cmd(fpkt, frm);
1191                 break;
1192 
1193         case LA_ELS_ADISC:
1194                 fcoei_fill_els_adisc_cmd(fpkt, frm);
1195                 break;
1196 
1197         case LA_ELS_LOGO:
1198                 /*
1199                  * For LOGO, we expect response within E_D_TOV
1200                  */
1201                 xch->xch_start_tick = ddi_get_lbolt();
1202                 xch->xch_end_tick = xch->xch_start_tick +
1203                     FCOE_SEC2TICK(2);
1204                 fcoei_fill_els_logo_cmd(fpkt, frm);
1205                 break;
1206         case LA_ELS_RLS:
1207                 fcoei_fill_els_rls_cmd(fpkt, frm);
1208                 break;
1209         case LA_ELS_RNID:
1210                 fcoei_fill_els_rnid_cmd(fpkt, frm);
1211                 break;
1212         default:
1213                 fcoei_complete_xch(xch, frm, FC_PKT_FAILURE,
1214                     FC_REASON_CMD_UNSUPPORTED);
1215                 return;
1216         }
1217 
1218         /*
1219          * set ifm_rtcl
1220          */
1221         FRM2IFM(frm)->ifm_rctl = fpkt->pkt_cmd_fhdr.r_ctl;
1222 
1223         /*
1224          * FCPH
1225          */
1226         FFM_R_CTL(fpkt->pkt_cmd_fhdr.r_ctl, frm);
1227         FFM_D_ID(fpkt->pkt_cmd_fhdr.d_id, frm);
1228         FFM_S_ID(fpkt->pkt_cmd_fhdr.s_id, frm);
1229         FFM_TYPE(fpkt->pkt_cmd_fhdr.type, frm);
1230         FFM_F_CTL(0x290000, frm);
1231         FFM_OXID(xch->xch_oxid, frm);
1232         FFM_RXID(xch->xch_rxid, frm);
1233 
1234         xch->xch_ss->ss_eport->eport_tx_frame(frm);
1235 }
1236 
1237 /*
1238  * fcoei_initiate_els_resp
1239  *      Originate ELS response
1240  *
1241  * Input:
1242  *      xch = the associated exchange
1243  *
1244  * Returns:
1245  *      N/A
1246  *
1247  * Comments:
1248  *      N/A
1249  */
1250 static void
1251 fcoei_initiate_els_resp(fcoei_exchange_t *xch)
1252 {
1253         fc_packet_t     *fpkt = xch->xch_fpkt;
1254         fcoe_frame_t    *frm;
1255 
1256         ASSERT((fpkt->pkt_cmdlen % 4) == 0);
1257         frm = xch->xch_ss->ss_eport->eport_alloc_frame(xch->xch_ss->ss_eport,
1258             fpkt->pkt_cmdlen + FCFH_SIZE, NULL);
1259         if (!frm) {
1260                 ASSERT(0);
1261         } else {
1262                 fcoei_init_ifm(frm, xch);
1263                 bzero(frm->frm_payload, fpkt->pkt_cmdlen);
1264         }
1265 
1266         /*
1267          * This will affect timing check
1268          */
1269         xch->xch_cnt = xch->xch_ss->ss_unsol_cnt;
1270         atomic_add_32(xch->xch_cnt, 1);
1271 
1272         /*
1273          * Set ifm_rctl
1274          */
1275         FRM2IFM(frm)->ifm_rctl = fpkt->pkt_cmd_fhdr.r_ctl;
1276 
1277         /*
1278          * FCPH
1279          */
1280         FFM_R_CTL(fpkt->pkt_cmd_fhdr.r_ctl, frm);
1281         FFM_D_ID(fpkt->pkt_cmd_fhdr.d_id, frm);
1282         FFM_S_ID(fpkt->pkt_cmd_fhdr.s_id, frm);
1283         FFM_TYPE(fpkt->pkt_cmd_fhdr.type, frm);
1284         FFM_F_CTL(0x980000, frm);
1285         FFM_OXID(xch->xch_oxid, frm);
1286         FFM_RXID(xch->xch_rxid, frm);
1287 
1288         switch (((uint8_t *)&fpkt->pkt_fca_rsvd1)[0]) {
1289         case LA_ELS_FLOGI:
1290                 fcoei_fill_els_logi_resp(fpkt, frm);
1291                 break;
1292 
1293         case LA_ELS_PLOGI:
1294                 if (FRM2SS(frm)->ss_eport->eport_flags &
1295                     EPORT_FLAG_IS_DIRECT_P2P) {
1296                         FRM2SS(frm)->ss_p2p_info.fca_d_id = FRM_S_ID(frm);
1297                         FRM2SS(frm)->ss_p2p_info.d_id = FRM_D_ID(frm);
1298                 }
1299 
1300                 fcoei_fill_els_logi_resp(fpkt, frm);
1301                 break;
1302 
1303         case LA_ELS_PRLI:
1304                 fcoei_fill_els_prli_resp(fpkt, frm);
1305                 break;
1306 
1307         case LA_ELS_ADISC:
1308                 fcoei_fill_els_adisc_resp(fpkt, frm);
1309                 break;
1310 
1311         case LA_ELS_LOGO:
1312                 fcoei_fill_els_logo_resp(fpkt, frm);
1313                 break;
1314         case LA_ELS_RSCN:
1315                 fcoei_fill_els_acc_resp(fpkt, frm);
1316                 break;
1317 
1318         default:
1319                 fcoei_complete_xch(xch, frm, FC_PKT_FAILURE,
1320                     FC_REASON_CMD_UNSUPPORTED);
1321                 return;
1322         }
1323 
1324         xch->xch_ss->ss_eport->eport_tx_frame(frm);
1325 }
1326 
1327 /*
1328  * fcoei_fill_els_logi_cmd
1329  *      Fill SCR (state change register) command frame
1330  *
1331  * Input:
1332  *      fpkt = LV fc_packet
1333  *      frm = Unsolicited frame containing LOGI response
1334  *
1335  * Returns:
1336  *      N/A
1337  *
1338  * Comments:
1339  *      N/A
1340  */
1341 static void
1342 fcoei_fill_els_logi_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm)
1343 {
1344         la_els_logi_t   *els_logi = (la_els_logi_t *)(void *)fpkt->pkt_cmd;
1345         int              offset;
1346 
1347         /*
1348          * fill ls_code
1349          */
1350         offset = 0;
1351         FCOE_V2B_1(els_logi->ls_code.ls_code, FPLD + offset);
1352 
1353         /*
1354          * fill common service parameters
1355          */
1356         offset = 4;
1357         FCOE_V2B_2(els_logi->common_service.fcph_version, FPLD + offset);
1358 
1359         offset = 6;
1360         FCOE_V2B_2(els_logi->common_service.btob_credit, FPLD + offset);
1361 
1362         offset = 8;
1363         FCOE_V2B_2(els_logi->common_service.cmn_features, FPLD + offset);
1364 
1365         offset = 10;
1366         FCOE_V2B_2(els_logi->common_service.rx_bufsize, FPLD + offset);
1367 
1368         offset = 12;
1369         FCOE_V2B_2(els_logi->common_service.conc_sequences, FPLD + offset);
1370 
1371         offset = 14;
1372         FCOE_V2B_2(els_logi->common_service.relative_offset, FPLD + offset);
1373 
1374         offset = 16;
1375         FCOE_V2B_4(els_logi->common_service.e_d_tov, FPLD + offset);
1376 
1377         /*
1378          * port/node wwn
1379          */
1380         offset = 20;
1381         bcopy(&els_logi->nport_ww_name, FPLD + offset, 8);
1382 
1383         offset = 28;
1384         bcopy(&els_logi->node_ww_name, FPLD + offset, 8);
1385 
1386         /*
1387          * class_3
1388          */
1389         offset = 68;
1390         FCOE_V2B_2(els_logi->class_3.class_opt, FPLD + offset);
1391 
1392         offset = 70;
1393         FCOE_V2B_2(els_logi->class_3.initiator_ctl, FPLD + offset);
1394 
1395         offset = 72;
1396         FCOE_V2B_2(els_logi->class_3.recipient_ctl, FPLD + offset);
1397 
1398         offset = 74;
1399         FCOE_V2B_2(els_logi->class_3.rcv_size, FPLD + offset);
1400 
1401         offset = 76;
1402         FCOE_V2B_2(els_logi->class_3.conc_sequences, FPLD + offset);
1403 
1404         offset = 78;
1405         FCOE_V2B_2(els_logi->class_3.n_port_e_to_e_credit, FPLD + offset);
1406 
1407         offset = 80;
1408         FCOE_V2B_2(els_logi->class_3.open_seq_per_xchng, FPLD + offset);
1409         /*
1410          * needn't touch other fields
1411          */
1412 }
1413 
1414 /*
1415  * fcoei_fill_prli_cmd
1416  *      Fill PRLI command frame
1417  *
1418  * Input:
1419  *      fpkt = LV fc_packet
1420  *      frm = Unsolicited frame containing PRLI response
1421  *
1422  * Returns:
1423  *      N/A
1424  *
1425  * Comments:
1426  *      N/A
1427  */
1428 static void
1429 fcoei_fill_els_prli_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm)
1430 {
1431         int              offset     = 0;
1432         la_els_prli_t   *els_prli   = (la_els_prli_t *)(void *)fpkt->pkt_cmd;
1433         struct fcp_prli *fcp_spp    =
1434             (struct fcp_prli *)(void *)els_prli->service_params;
1435 
1436         /*
1437          * fill basic PRLI fields
1438          */
1439         offset = 0;
1440         FCOE_V2B_1(els_prli->ls_code, FPLD + offset);
1441 
1442         offset = 1;
1443         FCOE_V2B_1(els_prli->page_length, FPLD + offset);
1444 
1445         offset = 2;
1446         FCOE_V2B_2(els_prli->payload_length, FPLD + offset);
1447 
1448         /*
1449          * fill FCP service parameters page
1450          */
1451         offset = 4;
1452         FCOE_V2B_1(fcp_spp->type, FPLD + offset);
1453 
1454         /*
1455          * PRLI flags, only 3 bits are valid
1456          */
1457         offset = 6;
1458 
1459         FCOE_V2B_2(((fcp_spp->orig_process_assoc_valid << 15) |
1460             (fcp_spp->resp_process_assoc_valid << 14) |
1461             (fcp_spp->establish_image_pair << 13)), FPLD + offset);
1462 
1463         /*
1464          * process associator
1465          */
1466         offset = 8;
1467         FCOE_V2B_4(fcp_spp->orig_process_associator, FPLD + offset);
1468 
1469         offset = 12;
1470         FCOE_V2B_4(fcp_spp->resp_process_associator, FPLD + offset);
1471 
1472         /*
1473          * FC-4 type
1474          */
1475         offset = 16;
1476         FCOE_V2B_4((fcp_spp->retry << 8) |
1477             (fcp_spp->confirmed_compl_allowed << 7) |
1478             (fcp_spp->data_overlay_allowed << 6) |
1479             (fcp_spp->initiator_fn << 5) | (fcp_spp->target_fn << 4) |
1480             (fcp_spp->read_xfer_rdy_disabled << 1) |
1481             (fcp_spp->write_xfer_rdy_disabled), FPLD + offset);
1482 }
1483 
1484 /*
1485  * fcoei_fill_els_scr_cmd
1486  *      Fill SCR (state change register) command frame
1487  *
1488  * Input:
1489  *      fpkt = LV fc_packet
1490  *      frm = Unsolicited frame containing SCR command
1491  *
1492  * Returns:
1493  *      N/A
1494  *
1495  * Comments:
1496  *      N/A
1497  */
1498 static void
1499 fcoei_fill_els_scr_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm)
1500 {
1501         fc_scr_req_t    *els_scr = (fc_scr_req_t *)(void *)fpkt->pkt_cmd;
1502         int              offset;
1503 
1504         offset = 0;
1505         FCOE_V2B_1(els_scr->ls_code.ls_code, FPLD + offset);
1506 
1507         offset = 7;
1508         FCOE_V2B_1(els_scr->scr_func, FPLD + offset);
1509 }
1510 
1511 /*
1512  * fcoei_fill_els_adisc_cmd
1513  *      Fill ADISC command frame
1514  *
1515  * Input:
1516  *      fpkt = LV fc_packet
1517  *      frm = Unsolicited frame containing ADISC command
1518  *
1519  * Returns:
1520  *      N/A
1521  *
1522  * Comments:
1523  *      N/A
1524  */
1525 static void
1526 fcoei_fill_els_adisc_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm)
1527 {
1528         la_els_adisc_t  *els_adisc = (la_els_adisc_t *)(void *)fpkt->pkt_cmd;
1529         int              offset;
1530 
1531         offset = 0;
1532         FCOE_V2B_1(els_adisc->ls_code.ls_code, FPLD + offset);
1533 
1534         offset = 5;
1535         FCOE_V2B_3(els_adisc->hard_addr.hard_addr, FPLD + offset);
1536 
1537         offset = 8;
1538         bcopy(&els_adisc->port_wwn, FPLD + offset, 8);
1539 
1540         offset = 16;
1541         bcopy(&els_adisc->node_wwn, FPLD + offset, 8);
1542 
1543         offset = 25;
1544         FCOE_V2B_3(els_adisc->nport_id.port_id, FPLD + offset);
1545 }
1546 
1547 /*
1548  * fcoei_fill_els_linit_cmd
1549  *      Fill LINIT command frame
1550  *
1551  * Input:
1552  *      fpkt = LV fc_packet
1553  *      frm = Unsolicited frame containing LINIT command
1554  *
1555  * Returns:
1556  *      N/A
1557  *
1558  * Comments:
1559  *      N/A
1560  */
1561 /* ARGSUSED */
1562 static void
1563 fcoei_fill_els_linit_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm)
1564 {
1565         ASSERT(fpkt && frm);
1566 }
1567 
1568 /*
1569  * fcoei_fill_els_logo_cmd
1570  *      Fill LOGO command frame
1571  *
1572  * Input:
1573  *      fpkt = LV fc_packet
1574  *      frm = Unsolicited frame containing LOGO command
1575  *
1576  * Returns:
1577  *      N/A
1578  *
1579  * Comments:
1580  *      N/A
1581  */
1582 static void
1583 fcoei_fill_els_logo_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm)
1584 {
1585         la_els_logo_t   *els_logo   = (la_els_logo_t *)(void *)fpkt->pkt_cmd;
1586         int              offset;
1587 
1588         offset = 0;
1589         FCOE_V2B_1(els_logo->ls_code.ls_code, FPLD + offset);
1590 
1591         offset = 5;
1592         FCOE_V2B_3(els_logo->nport_id.port_id, FPLD + offset);
1593 
1594         offset = 8;
1595         bcopy(&els_logo->nport_ww_name, FPLD + offset, 8);
1596 }
1597 
1598 static void
1599 fcoei_fill_els_rls_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm)
1600 {
1601         la_els_rls_t    *els_rls = (la_els_rls_t *)(void *)fpkt->pkt_cmd;
1602         int             offset;
1603 
1604         offset = 0;
1605         FCOE_V2B_1(els_rls->ls_code.ls_code, FPLD + offset);
1606 
1607         offset = 5;
1608         FCOE_V2B_3(els_rls->rls_portid.port_id, FPLD + offset);
1609 }
1610 
1611 static void
1612 fcoei_fill_els_rnid_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm)
1613 {
1614         la_els_rnid_t *els_rnid = (la_els_rnid_t *)(void *)fpkt->pkt_cmd;
1615         int             offset;
1616 
1617         offset = 0;
1618         FCOE_V2B_1(els_rnid->ls_code.ls_code, FPLD + offset);
1619 
1620         offset = 4;
1621         bcopy(&els_rnid->data_format, FPLD + offset, 1);
1622 }
1623 /*
1624  * fcoei_fill_els_acc_resp
1625  *      Fill ELS ACC response frame
1626  *
1627  * Input:
1628  *      fpkt = LV fc_packet
1629  *      frm = Unsolicited frame containing ELS ACC response
1630  *
1631  * Returns:
1632  *      N/A
1633  *
1634  * Comments:
1635  *      N/A
1636  */
1637 static void
1638 fcoei_fill_els_acc_resp(fc_packet_t *fpkt, fcoe_frame_t *frm)
1639 {
1640         ls_code_t       *els_code = (ls_code_t *)(void *)fpkt->pkt_cmd;
1641         int              offset;
1642 
1643         offset = 0;
1644         FCOE_V2B_1(els_code->ls_code, FPLD + offset);
1645 
1646         offset = 1;
1647         FCOE_V2B_3(els_code->mbz, FPLD + offset);
1648 }
1649 
1650 /*
1651  * fcoei_fill_els_rjt_resp
1652  *      Fill ELS RJT response frame
1653  *
1654  * Input:
1655  *      fpkt = LV fc_packet
1656  *      frm = Unsolicited frame containg ELS RJT response
1657  *
1658  * Returns:
1659  *      N/A
1660  *
1661  * Comments:
1662  *      N/A
1663  */
1664 static void
1665 fcoei_fill_els_rjt_resp(fc_packet_t *fpkt, fcoe_frame_t *frm)
1666 {
1667         la_els_rjt_t    *els_rjt = (la_els_rjt_t *)(void *)fpkt->pkt_cmd;
1668         int              offset;
1669 
1670         offset = 0; /* reset ls code */
1671         FCOE_V2B_1(els_rjt->ls_code.ls_code, FPLD + offset);
1672 
1673         offset = 5; /* reason code */
1674         FCOE_V2B_1(els_rjt->action, FPLD + offset);
1675 
1676         offset = 6; /* reason explanation */
1677         FCOE_V2B_1(els_rjt->reason, FPLD + offset);
1678 
1679         offset = 7; /* vendor unique */
1680         FCOE_V2B_1(els_rjt->vu, FPLD + offset);
1681 }
1682 
1683 /*
1684  * fcoei_fill_els_adisc_resp
1685  *      Fill ADISC response frame
1686  *
1687  * Input:
1688  *      fpkt = LV fc_packet
1689  *      frm = Unsolicited frame containing ADISC response
1690  *
1691  * Returns:
1692  *      N/A
1693  *
1694  * Comments:
1695  *      N/A
1696  */
1697 static void
1698 fcoei_fill_els_adisc_resp(fc_packet_t *fpkt, fcoe_frame_t *frm)
1699 {
1700         la_els_adisc_t  *els_adisc = (la_els_adisc_t *)(void *)fpkt->pkt_cmd;
1701         int              offset;
1702 
1703         if (els_adisc->ls_code.ls_code == LA_ELS_RJT) {
1704                 fcoei_fill_els_rjt_resp(fpkt, frm);
1705         } else {
1706                 offset = 0;
1707                 FCOE_V2B_1(els_adisc->ls_code.ls_code, FPLD + offset);
1708 
1709                 offset = 5;
1710                 FCOE_V2B_3(els_adisc->hard_addr.hard_addr, FPLD + offset);
1711 
1712                 offset = 8;
1713                 bcopy(&els_adisc->port_wwn, FPLD + offset, FC_WWN_SIZE);
1714 
1715                 offset = 16;
1716                 bcopy(&els_adisc->node_wwn, FPLD + offset, FC_WWN_SIZE);
1717 
1718                 offset = 25;
1719                 FCOE_V2B_3(els_adisc->nport_id.port_id, FPLD + offset);
1720         }
1721 }
1722 
1723 /*
1724  * fcoei_fill_els_logi_resp
1725  *      Fill FLOGI/PLOGI response frame
1726  *
1727  * Input:
1728  *      fpkt = LV fc_packet
1729  *      frm = Unsolicited frame containing LOGI response
1730  *
1731  * Returns:
1732  *      N/A
1733  *
1734  * Comments:
1735  *      N/A
1736  */
1737 static void
1738 fcoei_fill_els_logi_resp(fc_packet_t *fpkt, fcoe_frame_t *frm)
1739 {
1740         ls_code_t       *els_code = (ls_code_t *)(void *)fpkt->pkt_cmd;
1741 
1742         if (els_code->ls_code == LA_ELS_RJT) {
1743                 fcoei_fill_els_rjt_resp(fpkt, frm);
1744         } else {
1745                 fcoei_fill_els_logi_cmd(fpkt, frm);
1746         }
1747 }
1748 
1749 /*
1750  * fcoei_fill_els_prli_resp
1751  *      Fill PRLI response frame
1752  *
1753  * Input:
1754  *      fpkt = LV fc_packet
1755  *      frm = Unsolicited frame containing PRLI response
1756  *
1757  * Returns:
1758  *      N/A
1759  *
1760  * Comments:
1761  *      N/A
1762  */
1763 static void
1764 fcoei_fill_els_prli_resp(fc_packet_t *fpkt, fcoe_frame_t *frm)
1765 {
1766         ls_code_t       *els_code = (ls_code_t *)(void *)fpkt->pkt_cmd;
1767 
1768         if (els_code->ls_code == LA_ELS_RJT) {
1769                 fcoei_fill_els_rjt_resp(fpkt, frm);
1770         } else {
1771                 fcoei_fill_els_prli_cmd(fpkt, frm);
1772         }
1773 }
1774 
1775 /*
1776  * fcoei_fill_els_logo_resp
1777  *      Fill LOGO response frame
1778  *
1779  * Input:
1780  *      fpkt = LV fc_packet
1781  *      frm = Unsolicited frame containing LOGO response
1782  *
1783  * Returns:
1784  *      N/A
1785  *
1786  * Comments:
1787  *      N/A
1788  */
1789 static void
1790 fcoei_fill_els_logo_resp(fc_packet_t *fpkt, fcoe_frame_t *frm)
1791 {
1792         ls_code_t       *els_code   = (ls_code_t *)(void *)fpkt->pkt_cmd;
1793 
1794         if (els_code->ls_code == LA_ELS_RJT) {
1795                 fcoei_fill_els_rjt_resp(fpkt, frm);
1796         } else {
1797                 fcoei_fill_els_acc_resp(fpkt, frm);
1798         }
1799 }
1800 
1801 /*
1802  * fcoei_logo_peer
1803  *      Send LOGO to the peer to emulate link offline event
1804  *
1805  * Input:
1806  *      arg - fcoei soft state set in fcoei_bind_port
1807  *
1808  * Returns:
1809  *      N/A
1810  *
1811  * Comments:
1812  *      N/A
1813  */
1814 static void
1815 fcoei_logo_peer(void *arg)
1816 {
1817         fcoei_soft_state_t      *ss = (fcoei_soft_state_t *)arg;
1818         fc_packet_t             *fpkt;
1819         fcoei_exchange_t        *xch;
1820         la_els_logo_t           *els_logo;
1821 
1822         /*
1823          * Allocate space for exchange
1824          */
1825         xch = kmem_zalloc(sizeof (*xch), KM_SLEEP);
1826 
1827         /*
1828          * Allocate space for fc_packet
1829          */
1830         fpkt = kmem_zalloc(sizeof (fc_packet_t), KM_SLEEP);
1831         fpkt->pkt_cmdlen = 20;
1832         fpkt->pkt_cmd = kmem_zalloc(fpkt->pkt_cmdlen, KM_SLEEP);
1833         fpkt->pkt_rsplen = 20;
1834         fpkt->pkt_resp = kmem_zalloc(fpkt->pkt_rsplen, KM_SLEEP);
1835 
1836         /*
1837          * Link them together
1838          */
1839         fpkt->pkt_fca_private = xch;
1840         (void) fcoei_init_pkt(ss, fpkt, 0);
1841 
1842         /*
1843          * Initialize FC frame header
1844          */
1845         if (ss->ss_eport->eport_flags & EPORT_FLAG_IS_DIRECT_P2P) {
1846                 fpkt->pkt_cmd_fhdr.d_id = ss->ss_p2p_info.d_id;
1847         } else {
1848                 fpkt->pkt_cmd_fhdr.d_id = 0xFFFFFE;
1849         }
1850 
1851         fpkt->pkt_cmd_fhdr.s_id = ss->ss_p2p_info.fca_d_id;
1852         fpkt->pkt_cmd_fhdr.r_ctl = R_CTL_ELS_REQ;
1853         fpkt->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS;
1854         fpkt->pkt_cmd_fhdr.f_ctl = 0x290000;
1855         fpkt->pkt_timeout = 1;
1856 
1857         /*
1858          * Initialize LOGO payload
1859          */
1860         els_logo = (la_els_logo_t *)(void *)fpkt->pkt_cmd;
1861         els_logo->ls_code.ls_code = LA_ELS_LOGO;
1862         els_logo->nport_id.port_id = ss->ss_p2p_info.fca_d_id;
1863         bcopy(ss->ss_eport->eport_portwwn, &els_logo->nport_ww_name, 8);
1864 
1865         /*
1866          * Set the completion function
1867          */
1868         fpkt->pkt_comp = fcoei_fpkt_comp;
1869         if (fcoei_transport(ss, fpkt) != FC_SUCCESS) {
1870                 FCOEI_LOG(__FUNCTION__, "fcoei_transport LOGO failed");
1871                 fcoei_fpkt_comp(fpkt);
1872         }
1873 }
1874 
1875 /*
1876  * fcoei_fpkt_comp
1877  *      internal exchange completion
1878  *
1879  * Input:
1880  *      fpkt - fc_packet_t to be completed
1881  *
1882  * Returns:
1883  *      N/A
1884  *
1885  * Comments:
1886  *
1887  */
1888 static void
1889 fcoei_fpkt_comp(fc_packet_t *fpkt)
1890 {
1891         fcoei_exchange_t        *xch = FPKT2XCH(fpkt);
1892 
1893         FCOEI_LOG(__FUNCTION__, "internal exchange is completed: %p", xch);
1894 
1895         (void) fcoei_un_init_pkt(xch->xch_ss, xch->xch_fpkt);
1896         kmem_free(xch->xch_fpkt->pkt_cmd, xch->xch_fpkt->pkt_cmdlen);
1897         kmem_free(xch->xch_fpkt->pkt_resp, xch->xch_fpkt->pkt_rsplen);
1898         kmem_free(xch->xch_fpkt, sizeof (fc_packet_t));
1899         kmem_free(xch, sizeof (fcoei_exchange_t));
1900 }
1901 
1902 /*
1903  * fcoei_xch_abort
1904  *      Prepare to abort the exchange
1905  *
1906  * Input:
1907  *      key = oxid/rxid of the exchange
1908  *      val = the exchange
1909  *      arg = the soft state
1910  *
1911  * Returns:
1912  *      MH_WALK_CONTINUE = continue to walk
1913  *
1914  * Comments:
1915  *      N/A
1916  */
1917 /* ARGSUSED */
1918 static uint32_t
1919 fcoei_xch_abort(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
1920 {
1921         fcoei_exchange_t        *xch = (fcoei_exchange_t *)val;
1922 
1923         ASSERT(arg == xch->xch_ss);
1924         ASSERT(CMHK(key) != 0xFFFF);
1925         xch->xch_flags |= XCH_FLAG_ABORT;
1926         xch->xch_fpkt->pkt_state = FC_PKT_LOCAL_RJT;
1927         xch->xch_fpkt->pkt_reason = FC_REASON_OFFLINE;
1928         list_insert_tail(&xch->xch_ss->ss_comp_xch_list, xch);
1929         return (MH_WALK_CONTINUE);
1930 }
1931 
1932 /*
1933  * fcoei_init_fcatran_vectors
1934  *      Initialize fc_fca_tran vectors that are defined in this file
1935  *
1936  * Input:
1937  *      fcatran - fc_fca_tran of the soft state
1938  *
1939  * Returns:
1940  *      N/A
1941  *
1942  * Comments:
1943  *      N/A
1944  */
1945 void
1946 fcoei_init_fcatran_vectors(fc_fca_tran_t *fcatran)
1947 {
1948         fcatran->fca_bind_port        = fcoei_bind_port;
1949         fcatran->fca_unbind_port = fcoei_unbind_port;
1950         fcatran->fca_init_pkt         = fcoei_init_pkt;
1951         fcatran->fca_un_init_pkt = fcoei_un_init_pkt;
1952         fcatran->fca_els_send         = fcoei_els_send;
1953         fcatran->fca_get_cap  = fcoei_get_cap;
1954         fcatran->fca_set_cap  = fcoei_set_cap;
1955         fcatran->fca_getmap   = fcoei_getmap;
1956         fcatran->fca_transport        = fcoei_transport;
1957         fcatran->fca_ub_alloc         = fcoei_ub_alloc;
1958         fcatran->fca_ub_free  = fcoei_ub_free;
1959         fcatran->fca_ub_release       = fcoei_ub_release;
1960         fcatran->fca_abort    = fcoei_abort;
1961         fcatran->fca_reset    = fcoei_reset;
1962         fcatran->fca_port_manage = fcoei_port_manage;
1963         fcatran->fca_get_device       = fcoei_get_device;
1964         fcatran->fca_notify   = fcoei_notify;
1965 }
1966 
1967 /*
1968  * fcoei_process_event_reset
1969  *      link reset phase II
1970  *
1971  * Input:
1972  *      arg - fcoei soft state set in fcoei_bind_port
1973  *
1974  * Returns:
1975  *      N/A
1976  *
1977  * Comments:
1978  *
1979  */
1980 void
1981 fcoei_process_event_reset(fcoei_event_t *ae)
1982 {
1983         fcoei_soft_state_t      *ss = (fcoei_soft_state_t *)ae->ae_obj;
1984 
1985         ASSERT(!MUTEX_HELD(&ss->ss_watchdog_mutex));
1986         kmem_free(ae, sizeof (*ae));
1987 
1988         mod_hash_walk(ss->ss_sol_oxid_hash, fcoei_xch_abort, ss);
1989         mod_hash_walk(ss->ss_unsol_rxid_hash, fcoei_xch_abort, ss);
1990         fcoei_handle_comp_xch_list(ss);
1991 
1992         /*
1993          * Notify LV that the link is up now
1994          */
1995         ss->ss_eport->eport_ctl(ss->ss_eport, FCOE_CMD_PORT_ONLINE, 0);
1996 }
1997 
1998 /*
1999  * fcoei_process_event_exchange
2000  *      Process exchange in the single thread context
2001  *
2002  * Input:
2003  *      ae = the exchange event
2004  *
2005  * Returns:
2006  *      N/A
2007  *
2008  * Comments:
2009  *      N/A
2010  */
2011 void
2012 fcoei_process_event_exchange(fcoei_event_t *ae)
2013 {
2014         fcoei_exchange_t        *xch  = (fcoei_exchange_t *)ae->ae_obj;
2015         fcoei_exchange_t        *xch_tmp;
2016         fc_packet_t             *fpkt = xch->xch_fpkt;
2017 
2018         /*
2019          * These 4 elements need reset, pkt_state & pkt_reason will be set
2020          */
2021         fpkt->pkt_action = 0;
2022         fpkt->pkt_expln = 0;
2023         fpkt->pkt_data_resid = 0;
2024         fpkt->pkt_resp_resid = 0;
2025 
2026         /*
2027          * port state sanity checking
2028          */
2029         if ((xch->xch_ss->ss_link_state != FC_STATE_ONLINE) ||
2030             xch->xch_ss->ss_port_event_counter) {
2031                 /*
2032                  * LV will retry it after one second
2033                  */
2034                 fcoei_complete_xch(xch, NULL, FC_PKT_PORT_OFFLINE,
2035                     FC_REASON_OFFLINE);
2036                 return;
2037         }
2038 
2039         switch (fpkt->pkt_cmd_fhdr.r_ctl) {
2040         case R_CTL_COMMAND:
2041                 FCOEI_INIT_SOL_ID_HASH(xch, xch_tmp);
2042                 fcoei_initiate_fcp_cmd(xch);
2043                 break;
2044 
2045         case R_CTL_ELS_REQ:
2046                 FCOEI_INIT_SOL_ID_HASH(xch, xch_tmp);
2047                 fcoei_initiate_els_req(xch);
2048                 break;
2049 
2050         case R_CTL_UNSOL_CONTROL:
2051                 FCOEI_INIT_SOL_ID_HASH(xch, xch_tmp);
2052                 fcoei_initiate_ct_req(xch);
2053                 break;
2054 
2055         case R_CTL_ELS_RSP:
2056                 /*
2057                  * Caution: in leadville, it still uses pkt_cmd_fhdr
2058                  * oxid & rxid have been decided when we get unsolicited frames.
2059                  * pkt_cmd_fhdr has contained the right oxid and rxid now.
2060                  */
2061                 FCOEI_INIT_UNSOL_ID_HASH(xch);
2062                 fcoei_initiate_els_resp(xch);
2063                 break;
2064 
2065         default:
2066                 fcoei_complete_xch(xch, NULL, FC_PKT_FAILURE,
2067                     FC_REASON_CMD_UNSUPPORTED);
2068         }
2069 }