Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/scsi/bfa/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 161 kB image not shown  

Quelle  bfa_svc.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_plog.h"
#include "bfa_cs.h"
#include "bfa_modules.h"

BFA_TRC_FILE(HAL, FCXP);

/*
 * LPS related definitions
 */

#define BFA_LPS_MIN_LPORTS      (1)
#define BFA_LPS_MAX_LPORTS      (256)

/*
 * Maximum Vports supported per physical port or vf.
 */

#define BFA_LPS_MAX_VPORTS_SUPP_CB  255
#define BFA_LPS_MAX_VPORTS_SUPP_CT  190


/*
 * FC PORT related definitions
 */

/*
 * The port is considered disabled if corresponding physical port or IOC are
 * disabled explicitly
 */

#define BFA_PORT_IS_DISABLED(bfa) \
 ((bfa_fcport_is_disabled(bfa) == BFA_TRUE) || \
 (bfa_ioc_is_disabled(&bfa->ioc) == BFA_TRUE))

/*
 * RPORT related definitions
 */

#define bfa_rport_offline_cb(__rp) do {     \
 if ((__rp)->bfa->fcs)      \
  bfa_cb_rport_offline((__rp)->rport_drv);      \
 else {        \
  bfa_cb_queue((__rp)->bfa, &(__rp)->hcb_qe,  \
    __bfa_cb_rport_offline, (__rp));      \
 }        \
while (0)

#define bfa_rport_online_cb(__rp) do {     \
 if ((__rp)->bfa->fcs)      \
  bfa_cb_rport_online((__rp)->rport_drv);      \
 else {        \
  bfa_cb_queue((__rp)->bfa, &(__rp)->hcb_qe,  \
      __bfa_cb_rport_online, (__rp));      \
  }       \
while (0)

/*
 * forward declarations FCXP related functions
 */

static void __bfa_fcxp_send_cbfn(void *cbarg, bfa_boolean_t complete);
static void hal_fcxp_rx_plog(struct bfa_s *bfa, struct bfa_fcxp_s *fcxp,
    struct bfi_fcxp_send_rsp_s *fcxp_rsp);
static void hal_fcxp_tx_plog(struct bfa_s *bfa, u32 reqlen,
    struct bfa_fcxp_s *fcxp, struct fchs_s *fchs);
static void bfa_fcxp_qresume(void *cbarg);
static void bfa_fcxp_queue(struct bfa_fcxp_s *fcxp,
    struct bfi_fcxp_send_req_s *send_req);

/*
 * forward declarations for LPS functions
 */

static void bfa_lps_login_rsp(struct bfa_s *bfa,
    struct bfi_lps_login_rsp_s *rsp);
static void bfa_lps_no_res(struct bfa_lps_s *first_lps, u8 count);
static void bfa_lps_logout_rsp(struct bfa_s *bfa,
    struct bfi_lps_logout_rsp_s *rsp);
static void bfa_lps_reqq_resume(void *lps_arg);
static void bfa_lps_free(struct bfa_lps_s *lps);
static void bfa_lps_send_login(struct bfa_lps_s *lps);
static void bfa_lps_send_logout(struct bfa_lps_s *lps);
static void bfa_lps_send_set_n2n_pid(struct bfa_lps_s *lps);
static void bfa_lps_login_comp(struct bfa_lps_s *lps);
static void bfa_lps_logout_comp(struct bfa_lps_s *lps);
static void bfa_lps_cvl_event(struct bfa_lps_s *lps);

/*
 * forward declaration for LPS state machine
 */

static void bfa_lps_sm_init(struct bfa_lps_s *lps, enum bfa_lps_event event);
static void bfa_lps_sm_login(struct bfa_lps_s *lps, enum bfa_lps_event event);
static void bfa_lps_sm_loginwait(struct bfa_lps_s *lps, enum bfa_lps_event
     event);
static void bfa_lps_sm_online(struct bfa_lps_s *lps, enum bfa_lps_event event);
static void bfa_lps_sm_online_n2n_pid_wait(struct bfa_lps_s *lps,
     enum bfa_lps_event event);
static void bfa_lps_sm_logout(struct bfa_lps_s *lps, enum bfa_lps_event event);
static void bfa_lps_sm_logowait(struct bfa_lps_s *lps, enum bfa_lps_event
     event);

/*
 * forward declaration for FC Port functions
 */

static bfa_boolean_t bfa_fcport_send_enable(struct bfa_fcport_s *fcport);
static bfa_boolean_t bfa_fcport_send_disable(struct bfa_fcport_s *fcport);
static void bfa_fcport_update_linkinfo(struct bfa_fcport_s *fcport);
static void bfa_fcport_reset_linkinfo(struct bfa_fcport_s *fcport);
static void bfa_fcport_set_wwns(struct bfa_fcport_s *fcport);
static void __bfa_cb_fcport_event(void *cbarg, bfa_boolean_t complete);
static void bfa_fcport_scn(struct bfa_fcport_s *fcport,
   enum bfa_port_linkstate event, bfa_boolean_t trunk);
static void bfa_fcport_queue_cb(struct bfa_fcport_ln_s *ln,
    enum bfa_port_linkstate event);
static void __bfa_cb_fcport_stats_clr(void *cbarg, bfa_boolean_t complete);
static void bfa_fcport_stats_get_timeout(void *cbarg);
static void bfa_fcport_stats_clr_timeout(void *cbarg);
static void bfa_trunk_iocdisable(struct bfa_s *bfa);

/*
 * forward declaration for FC PORT state machine
 */

static void     bfa_fcport_sm_uninit(struct bfa_fcport_s *fcport,
     enum bfa_fcport_sm_event event);
static void     bfa_fcport_sm_enabling_qwait(struct bfa_fcport_s *fcport,
     enum bfa_fcport_sm_event event);
static void     bfa_fcport_sm_enabling(struct bfa_fcport_s *fcport,
     enum bfa_fcport_sm_event event);
static void     bfa_fcport_sm_linkdown(struct bfa_fcport_s *fcport,
     enum bfa_fcport_sm_event event);
static void     bfa_fcport_sm_linkup(struct bfa_fcport_s *fcport,
     enum bfa_fcport_sm_event event);
static void     bfa_fcport_sm_disabling(struct bfa_fcport_s *fcport,
     enum bfa_fcport_sm_event event);
static void     bfa_fcport_sm_disabling_qwait(struct bfa_fcport_s *fcport,
     enum bfa_fcport_sm_event event);
static void     bfa_fcport_sm_toggling_qwait(struct bfa_fcport_s *fcport,
     enum bfa_fcport_sm_event event);
static void     bfa_fcport_sm_disabled(struct bfa_fcport_s *fcport,
     enum bfa_fcport_sm_event event);
static void     bfa_fcport_sm_stopped(struct bfa_fcport_s *fcport,
     enum bfa_fcport_sm_event event);
static void     bfa_fcport_sm_iocdown(struct bfa_fcport_s *fcport,
     enum bfa_fcport_sm_event event);
static void     bfa_fcport_sm_iocfail(struct bfa_fcport_s *fcport,
     enum bfa_fcport_sm_event event);
static void bfa_fcport_sm_dport(struct bfa_fcport_s *fcport,
     enum bfa_fcport_sm_event event);
static void     bfa_fcport_sm_ddport(struct bfa_fcport_s *fcport,
     enum bfa_fcport_sm_event event);
static void bfa_fcport_sm_faa_misconfig(struct bfa_fcport_s *fcport,
     enum bfa_fcport_sm_event event);

static void     bfa_fcport_ln_sm_dn(struct bfa_fcport_ln_s *ln,
     enum bfa_fcport_ln_sm_event event);
static void     bfa_fcport_ln_sm_dn_nf(struct bfa_fcport_ln_s *ln,
     enum bfa_fcport_ln_sm_event event);
static void     bfa_fcport_ln_sm_dn_up_nf(struct bfa_fcport_ln_s *ln,
     enum bfa_fcport_ln_sm_event event);
static void     bfa_fcport_ln_sm_up(struct bfa_fcport_ln_s *ln,
     enum bfa_fcport_ln_sm_event event);
static void     bfa_fcport_ln_sm_up_nf(struct bfa_fcport_ln_s *ln,
     enum bfa_fcport_ln_sm_event event);
static void     bfa_fcport_ln_sm_up_dn_nf(struct bfa_fcport_ln_s *ln,
     enum bfa_fcport_ln_sm_event event);
static void     bfa_fcport_ln_sm_up_dn_up_nf(struct bfa_fcport_ln_s *ln,
     enum bfa_fcport_ln_sm_event event);

struct bfa_fcport_sm_table_s {
 bfa_fcport_sm_t sm;  /*  state machine function */
 enum bfa_port_states state; /*  state machine encoding */
 char  *name;  /*  state name for display */
};

static inline enum bfa_port_states
bfa_fcport_sm_to_state(struct bfa_fcport_sm_table_s *smt, bfa_fcport_sm_t sm)
{
 int i = 0;

 while (smt[i].sm && smt[i].sm != sm)
  i++;
 return smt[i].state;
}

static struct bfa_fcport_sm_table_s hal_port_sm_table[] = {
 {BFA_SM(bfa_fcport_sm_uninit), BFA_PORT_ST_UNINIT},
 {BFA_SM(bfa_fcport_sm_enabling_qwait), BFA_PORT_ST_ENABLING_QWAIT},
 {BFA_SM(bfa_fcport_sm_enabling), BFA_PORT_ST_ENABLING},
 {BFA_SM(bfa_fcport_sm_linkdown), BFA_PORT_ST_LINKDOWN},
 {BFA_SM(bfa_fcport_sm_linkup), BFA_PORT_ST_LINKUP},
 {BFA_SM(bfa_fcport_sm_disabling_qwait), BFA_PORT_ST_DISABLING_QWAIT},
 {BFA_SM(bfa_fcport_sm_toggling_qwait), BFA_PORT_ST_TOGGLING_QWAIT},
 {BFA_SM(bfa_fcport_sm_disabling), BFA_PORT_ST_DISABLING},
 {BFA_SM(bfa_fcport_sm_disabled), BFA_PORT_ST_DISABLED},
 {BFA_SM(bfa_fcport_sm_stopped), BFA_PORT_ST_STOPPED},
 {BFA_SM(bfa_fcport_sm_iocdown), BFA_PORT_ST_IOCDOWN},
 {BFA_SM(bfa_fcport_sm_iocfail), BFA_PORT_ST_IOCDOWN},
 {BFA_SM(bfa_fcport_sm_dport), BFA_PORT_ST_DPORT},
 {BFA_SM(bfa_fcport_sm_ddport), BFA_PORT_ST_DDPORT},
 {BFA_SM(bfa_fcport_sm_faa_misconfig), BFA_PORT_ST_FAA_MISCONFIG},
};


/*
 * forward declaration for RPORT related functions
 */

static struct bfa_rport_s *bfa_rport_alloc(struct bfa_rport_mod_s *rp_mod);
static void  bfa_rport_free(struct bfa_rport_s *rport);
static bfa_boolean_t bfa_rport_send_fwcreate(struct bfa_rport_s *rp);
static bfa_boolean_t bfa_rport_send_fwdelete(struct bfa_rport_s *rp);
static bfa_boolean_t bfa_rport_send_fwspeed(struct bfa_rport_s *rp);
static void  __bfa_cb_rport_online(void *cbarg,
      bfa_boolean_t complete);
static void  __bfa_cb_rport_offline(void *cbarg,
      bfa_boolean_t complete);

/*
 * forward declaration for RPORT state machine
 */

static void     bfa_rport_sm_uninit(struct bfa_rport_s *rp,
     enum bfa_rport_event event);
static void     bfa_rport_sm_created(struct bfa_rport_s *rp,
     enum bfa_rport_event event);
static void     bfa_rport_sm_fwcreate(struct bfa_rport_s *rp,
     enum bfa_rport_event event);
