Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  bfa_fcs_lport.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
 * Copyright (c) 2014- QLogic Corporation.
 * All rights reserved
 * www.qlogic.com
 *
 * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
 */


#include "bfad_drv.h"
#include "bfad_im.h"
#include "bfa_fcs.h"
#include "bfa_fcbuild.h"
#include "bfa_fc.h"

BFA_TRC_FILE(FCS, PORT);

/*
 * ALPA to LIXA bitmap mapping
 *
 * ALPA 0x00 (Word 0, Bit 30) is invalid for N_Ports. Also Word 0 Bit 31
 * is for L_bit (login required) and is filled as ALPA 0x00 here.
 */

static const u8 loop_alpa_map[] = {
 0x00, 0x00, 0x01, 0x02, 0x04, 0x08, 0x0F, 0x10, /* Word 0 Bits 31..24 */
 0x17, 0x18, 0x1B, 0x1D, 0x1E, 0x1F, 0x23, 0x25, /* Word 0 Bits 23..16 */
 0x26, 0x27, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, /* Word 0 Bits 15..08 */
 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x39, 0x3A, /* Word 0 Bits 07..00 */

 0x3C, 0x43, 0x45, 0x46, 0x47, 0x49, 0x4A, 0x4B, /* Word 1 Bits 31..24 */
 0x4C, 0x4D, 0x4E, 0x51, 0x52, 0x53, 0x54, 0x55, /* Word 1 Bits 23..16 */
 0x56, 0x59, 0x5A, 0x5C, 0x63, 0x65, 0x66, 0x67, /* Word 1 Bits 15..08 */
 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x71, 0x72, /* Word 1 Bits 07..00 */

 0x73, 0x74, 0x75, 0x76, 0x79, 0x7A, 0x7C, 0x80, /* Word 2 Bits 31..24 */
 0x81, 0x82, 0x84, 0x88, 0x8F, 0x90, 0x97, 0x98, /* Word 2 Bits 23..16 */
 0x9B, 0x9D, 0x9E, 0x9F, 0xA3, 0xA5, 0xA6, 0xA7, /* Word 2 Bits 15..08 */
 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xB1, 0xB2, /* Word 2 Bits 07..00 */

 0xB3, 0xB4, 0xB5, 0xB6, 0xB9, 0xBA, 0xBC, 0xC3, /* Word 3 Bits 31..24 */
 0xC5, 0xC6, 0xC7, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, /* Word 3 Bits 23..16 */
 0xCE, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD9, /* Word 3 Bits 15..08 */
 0xDA, 0xDC, 0xE0, 0xE1, 0xE2, 0xE4, 0xE8, 0xEF, /* Word 3 Bits 07..00 */
};

static void     bfa_fcs_lport_send_ls_rjt(struct bfa_fcs_lport_s *port,
      struct fchs_s *rx_fchs, u8 reason_code,
      u8 reason_code_expl);
static void     bfa_fcs_lport_plogi(struct bfa_fcs_lport_s *port,
   struct fchs_s *rx_fchs, struct fc_logi_s *plogi);
static void     bfa_fcs_lport_online_actions(struct bfa_fcs_lport_s *port);
static void     bfa_fcs_lport_offline_actions(struct bfa_fcs_lport_s *port);
static void     bfa_fcs_lport_unknown_init(struct bfa_fcs_lport_s *port);
static void     bfa_fcs_lport_unknown_online(struct bfa_fcs_lport_s *port);
static void     bfa_fcs_lport_unknown_offline(struct bfa_fcs_lport_s *port);
static void     bfa_fcs_lport_deleted(struct bfa_fcs_lport_s *port);
static void     bfa_fcs_lport_echo(struct bfa_fcs_lport_s *port,
   struct fchs_s *rx_fchs,
   struct fc_echo_s *echo, u16 len);
static void     bfa_fcs_lport_rnid(struct bfa_fcs_lport_s *port,
   struct fchs_s *rx_fchs,
   struct fc_rnid_cmd_s *rnid, u16 len);
static void     bfa_fs_port_get_gen_topo_data(struct bfa_fcs_lport_s *port,
   struct fc_rnid_general_topology_data_s *gen_topo_data);

static void bfa_fcs_lport_fab_init(struct bfa_fcs_lport_s *port);
static void bfa_fcs_lport_fab_online(struct bfa_fcs_lport_s *port);
static void bfa_fcs_lport_fab_offline(struct bfa_fcs_lport_s *port);

static void bfa_fcs_lport_n2n_init(struct bfa_fcs_lport_s *port);
static void bfa_fcs_lport_n2n_online(struct bfa_fcs_lport_s *port);
static void bfa_fcs_lport_n2n_offline(struct bfa_fcs_lport_s *port);

static void bfa_fcs_lport_loop_init(struct bfa_fcs_lport_s *port);
static void bfa_fcs_lport_loop_online(struct bfa_fcs_lport_s *port);
static void bfa_fcs_lport_loop_offline(struct bfa_fcs_lport_s *port);

static struct {
 void  (*init) (struct bfa_fcs_lport_s *port);
 void  (*online) (struct bfa_fcs_lport_s *port);
 void  (*offline) (struct bfa_fcs_lport_s *port);
} __port_action[] = {
 [BFA_FCS_FABRIC_UNKNOWN] = {
  .init = bfa_fcs_lport_unknown_init,
  .online = bfa_fcs_lport_unknown_online,
  .offline = bfa_fcs_lport_unknown_offline
 },
 [BFA_FCS_FABRIC_SWITCHED] = {
  .init = bfa_fcs_lport_fab_init,
  .online = bfa_fcs_lport_fab_online,
  .offline = bfa_fcs_lport_fab_offline
 },
 [BFA_FCS_FABRIC_N2N] = {
  .init = bfa_fcs_lport_n2n_init,
  .online = bfa_fcs_lport_n2n_online,
  .offline = bfa_fcs_lport_n2n_offline
 },
 [BFA_FCS_FABRIC_LOOP] = {
  .init = bfa_fcs_lport_loop_init,
  .online = bfa_fcs_lport_loop_online,
  .offline = bfa_fcs_lport_loop_offline
 },
};

static void     bfa_fcs_lport_sm_uninit(struct bfa_fcs_lport_s *port,
     enum bfa_fcs_lport_event event);
static void     bfa_fcs_lport_sm_init(struct bfa_fcs_lport_s *port,
     enum bfa_fcs_lport_event event);
static void     bfa_fcs_lport_sm_online(struct bfa_fcs_lport_s *port,
     enum bfa_fcs_lport_event event);
static void     bfa_fcs_lport_sm_offline(struct bfa_fcs_lport_s *port,
     enum bfa_fcs_lport_event event);
static void     bfa_fcs_lport_sm_deleting(struct bfa_fcs_lport_s *port,
     enum bfa_fcs_lport_event event);
static void bfa_fcs_lport_sm_stopping(struct bfa_fcs_lport_s *port,
     enum bfa_fcs_lport_event event);

static void
bfa_fcs_lport_sm_uninit(
 struct bfa_fcs_lport_s *port,
 enum bfa_fcs_lport_event event)
{
 bfa_trc(port->fcs, port->port_cfg.pwwn);
 bfa_trc(port->fcs, event);

 switch (event) {
 case BFA_FCS_PORT_SM_CREATE:
  bfa_sm_set_state(port, bfa_fcs_lport_sm_init);
  break;

 default:
  bfa_sm_fault(port->fcs, event);
 }
}

static void
bfa_fcs_lport_sm_init(struct bfa_fcs_lport_s *port,
   enum bfa_fcs_lport_event event)
{
 bfa_trc(port->fcs, port->port_cfg.pwwn);
 bfa_trc(port->fcs, event);

 switch (event) {
 case BFA_FCS_PORT_SM_ONLINE:
  bfa_sm_set_state(port, bfa_fcs_lport_sm_online);
  bfa_fcs_lport_online_actions(port);
  break;

 case BFA_FCS_PORT_SM_DELETE:
  bfa_sm_set_state(port, bfa_fcs_lport_sm_uninit);
  bfa_fcs_lport_deleted(port);
  break;

 case BFA_FCS_PORT_SM_STOP:
  /* If vport - send completion call back */
  if (port->vport)
   bfa_fcs_vport_stop_comp(port->vport);
  else
   bfa_wc_down(&(port->fabric->stop_wc));
  break;

 case BFA_FCS_PORT_SM_OFFLINE:
  break;

 default:
  bfa_sm_fault(port->fcs, event);
 }
}

static void
bfa_fcs_lport_sm_online(
 struct bfa_fcs_lport_s *port,
 enum bfa_fcs_lport_event event)
{
 struct bfa_fcs_rport_s *rport;
 struct list_head  *qe, *qen;

 bfa_trc(port->fcs, port->port_cfg.pwwn);
 bfa_trc(port->fcs, event);

 switch (event) {
 case BFA_FCS_PORT_SM_OFFLINE:
  bfa_sm_set_state(port, bfa_fcs_lport_sm_offline);
  bfa_fcs_lport_offline_actions(port);
  break;

 case BFA_FCS_PORT_SM_STOP:
  __port_action[port->fabric->fab_type].offline(port);

  if (port->num_rports == 0) {
   bfa_sm_set_state(port, bfa_fcs_lport_sm_init);
   /* If vport - send completion call back */
   if (port->vport)
    bfa_fcs_vport_stop_comp(port->vport);
   else
    bfa_wc_down(&(port->fabric->stop_wc));
  } else {
   bfa_sm_set_state(port, bfa_fcs_lport_sm_stopping);
   list_for_each_safe(qe, qen, &port->rport_q) {
    rport = (struct bfa_fcs_rport_s *) qe;
    bfa_sm_send_event(rport, RPSM_EVENT_DELETE);
   }
  }
  break;

 case BFA_FCS_PORT_SM_DELETE:

  __port_action[port->fabric->fab_type].offline(port);

  if (port->num_rports == 0) {
   bfa_sm_set_state(port, bfa_fcs_lport_sm_uninit);
   bfa_fcs_lport_deleted(port);
  } else {
   bfa_sm_set_state(port, bfa_fcs_lport_sm_deleting);
   list_for_each_safe(qe, qen, &port->rport_q) {
    rport = (struct bfa_fcs_rport_s *) qe;
    bfa_sm_send_event(rport, RPSM_EVENT_DELETE);
   }
  }
  break;

 case BFA_FCS_PORT_SM_DELRPORT:
  break;

 default:
  bfa_sm_fault(port->fcs, event);
 }
}

static void
bfa_fcs_lport_sm_offline(
 struct bfa_fcs_lport_s *port,
 enum bfa_fcs_lport_event event)
{
 struct bfa_fcs_rport_s *rport;
 struct list_head  *qe, *qen;

 bfa_trc(port->fcs, port->port_cfg.pwwn);
 bfa_trc(port->fcs, event);