static void     bfa_rport_sm_online(struct bfa_rport_s *rp,
     enum bfa_rport_event event);
static void     bfa_rport_sm_fwdelete(struct bfa_rport_s *rp,
     enum bfa_rport_event event);
static void     bfa_rport_sm_offline(struct bfa_rport_s *rp,
     enum bfa_rport_event event);
static void     bfa_rport_sm_deleting(struct bfa_rport_s *rp,
     enum bfa_rport_event event);
static void     bfa_rport_sm_offline_pending(struct bfa_rport_s *rp,
     enum bfa_rport_event event);
static void     bfa_rport_sm_delete_pending(struct bfa_rport_s *rp,
     enum bfa_rport_event event);
static void     bfa_rport_sm_iocdisable(struct bfa_rport_s *rp,
     enum bfa_rport_event event);
static void     bfa_rport_sm_fwcreate_qfull(struct bfa_rport_s *rp,
     enum bfa_rport_event event);
static void     bfa_rport_sm_fwdelete_qfull(struct bfa_rport_s *rp,
     enum bfa_rport_event event);
static void     bfa_rport_sm_deleting_qfull(struct bfa_rport_s *rp,
     enum bfa_rport_event event);

/*
 * PLOG related definitions
 */

static int
plkd_validate_logrec(struct bfa_plog_rec_s *pl_rec)
{
 if ((pl_rec->log_type != BFA_PL_LOG_TYPE_INT) &&
  (pl_rec->log_type != BFA_PL_LOG_TYPE_STRING))
  return 1;

 if ((pl_rec->log_type != BFA_PL_LOG_TYPE_INT) &&
  (pl_rec->log_num_ints > BFA_PL_INT_LOG_SZ))
  return 1;

 return 0;
}

static void
bfa_plog_add(struct bfa_plog_s *plog, struct bfa_plog_rec_s *pl_rec)
{
 u16 tail;
 struct bfa_plog_rec_s *pl_recp;

 if (plog->plog_enabled == 0)
  return;

 if (plkd_validate_logrec(pl_rec)) {
  WARN_ON(1);
  return;
 }

 tail = plog->tail;

 pl_recp = &(plog->plog_recs[tail]);

 memcpy(pl_recp, pl_rec, sizeof(struct bfa_plog_rec_s));

 pl_recp->tv = ktime_get_real_seconds();
 BFA_PL_LOG_REC_INCR(plog->tail);

 if (plog->head == plog->tail)
  BFA_PL_LOG_REC_INCR(plog->head);
}

void
bfa_plog_init(struct bfa_plog_s *plog)
{
 memset((char *)plog, 0, sizeof(struct bfa_plog_s));

 memcpy(plog->plog_sig, BFA_PL_SIG_STR, BFA_PL_SIG_LEN);
 plog->head = plog->tail = 0;
 plog->plog_enabled = 1;
}

void
bfa_plog_str(struct bfa_plog_s *plog, enum bfa_plog_mid mid,
  enum bfa_plog_eid event,
  u16 misc, char *log_str)
{
 struct bfa_plog_rec_s  lp;

 if (plog->plog_enabled) {
  memset(&lp, 0, sizeof(struct bfa_plog_rec_s));
  lp.mid = mid;
  lp.eid = event;
  lp.log_type = BFA_PL_LOG_TYPE_STRING;
  lp.misc = misc;
  strscpy(lp.log_entry.string_log, log_str,
   BFA_PL_STRING_LOG_SZ);
  lp.log_entry.string_log[BFA_PL_STRING_LOG_SZ - 1] = '\0';
  bfa_plog_add(plog, &lp);
 }
}

void
bfa_plog_intarr(struct bfa_plog_s *plog, enum bfa_plog_mid mid,
  enum bfa_plog_eid event,
  u16 misc, u32 *intarr, u32 num_ints)
{
 struct bfa_plog_rec_s  lp;
 u32 i;

 if (num_ints > BFA_PL_INT_LOG_SZ)
  num_ints = BFA_PL_INT_LOG_SZ;

 if (plog->plog_enabled) {
  memset(&lp, 0, sizeof(struct bfa_plog_rec_s));
  lp.mid = mid;
  lp.eid = event;
  lp.log_type = BFA_PL_LOG_TYPE_INT;
  lp.misc = misc;

  for (i = 0; i < num_ints; i++)
   lp.log_entry.int_log[i] = intarr[i];

  lp.log_num_ints = (u8) num_ints;

  bfa_plog_add(plog, &lp);
 }
}

void
bfa_plog_fchdr(struct bfa_plog_s *plog, enum bfa_plog_mid mid,
   enum bfa_plog_eid event,
   u16 misc, struct fchs_s *fchdr)
{
 u32 *tmp_int = (u32 *) fchdr;
 u32 ints[BFA_PL_INT_LOG_SZ];

 if (plog->plog_enabled) {
  ints[0] = tmp_int[0];
  ints[1] = tmp_int[1];
  ints[2] = tmp_int[4];

  bfa_plog_intarr(plog, mid, event, misc, ints, 3);
 }
}

void
bfa_plog_fchdr_and_pl(struct bfa_plog_s *plog, enum bfa_plog_mid mid,
        enum bfa_plog_eid event, u16 misc, struct fchs_s *fchdr,
        u32 pld_w0)
{
 u32 *tmp_int = (u32 *) fchdr;
 u32 ints[BFA_PL_INT_LOG_SZ];

 if (plog->plog_enabled) {
  ints[0] = tmp_int[0];
  ints[1] = tmp_int[1];
  ints[2] = tmp_int[4];
  ints[3] = pld_w0;

  bfa_plog_intarr(plog, mid, event, misc, ints, 4);
 }
}


/*
 *  fcxp_pvt BFA FCXP private functions
 */


static void
claim_fcxps_mem(struct bfa_fcxp_mod_s *mod)
{
 u16 i;
 struct bfa_fcxp_s *fcxp;

 fcxp = (struct bfa_fcxp_s *) bfa_mem_kva_curp(mod);
 memset(fcxp, 0, sizeof(struct bfa_fcxp_s) * mod->num_fcxps);

 INIT_LIST_HEAD(&mod->fcxp_req_free_q);
 INIT_LIST_HEAD(&mod->fcxp_rsp_free_q);
 INIT_LIST_HEAD(&mod->fcxp_active_q);
 INIT_LIST_HEAD(&mod->fcxp_req_unused_q);
 INIT_LIST_HEAD(&mod->fcxp_rsp_unused_q);

 mod->fcxp_list = fcxp;

 for (i = 0; i < mod->num_fcxps; i++) {
  fcxp->fcxp_mod = mod;
  fcxp->fcxp_tag = i;

  if (i < (mod->num_fcxps / 2)) {
   list_add_tail(&fcxp->qe, &mod->fcxp_req_free_q);
   fcxp->req_rsp = BFA_TRUE;
  } else {
   list_add_tail(&fcxp->qe, &mod->fcxp_rsp_free_q);
   fcxp->req_rsp = BFA_FALSE;
  }

  bfa_reqq_winit(&fcxp->reqq_wqe, bfa_fcxp_qresume, fcxp);
  fcxp->reqq_waiting = BFA_FALSE;

  fcxp = fcxp + 1;
 }

 bfa_mem_kva_curp(mod) = (void *)fcxp;
}

void
bfa_fcxp_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *minfo,
  struct bfa_s *bfa)
{
 struct bfa_fcxp_mod_s *fcxp_mod = BFA_FCXP_MOD(bfa);
 struct bfa_mem_kva_s *fcxp_kva = BFA_MEM_FCXP_KVA(bfa);
 struct bfa_mem_dma_s *seg_ptr;
 u16 nsegs, idx, per_seg_fcxp;
 u16 num_fcxps = cfg->fwcfg.num_fcxp_reqs;
 u32 per_fcxp_sz;

 if (num_fcxps == 0)
  return;

 if (cfg->drvcfg.min_cfg)
  per_fcxp_sz = 2 * BFA_FCXP_MAX_IBUF_SZ;
 else
  per_fcxp_sz = BFA_FCXP_MAX_IBUF_SZ + BFA_FCXP_MAX_LBUF_SZ;

 /* dma memory */
 nsegs = BFI_MEM_DMA_NSEGS(num_fcxps, per_fcxp_sz);
 per_seg_fcxp = BFI_MEM_NREQS_SEG(per_fcxp_sz);

 bfa_mem_dma_seg_iter(fcxp_mod, seg_ptr, nsegs, idx) {
  if (num_fcxps >= per_seg_fcxp) {
   num_fcxps -= per_seg_fcxp;
   bfa_mem_dma_setup(minfo, seg_ptr,
    per_seg_fcxp * per_fcxp_sz);
  } else
   bfa_mem_dma_setup(minfo, seg_ptr,
    num_fcxps * per_fcxp_sz);
 }

 /* kva memory */
 bfa_mem_kva_setup(minfo, fcxp_kva,
  cfg->fwcfg.num_fcxp_reqs * sizeof(struct bfa_fcxp_s));
}

void
bfa_fcxp_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
  struct bfa_pcidev_s *pcidev)
{
 struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa);

 mod->bfa = bfa;
 mod->num_fcxps = cfg->fwcfg.num_fcxp_reqs;

 /*
 * Initialize FCXP request and response payload sizes.
 */

 mod->req_pld_sz = mod->rsp_pld_sz = BFA_FCXP_MAX_IBUF_SZ;
 if (!cfg->drvcfg.min_cfg)
  mod->rsp_pld_sz = BFA_FCXP_MAX_LBUF_SZ;

 INIT_LIST_HEAD(&mod->req_wait_q);
 INIT_LIST_HEAD(&mod->rsp_wait_q);

 claim_fcxps_mem(mod);
}

void
bfa_fcxp_iocdisable(struct bfa_s *bfa)
{
 struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa);
 struct bfa_fcxp_s *fcxp;
 struct list_head       *qe, *qen;

 /* Enqueue unused fcxp resources to free_q */
 list_splice_tail_init(&mod->fcxp_req_unused_q, &mod->fcxp_req_free_q);
 list_splice_tail_init(&mod->fcxp_rsp_unused_q, &mod->fcxp_rsp_free_q);

 list_for_each_safe(qe, qen, &mod->fcxp_active_q) {
  fcxp = (struct bfa_fcxp_s *) qe;
  if (fcxp->caller == NULL) {
   fcxp->send_cbfn(fcxp->caller, fcxp, fcxp->send_cbarg,
     BFA_STATUS_IOC_FAILURE, 0, 0, NULL);
   bfa_fcxp_free(fcxp);
  } else {
   fcxp->rsp_status = BFA_STATUS_IOC_FAILURE;
   bfa_cb_queue(bfa, &fcxp->hcb_qe,
         __bfa_fcxp_send_cbfn, fcxp);
  }
 }
}

static struct bfa_fcxp_s *
bfa_fcxp_get(struct bfa_fcxp_mod_s *fm, bfa_boolean_t req)
{
 struct bfa_fcxp_s *fcxp;

 if (req)
  bfa_q_deq(&fm->fcxp_req_free_q, &fcxp);
 else
  bfa_q_deq(&fm->fcxp_rsp_free_q, &fcxp);

 if (fcxp)
  list_add_tail(&fcxp->qe, &fm->fcxp_active_q);

 return fcxp;
}

static void
bfa_fcxp_init_reqrsp(struct bfa_fcxp_s *fcxp,
        struct bfa_s *bfa,
        u8 *use_ibuf,
        u32 *nr_sgles,
        bfa_fcxp_get_sgaddr_t *r_sga_cbfn,
        bfa_fcxp_get_sglen_t *r_sglen_cbfn,
        struct list_head *r_sgpg_q,
        int n_sgles,
        bfa_fcxp_get_sgaddr_t sga_cbfn,
        bfa_fcxp_get_sglen_t sglen_cbfn)
{

 WARN_ON(bfa == NULL);

 bfa_trc(bfa, fcxp->fcxp_tag);

 if (n_sgles == 0) {
  *use_ibuf = 1;
 } else {
  WARN_ON(*sga_cbfn == NULL);
  WARN_ON(*sglen_cbfn == NULL);

  *use_ibuf = 0;
  *r_sga_cbfn = sga_cbfn;
  *r_sglen_cbfn = sglen_cbfn;

  *nr_sgles = n_sgles;

  /*
 * alloc required sgpgs
 */

  if (n_sgles > BFI_SGE_INLINE)
   WARN_ON(1);
 }

}