 switch (event) {
 case BFA_FCS_PORT_SM_ONLINE:
  bfa_sm_set_state(port, bfa_fcs_lport_sm_online);
  bfa_fcs_lport_online_actions(port);
  break;

 case BFA_FCS_PORT_SM_STOP:
  if (port->num_rports == 0) {
   bfa_sm_set_state(port, bfa_fcs_lport_sm_init);
   /* If vport - send completion call back */
   if (port->vport)
    bfa_fcs_vport_stop_comp(port->vport);
   else
    bfa_wc_down(&(port->fabric->stop_wc));
  } else {
   bfa_sm_set_state(port, bfa_fcs_lport_sm_stopping);
   list_for_each_safe(qe, qen, &port->rport_q) {
    rport = (struct bfa_fcs_rport_s *) qe;
    bfa_sm_send_event(rport, RPSM_EVENT_DELETE);
   }
  }
  break;

 case BFA_FCS_PORT_SM_DELETE:
  if (port->num_rports == 0) {
   bfa_sm_set_state(port, bfa_fcs_lport_sm_uninit);
   bfa_fcs_lport_deleted(port);
  } else {
   bfa_sm_set_state(port, bfa_fcs_lport_sm_deleting);
   list_for_each_safe(qe, qen, &port->rport_q) {
    rport = (struct bfa_fcs_rport_s *) qe;
    bfa_sm_send_event(rport, RPSM_EVENT_DELETE);
   }
  }
  break;

 case BFA_FCS_PORT_SM_DELRPORT:
 case BFA_FCS_PORT_SM_OFFLINE:
  break;

 default:
  bfa_sm_fault(port->fcs, event);
 }
}

static void
bfa_fcs_lport_sm_stopping(struct bfa_fcs_lport_s *port,
     enum bfa_fcs_lport_event event)
{
 bfa_trc(port->fcs, port->port_cfg.pwwn);
 bfa_trc(port->fcs, event);

 switch (event) {
 case BFA_FCS_PORT_SM_DELRPORT:
  if (port->num_rports == 0) {
   bfa_sm_set_state(port, bfa_fcs_lport_sm_init);
   /* If vport - send completion call back */
   if (port->vport)
    bfa_fcs_vport_stop_comp(port->vport);
   else
    bfa_wc_down(&(port->fabric->stop_wc));
  }
  break;

 default:
  bfa_sm_fault(port->fcs, event);
 }
}

static void
bfa_fcs_lport_sm_deleting(
 struct bfa_fcs_lport_s *port,
 enum bfa_fcs_lport_event event)
{
 bfa_trc(port->fcs, port->port_cfg.pwwn);
 bfa_trc(port->fcs, event);

 switch (event) {
 case BFA_FCS_PORT_SM_DELRPORT:
  if (port->num_rports == 0) {
   bfa_sm_set_state(port, bfa_fcs_lport_sm_uninit);
   bfa_fcs_lport_deleted(port);
  }
  break;

 default:
  bfa_sm_fault(port->fcs, event);
 }
}

/*
 *  fcs_port_pvt
 */


/*
 * Send AEN notification
 */

static void
bfa_fcs_lport_aen_post(struct bfa_fcs_lport_s *port,
   enum bfa_lport_aen_event event)
{
 struct bfad_s *bfad = (struct bfad_s *)port->fabric->fcs->bfad;
 struct bfa_aen_entry_s  *aen_entry;

 bfad_get_aen_entry(bfad, aen_entry);
 if (!aen_entry)
  return;

 aen_entry->aen_data.lport.vf_id = port->fabric->vf_id;
 aen_entry->aen_data.lport.roles = port->port_cfg.roles;
 aen_entry->aen_data.lport.ppwwn = bfa_fcs_lport_get_pwwn(
     bfa_fcs_get_base_port(port->fcs));
 aen_entry->aen_data.lport.lpwwn = bfa_fcs_lport_get_pwwn(port);

 /* Send the AEN notification */
 bfad_im_post_vendor_event(aen_entry, bfad, ++port->fcs->fcs_aen_seq,
      BFA_AEN_CAT_LPORT, event);
}

/*
 * Send a LS reject
 */

static void
bfa_fcs_lport_send_ls_rjt(struct bfa_fcs_lport_s *port, struct fchs_s *rx_fchs,
    u8 reason_code, u8 reason_code_expl)
{
 struct fchs_s fchs;
 struct bfa_fcxp_s *fcxp;
 struct bfa_rport_s *bfa_rport = NULL;
 int  len;

 bfa_trc(port->fcs, rx_fchs->d_id);
 bfa_trc(port->fcs, rx_fchs->s_id);

 fcxp = bfa_fcs_fcxp_alloc(port->fcs, BFA_FALSE);
 if (!fcxp)
  return;

 len = fc_ls_rjt_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
         rx_fchs->s_id, bfa_fcs_lport_get_fcid(port),
         rx_fchs->ox_id, reason_code, reason_code_expl);

 bfa_fcxp_send(fcxp, bfa_rport, port->fabric->vf_id, port->lp_tag,
     BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, NULL,
     FC_MAX_PDUSZ, 0);
}

/*
 * Send a FCCT Reject
 */

static void
bfa_fcs_lport_send_fcgs_rjt(struct bfa_fcs_lport_s *port,
 struct fchs_s *rx_fchs, u8 reason_code, u8 reason_code_expl)
{
 struct fchs_s   fchs;
 struct bfa_fcxp_s *fcxp;
 struct bfa_rport_s *bfa_rport = NULL;
 int             len;
 struct ct_hdr_s *rx_cthdr = (struct ct_hdr_s *)(rx_fchs + 1);
 struct ct_hdr_s *ct_hdr;

 bfa_trc(port->fcs, rx_fchs->d_id);
 bfa_trc(port->fcs, rx_fchs->s_id);

 fcxp = bfa_fcs_fcxp_alloc(port->fcs, BFA_FALSE);
 if (!fcxp)
  return;

 ct_hdr = bfa_fcxp_get_reqbuf(fcxp);
 ct_hdr->gs_type = rx_cthdr->gs_type;
 ct_hdr->gs_sub_type = rx_cthdr->gs_sub_type;

 len = fc_gs_rjt_build(&fchs, ct_hdr, rx_fchs->s_id,
   bfa_fcs_lport_get_fcid(port),
   rx_fchs->ox_id, reason_code, reason_code_expl);

 bfa_fcxp_send(fcxp, bfa_rport, port->fabric->vf_id, port->lp_tag,
   BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, NULL,
   FC_MAX_PDUSZ, 0);
}

/*
 * Process incoming plogi from a remote port.
 */

static void
bfa_fcs_lport_plogi(struct bfa_fcs_lport_s *port,
  struct fchs_s *rx_fchs, struct fc_logi_s *plogi)
{
 struct bfa_fcs_rport_s *rport;

 bfa_trc(port->fcs, rx_fchs->d_id);
 bfa_trc(port->fcs, rx_fchs->s_id);

 /*
 * If min cfg mode is enabled, drop any incoming PLOGIs
 */

 if (__fcs_min_cfg(port->fcs)) {
  bfa_trc(port->fcs, rx_fchs->s_id);
  return;
 }

 if (fc_plogi_parse(rx_fchs) != FC_PARSE_OK) {
  bfa_trc(port->fcs, rx_fchs->s_id);
  /*
 * send a LS reject
 */

  bfa_fcs_lport_send_ls_rjt(port, rx_fchs,
     FC_LS_RJT_RSN_PROTOCOL_ERROR,
     FC_LS_RJT_EXP_SPARMS_ERR_OPTIONS);
  return;
 }

 /*
 * Direct Attach P2P mode : verify address assigned by the r-port.
 */

 if ((!bfa_fcs_fabric_is_switched(port->fabric)) &&
  (memcmp((void *)&bfa_fcs_lport_get_pwwn(port),
      (void *)&plogi->port_name, sizeof(wwn_t)) < 0)) {
  if (BFA_FCS_PID_IS_WKA(rx_fchs->d_id)) {
   /* Address assigned to us cannot be a WKA */
   bfa_fcs_lport_send_ls_rjt(port, rx_fchs,
     FC_LS_RJT_RSN_PROTOCOL_ERROR,
     FC_LS_RJT_EXP_INVALID_NPORT_ID);
   return;
  }
  port->pid  = rx_fchs->d_id;
  bfa_lps_set_n2n_pid(port->fabric->lps, rx_fchs->d_id);
 }

 /*
 * First, check if we know the device by pwwn.
 */

 rport = bfa_fcs_lport_get_rport_by_pwwn(port, plogi->port_name);
 if (rport) {
  /*
 * Direct Attach P2P mode : handle address assigned by r-port.
 */

  if ((!bfa_fcs_fabric_is_switched(port->fabric)) &&
   (memcmp((void *)&bfa_fcs_lport_get_pwwn(port),
   (void *)&plogi->port_name, sizeof(wwn_t)) < 0)) {
   port->pid  = rx_fchs->d_id;
   bfa_lps_set_n2n_pid(port->fabric->lps, rx_fchs->d_id);
   rport->pid = rx_fchs->s_id;
  }
  bfa_fcs_rport_plogi(rport, rx_fchs, plogi);
  return;
 }

 /*
 * Next, lookup rport by PID.
 */

 rport = bfa_fcs_lport_get_rport_by_pid(port, rx_fchs->s_id);
 if (!rport) {
  /*
 * Inbound PLOGI from a new device.
 */

  bfa_fcs_rport_plogi_create(port, rx_fchs, plogi);
  return;
 }

 /*
 * Rport is known only by PID.
 */

 if (rport->pwwn) {
  /*
 * This is a different device with the same pid. Old device
 * disappeared. Send implicit LOGO to old device.
 */

  WARN_ON(rport->pwwn == plogi->port_name);
  bfa_sm_send_event(rport, RPSM_EVENT_LOGO_IMP);

  /*
 * Inbound PLOGI from a new device (with old PID).
 */

  bfa_fcs_rport_plogi_create(port, rx_fchs, plogi);
  return;
 }

 /*
 * PLOGI crossing each other.
 */

 WARN_ON(rport->pwwn != WWN_NULL);
 bfa_fcs_rport_plogi(rport, rx_fchs, plogi);
}

/*
 * Process incoming ECHO.
 * Since it does not require a login, it is processed here.
 */

static void
bfa_fcs_lport_echo(struct bfa_fcs_lport_s *port, struct fchs_s *rx_fchs,
  struct fc_echo_s *echo, u16 rx_len)
{
 struct fchs_s  fchs;
 struct bfa_fcxp_s *fcxp;
 struct bfa_rport_s *bfa_rport = NULL;
 int   len, pyld_len;

 bfa_trc(port->fcs, rx_fchs->s_id);
 bfa_trc(port->fcs, rx_fchs->d_id);

 fcxp = bfa_fcs_fcxp_alloc(port->fcs, BFA_FALSE);
 if (!fcxp)
  return;