static void
bfa_fcxp_init(struct bfa_fcxp_s *fcxp,
        void *caller, struct bfa_s *bfa, int nreq_sgles,
        int nrsp_sgles, bfa_fcxp_get_sgaddr_t req_sga_cbfn,
        bfa_fcxp_get_sglen_t req_sglen_cbfn,
        bfa_fcxp_get_sgaddr_t rsp_sga_cbfn,
        bfa_fcxp_get_sglen_t rsp_sglen_cbfn)
{

 WARN_ON(bfa == NULL);

 bfa_trc(bfa, fcxp->fcxp_tag);

 fcxp->caller = caller;

 bfa_fcxp_init_reqrsp(fcxp, bfa,
  &fcxp->use_ireqbuf, &fcxp->nreq_sgles, &fcxp->req_sga_cbfn,
  &fcxp->req_sglen_cbfn, &fcxp->req_sgpg_q,
  nreq_sgles, req_sga_cbfn, req_sglen_cbfn);

 bfa_fcxp_init_reqrsp(fcxp, bfa,
  &fcxp->use_irspbuf, &fcxp->nrsp_sgles, &fcxp->rsp_sga_cbfn,
  &fcxp->rsp_sglen_cbfn, &fcxp->rsp_sgpg_q,
  nrsp_sgles, rsp_sga_cbfn, rsp_sglen_cbfn);

}

static void
bfa_fcxp_put(struct bfa_fcxp_s *fcxp)
{
 struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod;
 struct bfa_fcxp_wqe_s *wqe;

 if (fcxp->req_rsp)
  bfa_q_deq(&mod->req_wait_q, &wqe);
 else
  bfa_q_deq(&mod->rsp_wait_q, &wqe);

 if (wqe) {
  bfa_trc(mod->bfa, fcxp->fcxp_tag);

  bfa_fcxp_init(fcxp, wqe->caller, wqe->bfa, wqe->nreq_sgles,
   wqe->nrsp_sgles, wqe->req_sga_cbfn,
   wqe->req_sglen_cbfn, wqe->rsp_sga_cbfn,
   wqe->rsp_sglen_cbfn);

  wqe->alloc_cbfn(wqe->alloc_cbarg, fcxp);
  return;
 }

 WARN_ON(!bfa_q_is_on_q(&mod->fcxp_active_q, fcxp));
 list_del(&fcxp->qe);

 if (fcxp->req_rsp)
  list_add_tail(&fcxp->qe, &mod->fcxp_req_free_q);
 else
  list_add_tail(&fcxp->qe, &mod->fcxp_rsp_free_q);
}

static void
bfa_fcxp_null_comp(void *bfad_fcxp, struct bfa_fcxp_s *fcxp, void *cbarg,
     bfa_status_t req_status, u32 rsp_len,
     u32 resid_len, struct fchs_s *rsp_fchs)
{
 /* discarded fcxp completion */
}

static void
__bfa_fcxp_send_cbfn(void *cbarg, bfa_boolean_t complete)
{
 struct bfa_fcxp_s *fcxp = cbarg;

 if (complete) {
  fcxp->send_cbfn(fcxp->caller, fcxp, fcxp->send_cbarg,
    fcxp->rsp_status, fcxp->rsp_len,
    fcxp->residue_len, &fcxp->rsp_fchs);
 } else {
  bfa_fcxp_free(fcxp);
 }
}

static void
hal_fcxp_send_comp(struct bfa_s *bfa, struct bfi_fcxp_send_rsp_s *fcxp_rsp)
{
 struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa);
 struct bfa_fcxp_s *fcxp;
 u16  fcxp_tag = be16_to_cpu(fcxp_rsp->fcxp_tag);

 bfa_trc(bfa, fcxp_tag);

 fcxp_rsp->rsp_len = be32_to_cpu(fcxp_rsp->rsp_len);

 /*
 * @todo f/w should not set residue to non-0 when everything
 *  is received.
 */

 if (fcxp_rsp->req_status == BFA_STATUS_OK)
  fcxp_rsp->residue_len = 0;
 else
  fcxp_rsp->residue_len = be32_to_cpu(fcxp_rsp->residue_len);

 fcxp = BFA_FCXP_FROM_TAG(mod, fcxp_tag);

 WARN_ON(fcxp->send_cbfn == NULL);

 hal_fcxp_rx_plog(mod->bfa, fcxp, fcxp_rsp);

 if (fcxp->send_cbfn != NULL) {
  bfa_trc(mod->bfa, (NULL == fcxp->caller));
  if (fcxp->caller == NULL) {
   fcxp->send_cbfn(fcxp->caller, fcxp, fcxp->send_cbarg,
     fcxp_rsp->req_status, fcxp_rsp->rsp_len,
     fcxp_rsp->residue_len, &fcxp_rsp->fchs);
   /*
 * fcxp automatically freed on return from the callback
 */

   bfa_fcxp_free(fcxp);
  } else {
   fcxp->rsp_status = fcxp_rsp->req_status;
   fcxp->rsp_len = fcxp_rsp->rsp_len;
   fcxp->residue_len = fcxp_rsp->residue_len;
   fcxp->rsp_fchs = fcxp_rsp->fchs;

   bfa_cb_queue(bfa, &fcxp->hcb_qe,
     __bfa_fcxp_send_cbfn, fcxp);
  }
 } else {
  bfa_trc(bfa, (NULL == fcxp->send_cbfn));
 }
}

static void
hal_fcxp_tx_plog(struct bfa_s *bfa, u32 reqlen, struct bfa_fcxp_s *fcxp,
   struct fchs_s *fchs)
{
 /*
 * TODO: TX ox_id
 */

 if (reqlen > 0) {
  if (fcxp->use_ireqbuf) {
   u32 pld_w0 =
    *((u32 *) BFA_FCXP_REQ_PLD(fcxp));

   bfa_plog_fchdr_and_pl(bfa->plog, BFA_PL_MID_HAL_FCXP,
     BFA_PL_EID_TX,
     reqlen + sizeof(struct fchs_s), fchs,
     pld_w0);
  } else {
   bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_FCXP,
     BFA_PL_EID_TX,
     reqlen + sizeof(struct fchs_s),
     fchs);
  }
 } else {
  bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_FCXP, BFA_PL_EID_TX,
          reqlen + sizeof(struct fchs_s), fchs);
 }
}

static void
hal_fcxp_rx_plog(struct bfa_s *bfa, struct bfa_fcxp_s *fcxp,
   struct bfi_fcxp_send_rsp_s *fcxp_rsp)
{
 if (fcxp_rsp->rsp_len > 0) {
  if (fcxp->use_irspbuf) {
   u32 pld_w0 =
    *((u32 *) BFA_FCXP_RSP_PLD(fcxp));

   bfa_plog_fchdr_and_pl(bfa->plog, BFA_PL_MID_HAL_FCXP,
           BFA_PL_EID_RX,
           (u16) fcxp_rsp->rsp_len,
           &fcxp_rsp->fchs, pld_w0);
  } else {
   bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_FCXP,
           BFA_PL_EID_RX,
           (u16) fcxp_rsp->rsp_len,
           &fcxp_rsp->fchs);
  }
 } else {
  bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_FCXP, BFA_PL_EID_RX,
          (u16) fcxp_rsp->rsp_len, &fcxp_rsp->fchs);
 }
}

/*
 * Handler to resume sending fcxp when space in available in cpe queue.
 */

static void
bfa_fcxp_qresume(void *cbarg)
{
 struct bfa_fcxp_s  *fcxp = cbarg;
 struct bfa_s   *bfa = fcxp->fcxp_mod->bfa;
 struct bfi_fcxp_send_req_s *send_req;

 fcxp->reqq_waiting = BFA_FALSE;
 send_req = bfa_reqq_next(bfa, BFA_REQQ_FCXP);
 bfa_fcxp_queue(fcxp, send_req);
}

/*
 * Queue fcxp send request to foimrware.
 */

static void
bfa_fcxp_queue(struct bfa_fcxp_s *fcxp, struct bfi_fcxp_send_req_s *send_req)
{
 struct bfa_s   *bfa = fcxp->fcxp_mod->bfa;
 struct bfa_fcxp_req_info_s *reqi = &fcxp->req_info;
 struct bfa_fcxp_rsp_info_s *rspi = &fcxp->rsp_info;
 struct bfa_rport_s  *rport = reqi->bfa_rport;

 bfi_h2i_set(send_req->mh, BFI_MC_FCXP, BFI_FCXP_H2I_SEND_REQ,
      bfa_fn_lpu(bfa));

 send_req->fcxp_tag = cpu_to_be16(fcxp->fcxp_tag);
 if (rport) {
  send_req->rport_fw_hndl = rport->fw_handle;
  send_req->max_frmsz = cpu_to_be16(rport->rport_info.max_frmsz);
  if (send_req->max_frmsz == 0)
   send_req->max_frmsz = cpu_to_be16(FC_MAX_PDUSZ);
 } else {
  send_req->rport_fw_hndl = 0;
  send_req->max_frmsz = cpu_to_be16(FC_MAX_PDUSZ);
 }

 send_req->vf_id = cpu_to_be16(reqi->vf_id);
 send_req->lp_fwtag = bfa_lps_get_fwtag(bfa, reqi->lp_tag);
 send_req->class = reqi->class;
 send_req->rsp_timeout = rspi->rsp_timeout;
 send_req->cts = reqi->cts;
 send_req->fchs = reqi->fchs;

 send_req->req_len = cpu_to_be32(reqi->req_tot_len);
 send_req->rsp_maxlen = cpu_to_be32(rspi->rsp_maxlen);

 /*
 * setup req sgles
 */

 if (fcxp->use_ireqbuf == 1) {
  bfa_alen_set(&send_req->req_alen, reqi->req_tot_len,
     BFA_FCXP_REQ_PLD_PA(fcxp));
 } else {
  if (fcxp->nreq_sgles > 0) {
   WARN_ON(fcxp->nreq_sgles != 1);
   bfa_alen_set(&send_req->req_alen, reqi->req_tot_len,
    fcxp->req_sga_cbfn(fcxp->caller, 0));
  } else {
   WARN_ON(reqi->req_tot_len != 0);
   bfa_alen_set(&send_req->rsp_alen, 0, 0);
  }
 }

 /*
 * setup rsp sgles
 */

 if (fcxp->use_irspbuf == 1) {
  WARN_ON(rspi->rsp_maxlen > BFA_FCXP_MAX_LBUF_SZ);

  bfa_alen_set(&send_req->rsp_alen, rspi->rsp_maxlen,
     BFA_FCXP_RSP_PLD_PA(fcxp));
 } else {
  if (fcxp->nrsp_sgles > 0) {
   WARN_ON(fcxp->nrsp_sgles != 1);
   bfa_alen_set(&send_req->rsp_alen, rspi->rsp_maxlen,
    fcxp->rsp_sga_cbfn(fcxp->caller, 0));

  } else {
   WARN_ON(rspi->rsp_maxlen != 0);
   bfa_alen_set(&send_req->rsp_alen, 0, 0);
  }
 }

 hal_fcxp_tx_plog(bfa, reqi->req_tot_len, fcxp, &reqi->fchs);

 bfa_reqq_produce(bfa, BFA_REQQ_FCXP, send_req->mh);

 bfa_trc(bfa, bfa_reqq_pi(bfa, BFA_REQQ_FCXP));
 bfa_trc(bfa, bfa_reqq_ci(bfa, BFA_REQQ_FCXP));
}

/*
 * Allocate an FCXP instance to send a response or to send a request
 * that has a response. Request/response buffers are allocated by caller.
 *
 * @param[in] bfa BFA bfa instance
 * @param[in] nreq_sgles Number of SG elements required for request
 * buffer. 0, if fcxp internal buffers are used.
 * Use bfa_fcxp_get_reqbuf() to get the
 * internal req buffer.
 * @param[in] req_sgles SG elements describing request buffer. Will be
 * copied in by BFA and hence can be freed on
 * return from this function.
 * @param[in] get_req_sga function ptr to be called to get a request SG
 * Address (given the sge index).
 * @param[in] get_req_sglen function ptr to be called to get a request SG
 * len (given the sge index).
 * @param[in] get_rsp_sga function ptr to be called to get a response SG
 * Address (given the sge index).
 * @param[in] get_rsp_sglen function ptr to be called to get a response SG
 * len (given the sge index).
 * @param[in] req Allocated FCXP is used to send req or rsp?
 * request - BFA_TRUE, response - BFA_FALSE
 *
 * @return FCXP instance. NULL on failure.
 */

struct bfa_fcxp_s *
bfa_fcxp_req_rsp_alloc(void *caller, struct bfa_s *bfa, int nreq_sgles,
  int nrsp_sgles, bfa_fcxp_get_sgaddr_t req_sga_cbfn,
  bfa_fcxp_get_sglen_t req_sglen_cbfn,
  bfa_fcxp_get_sgaddr_t rsp_sga_cbfn,
  bfa_fcxp_get_sglen_t rsp_sglen_cbfn, bfa_boolean_t req)
{
 struct bfa_fcxp_s *fcxp = NULL;

 WARN_ON(bfa == NULL);

 fcxp = bfa_fcxp_get(BFA_FCXP_MOD(bfa), req);
 if (fcxp == NULL)
  return NULL;

 bfa_trc(bfa, fcxp->fcxp_tag);

 bfa_fcxp_init(fcxp, caller, bfa, nreq_sgles, nrsp_sgles, req_sga_cbfn,
   req_sglen_cbfn, rsp_sga_cbfn, rsp_sglen_cbfn);

 return fcxp;
}

/*
 * Get the internal request buffer pointer
 *
 * @param[in] fcxp BFA fcxp pointer
 *
 * @return pointer to the internal request buffer
 */

void *
bfa_fcxp_get_reqbuf(struct bfa_fcxp_s *fcxp)
{
 struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod;
 void *reqbuf;

 WARN_ON(fcxp->use_ireqbuf != 1);
 reqbuf = bfa_mem_get_dmabuf_kva(mod, fcxp->fcxp_tag,
    mod->req_pld_sz + mod->rsp_pld_sz);
 return reqbuf;
}

/*
 * Get the internal response buffer pointer
 *
 * @param[in] fcxp BFA fcxp pointer
 *
 * @return pointer to the internal request buffer
 */

void *
bfa_fcxp_get_rspbuf(struct bfa_fcxp_s *fcxp)
{
 struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod;
 void *fcxp_buf;

 WARN_ON(fcxp->use_irspbuf != 1);

 fcxp_buf = bfa_mem_get_dmabuf_kva(mod, fcxp->fcxp_tag,
    mod->req_pld_sz + mod->rsp_pld_sz);

 /* fcxp_buf = req_buf + rsp_buf :- add req_buf_sz to get to rsp_buf */
 return ((u8 *) fcxp_buf) + mod->req_pld_sz;
}

/*
 * Free the BFA FCXP
 *
 * @param[in] fcxp BFA fcxp pointer
 *
 * @return void
 */

void
bfa_fcxp_free(struct bfa_fcxp_s *fcxp)
{
 struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod;

 WARN_ON(fcxp == NULL);
 bfa_trc(mod->bfa, fcxp->fcxp_tag);
 bfa_fcxp_put(fcxp);
}

/*
 * Send a FCXP request
 *
 * @param[in] fcxp BFA fcxp pointer
 * @param[in] rport BFA rport pointer. Could be left NULL for WKA rports
 * @param[in] vf_id virtual Fabric ID
 * @param[in] lp_tag lport tag
 * @param[in] cts use Continuous sequence
 * @param[in] cos fc Class of Service
 * @param[in] reqlen request length, does not include FCHS length
 * @param[in] fchs fc Header Pointer. The header content will be copied
 * in by BFA.
 *
 * @param[in] cbfn call back function to be called on receiving
 * the response
 * @param[in] cbarg arg for cbfn
 * @param[in] rsp_timeout
 * response timeout
 *
 * @return bfa_status_t
 */

void
bfa_fcxp_send(struct bfa_fcxp_s *fcxp, struct bfa_rport_s *rport,
       u16 vf_id, u8 lp_tag, bfa_boolean_t cts, enum fc_cos cos,
       u32 reqlen, struct fchs_s *fchs, bfa_cb_fcxp_send_t cbfn,
       void *cbarg, u32 rsp_maxlen, u8 rsp_timeout)
{
 struct bfa_s   *bfa  = fcxp->fcxp_mod->bfa;
 struct bfa_fcxp_req_info_s *reqi = &fcxp->req_info;
 struct bfa_fcxp_rsp_info_s *rspi = &fcxp->rsp_info;
 struct bfi_fcxp_send_req_s *send_req;

 bfa_trc(bfa, fcxp->fcxp_tag);

 /*
 * setup request/response info
 */

 reqi->bfa_rport = rport;
 reqi->vf_id = vf_id;
 reqi->lp_tag = lp_tag;
 reqi->class = cos;
 rspi->rsp_timeout = rsp_timeout;
 reqi->cts = cts;
 reqi->fchs = *fchs;
 reqi->req_tot_len = reqlen;
 rspi->rsp_maxlen = rsp_maxlen;
 fcxp->send_cbfn = cbfn ? cbfn : bfa_fcxp_null_comp;
 fcxp->send_cbarg = cbarg;

 /*
 * If no room in CPE queue, wait for space in request queue
 */

 send_req = bfa_reqq_next(bfa, BFA_REQQ_FCXP);
 if (!send_req) {
  bfa_trc(bfa, fcxp->fcxp_tag);
  fcxp->reqq_waiting = BFA_TRUE;
  bfa_reqq_wait(bfa, BFA_REQQ_FCXP, &fcxp->reqq_wqe);
  return;
 }

 bfa_fcxp_queue(fcxp, send_req);
}

void
bfa_fcxp_req_rsp_alloc_wait(struct bfa_s *bfa, struct bfa_fcxp_wqe_s *wqe,
        bfa_fcxp_alloc_cbfn_t alloc_cbfn, void *alloc_cbarg,
        void *caller, int nreq_sgles,
        int nrsp_sgles, bfa_fcxp_get_sgaddr_t req_sga_cbfn,
        bfa_fcxp_get_sglen_t req_sglen_cbfn,
        bfa_fcxp_get_sgaddr_t rsp_sga_cbfn,
        bfa_fcxp_get_sglen_t rsp_sglen_cbfn, bfa_boolean_t req)
{
 struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa);

 if (req)
  WARN_ON(!list_empty(&mod->fcxp_req_free_q));
 else
  WARN_ON(!list_empty(&mod->fcxp_rsp_free_q));

 wqe->alloc_cbfn = alloc_cbfn;
 wqe->alloc_cbarg = alloc_cbarg;
 wqe->caller = caller;
 wqe->bfa = bfa;
 wqe->nreq_sgles = nreq_sgles;
 wqe->nrsp_sgles = nrsp_sgles;
 wqe->req_sga_cbfn = req_sga_cbfn;
 wqe->req_sglen_cbfn = req_sglen_cbfn;
 wqe->rsp_sga_cbfn = rsp_sga_cbfn;
 wqe->rsp_sglen_cbfn = rsp_sglen_cbfn;

 if (req)
  list_add_tail(&wqe->qe, &mod->req_wait_q);
 else
  list_add_tail(&wqe->qe, &mod->rsp_wait_q);
}

void
bfa_fcxp_walloc_cancel(struct bfa_s *bfa, struct bfa_fcxp_wqe_s *wqe)
{
 struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa);

 WARN_ON(!bfa_q_is_on_q(&mod->req_wait_q, wqe) ||
  !bfa_q_is_on_q(&mod->rsp_wait_q, wqe));
 list_del(&wqe->qe);
}

void
bfa_fcxp_discard(struct bfa_fcxp_s *fcxp)
{
 /*
 * If waiting for room in request queue, cancel reqq wait
 * and free fcxp.
 */

 if (fcxp->reqq_waiting) {
  fcxp->reqq_waiting = BFA_FALSE;
  bfa_reqq_wcancel(&fcxp->reqq_wqe);
  bfa_fcxp_free(fcxp);
  return;
 }

 fcxp->send_cbfn = bfa_fcxp_null_comp;
}

void
bfa_fcxp_isr(struct bfa_s *bfa, struct bfi_msg_s *msg)
{
 switch (msg->mhdr.msg_id) {
 case BFI_FCXP_I2H_SEND_RSP:
  hal_fcxp_send_comp(bfa, (struct bfi_fcxp_send_rsp_s *) msg);
  break;

 default:
  bfa_trc(bfa, msg->mhdr.msg_id);
  WARN_ON(1);
 }
}

u32
bfa_fcxp_get_maxrsp(struct bfa_s *bfa)
{
 struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa);

 return mod->rsp_pld_sz;
}

void
bfa_fcxp_res_recfg(struct bfa_s *bfa, u16 num_fcxp_fw)
{
 struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa);
 struct list_head *qe;
 int i;

 for (i = 0; i < (mod->num_fcxps - num_fcxp_fw); i++) {
  if (i < ((mod->num_fcxps - num_fcxp_fw) / 2)) {
   bfa_q_deq_tail(&mod->fcxp_req_free_q, &qe);
   list_add_tail(qe, &mod->fcxp_req_unused_q);
  } else {
   bfa_q_deq_tail(&mod->fcxp_rsp_free_q, &qe);
   list_add_tail(qe, &mod->fcxp_rsp_unused_q);
  }
 }
}

/*
 *  BFA LPS state machine functions
 */


/*
 * Init state -- no login
 */

static void
bfa_lps_sm_init(struct bfa_lps_s *lps, enum bfa_lps_event event)
{
 bfa_trc(lps->bfa, lps->bfa_tag);
 bfa_trc(lps->bfa, event);

 switch (event) {
 case BFA_LPS_SM_LOGIN:
  if (bfa_reqq_full(lps->bfa, lps->reqq)) {
   bfa_sm_set_state(lps, bfa_lps_sm_loginwait);
   bfa_reqq_wait(lps->bfa, lps->reqq, &lps->wqe);
  } else {
   bfa_sm_set_state(lps, bfa_lps_sm_login);
   bfa_lps_send_login(lps);
  }

  if (lps->fdisc)
   bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS,
    BFA_PL_EID_LOGIN, 0, "FDISC Request");
  else
   bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS,
    BFA_PL_EID_LOGIN, 0, "FLOGI Request");
  break;

 case BFA_LPS_SM_LOGOUT:
  bfa_lps_logout_comp(lps);
  break;

 case BFA_LPS_SM_DELETE:
  bfa_lps_free(lps);
  break;

 case BFA_LPS_SM_RX_CVL:
 case BFA_LPS_SM_OFFLINE:
  break;

 case BFA_LPS_SM_FWRSP:
  /*
 * Could happen when fabric detects loopback and discards
 * the lps request. Fw will eventually sent out the timeout
 * Just ignore
 */

  break;
 case BFA_LPS_SM_SET_N2N_PID:
  /*
 * When topology is set to loop, bfa_lps_set_n2n_pid() sends
 * this event. Ignore this event.
 */

  break;

 default:
  bfa_sm_fault(lps->bfa, event);
 }
}