 len = fc_ls_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
    rx_fchs->s_id, bfa_fcs_lport_get_fcid(port),
    rx_fchs->ox_id);

 /*
 * Copy the payload (if any) from the echo frame
 */

 pyld_len = rx_len - sizeof(struct fchs_s);
 bfa_trc(port->fcs, rx_len);
 bfa_trc(port->fcs, pyld_len);

 if (pyld_len > len)
  memcpy(((u8 *) bfa_fcxp_get_reqbuf(fcxp)) +
   sizeof(struct fc_echo_s), (echo + 1),
   (pyld_len - sizeof(struct fc_echo_s)));

 bfa_fcxp_send(fcxp, bfa_rport, port->fabric->vf_id, port->lp_tag,
   BFA_FALSE, FC_CLASS_3, pyld_len, &fchs, NULL, NULL,
   FC_MAX_PDUSZ, 0);
}

/*
 * Process incoming RNID.
 * Since it does not require a login, it is processed here.
 */

static void
bfa_fcs_lport_rnid(struct bfa_fcs_lport_s *port, struct fchs_s *rx_fchs,
  struct fc_rnid_cmd_s *rnid, u16 rx_len)
{
 struct fc_rnid_common_id_data_s common_id_data;
 struct fc_rnid_general_topology_data_s gen_topo_data;
 struct fchs_s fchs;
 struct bfa_fcxp_s *fcxp;
 struct bfa_rport_s *bfa_rport = NULL;
 u16 len;
 u32 data_format;

 bfa_trc(port->fcs, rx_fchs->s_id);
 bfa_trc(port->fcs, rx_fchs->d_id);
 bfa_trc(port->fcs, rx_len);

 fcxp = bfa_fcs_fcxp_alloc(port->fcs, BFA_FALSE);
 if (!fcxp)
  return;

 /*
 * Check Node Indentification Data Format
 * We only support General Topology Discovery Format.
 * For any other requested Data Formats, we return Common Node Id Data
 * only, as per FC-LS.
 */

 bfa_trc(port->fcs, rnid->node_id_data_format);
 if (rnid->node_id_data_format == RNID_NODEID_DATA_FORMAT_DISCOVERY) {
  data_format = RNID_NODEID_DATA_FORMAT_DISCOVERY;
  /*
 * Get General topology data for this port
 */

  bfa_fs_port_get_gen_topo_data(port, &gen_topo_data);
 } else {
  data_format = RNID_NODEID_DATA_FORMAT_COMMON;
 }

 /*
 * Copy the Node Id Info
 */

 common_id_data.port_name = bfa_fcs_lport_get_pwwn(port);
 common_id_data.node_name = bfa_fcs_lport_get_nwwn(port);

 len = fc_rnid_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
    rx_fchs->s_id, bfa_fcs_lport_get_fcid(port),
    rx_fchs->ox_id, data_format, &common_id_data,
    &gen_topo_data);

 bfa_fcxp_send(fcxp, bfa_rport, port->fabric->vf_id, port->lp_tag,
   BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, NULL,
   FC_MAX_PDUSZ, 0);
}

/*
 *  Fill out General Topolpgy Discovery Data for RNID ELS.
 */

static void
bfa_fs_port_get_gen_topo_data(struct bfa_fcs_lport_s *port,
   struct fc_rnid_general_topology_data_s *gen_topo_data)
{
 memset(gen_topo_data, 0,
        sizeof(struct fc_rnid_general_topology_data_s));

 gen_topo_data->asso_type = cpu_to_be32(RNID_ASSOCIATED_TYPE_HOST);
 gen_topo_data->phy_port_num = 0; /* @todo */
 gen_topo_data->num_attached_nodes = cpu_to_be32(1);
}

static void
bfa_fcs_lport_online_actions(struct bfa_fcs_lport_s *port)
{
 struct bfad_s *bfad = (struct bfad_s *)port->fcs->bfad;
 char lpwwn_buf[BFA_STRING_32];

 bfa_trc(port->fcs, port->fabric->oper_type);

 __port_action[port->fabric->fab_type].init(port);
 __port_action[port->fabric->fab_type].online(port);

 wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(port));
 BFA_LOG(KERN_WARNING, bfad, bfa_log_level,
  "Logical port online: WWN = %s Role = %s\n",
  lpwwn_buf, "Initiator");
 bfa_fcs_lport_aen_post(port, BFA_LPORT_AEN_ONLINE);

 bfad->bfad_flags |= BFAD_PORT_ONLINE;
}

static void
bfa_fcs_lport_offline_actions(struct bfa_fcs_lport_s *port)
{
 struct list_head *qe, *qen;
 struct bfa_fcs_rport_s *rport;
 struct bfad_s *bfad = (struct bfad_s *)port->fcs->bfad;
 char    lpwwn_buf[BFA_STRING_32];

 bfa_trc(port->fcs, port->fabric->oper_type);

 __port_action[port->fabric->fab_type].offline(port);

 wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(port));
 if (bfa_sm_cmp_state(port->fabric,
   bfa_fcs_fabric_sm_online) == BFA_TRUE) {
  BFA_LOG(KERN_WARNING, bfad, bfa_log_level,
  "Logical port lost fabric connectivity: WWN = %s Role = %s\n",
  lpwwn_buf, "Initiator");
  bfa_fcs_lport_aen_post(port, BFA_LPORT_AEN_DISCONNECT);
 } else {
  BFA_LOG(KERN_WARNING, bfad, bfa_log_level,
  "Logical port taken offline: WWN = %s Role = %s\n",
  lpwwn_buf, "Initiator");
  bfa_fcs_lport_aen_post(port, BFA_LPORT_AEN_OFFLINE);
 }

 list_for_each_safe(qe, qen, &port->rport_q) {
  rport = (struct bfa_fcs_rport_s *) qe;
  bfa_sm_send_event(rport, RPSM_EVENT_LOGO_IMP);
 }
}

static void
bfa_fcs_lport_unknown_init(struct bfa_fcs_lport_s *port)
{
 WARN_ON(1);
}

static void
bfa_fcs_lport_unknown_online(struct bfa_fcs_lport_s *port)
{
 WARN_ON(1);
}

static void
bfa_fcs_lport_unknown_offline(struct bfa_fcs_lport_s *port)
{
 WARN_ON(1);
}

static void
bfa_fcs_lport_abts_acc(struct bfa_fcs_lport_s *port, struct fchs_s *rx_fchs)
{
 struct fchs_s fchs;
 struct bfa_fcxp_s *fcxp;
 int  len;

 bfa_trc(port->fcs, rx_fchs->d_id);
 bfa_trc(port->fcs, rx_fchs->s_id);

 fcxp = bfa_fcs_fcxp_alloc(port->fcs, BFA_FALSE);
 if (!fcxp)
  return;

 len = fc_ba_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
   rx_fchs->s_id, bfa_fcs_lport_get_fcid(port),
   rx_fchs->ox_id, 0);

 bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag,
     BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, NULL,
     FC_MAX_PDUSZ, 0);
}
static void
bfa_fcs_lport_deleted(struct bfa_fcs_lport_s *port)
{
 struct bfad_s *bfad = (struct bfad_s *)port->fcs->bfad;
 char    lpwwn_buf[BFA_STRING_32];

 wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(port));
 BFA_LOG(KERN_INFO, bfad, bfa_log_level,
  "Logical port deleted: WWN = %s Role = %s\n",
  lpwwn_buf, "Initiator");
 bfa_fcs_lport_aen_post(port, BFA_LPORT_AEN_DELETE);

 /* Base port will be deleted by the OS driver */
 if (port->vport)
  bfa_fcs_vport_delete_comp(port->vport);
 else
  bfa_wc_down(&port->fabric->wc);
}


/*
 * Unsolicited frame receive handling.
 */

void
bfa_fcs_lport_uf_recv(struct bfa_fcs_lport_s *lport,
   struct fchs_s *fchs, u16 len)
{
 u32 pid = fchs->s_id;
 struct bfa_fcs_rport_s *rport = NULL;
 struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1);

 bfa_stats(lport, uf_recvs);
 bfa_trc(lport->fcs, fchs->type);

 if (!bfa_fcs_lport_is_online(lport)) {
  /*
 * In direct attach topology, it is possible to get a PLOGI
 * before the lport is online due to port feature
 * (QoS/Trunk/FEC/CR), so send a rjt
 */

  if ((fchs->type == FC_TYPE_ELS) &&
   (els_cmd->els_code == FC_ELS_PLOGI)) {
   bfa_fcs_lport_send_ls_rjt(lport, fchs,
    FC_LS_RJT_RSN_UNABLE_TO_PERF_CMD,
    FC_LS_RJT_EXP_NO_ADDL_INFO);
   bfa_stats(lport, plogi_rcvd);
  } else
   bfa_stats(lport, uf_recv_drops);

  return;
 }

 /*
 * First, handle ELSs that donot require a login.
 */

 /*
 * Handle PLOGI first
 */

 if ((fchs->type == FC_TYPE_ELS) &&
  (els_cmd->els_code == FC_ELS_PLOGI)) {
  bfa_fcs_lport_plogi(lport, fchs, (struct fc_logi_s *) els_cmd);
  return;
 }

 /*
 * Handle ECHO separately.
 */

 if ((fchs->type == FC_TYPE_ELS) && (els_cmd->els_code == FC_ELS_ECHO)) {
  bfa_fcs_lport_echo(lport, fchs,
    (struct fc_echo_s *)els_cmd, len);
  return;
 }

 /*
 * Handle RNID separately.
 */

 if ((fchs->type == FC_TYPE_ELS) && (els_cmd->els_code == FC_ELS_RNID)) {
  bfa_fcs_lport_rnid(lport, fchs,
   (struct fc_rnid_cmd_s *) els_cmd, len);
  return;
 }

 if (fchs->type == FC_TYPE_BLS) {
  if ((fchs->routing == FC_RTG_BASIC_LINK) &&
    (fchs->cat_info == FC_CAT_ABTS))
   bfa_fcs_lport_abts_acc(lport, fchs);
  return;
 }

 if (fchs->type == FC_TYPE_SERVICES) {
  /*
 * Unhandled FC-GS frames. Send a FC-CT Reject
 */

  bfa_fcs_lport_send_fcgs_rjt(lport, fchs, CT_RSN_NOT_SUPP,
    CT_NS_EXP_NOADDITIONAL);
  return;
 }

 /*
 * look for a matching remote port ID
 */

 rport = bfa_fcs_lport_get_rport_by_pid(lport, pid);
 if (rport) {
  bfa_trc(rport->fcs, fchs->s_id);
  bfa_trc(rport->fcs, fchs->d_id);
  bfa_trc(rport->fcs, fchs->type);

  bfa_fcs_rport_uf_recv(rport, fchs, len);
  return;
 }

 /*
 * Only handles ELS frames for now.
 */

 if (fchs->type != FC_TYPE_ELS) {
  bfa_trc(lport->fcs, fchs->s_id);
  bfa_trc(lport->fcs, fchs->d_id);
  /* ignore type FC_TYPE_FC_FSS */
  if (fchs->type != FC_TYPE_FC_FSS)
   bfa_sm_fault(lport->fcs, fchs->type);
  return;
 }

 bfa_trc(lport->fcs, els_cmd->els_code);
 if (els_cmd->els_code == FC_ELS_RSCN) {
  bfa_fcs_lport_scn_process_rscn(lport, fchs, len);
  return;
 }

 if (els_cmd->els_code == FC_ELS_LOGO) {
  /*
 * @todo Handle LOGO frames received.
 */

  return;
 }

 if (els_cmd->els_code == FC_ELS_PRLI) {
  /*
 * @todo Handle PRLI frames received.
 */

  return;
 }

 /*
 * Unhandled ELS frames. Send a LS_RJT.
 */

 bfa_fcs_lport_send_ls_rjt(lport, fchs, FC_LS_RJT_RSN_CMD_NOT_SUPP,
     FC_LS_RJT_EXP_NO_ADDL_INFO);

}