/*
 * login is in progress -- awaiting response from firmware
 */

static void
bfa_lps_sm_login(struct bfa_lps_s *lps, enum bfa_lps_event event)
{
 bfa_trc(lps->bfa, lps->bfa_tag);
 bfa_trc(lps->bfa, event);

 switch (event) {
 case BFA_LPS_SM_FWRSP:
  if (lps->status == BFA_STATUS_OK) {
   bfa_sm_set_state(lps, bfa_lps_sm_online);
   if (lps->fdisc)
    bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS,
     BFA_PL_EID_LOGIN, 0, "FDISC Accept");
   else
    bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS,
     BFA_PL_EID_LOGIN, 0, "FLOGI Accept");
   /* If N2N, send the assigned PID to FW */
   bfa_trc(lps->bfa, lps->fport);
   bfa_trc(lps->bfa, lps->lp_pid);

   if (!lps->fport && lps->lp_pid)
    bfa_sm_send_event(lps, BFA_LPS_SM_SET_N2N_PID);
  } else {
   bfa_sm_set_state(lps, bfa_lps_sm_init);
   if (lps->fdisc)
    bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS,
     BFA_PL_EID_LOGIN, 0,
     "FDISC Fail (RJT or timeout)");
   else
    bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS,
     BFA_PL_EID_LOGIN, 0,
     "FLOGI Fail (RJT or timeout)");
  }
  bfa_lps_login_comp(lps);
  break;

 case BFA_LPS_SM_OFFLINE:
 case BFA_LPS_SM_DELETE:
  bfa_sm_set_state(lps, bfa_lps_sm_init);
  break;

 case BFA_LPS_SM_SET_N2N_PID:
  bfa_trc(lps->bfa, lps->fport);
  bfa_trc(lps->bfa, lps->lp_pid);
  break;

 default:
  bfa_sm_fault(lps->bfa, event);
 }
}

/*
 * login pending - awaiting space in request queue
 */

static void
bfa_lps_sm_loginwait(struct bfa_lps_s *lps, enum bfa_lps_event event)
{
 bfa_trc(lps->bfa, lps->bfa_tag);
 bfa_trc(lps->bfa, event);

 switch (event) {
 case BFA_LPS_SM_RESUME:
  bfa_sm_set_state(lps, bfa_lps_sm_login);
  bfa_lps_send_login(lps);
  break;

 case BFA_LPS_SM_OFFLINE:
 case BFA_LPS_SM_DELETE:
  bfa_sm_set_state(lps, bfa_lps_sm_init);
  bfa_reqq_wcancel(&lps->wqe);
  break;

 case BFA_LPS_SM_RX_CVL:
  /*
 * Login was not even sent out; so when getting out
 * of this state, it will appear like a login retry
 * after Clear virtual link
 */

  break;

 default:
  bfa_sm_fault(lps->bfa, event);
 }
}

/*
 * login complete
 */

static void
bfa_lps_sm_online(struct bfa_lps_s *lps, enum bfa_lps_event event)
{
 bfa_trc(lps->bfa, lps->bfa_tag);
 bfa_trc(lps->bfa, event);

 switch (event) {
 case BFA_LPS_SM_LOGOUT:
  if (bfa_reqq_full(lps->bfa, lps->reqq)) {
   bfa_sm_set_state(lps, bfa_lps_sm_logowait);
   bfa_reqq_wait(lps->bfa, lps->reqq, &lps->wqe);
  } else {
   bfa_sm_set_state(lps, bfa_lps_sm_logout);
   bfa_lps_send_logout(lps);
  }
  bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS,
   BFA_PL_EID_LOGO, 0, "Logout");
  break;

 case BFA_LPS_SM_RX_CVL:
  bfa_sm_set_state(lps, bfa_lps_sm_init);

  /* Let the vport module know about this event */
  bfa_lps_cvl_event(lps);
  bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS,
   BFA_PL_EID_FIP_FCF_CVL, 0, "FCF Clear Virt. Link Rx");
  break;

 case BFA_LPS_SM_SET_N2N_PID:
  if (bfa_reqq_full(lps->bfa, lps->reqq)) {
   bfa_sm_set_state(lps, bfa_lps_sm_online_n2n_pid_wait);
   bfa_reqq_wait(lps->bfa, lps->reqq, &lps->wqe);
  } else
   bfa_lps_send_set_n2n_pid(lps);
  break;

 case BFA_LPS_SM_OFFLINE:
 case BFA_LPS_SM_DELETE:
  bfa_sm_set_state(lps, bfa_lps_sm_init);
  break;

 default:
  bfa_sm_fault(lps->bfa, event);
 }
}

/*
 * login complete
 */

static void
bfa_lps_sm_online_n2n_pid_wait(struct bfa_lps_s *lps, enum bfa_lps_event event)
{
 bfa_trc(lps->bfa, lps->bfa_tag);
 bfa_trc(lps->bfa, event);

 switch (event) {
 case BFA_LPS_SM_RESUME:
  bfa_sm_set_state(lps, bfa_lps_sm_online);
  bfa_lps_send_set_n2n_pid(lps);
  break;

 case BFA_LPS_SM_LOGOUT:
  bfa_sm_set_state(lps, bfa_lps_sm_logowait);
  bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS,
   BFA_PL_EID_LOGO, 0, "Logout");
  break;

 case BFA_LPS_SM_RX_CVL:
  bfa_sm_set_state(lps, bfa_lps_sm_init);
  bfa_reqq_wcancel(&lps->wqe);

  /* Let the vport module know about this event */
  bfa_lps_cvl_event(lps);
  bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS,
   BFA_PL_EID_FIP_FCF_CVL, 0, "FCF Clear Virt. Link Rx");
  break;

 case BFA_LPS_SM_OFFLINE:
 case BFA_LPS_SM_DELETE:
  bfa_sm_set_state(lps, bfa_lps_sm_init);
  bfa_reqq_wcancel(&lps->wqe);
  break;

 default:
  bfa_sm_fault(lps->bfa, event);
 }
}

/*
 * logout in progress - awaiting firmware response
 */

static void
bfa_lps_sm_logout(struct bfa_lps_s *lps, enum bfa_lps_event event)
{
 bfa_trc(lps->bfa, lps->bfa_tag);
 bfa_trc(lps->bfa, event);

 switch (event) {
 case BFA_LPS_SM_FWRSP:
 case BFA_LPS_SM_OFFLINE:
  bfa_sm_set_state(lps, bfa_lps_sm_init);
  bfa_lps_logout_comp(lps);
  break;

 case BFA_LPS_SM_DELETE:
  bfa_sm_set_state(lps, bfa_lps_sm_init);
  break;

 default:
  bfa_sm_fault(lps->bfa, event);
 }
}

/*
 * logout pending -- awaiting space in request queue
 */

static void
bfa_lps_sm_logowait(struct bfa_lps_s *lps, enum bfa_lps_event event)
{
 bfa_trc(lps->bfa, lps->bfa_tag);
 bfa_trc(lps->bfa, event);

 switch (event) {
 case BFA_LPS_SM_RESUME:
  bfa_sm_set_state(lps, bfa_lps_sm_logout);
  bfa_lps_send_logout(lps);
  break;

 case BFA_LPS_SM_OFFLINE:
 case BFA_LPS_SM_DELETE:
  bfa_sm_set_state(lps, bfa_lps_sm_init);
  bfa_reqq_wcancel(&lps->wqe);
  break;

 default:
  bfa_sm_fault(lps->bfa, event);
 }
}



/*
 *  lps_pvt BFA LPS private functions
 */


/*
 * return memory requirement
 */

void
bfa_lps_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *minfo,
  struct bfa_s *bfa)
{
 struct bfa_mem_kva_s *lps_kva = BFA_MEM_LPS_KVA(bfa);

 if (cfg->drvcfg.min_cfg)
  bfa_mem_kva_setup(minfo, lps_kva,
   sizeof(struct bfa_lps_s) * BFA_LPS_MIN_LPORTS);
 else
  bfa_mem_kva_setup(minfo, lps_kva,
   sizeof(struct bfa_lps_s) * BFA_LPS_MAX_LPORTS);
}

/*
 * bfa module attach at initialization time
 */

void
bfa_lps_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
 struct bfa_pcidev_s *pcidev)
{
 struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa);
 struct bfa_lps_s *lps;
 int   i;

 mod->num_lps = BFA_LPS_MAX_LPORTS;
 if (cfg->drvcfg.min_cfg)
  mod->num_lps = BFA_LPS_MIN_LPORTS;
 else
  mod->num_lps = BFA_LPS_MAX_LPORTS;
 mod->lps_arr = lps = (struct bfa_lps_s *) bfa_mem_kva_curp(mod);

 bfa_mem_kva_curp(mod) += mod->num_lps * sizeof(struct bfa_lps_s);

 INIT_LIST_HEAD(&mod->lps_free_q);
 INIT_LIST_HEAD(&mod->lps_active_q);
 INIT_LIST_HEAD(&mod->lps_login_q);

 for (i = 0; i < mod->num_lps; i++, lps++) {
  lps->bfa = bfa;
  lps->bfa_tag = (u8) i;
  lps->reqq = BFA_REQQ_LPS;
  bfa_reqq_winit(&lps->wqe, bfa_lps_reqq_resume, lps);
  list_add_tail(&lps->qe, &mod->lps_free_q);
 }
}

/*
 * IOC in disabled state -- consider all lps offline
 */

void
bfa_lps_iocdisable(struct bfa_s *bfa)
{
 struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa);
 struct bfa_lps_s *lps;
 struct list_head  *qe, *qen;

 list_for_each_safe(qe, qen, &mod->lps_active_q) {
  lps = (struct bfa_lps_s *) qe;
  bfa_sm_send_event(lps, BFA_LPS_SM_OFFLINE);
 }
 list_for_each_safe(qe, qen, &mod->lps_login_q) {
  lps = (struct bfa_lps_s *) qe;
  bfa_sm_send_event(lps, BFA_LPS_SM_OFFLINE);
 }
 list_splice_tail_init(&mod->lps_login_q, &mod->lps_active_q);
}

/*
 * Firmware login response
 */

static void
bfa_lps_login_rsp(struct bfa_s *bfa, struct bfi_lps_login_rsp_s *rsp)
{
 struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa);
 struct bfa_lps_s *lps;

 WARN_ON(rsp->bfa_tag >= mod->num_lps);
 lps = BFA_LPS_FROM_TAG(mod, rsp->bfa_tag);

 lps->status = rsp->status;
 switch (rsp->status) {
 case BFA_STATUS_OK:
  lps->fw_tag = rsp->fw_tag;
  lps->fport = rsp->f_port;
  if (lps->fport)
   lps->lp_pid = rsp->lp_pid;
  lps->npiv_en = rsp->npiv_en;
  lps->pr_bbcred = be16_to_cpu(rsp->bb_credit);
  lps->pr_pwwn = rsp->port_name;
  lps->pr_nwwn = rsp->node_name;
  lps->auth_req = rsp->auth_req;
  lps->lp_mac = rsp->lp_mac;
  lps->brcd_switch = rsp->brcd_switch;
  lps->fcf_mac = rsp->fcf_mac;

  break;

 case BFA_STATUS_FABRIC_RJT:
  lps->lsrjt_rsn = rsp->lsrjt_rsn;
  lps->lsrjt_expl = rsp->lsrjt_expl;

  break;

 case BFA_STATUS_EPROTOCOL:
  lps->ext_status = rsp->ext_status;

  break;

 case BFA_STATUS_VPORT_MAX:
  if (rsp->ext_status)
   bfa_lps_no_res(lps, rsp->ext_status);
  break;

 default:
  /* Nothing to do with other status */
  break;
 }

 list_del(&lps->qe);
 list_add_tail(&lps->qe, &mod->lps_active_q);
 bfa_sm_send_event(lps, BFA_LPS_SM_FWRSP);
}