/*
 *   PID based Lookup for a R-Port in the Port R-Port Queue
 */

struct bfa_fcs_rport_s *
bfa_fcs_lport_get_rport_by_pid(struct bfa_fcs_lport_s *port, u32 pid)
{
 struct bfa_fcs_rport_s *rport;
 struct list_head *qe;

 list_for_each(qe, &port->rport_q) {
  rport = (struct bfa_fcs_rport_s *) qe;
  if (rport->pid == pid)
   return rport;
 }

 bfa_trc(port->fcs, pid);
 return NULL;
}

/*
 * OLD_PID based Lookup for a R-Port in the Port R-Port Queue
 */

struct bfa_fcs_rport_s *
bfa_fcs_lport_get_rport_by_old_pid(struct bfa_fcs_lport_s *port, u32 pid)
{
 struct bfa_fcs_rport_s *rport;
 struct list_head *qe;

 list_for_each(qe, &port->rport_q) {
  rport = (struct bfa_fcs_rport_s *) qe;
  if (rport->old_pid == pid)
   return rport;
 }

 bfa_trc(port->fcs, pid);
 return NULL;
}

/*
 *   PWWN based Lookup for a R-Port in the Port R-Port Queue
 */

struct bfa_fcs_rport_s *
bfa_fcs_lport_get_rport_by_pwwn(struct bfa_fcs_lport_s *port, wwn_t pwwn)
{
 struct bfa_fcs_rport_s *rport;
 struct list_head *qe;

 list_for_each(qe, &port->rport_q) {
  rport = (struct bfa_fcs_rport_s *) qe;
  if (wwn_is_equal(rport->pwwn, pwwn))
   return rport;
 }

 bfa_trc(port->fcs, pwwn);
 return NULL;
}

/*
 * PWWN & PID based Lookup for a R-Port in the Port R-Port Queue
 */

struct bfa_fcs_rport_s *
bfa_fcs_lport_get_rport_by_qualifier(struct bfa_fcs_lport_s *port,
         wwn_t pwwn, u32 pid)
{
 struct bfa_fcs_rport_s *rport;
 struct list_head *qe;

 list_for_each(qe, &port->rport_q) {
  rport = (struct bfa_fcs_rport_s *) qe;
  if (wwn_is_equal(rport->pwwn, pwwn) && rport->pid == pid)
   return rport;
 }

 bfa_trc(port->fcs, pwwn);
 return NULL;
}

/*
 * Called by rport module when new rports are discovered.
 */

void
bfa_fcs_lport_add_rport(
 struct bfa_fcs_lport_s *port,
 struct bfa_fcs_rport_s *rport)
{
 list_add_tail(&rport->qe, &port->rport_q);
 port->num_rports++;
}

/*
 * Called by rport module to when rports are deleted.
 */

void
bfa_fcs_lport_del_rport(
 struct bfa_fcs_lport_s *port,
 struct bfa_fcs_rport_s *rport)
{
 WARN_ON(!bfa_q_is_on_q(&port->rport_q, rport));
 list_del(&rport->qe);
 port->num_rports--;

 bfa_sm_send_event(port, BFA_FCS_PORT_SM_DELRPORT);
}

/*
 * Called by fabric for base port when fabric login is complete.
 * Called by vport for virtual ports when FDISC is complete.
 */

void
bfa_fcs_lport_online(struct bfa_fcs_lport_s *port)
{
 bfa_sm_send_event(port, BFA_FCS_PORT_SM_ONLINE);
}

/*
 * Called by fabric for base port when fabric goes offline.
 * Called by vport for virtual ports when virtual port becomes offline.
 */

void
bfa_fcs_lport_offline(struct bfa_fcs_lport_s *port)
{
 bfa_sm_send_event(port, BFA_FCS_PORT_SM_OFFLINE);
}

/*
 * Called by fabric for base port and by vport for virtual ports
 * when target mode driver is unloaded.
 */

void
bfa_fcs_lport_stop(struct bfa_fcs_lport_s *port)
{
 bfa_sm_send_event(port, BFA_FCS_PORT_SM_STOP);
}

/*
 * Called by fabric to delete base lport and associated resources.
 *
 * Called by vport to delete lport and associated resources. Should call
 * bfa_fcs_vport_delete_comp() for vports on completion.
 */

void
bfa_fcs_lport_delete(struct bfa_fcs_lport_s *port)
{
 bfa_sm_send_event(port, BFA_FCS_PORT_SM_DELETE);
}

/*
 * Return TRUE if port is online, else return FALSE
 */

bfa_boolean_t
bfa_fcs_lport_is_online(struct bfa_fcs_lport_s *port)
{
 return bfa_sm_cmp_state(port, bfa_fcs_lport_sm_online);
}

/*
  * Attach time initialization of logical ports.
 */

void
bfa_fcs_lport_attach(struct bfa_fcs_lport_s *lport, struct bfa_fcs_s *fcs,
     u16 vf_id, struct bfa_fcs_vport_s *vport)
{
 lport->fcs = fcs;
 lport->fabric = bfa_fcs_vf_lookup(fcs, vf_id);
 lport->vport = vport;
 lport->lp_tag = (vport) ? vport->lps->bfa_tag :
      lport->fabric->lps->bfa_tag;

 INIT_LIST_HEAD(&lport->rport_q);
 lport->num_rports = 0;
}

/*
 * Logical port initialization of base or virtual port.
 * Called by fabric for base port or by vport for virtual ports.
 */


void
bfa_fcs_lport_init(struct bfa_fcs_lport_s *lport,
 struct bfa_lport_cfg_s *port_cfg)
{
 struct bfa_fcs_vport_s *vport = lport->vport;
 struct bfad_s *bfad = (struct bfad_s *)lport->fcs->bfad;
 char    lpwwn_buf[BFA_STRING_32];

 lport->port_cfg = *port_cfg;

 lport->bfad_port = bfa_fcb_lport_new(lport->fcs->bfad, lport,
     lport->port_cfg.roles,
     lport->fabric->vf_drv,
     vport ? vport->vport_drv : NULL);

 wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(lport));
 BFA_LOG(KERN_INFO, bfad, bfa_log_level,
  "New logical port created: WWN = %s Role = %s\n",
  lpwwn_buf, "Initiator");
 bfa_fcs_lport_aen_post(lport, BFA_LPORT_AEN_NEW);

 bfa_sm_set_state(lport, bfa_fcs_lport_sm_uninit);
 bfa_sm_send_event(lport, BFA_FCS_PORT_SM_CREATE);
}

void
bfa_fcs_lport_set_symname(struct bfa_fcs_lport_s *port,
    char *symname)
{
 strcpy(port->port_cfg.sym_name.symname, symname);

 if (bfa_sm_cmp_state(port, bfa_fcs_lport_sm_online))
  bfa_fcs_lport_ns_util_send_rspn_id(
   BFA_FCS_GET_NS_FROM_PORT(port), NULL);
}

/*
 *  fcs_lport_api
 */


void
bfa_fcs_lport_get_attr(
 struct bfa_fcs_lport_s *port,
 struct bfa_lport_attr_s *port_attr)
{
 if (bfa_sm_cmp_state(port, bfa_fcs_lport_sm_online))
  port_attr->pid = port->pid;
 else
  port_attr->pid = 0;

 port_attr->port_cfg = port->port_cfg;

 if (port->fabric) {
  port_attr->port_type = port->fabric->oper_type;
  port_attr->loopback = bfa_sm_cmp_state(port->fabric,
    bfa_fcs_fabric_sm_loopback);
  port_attr->authfail =
   bfa_sm_cmp_state(port->fabric,
    bfa_fcs_fabric_sm_auth_failed);
  port_attr->fabric_name  = bfa_fcs_lport_get_fabric_name(port);
  memcpy(port_attr->fabric_ip_addr,
   bfa_fcs_lport_get_fabric_ipaddr(port),
   BFA_FCS_FABRIC_IPADDR_SZ);

  if (port->vport != NULL) {
   port_attr->port_type = BFA_PORT_TYPE_VPORT;
   port_attr->fpma_mac =
    port->vport->lps->lp_mac;
  } else {
   port_attr->fpma_mac =
    port->fabric->lps->lp_mac;
  }
 } else {
  port_attr->port_type = BFA_PORT_TYPE_UNKNOWN;
  port_attr->state = BFA_LPORT_UNINIT;
 }
}

/*
 *  bfa_fcs_lport_fab port fab functions
 */


/*
 *   Called by port to initialize fabric services of the base port.
 */

static void
bfa_fcs_lport_fab_init(struct bfa_fcs_lport_s *port)
{
 bfa_fcs_lport_ns_init(port);
 bfa_fcs_lport_scn_init(port);
 bfa_fcs_lport_ms_init(port);
}

/*
 *   Called by port to notify transition to online state.
 */

static void
bfa_fcs_lport_fab_online(struct bfa_fcs_lport_s *port)
{
 bfa_fcs_lport_ns_online(port);
 bfa_fcs_lport_fab_scn_online(port);
}

/*
 *   Called by port to notify transition to offline state.
 */

static void
bfa_fcs_lport_fab_offline(struct bfa_fcs_lport_s *port)
{
 bfa_fcs_lport_ns_offline(port);
 bfa_fcs_lport_scn_offline(port);
 bfa_fcs_lport_ms_offline(port);
}

/*
 *  bfa_fcs_lport_n2n  functions
 */


/*
 *   Called by fcs/port to initialize N2N topology.
 */

static void
bfa_fcs_lport_n2n_init(struct bfa_fcs_lport_s *port)
{
}

/*
 *   Called by fcs/port to notify transition to online state.
 */