static void
bfa_lps_no_res(struct bfa_lps_s *first_lps, u8 count)
{
 struct bfa_s  *bfa = first_lps->bfa;
 struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa);
 struct list_head *qe, *qe_next;
 struct bfa_lps_s *lps;

 bfa_trc(bfa, count);

 qe = bfa_q_next(first_lps);

 while (count && qe) {
  qe_next = bfa_q_next(qe);
  lps = (struct bfa_lps_s *)qe;
  bfa_trc(bfa, lps->bfa_tag);
  lps->status = first_lps->status;
  list_del(&lps->qe);
  list_add_tail(&lps->qe, &mod->lps_active_q);
  bfa_sm_send_event(lps, BFA_LPS_SM_FWRSP);
  qe = qe_next;
  count--;
 }
}

/*
 * Firmware logout response
 */

static void
bfa_lps_logout_rsp(struct bfa_s *bfa, struct bfi_lps_logout_rsp_s *rsp)
{
 struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa);
 struct bfa_lps_s *lps;

 WARN_ON(rsp->bfa_tag >= mod->num_lps);
 lps = BFA_LPS_FROM_TAG(mod, rsp->bfa_tag);

 bfa_sm_send_event(lps, BFA_LPS_SM_FWRSP);
}

/*
 * Firmware received a Clear virtual link request (for FCoE)
 */

static void
bfa_lps_rx_cvl_event(struct bfa_s *bfa, struct bfi_lps_cvl_event_s *cvl)
{
 struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa);
 struct bfa_lps_s *lps;

 lps = BFA_LPS_FROM_TAG(mod, cvl->bfa_tag);

 bfa_sm_send_event(lps, BFA_LPS_SM_RX_CVL);
}

/*
 * Space is available in request queue, resume queueing request to firmware.
 */

static void
bfa_lps_reqq_resume(void *lps_arg)
{
 struct bfa_lps_s *lps = lps_arg;

 bfa_sm_send_event(lps, BFA_LPS_SM_RESUME);
}

/*
 * lps is freed -- triggered by vport delete
 */

static void
bfa_lps_free(struct bfa_lps_s *lps)
{
 struct bfa_lps_mod_s *mod = BFA_LPS_MOD(lps->bfa);

 lps->lp_pid = 0;
 list_del(&lps->qe);
 list_add_tail(&lps->qe, &mod->lps_free_q);
}

/*
 * send login request to firmware
 */

static void
bfa_lps_send_login(struct bfa_lps_s *lps)
{
 struct bfa_lps_mod_s *mod = BFA_LPS_MOD(lps->bfa);
 struct bfi_lps_login_req_s *m;

 m = bfa_reqq_next(lps->bfa, lps->reqq);
 WARN_ON(!m);

 bfi_h2i_set(m->mh, BFI_MC_LPS, BFI_LPS_H2I_LOGIN_REQ,
  bfa_fn_lpu(lps->bfa));

 m->bfa_tag = lps->bfa_tag;
 m->alpa  = lps->alpa;
 m->pdu_size = cpu_to_be16(lps->pdusz);
 m->pwwn  = lps->pwwn;
 m->nwwn  = lps->nwwn;
 m->fdisc = lps->fdisc;
 m->auth_en = lps->auth_en;

 bfa_reqq_produce(lps->bfa, lps->reqq, m->mh);
 list_del(&lps->qe);
 list_add_tail(&lps->qe, &mod->lps_login_q);
}

/*
 * send logout request to firmware
 */

static void
bfa_lps_send_logout(struct bfa_lps_s *lps)
{
 struct bfi_lps_logout_req_s *m;

 m = bfa_reqq_next(lps->bfa, lps->reqq);
 WARN_ON(!m);

 bfi_h2i_set(m->mh, BFI_MC_LPS, BFI_LPS_H2I_LOGOUT_REQ,
  bfa_fn_lpu(lps->bfa));

 m->fw_tag = lps->fw_tag;
 m->port_name = lps->pwwn;
 bfa_reqq_produce(lps->bfa, lps->reqq, m->mh);
}

/*
 * send n2n pid set request to firmware
 */

static void
bfa_lps_send_set_n2n_pid(struct bfa_lps_s *lps)
{
 struct bfi_lps_n2n_pid_req_s *m;

 m = bfa_reqq_next(lps->bfa, lps->reqq);
 WARN_ON(!m);

 bfi_h2i_set(m->mh, BFI_MC_LPS, BFI_LPS_H2I_N2N_PID_REQ,
  bfa_fn_lpu(lps->bfa));

 m->fw_tag = lps->fw_tag;
 m->lp_pid = lps->lp_pid;
 bfa_reqq_produce(lps->bfa, lps->reqq, m->mh);
}

/*
 * Indirect login completion handler for non-fcs
 */

static void
bfa_lps_login_comp_cb(void *arg, bfa_boolean_t complete)
{
 struct bfa_lps_s *lps = arg;

 if (!complete)
  return;

 if (lps->fdisc)
  bfa_cb_lps_fdisc_comp(lps->bfa->bfad, lps->uarg, lps->status);
 else
  bfa_cb_lps_flogi_comp(lps->bfa->bfad, lps->uarg, lps->status);
}

/*
 * Login completion handler -- direct call for fcs, queue for others
 */

static void
bfa_lps_login_comp(struct bfa_lps_s *lps)
{
 if (!lps->bfa->fcs) {
  bfa_cb_queue(lps->bfa, &lps->hcb_qe, bfa_lps_login_comp_cb,
   lps);
  return;
 }

 if (lps->fdisc)
  bfa_cb_lps_fdisc_comp(lps->bfa->bfad, lps->uarg, lps->status);
 else
  bfa_cb_lps_flogi_comp(lps->bfa->bfad, lps->uarg, lps->status);
}

/*
 * Indirect logout completion handler for non-fcs
 */

static void
bfa_lps_logout_comp_cb(void *arg, bfa_boolean_t complete)
{
 struct bfa_lps_s *lps = arg;

 if (!complete)
  return;

 if (lps->fdisc)
  bfa_cb_lps_fdisclogo_comp(lps->bfa->bfad, lps->uarg);
 else
  bfa_cb_lps_flogo_comp(lps->bfa->bfad, lps->uarg);
}

/*
 * Logout completion handler -- direct call for fcs, queue for others
 */

static void
bfa_lps_logout_comp(struct bfa_lps_s *lps)
{
 if (!lps->bfa->fcs) {
  bfa_cb_queue(lps->bfa, &lps->hcb_qe, bfa_lps_logout_comp_cb,
   lps);
  return;
 }
 if (lps->fdisc)
  bfa_cb_lps_fdisclogo_comp(lps->bfa->bfad, lps->uarg);
}

/*
 * Clear virtual link completion handler for non-fcs
 */

static void
bfa_lps_cvl_event_cb(void *arg, bfa_boolean_t complete)
{
 struct bfa_lps_s *lps = arg;

 if (!complete)
  return;

 /* Clear virtual link to base port will result in link down */
 if (lps->fdisc)
  bfa_cb_lps_cvl_event(lps->bfa->bfad, lps->uarg);
}

/*
 * Received Clear virtual link event --direct call for fcs,
 * queue for others
 */

static void
bfa_lps_cvl_event(struct bfa_lps_s *lps)
{
 if (!lps->bfa->fcs) {
  bfa_cb_queue(lps->bfa, &lps->hcb_qe, bfa_lps_cvl_event_cb,
   lps);
  return;
 }

 /* Clear virtual link to base port will result in link down */
 if (lps->fdisc)
  bfa_cb_lps_cvl_event(lps->bfa->bfad, lps->uarg);
}



/*
 *  lps_public BFA LPS public functions
 */


u32
bfa_lps_get_max_vport(struct bfa_s *bfa)
{
 if (bfa_ioc_devid(&bfa->ioc) == BFA_PCI_DEVICE_ID_CT)
  return BFA_LPS_MAX_VPORTS_SUPP_CT;
 else
  return BFA_LPS_MAX_VPORTS_SUPP_CB;
}

/*
 * Allocate a lport srvice tag.
 */

struct bfa_lps_s  *
bfa_lps_alloc(struct bfa_s *bfa)
{
 struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa);
 struct bfa_lps_s *lps = NULL;

 bfa_q_deq(&mod->lps_free_q, &lps);

 if (lps == NULL)
  return NULL;

 list_add_tail(&lps->qe, &mod->lps_active_q);

 bfa_sm_set_state(lps, bfa_lps_sm_init);
 return lps;
}

/*
 * Free lport service tag. This can be called anytime after an alloc.
 * No need to wait for any pending login/logout completions.
 */

void
bfa_lps_delete(struct bfa_lps_s *lps)
{
 bfa_sm_send_event(lps, BFA_LPS_SM_DELETE);
}

/*
 * Initiate a lport login.
 */

void
bfa_lps_flogi(struct bfa_lps_s *lps, void *uarg, u8 alpa, u16 pdusz,
 wwn_t pwwn, wwn_t nwwn, bfa_boolean_t auth_en)
{
 lps->uarg = uarg;
 lps->alpa = alpa;
 lps->pdusz = pdusz;
 lps->pwwn = pwwn;
 lps->nwwn = nwwn;
 lps->fdisc = BFA_FALSE;
 lps->auth_en = auth_en;
 bfa_sm_send_event(lps, BFA_LPS_SM_LOGIN);
}

/*
 * Initiate a lport fdisc login.
 */

void
bfa_lps_fdisc(struct bfa_lps_s *lps, void *uarg, u16 pdusz, wwn_t pwwn,
 wwn_t nwwn)
{
 lps->uarg = uarg;
 lps->alpa = 0;
 lps->pdusz = pdusz;
 lps->pwwn = pwwn;
 lps->nwwn = nwwn;
 lps->fdisc = BFA_TRUE;
 lps->auth_en = BFA_FALSE;
 bfa_sm_send_event(lps, BFA_LPS_SM_LOGIN);
}


/*
 * Initiate a lport FDSIC logout.
 */

void
bfa_lps_fdisclogo(struct bfa_lps_s *lps)
{
 bfa_sm_send_event(lps, BFA_LPS_SM_LOGOUT);
}

u8
bfa_lps_get_fwtag(struct bfa_s *bfa, u8 lp_tag)
{
 struct bfa_lps_mod_s    *mod = BFA_LPS_MOD(bfa);

 return BFA_LPS_FROM_TAG(mod, lp_tag)->fw_tag;
}

/*
 * Return lport services tag given the pid
 */

u8
bfa_lps_get_tag_from_pid(struct bfa_s *bfa, u32 pid)
{
 struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa);
 struct bfa_lps_s *lps;
 int   i;

 for (i = 0, lps = mod->lps_arr; i < mod->num_lps; i++, lps++) {
  if (lps->lp_pid == pid)
   return lps->bfa_tag;
 }

 /* Return base port tag anyway */
 return 0;
}


/*
 * return port id assigned to the base lport
 */

u32
bfa_lps_get_base_pid(struct bfa_s *bfa)
{
 struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa);

 return BFA_LPS_FROM_TAG(mod, 0)->lp_pid;
}

/*
 * Set PID in case of n2n (which is assigned during PLOGI)
 */

void
bfa_lps_set_n2n_pid(struct bfa_lps_s *lps, uint32_t n2n_pid)
{
 bfa_trc(lps->bfa, lps->bfa_tag);
 bfa_trc(lps->bfa, n2n_pid);

 lps->lp_pid = n2n_pid;
 bfa_sm_send_event(lps, BFA_LPS_SM_SET_N2N_PID);
}

/*
 * LPS firmware message class handler.
 */