static void
bfa_fcs_lport_n2n_online(struct bfa_fcs_lport_s *port)
{
 struct bfa_fcs_lport_n2n_s *n2n_port = &port->port_topo.pn2n;
 struct bfa_lport_cfg_s *pcfg = &port->port_cfg;
 struct bfa_fcs_rport_s *rport;

 bfa_trc(port->fcs, pcfg->pwwn);

 /*
 * If our PWWN is > than that of the r-port, we have to initiate PLOGI
 * and assign an Address. if not, we need to wait for its PLOGI.
 *
 * If our PWWN is < than that of the remote port, it will send a PLOGI
 * with the PIDs assigned. The rport state machine take care of this
 * incoming PLOGI.
 */

 if (memcmp
     ((void *)&pcfg->pwwn, (void *)&n2n_port->rem_port_wwn,
      sizeof(wwn_t)) > 0) {
  port->pid = N2N_LOCAL_PID;
  bfa_lps_set_n2n_pid(port->fabric->lps, N2N_LOCAL_PID);
  /*
 * First, check if we know the device by pwwn.
 */

  rport = bfa_fcs_lport_get_rport_by_pwwn(port,
       n2n_port->rem_port_wwn);
  if (rport) {
   bfa_trc(port->fcs, rport->pid);
   bfa_trc(port->fcs, rport->pwwn);
   rport->pid = N2N_REMOTE_PID;
   bfa_sm_send_event(rport, RPSM_EVENT_PLOGI_SEND);
   return;
  }

  /*
 * In n2n there can be only one rport. Delete the old one
 * whose pid should be zero, because it is offline.
 */

  if (port->num_rports > 0) {
   rport = bfa_fcs_lport_get_rport_by_pid(port, 0);
   WARN_ON(rport == NULL);
   if (rport) {
    bfa_trc(port->fcs, rport->pwwn);
    bfa_sm_send_event(rport, RPSM_EVENT_DELETE);
   }
  }
  bfa_fcs_rport_create(port, N2N_REMOTE_PID);
 }
}

/*
 *   Called by fcs/port to notify transition to offline state.
 */

static void
bfa_fcs_lport_n2n_offline(struct bfa_fcs_lport_s *port)
{
 struct bfa_fcs_lport_n2n_s *n2n_port = &port->port_topo.pn2n;

 bfa_trc(port->fcs, port->pid);
 port->pid = 0;
 n2n_port->rem_port_wwn = 0;
 n2n_port->reply_oxid = 0;
}

static void
bfa_fcport_get_loop_attr(struct bfa_fcs_lport_s *port)
{
 int i = 0, j = 0, bit = 0, alpa_bit = 0;
 u8 k = 0;
 struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(port->fcs->bfa);

 port->port_topo.ploop.alpabm_valid = fcport->alpabm_valid;
 port->pid = fcport->myalpa;
 port->pid = bfa_hton3b(port->pid);

 for (i = 0; i < (FC_ALPA_MAX / 8); i++) {
  for (j = 0, alpa_bit = 0; j < 8; j++, alpa_bit++) {
   bfa_trc(port->fcs->bfa, fcport->alpabm.alpa_bm[i]);
   bit = (fcport->alpabm.alpa_bm[i] & (1 << (7 - j)));
   if (bit) {
    port->port_topo.ploop.alpa_pos_map[k] =
     loop_alpa_map[(i * 8) + alpa_bit];
    k++;
    bfa_trc(port->fcs->bfa, k);
    bfa_trc(port->fcs->bfa,
      port->port_topo.ploop.alpa_pos_map[k]);
   }
  }
 }
 port->port_topo.ploop.num_alpa = k;
}

/*
 * Called by fcs/port to initialize Loop topology.
 */

static void
bfa_fcs_lport_loop_init(struct bfa_fcs_lport_s *port)
{
}

/*
 * Called by fcs/port to notify transition to online state.
 */

static void
bfa_fcs_lport_loop_online(struct bfa_fcs_lport_s *port)
{
 u8 num_alpa = 0, alpabm_valid = 0;
 struct bfa_fcs_rport_s *rport;
 u8 *alpa_map = NULL;
 int i = 0;
 u32 pid;

 bfa_fcport_get_loop_attr(port);

 num_alpa = port->port_topo.ploop.num_alpa;
 alpabm_valid = port->port_topo.ploop.alpabm_valid;
 alpa_map = port->port_topo.ploop.alpa_pos_map;

 bfa_trc(port->fcs->bfa, port->pid);
 bfa_trc(port->fcs->bfa, num_alpa);
 if (alpabm_valid == 1) {
  for (i = 0; i < num_alpa; i++) {
   bfa_trc(port->fcs->bfa, alpa_map[i]);
   if (alpa_map[i] != bfa_hton3b(port->pid)) {
    pid = alpa_map[i];
    bfa_trc(port->fcs->bfa, pid);
    rport = bfa_fcs_lport_get_rport_by_pid(port,
      bfa_hton3b(pid));
    if (!rport)
     rport = bfa_fcs_rport_create(port,
      bfa_hton3b(pid));
   }
  }
 } else {
  for (i = 0; i < MAX_ALPA_COUNT; i++) {
   if (alpa_map[i] != port->pid) {
    pid = loop_alpa_map[i];
    bfa_trc(port->fcs->bfa, pid);
    rport = bfa_fcs_lport_get_rport_by_pid(port,
      bfa_hton3b(pid));
    if (!rport)
     rport = bfa_fcs_rport_create(port,
      bfa_hton3b(pid));
   }
  }
 }
}

/*
 * Called by fcs/port to notify transition to offline state.
 */

static void
bfa_fcs_lport_loop_offline(struct bfa_fcs_lport_s *port)
{
}

#define BFA_FCS_FDMI_CMD_MAX_RETRIES 2

/*
 * forward declarations
 */

static void     bfa_fcs_lport_fdmi_send_rhba(void *fdmi_cbarg,
         struct bfa_fcxp_s *fcxp_alloced);
static void     bfa_fcs_lport_fdmi_send_rprt(void *fdmi_cbarg,
         struct bfa_fcxp_s *fcxp_alloced);
static void     bfa_fcs_lport_fdmi_send_rpa(void *fdmi_cbarg,
        struct bfa_fcxp_s *fcxp_alloced);
static void     bfa_fcs_lport_fdmi_rhba_response(void *fcsarg,
      struct bfa_fcxp_s *fcxp,
      void *cbarg,
      bfa_status_t req_status,
      u32 rsp_len,
      u32 resid_len,
      struct fchs_s *rsp_fchs);
static void     bfa_fcs_lport_fdmi_rprt_response(void *fcsarg,
      struct bfa_fcxp_s *fcxp,
      void *cbarg,
      bfa_status_t req_status,
      u32 rsp_len,
      u32 resid_len,
      struct fchs_s *rsp_fchs);
static void     bfa_fcs_lport_fdmi_rpa_response(void *fcsarg,
            struct bfa_fcxp_s *fcxp,
            void *cbarg,
            bfa_status_t req_status,
            u32 rsp_len,
            u32 resid_len,
            struct fchs_s *rsp_fchs);
static void     bfa_fcs_lport_fdmi_timeout(void *arg);
static int bfa_fcs_lport_fdmi_build_rhba_pyld(struct bfa_fcs_lport_fdmi_s *fdmi,
        u8 *pyld);
static u16 bfa_fcs_lport_fdmi_build_rprt_pyld(struct bfa_fcs_lport_fdmi_s *fdmi,
        u8 *pyld);
static u16 bfa_fcs_lport_fdmi_build_rpa_pyld(struct bfa_fcs_lport_fdmi_s *fdmi,
       u8 *pyld);
static u16 bfa_fcs_lport_fdmi_build_portattr_block(struct bfa_fcs_lport_fdmi_s *
             fdmi, u8 *pyld);
static void bfa_fcs_fdmi_get_hbaattr(struct bfa_fcs_lport_fdmi_s *fdmi,
     struct bfa_fcs_fdmi_hba_attr_s *hba_attr);
static void bfa_fcs_fdmi_get_portattr(struct bfa_fcs_lport_fdmi_s *fdmi,
      struct bfa_fcs_fdmi_port_attr_s *port_attr);
u32 bfa_fcs_fdmi_convert_speed(enum bfa_port_speed pport_speed);

/*
 *  fcs_fdmi_sm FCS FDMI state machine
 */


static void     bfa_fcs_lport_fdmi_sm_offline(struct bfa_fcs_lport_fdmi_s *fdmi,
          enum port_fdmi_event event);
static void     bfa_fcs_lport_fdmi_sm_sending_rhba(
    struct bfa_fcs_lport_fdmi_s *fdmi,
    enum port_fdmi_event event);
static void     bfa_fcs_lport_fdmi_sm_rhba(struct bfa_fcs_lport_fdmi_s *fdmi,
       enum port_fdmi_event event);
static void     bfa_fcs_lport_fdmi_sm_rhba_retry(
    struct bfa_fcs_lport_fdmi_s *fdmi,
    enum port_fdmi_event event);
static void     bfa_fcs_lport_fdmi_sm_sending_rprt(
    struct bfa_fcs_lport_fdmi_s *fdmi,
    enum port_fdmi_event event);
static void     bfa_fcs_lport_fdmi_sm_rprt(struct bfa_fcs_lport_fdmi_s *fdmi,
       enum port_fdmi_event event);
static void     bfa_fcs_lport_fdmi_sm_rprt_retry(
    struct bfa_fcs_lport_fdmi_s *fdmi,
    enum port_fdmi_event event);
static void     bfa_fcs_lport_fdmi_sm_sending_rpa(
    struct bfa_fcs_lport_fdmi_s *fdmi,
    enum port_fdmi_event event);
static void     bfa_fcs_lport_fdmi_sm_rpa(struct bfa_fcs_lport_fdmi_s *fdmi,
      enum port_fdmi_event event);
static void     bfa_fcs_lport_fdmi_sm_rpa_retry(
    struct bfa_fcs_lport_fdmi_s *fdmi,
    enum port_fdmi_event event);
static void     bfa_fcs_lport_fdmi_sm_online(struct bfa_fcs_lport_fdmi_s *fdmi,
         enum port_fdmi_event event);
static void     bfa_fcs_lport_fdmi_sm_disabled(
    struct bfa_fcs_lport_fdmi_s *fdmi,
    enum port_fdmi_event event);
/*
 * Start in offline state - awaiting MS to send start.
 */

static void
bfa_fcs_lport_fdmi_sm_offline(struct bfa_fcs_lport_fdmi_s *fdmi,
        enum port_fdmi_event event)
{
 struct bfa_fcs_lport_s *port = fdmi->ms->port;

 bfa_trc(port->fcs, port->port_cfg.pwwn);
 bfa_trc(port->fcs, event);

 fdmi->retry_cnt = 0;

 switch (event) {
 case FDMISM_EVENT_PORT_ONLINE:
  if (port->vport) {
   /*
 * For Vports, register a new port.
 */

   bfa_sm_set_state(fdmi,
      bfa_fcs_lport_fdmi_sm_sending_rprt);
   bfa_fcs_lport_fdmi_send_rprt(fdmi, NULL);
  } else {
   /*
 * For a base port, we should first register the HBA
 * attribute. The HBA attribute also contains the base
 *  port registration.
 */

   bfa_sm_set_state(fdmi,
      bfa_fcs_lport_fdmi_sm_sending_rhba);
   bfa_fcs_lport_fdmi_send_rhba(fdmi, NULL);
  }
  break;

 case FDMISM_EVENT_PORT_OFFLINE:
  break;

 default:
  bfa_sm_fault(port->fcs, event);
 }
}