void
bfa_lps_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
{
 union bfi_lps_i2h_msg_u msg;

 bfa_trc(bfa, m->mhdr.msg_id);
 msg.msg = m;

 switch (m->mhdr.msg_id) {
 case BFI_LPS_I2H_LOGIN_RSP:
  bfa_lps_login_rsp(bfa, msg.login_rsp);
  break;

 case BFI_LPS_I2H_LOGOUT_RSP:
  bfa_lps_logout_rsp(bfa, msg.logout_rsp);
  break;

 case BFI_LPS_I2H_CVL_EVENT:
  bfa_lps_rx_cvl_event(bfa, msg.cvl_event);
  break;

 default:
  bfa_trc(bfa, m->mhdr.msg_id);
  WARN_ON(1);
 }
}

static void
bfa_fcport_aen_post(struct bfa_fcport_s *fcport, enum bfa_port_aen_event event)
{
 struct bfad_s *bfad = (struct bfad_s *)fcport->bfa->bfad;
 struct bfa_aen_entry_s  *aen_entry;

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

 aen_entry->aen_data.port.ioc_type = bfa_get_type(fcport->bfa);
 aen_entry->aen_data.port.pwwn = fcport->pwwn;

 /* Send the AEN notification */
 bfad_im_post_vendor_event(aen_entry, bfad, ++fcport->bfa->bfa_aen_seq,
      BFA_AEN_CAT_PORT, event);
}

/*
 * FC PORT state machine functions
 */

static void
bfa_fcport_sm_uninit(struct bfa_fcport_s *fcport,
   enum bfa_fcport_sm_event event)
{
 bfa_trc(fcport->bfa, event);

 switch (event) {
 case BFA_FCPORT_SM_START:
  /*
 * Start event after IOC is configured and BFA is started.
 */

  fcport->use_flash_cfg = BFA_TRUE;

  if (bfa_fcport_send_enable(fcport)) {
   bfa_trc(fcport->bfa, BFA_TRUE);
   bfa_sm_set_state(fcport, bfa_fcport_sm_enabling);
  } else {
   bfa_trc(fcport->bfa, BFA_FALSE);
   bfa_sm_set_state(fcport,
     bfa_fcport_sm_enabling_qwait);
  }
  break;

 case BFA_FCPORT_SM_ENABLE:
  /*
 * Port is persistently configured to be in enabled state. Do
 * not change state. Port enabling is done when START event is
 * received.
 */

  break;

 case BFA_FCPORT_SM_DISABLE:
  /*
 * If a port is persistently configured to be disabled, the
 * first event will a port disable request.
 */

  bfa_sm_set_state(fcport, bfa_fcport_sm_disabled);
  break;

 case BFA_FCPORT_SM_HWFAIL:
  bfa_sm_set_state(fcport, bfa_fcport_sm_iocdown);
  break;

 default:
  bfa_sm_fault(fcport->bfa, event);
 }
}

static void
bfa_fcport_sm_enabling_qwait(struct bfa_fcport_s *fcport,
    enum bfa_fcport_sm_event event)
{
 char pwwn_buf[BFA_STRING_32];
 struct bfad_s *bfad = (struct bfad_s *)fcport->bfa->bfad;
 bfa_trc(fcport->bfa, event);

 switch (event) {
 case BFA_FCPORT_SM_QRESUME:
  bfa_sm_set_state(fcport, bfa_fcport_sm_enabling);
  bfa_fcport_send_enable(fcport);
  break;

 case BFA_FCPORT_SM_STOP:
  bfa_reqq_wcancel(&fcport->reqq_wait);
  bfa_sm_set_state(fcport, bfa_fcport_sm_stopped);
  break;

 case BFA_FCPORT_SM_ENABLE:
  /*
 * Already enable is in progress.
 */

  break;

 case BFA_FCPORT_SM_DISABLE:
  /*
 * Just send disable request to firmware when room becomes
 * available in request queue.
 */

  bfa_sm_set_state(fcport, bfa_fcport_sm_disabled);
  bfa_reqq_wcancel(&fcport->reqq_wait);
  bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL,
    BFA_PL_EID_PORT_DISABLE, 0, "Port Disable");
  wwn2str(pwwn_buf, fcport->pwwn);
  BFA_LOG(KERN_INFO, bfad, bfa_log_level,
   "Base port disabled: WWN = %s\n", pwwn_buf);
  bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISABLE);
  break;

 case BFA_FCPORT_SM_LINKUP:
 case BFA_FCPORT_SM_LINKDOWN:
  /*
 * Possible to get link events when doing back-to-back
 * enable/disables.
 */

  break;

 case BFA_FCPORT_SM_HWFAIL:
  bfa_reqq_wcancel(&fcport->reqq_wait);
  bfa_sm_set_state(fcport, bfa_fcport_sm_iocdown);
  break;

 case BFA_FCPORT_SM_FAA_MISCONFIG:
  bfa_fcport_reset_linkinfo(fcport);
  bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISCONNECT);
  bfa_sm_set_state(fcport, bfa_fcport_sm_faa_misconfig);
  break;

 default:
  bfa_sm_fault(fcport->bfa, event);
 }
}

static void
bfa_fcport_sm_enabling(struct bfa_fcport_s *fcport,
      enum bfa_fcport_sm_event event)
{
 char pwwn_buf[BFA_STRING_32];
 struct bfad_s *bfad = (struct bfad_s *)fcport->bfa->bfad;
 bfa_trc(fcport->bfa, event);

 switch (event) {
 case BFA_FCPORT_SM_FWRSP:
 case BFA_FCPORT_SM_LINKDOWN:
  bfa_sm_set_state(fcport, bfa_fcport_sm_linkdown);
  break;

 case BFA_FCPORT_SM_LINKUP:
  bfa_fcport_update_linkinfo(fcport);
  bfa_sm_set_state(fcport, bfa_fcport_sm_linkup);

  WARN_ON(!fcport->event_cbfn);
  bfa_fcport_scn(fcport, BFA_PORT_LINKUP, BFA_FALSE);
  break;

 case BFA_FCPORT_SM_ENABLE:
  /*
 * Already being enabled.
 */

  break;

 case BFA_FCPORT_SM_DISABLE:
  if (bfa_fcport_send_disable(fcport))
   bfa_sm_set_state(fcport, bfa_fcport_sm_disabling);
  else
   bfa_sm_set_state(fcport,
      bfa_fcport_sm_disabling_qwait);

  bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL,
    BFA_PL_EID_PORT_DISABLE, 0, "Port Disable");
  wwn2str(pwwn_buf, fcport->pwwn);
  BFA_LOG(KERN_INFO, bfad, bfa_log_level,
   "Base port disabled: WWN = %s\n", pwwn_buf);
  bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISABLE);
  break;

 case BFA_FCPORT_SM_STOP:
  bfa_sm_set_state(fcport, bfa_fcport_sm_stopped);
  break;

 case BFA_FCPORT_SM_HWFAIL:
  bfa_sm_set_state(fcport, bfa_fcport_sm_iocdown);
  break;

 case BFA_FCPORT_SM_FAA_MISCONFIG:
  bfa_fcport_reset_linkinfo(fcport);
  bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISCONNECT);
  bfa_sm_set_state(fcport, bfa_fcport_sm_faa_misconfig);
  break;

 default:
  bfa_sm_fault(fcport->bfa, event);
 }
}

static void
bfa_fcport_sm_linkdown(struct bfa_fcport_s *fcport,
      enum bfa_fcport_sm_event event)
{
 struct bfi_fcport_event_s *pevent = fcport->event_arg.i2hmsg.event;
 char pwwn_buf[BFA_STRING_32];
 struct bfad_s *bfad = (struct bfad_s *)fcport->bfa->bfad;

 bfa_trc(fcport->bfa, event);

 switch (event) {
 case BFA_FCPORT_SM_LINKUP:
  bfa_fcport_update_linkinfo(fcport);
  bfa_sm_set_state(fcport, bfa_fcport_sm_linkup);
  WARN_ON(!fcport->event_cbfn);
  bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL,
    BFA_PL_EID_PORT_ST_CHANGE, 0, "Port Linkup");
  if (!bfa_ioc_get_fcmode(&fcport->bfa->ioc)) {

   bfa_trc(fcport->bfa,
    pevent->link_state.attr.vc_fcf.fcf.fipenabled);
   bfa_trc(fcport->bfa,
    pevent->link_state.attr.vc_fcf.fcf.fipfailed);

   if (pevent->link_state.attr.vc_fcf.fcf.fipfailed)
    bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL,
     BFA_PL_EID_FIP_FCF_DISC, 0,
     "FIP FCF Discovery Failed");
   else
    bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL,
     BFA_PL_EID_FIP_FCF_DISC, 0,
     "FIP FCF Discovered");
  }

  bfa_fcport_scn(fcport, BFA_PORT_LINKUP, BFA_FALSE);
  wwn2str(pwwn_buf, fcport->pwwn);
  BFA_LOG(KERN_INFO, bfad, bfa_log_level,
   "Base port online: WWN = %s\n", pwwn_buf);
  bfa_fcport_aen_post(fcport, BFA_PORT_AEN_ONLINE);

  /* If QoS is enabled and it is not online, send AEN */
  if (fcport->cfg.qos_enabled &&
      fcport->qos_attr.state != BFA_QOS_ONLINE)
   bfa_fcport_aen_post(fcport, BFA_PORT_AEN_QOS_NEG);
  break;

 case BFA_FCPORT_SM_LINKDOWN:
  /*
 * Possible to get link down event.
 */

  break;

 case BFA_FCPORT_SM_ENABLE:
  /*
 * Already enabled.
 */

  break;

 case BFA_FCPORT_SM_DISABLE:
  if (bfa_fcport_send_disable(fcport))
   bfa_sm_set_state(fcport, bfa_fcport_sm_disabling);
  else
   bfa_sm_set_state(fcport,
      bfa_fcport_sm_disabling_qwait);

  bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL,
    BFA_PL_EID_PORT_DISABLE, 0, "Port Disable");
  wwn2str(pwwn_buf, fcport->pwwn);
  BFA_LOG(KERN_INFO, bfad, bfa_log_level,
   "Base port disabled: WWN = %s\n", pwwn_buf);
  bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISABLE);
  break;

 case BFA_FCPORT_SM_STOP:
  bfa_sm_set_state(fcport, bfa_fcport_sm_stopped);
  break;

 case BFA_FCPORT_SM_HWFAIL:
  bfa_sm_set_state(fcport, bfa_fcport_sm_iocdown);
  break;

 case BFA_FCPORT_SM_FAA_MISCONFIG:
  bfa_fcport_reset_linkinfo(fcport);
  bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISCONNECT);
  bfa_sm_set_state(fcport, bfa_fcport_sm_faa_misconfig);
  break;

 default:
  bfa_sm_fault(fcport->bfa, event);
 }
}

static void
bfa_fcport_sm_linkup(struct bfa_fcport_s *fcport,
 enum bfa_fcport_sm_event event)
{
 char pwwn_buf[BFA_STRING_32];
 struct bfad_s *bfad = (struct bfad_s *)fcport->bfa->bfad;

 bfa_trc(fcport->bfa, event);