static void
bfa_fcs_lport_fdmi_sm_sending_rhba(struct bfa_fcs_lport_fdmi_s *fdmi,
      enum port_fdmi_event event)
{
 struct bfa_fcs_lport_s *port = fdmi->ms->port;

 bfa_trc(port->fcs, port->port_cfg.pwwn);
 bfa_trc(port->fcs, event);

 switch (event) {
 case FDMISM_EVENT_RHBA_SENT:
  bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_rhba);
  break;

 case FDMISM_EVENT_PORT_OFFLINE:
  bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline);
  bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(port),
        &fdmi->fcxp_wqe);
  break;

 default:
  bfa_sm_fault(port->fcs, event);
 }
}

static void
bfa_fcs_lport_fdmi_sm_rhba(struct bfa_fcs_lport_fdmi_s *fdmi,
   enum port_fdmi_event event)
{
 struct bfa_fcs_lport_s *port = fdmi->ms->port;

 bfa_trc(port->fcs, port->port_cfg.pwwn);
 bfa_trc(port->fcs, event);

 switch (event) {
 case FDMISM_EVENT_RSP_ERROR:
  /*
 * if max retries have not been reached, start timer for a
 * delayed retry
 */

  if (fdmi->retry_cnt++ < BFA_FCS_FDMI_CMD_MAX_RETRIES) {
   bfa_sm_set_state(fdmi,
     bfa_fcs_lport_fdmi_sm_rhba_retry);
   bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(port),
         &fdmi->timer,
         bfa_fcs_lport_fdmi_timeout, fdmi,
         BFA_FCS_RETRY_TIMEOUT);
  } else {
   /*
 * set state to offline
 */

   bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline);
  }
  break;

 case FDMISM_EVENT_RSP_OK:
  /*
 * Initiate Register Port Attributes
 */

  bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_sending_rpa);
  fdmi->retry_cnt = 0;
  bfa_fcs_lport_fdmi_send_rpa(fdmi, NULL);
  break;

 case FDMISM_EVENT_PORT_OFFLINE:
  bfa_fcxp_discard(fdmi->fcxp);
  bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline);
  break;

 default:
  bfa_sm_fault(port->fcs, event);
 }
}

static void
bfa_fcs_lport_fdmi_sm_rhba_retry(struct bfa_fcs_lport_fdmi_s *fdmi,
    enum port_fdmi_event event)
{
 struct bfa_fcs_lport_s *port = fdmi->ms->port;

 bfa_trc(port->fcs, port->port_cfg.pwwn);
 bfa_trc(port->fcs, event);

 switch (event) {
 case FDMISM_EVENT_TIMEOUT:
  /*
 * Retry Timer Expired. Re-send
 */

  bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_sending_rhba);
  bfa_fcs_lport_fdmi_send_rhba(fdmi, NULL);
  break;

 case FDMISM_EVENT_PORT_OFFLINE:
  bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline);
  bfa_timer_stop(&fdmi->timer);
  break;

 default:
  bfa_sm_fault(port->fcs, event);
 }
}

/*
* RPRT : Register Port
 */

static void
bfa_fcs_lport_fdmi_sm_sending_rprt(struct bfa_fcs_lport_fdmi_s *fdmi,
      enum port_fdmi_event event)
{
 struct bfa_fcs_lport_s *port = fdmi->ms->port;

 bfa_trc(port->fcs, port->port_cfg.pwwn);
 bfa_trc(port->fcs, event);

 switch (event) {
 case FDMISM_EVENT_RPRT_SENT:
  bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_rprt);
  break;

 case FDMISM_EVENT_PORT_OFFLINE:
  bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline);
  bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(port),
        &fdmi->fcxp_wqe);
  break;

 default:
  bfa_sm_fault(port->fcs, event);
 }
}

static void
bfa_fcs_lport_fdmi_sm_rprt(struct bfa_fcs_lport_fdmi_s *fdmi,
   enum port_fdmi_event event)
{
 struct bfa_fcs_lport_s *port = fdmi->ms->port;

 bfa_trc(port->fcs, port->port_cfg.pwwn);
 bfa_trc(port->fcs, event);

 switch (event) {
 case FDMISM_EVENT_RSP_ERROR:
  /*
 * if max retries have not been reached, start timer for a
 * delayed retry
 */

  if (fdmi->retry_cnt++ < BFA_FCS_FDMI_CMD_MAX_RETRIES) {
   bfa_sm_set_state(fdmi,
     bfa_fcs_lport_fdmi_sm_rprt_retry);
   bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(port),
         &fdmi->timer,
         bfa_fcs_lport_fdmi_timeout, fdmi,
         BFA_FCS_RETRY_TIMEOUT);

  } else {
   /*
 * set state to offline
 */

   bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline);
   fdmi->retry_cnt = 0;
  }
  break;

 case FDMISM_EVENT_RSP_OK:
  fdmi->retry_cnt = 0;
  bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_online);
  break;

 case FDMISM_EVENT_PORT_OFFLINE:
  bfa_fcxp_discard(fdmi->fcxp);
  bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline);
  break;

 default:
  bfa_sm_fault(port->fcs, event);
 }
}

static void
bfa_fcs_lport_fdmi_sm_rprt_retry(struct bfa_fcs_lport_fdmi_s *fdmi,
    enum port_fdmi_event event)
{
 struct bfa_fcs_lport_s *port = fdmi->ms->port;

 bfa_trc(port->fcs, port->port_cfg.pwwn);
 bfa_trc(port->fcs, event);

 switch (event) {
 case FDMISM_EVENT_TIMEOUT:
  /*
 * Retry Timer Expired. Re-send
 */

  bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_sending_rprt);
  bfa_fcs_lport_fdmi_send_rprt(fdmi, NULL);
  break;

 case FDMISM_EVENT_PORT_OFFLINE:
  bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline);
  bfa_timer_stop(&fdmi->timer);
  break;

 default:
  bfa_sm_fault(port->fcs, event);
 }
}

/*
 * Register Port Attributes
 */

static void
bfa_fcs_lport_fdmi_sm_sending_rpa(struct bfa_fcs_lport_fdmi_s *fdmi,
     enum port_fdmi_event event)
{
 struct bfa_fcs_lport_s *port = fdmi->ms->port;

 bfa_trc(port->fcs, port->port_cfg.pwwn);
 bfa_trc(port->fcs, event);

 switch (event) {
 case FDMISM_EVENT_RPA_SENT:
  bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_rpa);
  break;

 case FDMISM_EVENT_PORT_OFFLINE:
  bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline);
  bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(port),
        &fdmi->fcxp_wqe);
  break;

 default:
  bfa_sm_fault(port->fcs, event);
 }
}

static void
bfa_fcs_lport_fdmi_sm_rpa(struct bfa_fcs_lport_fdmi_s *fdmi,
   enum port_fdmi_event event)
{
 struct bfa_fcs_lport_s *port = fdmi->ms->port;

 bfa_trc(port->fcs, port->port_cfg.pwwn);
 bfa_trc(port->fcs, event);

 switch (event) {
 case FDMISM_EVENT_RSP_ERROR:
  /*
 * if max retries have not been reached, start timer for a
 * delayed retry
 */

  if (fdmi->retry_cnt++ < BFA_FCS_FDMI_CMD_MAX_RETRIES) {
   bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_rpa_retry);
   bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(port),
         &fdmi->timer,
         bfa_fcs_lport_fdmi_timeout, fdmi,
         BFA_FCS_RETRY_TIMEOUT);
  } else {
   /*
 * set state to offline
 */

   bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline);
   fdmi->retry_cnt = 0;
  }
  break;

 case FDMISM_EVENT_RSP_OK:
  bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_online);
  fdmi->retry_cnt = 0;
  break;

 case FDMISM_EVENT_PORT_OFFLINE:
  bfa_fcxp_discard(fdmi->fcxp);
  bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline);
  break;

 default:
  bfa_sm_fault(port->fcs, event);
 }
}

static void
bfa_fcs_lport_fdmi_sm_rpa_retry(struct bfa_fcs_lport_fdmi_s *fdmi,
          enum port_fdmi_event event)
{
 struct bfa_fcs_lport_s *port = fdmi->ms->port;

 bfa_trc(port->fcs, port->port_cfg.pwwn);
 bfa_trc(port->fcs, event);

 switch (event) {
 case FDMISM_EVENT_TIMEOUT:
  /*
 * Retry Timer Expired. Re-send
 */

  bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_sending_rpa);
  bfa_fcs_lport_fdmi_send_rpa(fdmi, NULL);
  break;

 case FDMISM_EVENT_PORT_OFFLINE:
  bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline);
  bfa_timer_stop(&fdmi->timer);
  break;

 default:
  bfa_sm_fault(port->fcs, event);
 }
}

static void
bfa_fcs_lport_fdmi_sm_online(struct bfa_fcs_lport_fdmi_s *fdmi,
    enum port_fdmi_event event)
{
 struct bfa_fcs_lport_s *port = fdmi->ms->port;

 bfa_trc(port->fcs, port->port_cfg.pwwn);
 bfa_trc(port->fcs, event);

 switch (event) {
 case FDMISM_EVENT_PORT_OFFLINE:
  bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline);
  break;

 default:
  bfa_sm_fault(port->fcs, event);
 }
}
/*
 *  FDMI is disabled state.
 */

static void
bfa_fcs_lport_fdmi_sm_disabled(struct bfa_fcs_lport_fdmi_s *fdmi,
        enum port_fdmi_event event)
{
 struct bfa_fcs_lport_s *port = fdmi->ms->port;

 bfa_trc(port->fcs, port->port_cfg.pwwn);
 bfa_trc(port->fcs, event);

 /* No op State. It can only be enabled at Driver Init. */
}

/*
*  RHBA : Register HBA Attributes.
 */

static void
bfa_fcs_lport_fdmi_send_rhba(void *fdmi_cbarg, struct bfa_fcxp_s *fcxp_alloced)
{
 struct bfa_fcs_lport_fdmi_s *fdmi = fdmi_cbarg;
 struct bfa_fcs_lport_s *port = fdmi->ms->port;
 struct fchs_s fchs;
 int             len, attr_len;
 struct bfa_fcxp_s *fcxp;
 u8        *pyld;

 bfa_trc(port->fcs, port->port_cfg.pwwn);

 fcxp = fcxp_alloced ? fcxp_alloced :
        bfa_fcs_fcxp_alloc(port->fcs, BFA_TRUE);
 if (!fcxp) {
  bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &fdmi->fcxp_wqe,
    bfa_fcs_lport_fdmi_send_rhba, fdmi, BFA_TRUE);
  return;
 }
 fdmi->fcxp = fcxp;

 pyld = bfa_fcxp_get_reqbuf(fcxp);
 memset(pyld, 0, FC_MAX_PDUSZ);

 len = fc_fdmi_reqhdr_build(&fchs, pyld, bfa_fcs_lport_get_fcid(port),
       FDMI_RHBA);

 attr_len =
  bfa_fcs_lport_fdmi_build_rhba_pyld(fdmi,
       (u8 *) ((struct ct_hdr_s *) pyld
             + 1));
 if (attr_len < 0)
  return;

 bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
     FC_CLASS_3, (len + attr_len), &fchs,
     bfa_fcs_lport_fdmi_rhba_response, (void *)fdmi,
     FC_MAX_PDUSZ, FC_FCCT_TOV);

 bfa_sm_send_event(fdmi, FDMISM_EVENT_RHBA_SENT);
}

static int
bfa_fcs_lport_fdmi_build_rhba_pyld(struct bfa_fcs_lport_fdmi_s *fdmi, u8 *pyld)
{
 struct bfa_fcs_lport_s *port = fdmi->ms->port;
 struct bfa_fcs_fdmi_hba_attr_s *fcs_hba_attr;
 struct fdmi_rhba_s *rhba = (struct fdmi_rhba_s *) pyld;
 struct fdmi_attr_s *attr;
 int        len;
 u8        *curr_ptr;
 u16 templen, count;

 fcs_hba_attr = kzalloc(sizeof(*fcs_hba_attr), GFP_KERNEL);
 if (!fcs_hba_attr)
  return -ENOMEM;

 /*
 * get hba attributes
 */

 bfa_fcs_fdmi_get_hbaattr(fdmi, fcs_hba_attr);

 rhba->hba_id = bfa_fcs_lport_get_pwwn(port);
 rhba->port_list.num_ports = cpu_to_be32(1);
 rhba->port_list.port_entry = bfa_fcs_lport_get_pwwn(port);

 len = sizeof(rhba->hba_id) + sizeof(rhba->port_list);

 count = 0;
 len += sizeof(rhba->hba_attr_blk.attr_count);

 /*
 * fill out the invididual entries of the HBA attrib Block
 */

 curr_ptr = (u8 *) &rhba->hba_attr_blk.hba_attr;

 /*
 * Node Name
 */

 attr = (struct fdmi_attr_s *) curr_ptr;
 attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_NODENAME);
 templen = sizeof(wwn_t);
 memcpy(attr->value, &bfa_fcs_lport_get_nwwn(port), templen);
 curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
 len += templen;
 count++;
 attr->len = cpu_to_be16(templen + sizeof(attr->type) +
        sizeof(templen));

 /*
 * Manufacturer
 */

 attr = (struct fdmi_attr_s *) curr_ptr;
 attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_MANUFACTURER);
 templen = (u16) strlen(fcs_hba_attr->manufacturer);
 memcpy(attr->value, fcs_hba_attr->manufacturer, templen);
 templen = fc_roundup(templen, sizeof(u32));
 curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
 len += templen;
 count++;
 attr->len = cpu_to_be16(templen + sizeof(attr->type) +
        sizeof(templen));

 /*
 * Serial Number
 */

 attr = (struct fdmi_attr_s *) curr_ptr;
 attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_SERIALNUM);
 templen = (u16) strlen(fcs_hba_attr->serial_num);
 memcpy(attr->value, fcs_hba_attr->serial_num, templen);
 templen = fc_roundup(templen, sizeof(u32));
 curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
 len += templen;
 count++;
 attr->len = cpu_to_be16(templen + sizeof(attr->type) +
        sizeof(templen));

 /*
 * Model
 */

 attr = (struct fdmi_attr_s *) curr_ptr;
 attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_MODEL);
 templen = (u16) strlen(fcs_hba_attr->model);
 memcpy(attr->value, fcs_hba_attr->model, templen);
 templen = fc_roundup(templen, sizeof(u32));
 curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
 len += templen;
 count++;
 attr->len = cpu_to_be16(templen + sizeof(attr->type) +
        sizeof(templen));

 /*
 * Model Desc
 */

 attr = (struct fdmi_attr_s *) curr_ptr;
 attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_MODEL_DESC);
 templen = (u16) strlen(fcs_hba_attr->model_desc);
 memcpy(attr->value, fcs_hba_attr->model_desc, templen);
 templen = fc_roundup(templen, sizeof(u32));
 curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
 len += templen;
 count++;
 attr->len = cpu_to_be16(templen + sizeof(attr->type) +
        sizeof(templen));

 /*
 * H/W Version
 */

 if (fcs_hba_attr->hw_version[0] != '\0') {
  attr = (struct fdmi_attr_s *) curr_ptr;
  attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_HW_VERSION);
  templen = (u16) strlen(fcs_hba_attr->hw_version);
  memcpy(attr->value, fcs_hba_attr->hw_version, templen);
  templen = fc_roundup(templen, sizeof(u32));
  curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
  len += templen;
  count++;
  attr->len = cpu_to_be16(templen + sizeof(attr->type) +
      sizeof(templen));
 }

 /*
 * Driver Version
 */

 attr = (struct fdmi_attr_s *) curr_ptr;
 attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_DRIVER_VERSION);
 templen = (u16) strlen(fcs_hba_attr->driver_version);
 memcpy(attr->value, fcs_hba_attr->driver_version, templen);
 templen = fc_roundup(templen, sizeof(u32));
 curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
 len += templen;
 count++;
 attr->len = cpu_to_be16(templen + sizeof(attr->type) +
        sizeof(templen));

 /*
 * Option Rom Version
 */

 if (fcs_hba_attr->option_rom_ver[0] != '\0') {
  attr = (struct fdmi_attr_s *) curr_ptr;
  attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_ROM_VERSION);
  templen = (u16) strlen(fcs_hba_attr->option_rom_ver);
  memcpy(attr->value, fcs_hba_attr->option_rom_ver, templen);
  templen = fc_roundup(templen, sizeof(u32));
  curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
  len += templen;
  count++;
  attr->len = cpu_to_be16(templen + sizeof(attr->type) +
      sizeof(templen));
 }

 attr = (struct fdmi_attr_s *) curr_ptr;
 attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_FW_VERSION);
 templen = (u16) strlen(fcs_hba_attr->fw_version);
 memcpy(attr->value, fcs_hba_attr->fw_version, templen);
 templen = fc_roundup(templen, sizeof(u32));
 curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
 len += templen;
 count++;
 attr->len = cpu_to_be16(templen + sizeof(attr->type) +
        sizeof(templen));

 /*
 * OS Name
 */

 if (fcs_hba_attr->os_name[0] != '\0') {
  attr = (struct fdmi_attr_s *) curr_ptr;
  attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_OS_NAME);
  templen = (u16) strlen(fcs_hba_attr->os_name);
  memcpy(attr->value, fcs_hba_attr->os_name, templen);
  templen = fc_roundup(templen, sizeof(u32));
  curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
  len += templen;
  count++;
  attr->len = cpu_to_be16(templen + sizeof(attr->type) +
     sizeof(templen));
 }

 /*
 * MAX_CT_PAYLOAD
 */

 attr = (struct fdmi_attr_s *) curr_ptr;
 attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_MAX_CT);
 templen = sizeof(fcs_hba_attr->max_ct_pyld);
 memcpy(attr->value, &fcs_hba_attr->max_ct_pyld, templen);
 templen = fc_roundup(templen, sizeof(u32));
 curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
 len += templen;
 count++;
 attr->len = cpu_to_be16(templen + sizeof(attr->type) +
        sizeof(templen));
 /*
 * Send extended attributes ( FOS 7.1 support )
 */

 if (fdmi->retry_cnt == 0) {
  attr = (struct fdmi_attr_s *) curr_ptr;
  attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_NODE_SYM_NAME);
  templen = sizeof(fcs_hba_attr->node_sym_name);
  memcpy(attr->value, &fcs_hba_attr->node_sym_name, templen);
  templen = fc_roundup(templen, sizeof(u32));
  curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
  len += templen;
  count++;
  attr->len = cpu_to_be16(templen + sizeof(attr->type) +
     sizeof(templen));

  attr = (struct fdmi_attr_s *) curr_ptr;
  attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_VENDOR_ID);
  templen = sizeof(fcs_hba_attr->vendor_info);
  memcpy(attr->value, &fcs_hba_attr->vendor_info, templen);
  templen = fc_roundup(templen, sizeof(u32));
  curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
  len += templen;
  count++;
  attr->len = cpu_to_be16(templen + sizeof(attr->type) +
     sizeof(templen));

  attr = (struct fdmi_attr_s *) curr_ptr;
  attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_NUM_PORTS);
  templen = sizeof(fcs_hba_attr->num_ports);
  memcpy(attr->value, &fcs_hba_attr->num_ports, templen);
  templen = fc_roundup(templen, sizeof(u32));
  curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
  len += templen;
  count++;
  attr->len = cpu_to_be16(templen + sizeof(attr->type) +
     sizeof(templen));

  attr = (struct fdmi_attr_s *) curr_ptr;
  attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_FABRIC_NAME);
  templen = sizeof(fcs_hba_attr->fabric_name);
  memcpy(attr->value, &fcs_hba_attr->fabric_name, templen);
  templen = fc_roundup(templen, sizeof(u32));
  curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
  len += templen;
  count++;
  attr->len = cpu_to_be16(templen + sizeof(attr->type) +
     sizeof(templen));

  attr = (struct fdmi_attr_s *) curr_ptr;
  attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_BIOS_VER);
  templen = sizeof(fcs_hba_attr->bios_ver);
  memcpy(attr->value, &fcs_hba_attr->bios_ver, templen);
  templen = fc_roundup(attr->len, sizeof(u32));
  curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
  len += templen;
  count++;
  attr->len = cpu_to_be16(templen + sizeof(attr->type) +
     sizeof(templen));
 }

 /*
 * Update size of payload
 */

 len += ((sizeof(attr->type) + sizeof(attr->len)) * count);

 rhba->hba_attr_blk.attr_count = cpu_to_be32(count);

 kfree(fcs_hba_attr);

 return len;
}

static void
bfa_fcs_lport_fdmi_rhba_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
    void *cbarg, bfa_status_t req_status,
    u32 rsp_len, u32 resid_len,
    struct fchs_s *rsp_fchs)
{
 struct bfa_fcs_lport_fdmi_s *fdmi =
    (struct bfa_fcs_lport_fdmi_s *) cbarg;
 struct bfa_fcs_lport_s *port = fdmi->ms->port;
 struct ct_hdr_s *cthdr = NULL;

 bfa_trc(port->fcs, port->port_cfg.pwwn);

 /*
 * Sanity Checks
 */

 if (req_status != BFA_STATUS_OK) {
  bfa_trc(port->fcs, req_status);
  bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_ERROR);
  return;
 }

 cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp);
 cthdr->cmd_rsp_code = be16_to_cpu(cthdr->cmd_rsp_code);

 if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) {
  bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_OK);
  return;
 }

 bfa_trc(port->fcs, cthdr->reason_code);
 bfa_trc(port->fcs, cthdr->exp_code);
 bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_ERROR);
}