 switch (event) {
 case BFA_FCPORT_SM_ENABLE:
  /*
 * Already enabled.
 */

  break;

 case BFA_FCPORT_SM_DISABLE:
  if (bfa_fcport_send_disable(fcport))
   bfa_sm_set_state(fcport, bfa_fcport_sm_disabling);
  else
   bfa_sm_set_state(fcport,
      bfa_fcport_sm_disabling_qwait);

  bfa_fcport_reset_linkinfo(fcport);
  bfa_fcport_scn(fcport, BFA_PORT_LINKDOWN, BFA_FALSE);
  bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL,
    BFA_PL_EID_PORT_DISABLE, 0, "Port Disable");
  wwn2str(pwwn_buf, fcport->pwwn);
  BFA_LOG(KERN_INFO, bfad, bfa_log_level,
   "Base port offline: WWN = %s\n", pwwn_buf);
  bfa_fcport_aen_post(fcport, BFA_PORT_AEN_OFFLINE);
  BFA_LOG(KERN_INFO, bfad, bfa_log_level,
   "Base port disabled: WWN = %s\n", pwwn_buf);
  bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISABLE);
  break;

 case BFA_FCPORT_SM_LINKDOWN:
  bfa_sm_set_state(fcport, bfa_fcport_sm_linkdown);
  bfa_fcport_reset_linkinfo(fcport);
  bfa_fcport_scn(fcport, BFA_PORT_LINKDOWN, BFA_FALSE);
  bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL,
    BFA_PL_EID_PORT_ST_CHANGE, 0, "Port Linkdown");
  wwn2str(pwwn_buf, fcport->pwwn);
  if (BFA_PORT_IS_DISABLED(fcport->bfa)) {
   BFA_LOG(KERN_INFO, bfad, bfa_log_level,
    "Base port offline: WWN = %s\n", pwwn_buf);
   bfa_fcport_aen_post(fcport, BFA_PORT_AEN_OFFLINE);
  } else {
   BFA_LOG(KERN_ERR, bfad, bfa_log_level,
    "Base port (WWN = %s) "
    "lost fabric connectivity\n", pwwn_buf);
   bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISCONNECT);
  }
  break;

 case BFA_FCPORT_SM_STOP:
  bfa_sm_set_state(fcport, bfa_fcport_sm_stopped);
  bfa_fcport_reset_linkinfo(fcport);
  wwn2str(pwwn_buf, fcport->pwwn);
  if (BFA_PORT_IS_DISABLED(fcport->bfa)) {
   BFA_LOG(KERN_INFO, bfad, bfa_log_level,
    "Base port offline: WWN = %s\n", pwwn_buf);
   bfa_fcport_aen_post(fcport, BFA_PORT_AEN_OFFLINE);
  } else {
   BFA_LOG(KERN_ERR, bfad, bfa_log_level,
    "Base port (WWN = %s) "
    "lost fabric connectivity\n", pwwn_buf);
   bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISCONNECT);
  }
  break;

 case BFA_FCPORT_SM_HWFAIL:
  bfa_sm_set_state(fcport, bfa_fcport_sm_iocdown);
  bfa_fcport_reset_linkinfo(fcport);
  bfa_fcport_scn(fcport, BFA_PORT_LINKDOWN, BFA_FALSE);
  wwn2str(pwwn_buf, fcport->pwwn);
  if (BFA_PORT_IS_DISABLED(fcport->bfa)) {
   BFA_LOG(KERN_INFO, bfad, bfa_log_level,
    "Base port offline: WWN = %s\n", pwwn_buf);
   bfa_fcport_aen_post(fcport, BFA_PORT_AEN_OFFLINE);
  } else {
   BFA_LOG(KERN_ERR, bfad, bfa_log_level,
    "Base port (WWN = %s) "
    "lost fabric connectivity\n", pwwn_buf);
   bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISCONNECT);
  }
  break;

 case BFA_FCPORT_SM_FAA_MISCONFIG:
  bfa_fcport_reset_linkinfo(fcport);
  bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISCONNECT);
  bfa_sm_set_state(fcport, bfa_fcport_sm_faa_misconfig);
  break;

 default:
  bfa_sm_fault(fcport->bfa, event);
 }
}

static void
bfa_fcport_sm_disabling_qwait(struct bfa_fcport_s *fcport,
     enum bfa_fcport_sm_event event)
{
 bfa_trc(fcport->bfa, event);

 switch (event) {
 case BFA_FCPORT_SM_QRESUME:
  bfa_sm_set_state(fcport, bfa_fcport_sm_disabling);
  bfa_fcport_send_disable(fcport);
  break;

 case BFA_FCPORT_SM_STOP:
  bfa_sm_set_state(fcport, bfa_fcport_sm_stopped);
  bfa_reqq_wcancel(&fcport->reqq_wait);
  break;

 case BFA_FCPORT_SM_ENABLE:
  bfa_sm_set_state(fcport, bfa_fcport_sm_toggling_qwait);
  break;

 case BFA_FCPORT_SM_DISABLE:
  /*
 * Already being disabled.
 */

  break;

 case BFA_FCPORT_SM_LINKUP:
 case BFA_FCPORT_SM_LINKDOWN:
  /*
 * Possible to get link events when doing back-to-back
 * enable/disables.
 */

  break;

 case BFA_FCPORT_SM_HWFAIL:
  bfa_sm_set_state(fcport, bfa_fcport_sm_iocfail);
  bfa_reqq_wcancel(&fcport->reqq_wait);
  break;

 case BFA_FCPORT_SM_FAA_MISCONFIG:
  bfa_fcport_reset_linkinfo(fcport);
  bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISCONNECT);
  bfa_sm_set_state(fcport, bfa_fcport_sm_faa_misconfig);
  break;

 default:
  bfa_sm_fault(fcport->bfa, event);
 }
}

static void
bfa_fcport_sm_toggling_qwait(struct bfa_fcport_s *fcport,
     enum bfa_fcport_sm_event event)
{
 bfa_trc(fcport->bfa, event);

 switch (event) {
 case BFA_FCPORT_SM_QRESUME:
  bfa_sm_set_state(fcport, bfa_fcport_sm_disabling);
  bfa_fcport_send_disable(fcport);
  if (bfa_fcport_send_enable(fcport))
   bfa_sm_set_state(fcport, bfa_fcport_sm_enabling);
  else
   bfa_sm_set_state(fcport,
      bfa_fcport_sm_enabling_qwait);
  break;

 case BFA_FCPORT_SM_STOP:
  bfa_sm_set_state(fcport, bfa_fcport_sm_stopped);
  bfa_reqq_wcancel(&fcport->reqq_wait);
  break;

 case BFA_FCPORT_SM_ENABLE:
  break;

 case BFA_FCPORT_SM_DISABLE:
  bfa_sm_set_state(fcport, bfa_fcport_sm_disabling_qwait);
  break;

 case BFA_FCPORT_SM_LINKUP:
 case BFA_FCPORT_SM_LINKDOWN:
  /*
 * Possible to get link events when doing back-to-back
 * enable/disables.
 */

  break;

 case BFA_FCPORT_SM_HWFAIL:
  bfa_sm_set_state(fcport, bfa_fcport_sm_iocfail);
  bfa_reqq_wcancel(&fcport->reqq_wait);
  break;

 default:
  bfa_sm_fault(fcport->bfa, event);
 }
}

static void
bfa_fcport_sm_disabling(struct bfa_fcport_s *fcport,
      enum bfa_fcport_sm_event event)
{
 char pwwn_buf[BFA_STRING_32];
 struct bfad_s *bfad = (struct bfad_s *)fcport->bfa->bfad;
 bfa_trc(fcport->bfa, event);

 switch (event) {
 case BFA_FCPORT_SM_FWRSP:
  bfa_sm_set_state(fcport, bfa_fcport_sm_disabled);
  break;

 case BFA_FCPORT_SM_DISABLE:
  /*
 * Already being disabled.
 */

  break;

 case BFA_FCPORT_SM_ENABLE:
  if (bfa_fcport_send_enable(fcport))
   bfa_sm_set_state(fcport, bfa_fcport_sm_enabling);
  else
   bfa_sm_set_state(fcport,
      bfa_fcport_sm_enabling_qwait);

  bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL,
    BFA_PL_EID_PORT_ENABLE, 0, "Port Enable");
  wwn2str(pwwn_buf, fcport->pwwn);
  BFA_LOG(KERN_INFO, bfad, bfa_log_level,
   "Base port enabled: WWN = %s\n", pwwn_buf);
  bfa_fcport_aen_post(fcport, BFA_PORT_AEN_ENABLE);
  break;

 case BFA_FCPORT_SM_STOP:
  bfa_sm_set_state(fcport, bfa_fcport_sm_stopped);
  break;

 case BFA_FCPORT_SM_LINKUP:
 case BFA_FCPORT_SM_LINKDOWN:
  /*
 * Possible to get link events when doing back-to-back
 * enable/disables.
 */

  break;

 case BFA_FCPORT_SM_HWFAIL:
  bfa_sm_set_state(fcport, bfa_fcport_sm_iocfail);
  break;

 default:
  bfa_sm_fault(fcport->bfa, event);
 }
}

static void
bfa_fcport_sm_disabled(struct bfa_fcport_s *fcport,
      enum bfa_fcport_sm_event event)
{
 char pwwn_buf[BFA_STRING_32];
 struct bfad_s *bfad = (struct bfad_s *)fcport->bfa->bfad;
 bfa_trc(fcport->bfa, event);

 switch (event) {
 case BFA_FCPORT_SM_START:
  /*
 * Ignore start event for a port that is disabled.
 */

  break;

 case BFA_FCPORT_SM_STOP:
  bfa_sm_set_state(fcport, bfa_fcport_sm_stopped);
  break;

 case BFA_FCPORT_SM_ENABLE:
  if (bfa_fcport_send_enable(fcport))
   bfa_sm_set_state(fcport, bfa_fcport_sm_enabling);
  else
   bfa_sm_set_state(fcport,
      bfa_fcport_sm_enabling_qwait);

  bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL,
    BFA_PL_EID_PORT_ENABLE, 0, "Port Enable");
  wwn2str(pwwn_buf, fcport->pwwn);
  BFA_LOG(KERN_INFO, bfad, bfa_log_level,
   "Base port enabled: WWN = %s\n", pwwn_buf);
  bfa_fcport_aen_post(fcport, BFA_PORT_AEN_ENABLE);
  break;

 case BFA_FCPORT_SM_DISABLE:
  /*
 * Already disabled.
 */

  break;

 case BFA_FCPORT_SM_HWFAIL:
  bfa_sm_set_state(fcport, bfa_fcport_sm_iocfail);
  break;

 case BFA_FCPORT_SM_DPORTENABLE:
  bfa_sm_set_state(fcport, bfa_fcport_sm_dport);
  break;

 case BFA_FCPORT_SM_DDPORTENABLE:
  bfa_sm_set_state(fcport, bfa_fcport_sm_ddport);
  break;

 default:
  bfa_sm_fault(fcport->bfa, event);
 }
}

static void
bfa_fcport_sm_stopped(struct bfa_fcport_s *fcport,
    enum bfa_fcport_sm_event event)
{
 bfa_trc(fcport->bfa, event);

 switch (event) {
 case BFA_FCPORT_SM_START:
  if (bfa_fcport_send_enable(fcport))
   bfa_sm_set_state(fcport, bfa_fcport_sm_enabling);
  else
   bfa_sm_set_state(fcport,
      bfa_fcport_sm_enabling_qwait);
  break;

 default:
  /*
 * Ignore all other events.
 */

  ;
 }
}

/*
 * Port is enabled. IOC is down/failed.
 */

static void
bfa_fcport_sm_iocdown(struct bfa_fcport_s *fcport,
    enum bfa_fcport_sm_event event)
{
 bfa_trc(fcport->bfa, event);

 switch (event) {
 case BFA_FCPORT_SM_START:
  if (bfa_fcport_send_enable(fcport))
   bfa_sm_set_state(fcport, bfa_fcport_sm_enabling);
  else
   bfa_sm_set_state(fcport,
      bfa_fcport_sm_enabling_qwait);
  break;

 default:
  /*
 * Ignore all events.
 */

  ;
 }
}

/*
 * Port is disabled. IOC is down/failed.
 */

static void
bfa_fcport_sm_iocfail(struct bfa_fcport_s *fcport,
    enum bfa_fcport_sm_event event)
{
 bfa_trc(fcport->bfa, event);

 switch (event) {
 case BFA_FCPORT_SM_START:
  bfa_sm_set_state(fcport, bfa_fcport_sm_disabled);
  break;

 case BFA_FCPORT_SM_ENABLE:
  bfa_sm_set_state(fcport, bfa_fcport_sm_iocdown);
  break;

 default:
  /*
 * Ignore all events.
 */

  ;
 }
}

static void
--> --------------------

--> maximum size reached

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

Messung V0.5
C=96 H=99 G=97

¤ Dauer der Verarbeitung: 0.15 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.