/*
*  RPRT : Register Port
 */

static void
bfa_fcs_lport_fdmi_send_rprt(void *fdmi_cbarg, struct bfa_fcxp_s *fcxp_alloced)
{
 struct bfa_fcs_lport_fdmi_s *fdmi = fdmi_cbarg;
 struct bfa_fcs_lport_s *port = fdmi->ms->port;
 struct fchs_s fchs;
 u16        len, attr_len;
 struct bfa_fcxp_s *fcxp;
 u8        *pyld;

 bfa_trc(port->fcs, port->port_cfg.pwwn);

 fcxp = fcxp_alloced ? fcxp_alloced :
        bfa_fcs_fcxp_alloc(port->fcs, BFA_TRUE);
 if (!fcxp) {
  bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &fdmi->fcxp_wqe,
    bfa_fcs_lport_fdmi_send_rprt, fdmi, BFA_TRUE);
  return;
 }
 fdmi->fcxp = fcxp;

 pyld = bfa_fcxp_get_reqbuf(fcxp);
 memset(pyld, 0, FC_MAX_PDUSZ);

 len = fc_fdmi_reqhdr_build(&fchs, pyld, bfa_fcs_lport_get_fcid(port),
       FDMI_RPRT);

 attr_len =
  bfa_fcs_lport_fdmi_build_rprt_pyld(fdmi,
       (u8 *) ((struct ct_hdr_s *) pyld
             + 1));

 bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
     FC_CLASS_3, len + attr_len, &fchs,
     bfa_fcs_lport_fdmi_rprt_response, (void *)fdmi,
     FC_MAX_PDUSZ, FC_FCCT_TOV);

 bfa_sm_send_event(fdmi, FDMISM_EVENT_RPRT_SENT);
}

/*
 * This routine builds Port Attribute Block that used in RPA, RPRT commands.
 */

static          u16
bfa_fcs_lport_fdmi_build_portattr_block(struct bfa_fcs_lport_fdmi_s *fdmi,
           u8 *pyld)
{
 struct bfa_fcs_fdmi_port_attr_s fcs_port_attr;
 struct fdmi_port_attr_s *port_attrib = (struct fdmi_port_attr_s *) pyld;
 struct fdmi_attr_s *attr;
 u8        *curr_ptr;
 u16        len;
 u8 count = 0;
 u16 templen;

 /*
 * get port attributes
 */

 bfa_fcs_fdmi_get_portattr(fdmi, &fcs_port_attr);

 len = sizeof(port_attrib->attr_count);

 /*
 * fill out the invididual entries
 */

 curr_ptr = (u8 *) &port_attrib->port_attr;

 /*
 * FC4 Types
 */

 attr = (struct fdmi_attr_s *) curr_ptr;
 attr->type = cpu_to_be16(FDMI_PORT_ATTRIB_FC4_TYPES);
 templen = sizeof(fcs_port_attr.supp_fc4_types);
 memcpy(attr->value, fcs_port_attr.supp_fc4_types, templen);
 curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
 len += templen;
 ++count;
 attr->len =
  cpu_to_be16(templen + sizeof(attr->type) +
        sizeof(templen));

 /*
 * Supported Speed
 */

 attr = (struct fdmi_attr_s *) curr_ptr;
 attr->type = cpu_to_be16(FDMI_PORT_ATTRIB_SUPP_SPEED);
 templen = sizeof(fcs_port_attr.supp_speed);
 memcpy(attr->value, &fcs_port_attr.supp_speed, templen);
 curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
 len += templen;
 ++count;
 attr->len =
  cpu_to_be16(templen + sizeof(attr->type) +
        sizeof(templen));

 /*
 * current Port Speed
 */

 attr = (struct fdmi_attr_s *) curr_ptr;
 attr->type = cpu_to_be16(FDMI_PORT_ATTRIB_PORT_SPEED);
 templen = sizeof(fcs_port_attr.curr_speed);
 memcpy(attr->value, &fcs_port_attr.curr_speed, templen);
 curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
 len += templen;
 ++count;
 attr->len = cpu_to_be16(templen + sizeof(attr->type) +
        sizeof(templen));

 /*
 * max frame size
 */

 attr = (struct fdmi_attr_s *) curr_ptr;
 attr->type = cpu_to_be16(FDMI_PORT_ATTRIB_FRAME_SIZE);
 templen = sizeof(fcs_port_attr.max_frm_size);
 memcpy(attr->value, &fcs_port_attr.max_frm_size, templen);
 curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
 len += templen;
 ++count;
 attr->len = cpu_to_be16(templen + sizeof(attr->type) +
        sizeof(templen));

 /*
 * OS Device Name
 */

 if (fcs_port_attr.os_device_name[0] != '\0') {
  attr = (struct fdmi_attr_s *) curr_ptr;
  attr->type = cpu_to_be16(FDMI_PORT_ATTRIB_DEV_NAME);
  templen = (u16) strlen(fcs_port_attr.os_device_name);
  memcpy(attr->value, fcs_port_attr.os_device_name, templen);
  templen = fc_roundup(templen, sizeof(u32));
  curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
  len += templen;
  ++count;
  attr->len = cpu_to_be16(templen + sizeof(attr->type) +
     sizeof(templen));
 }
 /*
 * Host Name
 */

 if (fcs_port_attr.host_name[0] != '\0') {
  attr = (struct fdmi_attr_s *) curr_ptr;
  attr->type = cpu_to_be16(FDMI_PORT_ATTRIB_HOST_NAME);
  templen = (u16) strlen(fcs_port_attr.host_name);
  memcpy(attr->value, fcs_port_attr.host_name, templen);
  templen = fc_roundup(templen, sizeof(u32));
  curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
  len += templen;
  ++count;
  attr->len = cpu_to_be16(templen + sizeof(attr->type) +
    sizeof(templen));
 }

 if (fdmi->retry_cnt == 0) {
  attr = (struct fdmi_attr_s *) curr_ptr;
  attr->type = cpu_to_be16(FDMI_PORT_ATTRIB_NODE_NAME);
  templen = sizeof(fcs_port_attr.node_name);
  memcpy(attr->value, &fcs_port_attr.node_name, templen);
  templen = fc_roundup(templen, sizeof(u32));
  curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
  len += templen;
  ++count;
  attr->len = cpu_to_be16(templen + sizeof(attr->type) +
     sizeof(templen));

  attr = (struct fdmi_attr_s *) curr_ptr;
  attr->type = cpu_to_be16(FDMI_PORT_ATTRIB_PORT_NAME);
  templen = sizeof(fcs_port_attr.port_name);
  memcpy(attr->value, &fcs_port_attr.port_name, templen);
  templen = fc_roundup(templen, sizeof(u32));
  curr_ptr += sizeof(attr->type) + sizeof(attr->len) + templen;
  len += templen;
  ++count;
  attr->len = cpu_to_be16(templen + sizeof(attr->type) +
     sizeof(templen));

  if (fcs_port_attr.port_sym_name.symname[0] != '\0') {
   attr = (struct fdmi_attr_s *) curr_ptr;
   attr->type =
    cpu_to_be16(FDMI_PORT_ATTRIB_PORT_SYM_NAME);
   templen = sizeof(fcs_port_attr.port_sym_name);
   memcpy(attr->value,
    &fcs_port_attr.port_sym_name, templen);
   templen = fc_roundup(templen, sizeof(u32));
   curr_ptr += sizeof(attr->type) +
     sizeof(templen) + templen;
   len += templen;
   ++count;
   attr->len = cpu_to_be16(templen +
    sizeof(attr->type) + sizeof(templen));
  }

  attr = (struct fdmi_attr_s *) curr_ptr;
  attr->type = cpu_to_be16(FDMI_PORT_ATTRIB_PORT_TYPE);
  templen = sizeof(fcs_port_attr.port_type);
  memcpy(attr->value, &fcs_port_attr.port_type, templen);
  templen = fc_roundup(templen, sizeof(u32));
  curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
  len += templen;
  ++count;
  attr->len = cpu_to_be16(templen + sizeof(attr->type) +
     sizeof(templen));

  attr = (struct fdmi_attr_s *) curr_ptr;
  attr->type = cpu_to_be16(FDMI_PORT_ATTRIB_SUPP_COS);
  templen = sizeof(fcs_port_attr.scos);
  memcpy(attr->value, &fcs_port_attr.scos, templen);
  templen = fc_roundup(templen, sizeof(u32));
  curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
  len += templen;
  ++count;
  attr->len = cpu_to_be16(templen + sizeof(attr->type) +
     sizeof(templen));

  attr = (struct fdmi_attr_s *) curr_ptr;
  attr->type = cpu_to_be16(FDMI_PORT_ATTRIB_PORT_FAB_NAME);
  templen = sizeof(fcs_port_attr.port_fabric_name);
  memcpy(attr->value, &fcs_port_attr.port_fabric_name, templen);
  templen = fc_roundup(templen, sizeof(u32));
  curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
  len += templen;
  ++count;
  attr->len = cpu_to_be16(templen + sizeof(attr->type) +
     sizeof(templen));

  attr = (struct fdmi_attr_s *) curr_ptr;
  attr->type = cpu_to_be16(FDMI_PORT_ATTRIB_PORT_FC4_TYPE);
  templen = sizeof(fcs_port_attr.port_act_fc4_type);
  memcpy(attr->value, fcs_port_attr.port_act_fc4_type,
    templen);
  templen = fc_roundup(templen, sizeof(u32));
  curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
  len += templen;
  ++count;
  attr->len = cpu_to_be16(templen + sizeof(attr->type) +
     sizeof(templen));

  attr = (struct fdmi_attr_s *) curr_ptr;
  attr->type = cpu_to_be16(FDMI_PORT_ATTRIB_PORT_STATE);
  templen = sizeof(fcs_port_attr.port_state);
  memcpy(attr->value, &fcs_port_attr.port_state, templen);
  templen = fc_roundup(templen, sizeof(u32));
  curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
  len += templen;
  ++count;
  attr->len = cpu_to_be16(templen + sizeof(attr->type) +
     sizeof(templen));

  attr = (struct fdmi_attr_s *) curr_ptr;
  attr->type = cpu_to_be16(FDMI_PORT_ATTRIB_PORT_NUM_RPRT);
  templen = sizeof(fcs_port_attr.num_ports);
  memcpy(attr->value, &fcs_port_attr.num_ports, templen);
  templen = fc_roundup(templen, sizeof(u32));
  curr_ptr += sizeof(attr->type) + sizeof(templen) + templen;
  len += templen;
  ++count;
  attr->len = cpu_to_be16(templen + sizeof(attr->type) +
    sizeof(templen));
 }

 /*
 * Update size of payload
 */

 port_attrib->attr_count = cpu_to_be32(count);
 len += ((sizeof(attr->type) + sizeof(attr->len)) * count);
 return len;
}

static          u16
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=95 H=100 G=97

¤ Dauer der Verarbeitung: 0.43 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge